Genians Security Center recently confirmed the continued distribution of compiled Python-based malware. This threat shows strong similarities to the attack scenario and TTPs identified in the report "Python Backdoor Threat Analysis Following an AI Deepfake Impersonation Campaign", published on May 11, 2026.
This attack was carried out through a spear phishing email titled "[Urgent] Security Check Notice Regarding Repeated One-Time Password (OTP) Generation". The sender was displayed as "Microsoft Account Team", making the email appear as though it had been sent by an official account security team. However, the actual sender domain was confirmed to be unrelated to Microsoft’s official domains.
The attack email contained a message impersonating an MS account security alert. It was designed to create concern over possible account compromise and OTP abuse, thereby inducing the recipient to execute the attachment. The email body instructed the recipient to refer to the attached advisory. However, the actual attachment was not an HWP document, but a ZIP archive that contained a malicious LNK file.
The email body stated that abnormal activity involving repeated generation of one-time passwords had recently been detected in the recipient’s MS account, and described this as a security threat associated with another person’s login attempt or a phishing attack. It also advised the user not to enter any authentication code they had not requested and to change their password immediately, while directing them to refer to the attached security advisory for detailed information on threat types and response methods.
This structure is a social engineering technique designed to make the recipient mistake the email for a legitimate security alert. Analysis shows that the threat actor used a ZIP archive disguised as a security advisory to lure the recipient into executing the malicious LNK file. This initiated a multi-stage infection flow that proceeds through PowerShell and Batch commands and ultimately installs the compiled Python-based NarwhalRAT.
[Figure 1-1] Attack Flow
This report provides an in-depth analysis of NarwhalRAT malware, which is assessed to primarily target Korean users. The malware integrates various information-stealing capabilities, including keylogging, screen capture, USB data collection, and remote command execution. It also has a manually operated structure in which the threat actor selectively activates each function through C2 commands.
The malware uses "naverwhale" as the name of its working directory and assigns the Hidden and System attributes to the created folder to enhance stealth. This is interpreted as an attempt to disguise itself as Naver Whale, a browser widely used in Korea, and suggests that Korean users are the primary targets of the attack.
Based on these characteristics, threat analysis researchers at Genians Security Center named the malware NarwhalRAT. The name combines the string "naverwhale" with "Narwhal", a whale species that inhabits the Arctic Ocean and is known for its long tusk. In particular, the symbolism of the "Arctic" was considered in relation to a possible connection with a state-sponsored threat actor, while the sharp tusk that resembles a horn naturally aligns with the spear phishing characteristics of this targeted attack.
NarwhalRAT also differs from RoKRAT, a representative malware family associated with the existing APT37 group, in that its concealment method and targeting of Korean users are directly reflected in the strings and behavioral structure within the code.
From a C2 infrastructure perspective, the malware uses Korean websites, including "daehoat[.]com" and "novel21[.]co.kr", as primary communication relays, while also implementing communication functionality based on the pCloud cloud storage API. In particular, pCloud-specific routines that process the "folderid" and "auth" parameters were identified within the code. This indicates that the malware was designed to use a legitimate cloud service as a secondary C2 channel in the form of a Dead-drop Resolver.
Dead-drop Resolver is a term derived from the concept of a "dead drop", a secret delivery location used in traditional espionage activities. It refers to a technique in which a threat actor does not embed the actual C2 server address directly in the malware, but instead delivers it through information hidden in an intermediary server, cloud storage, or similar location. In other words, the malware first connects to an intermediate relay such as "daehoat[.]com" to retrieve the actual C2 server or additional communication information, such as an access token, and then uses that information to communicate with a legitimate cloud service such as pCloud. This approach not only allows the communication to blend in with normal web traffic, but also enables the threat actor to flexibly change the actual C2 information and operate the infrastructure without modifying the malware. In addition, because the final C2 server is not immediately exposed during analysis, this structure makes detection and blocking more difficult.
This structure appears to be intended to maintain command delivery and data exchange through a cloud-based route even if the primary communication channel is blocked. It is also assessed to be designed to reduce direct exposure of pCloud access information and increase the concealment and operational stability of the threat infrastructure.
Accordingly, this report provides a detailed technical analysis of the execution flow, environmental conditions, encryption scheme, C2 communication structure, command processing, and information collection capabilities, along with the identified IoC information.
The initial infection begins when the recipient clicks the attachment in the spear phishing email. When the recipient executes the attachment in the email, the file "Cybersecurity Advisory Notice (Regarding One-Time Password Abuse).zip" is downloaded through the relay "fe01.co[.]kr".
The downloaded ZIP archive contains a file named "Cybersecurity Advisory Notice (Regarding One-Time Password Abuse).lnk", which is disguised as the same security advisory.
[Figure 2-1] Spear Phishing Email Screen
This method uses a filename designed to appear as a legitimate document and induce user execution. The LNK file then serves as the initial execution vector that leads to the installation of additional malware through the execution of PowerShell and Batch commands in later stages.
The internal command line of the LNK file is structured to hide the actual execution command by using CMD environment variable substring substitution.
First, it sets a random string variable named "a805aae" and dynamically restores commands such as powershell, ExecutionPolicy, Bypass, Command, Start-Process, and "curl.exe" by extracting specific characters in the format "%a805aae:~position,1%". This is an obfuscation technique designed to evade static detection and simple string-based analysis.
After deobfuscation, the LNK file executes PowerShell through "cmd.exe /k" and bypasses the PowerShell execution policy using the "-ExecutionPolicy Bypass" option. It then copies "C:\Windows\System32\curl.exe" and uses it for additional downloads, but simply concatenates the destination path in the form of "$env:TEMP+'uARKK20.exe'".
Because this process does not include the path separator (\), the actual file is not created as "%TEMP%\uARKK20.exe", but as "C:\Users\<USER>\AppData\Local\TempuARKK20.exe". This pattern is similar to the one observed in the report "Python Backdoor Threat Analysis Following an AI Deepfake Impersonation Campaign".
The use of a copied "curl.exe", a legitimate default Windows tool, is interpreted as an attempt to bypass command-line detection by security products or obscure execution traces. The technique of copying "curl.exe" and using it to download additional files can be classified as a Living Off The Land Binaries (LoLBins) technique, which abuses legitimate tools built into the system.
[Figure 2-2] Internal Arguments of the LNK File
The LNK file sends requests containing the "contents" and "board" parameters to the relay "webhostingkorea[.]com" and sequentially downloads two files.
The first downloaded file is saved as "%TEMP%\Cybersecurity Advisory Notice (Regarding One-Time Password Abuse).hwp". This file is assessed to serve as a decoy document that is opened to appear as the security advisory expected by the user.
The second downloaded file is saved as "%TEMP%\KHjWFcsE.bat". PowerShell then executes this BAT file in a hidden window. Therefore, this BAT file is assessed to be the actual next-stage execution script responsible for installing and executing the subsequent malware.
The "KHjWFcsE.bat" file downloaded through LNK execution also obfuscates commands by using CMD environment variable substring substitution. The batch file first declares a string variable named "a1373ro" and then reconstructs the actual commands by combining the required characters in the format "%a1373ro:~position,1%".
After deobfuscation, the BAT file uses "curl" to download "Python-3.10.0-embed-amd64.zip" from the official Python website to the path "C:\Users\Public\temp012.zip". It then creates the directory "C:\Users\Public\AccountPictures\UserInerfacePicture" and extracts the downloaded Python embedded package to that path using the "tar -xf" command.
After extraction, it deletes the existing "Python.exe" file and renames "Pythonw.exe" to "userscreen.exe". This is interpreted as an attempt to prevent a console window from being displayed when Python is executed. The temporary file "temp012.zip" is then deleted.
In the next step, it uses "curl" again to download an additional file from the relay "webhostingkorea[.]com". The downloaded file is saved under the name "config.cat" in the "UserInerfacePicture" path. Although the extension is disguised as ".cat", analysis confirmed that it is not a legitimate Windows security catalog file, but a compiled file in Python bytecode (.pyc) format.
[Figure 2-3] Decrypted Batch File Commands
This infection flow is interpreted as a strategy in which the threat actor does not directly include a malicious execution environment, but dynamically downloads the official Python embedded package from an external source to disguise the activity as a legitimate software installation.
In particular, by using the official Python distribution server, the threat actor increases the likelihood that the traffic will be recognized as normal by network security products. The actual malicious payload is delivered separately in a later stage, minimizing the likelihood of detection during the initial infection phase.
Across the overall attack process, the threat actor actively uses legitimate Windows tools such as "curl", "tar", and "schtasks", while combining PowerShell execution policy bypass and CMD environment variable substring substitution. This indicates an attempt to evade both static analysis and command-line-based detection.
In particular, disguising the final payload with the ".cat" extension is interpreted as an attempt to make it appear as a legitimate Windows catalog file, while it is actually configured to execute a compiled Python script based on Python bytecode.
For persistence, the malware also uses scheduled tasks ("schtasks") instead of common techniques such as registering a malicious service or adding a Run key. It also renames the executable to "userscreen.exe" to disguise it as a legitimate user interface component. This design makes it difficult for security personnel or users to immediately recognize the malicious nature of the file, even when checking the process lists and file paths.
As a result, the threat actor combines legitimate system tools, official distribution servers, legitimate-looking file extensions, and the Windows scheduled task feature to make the entire attack chain closely mimic legitimate system activity as possible. Through this approach, the actor likely seeks operational advantages by maintaining stealth for an extended period after initial intrusion, while also retaining the flexibility to replace or update additional Python-based payloads as needed.
"KHjWFcsE.bat" registers a Windows scheduled task to persistently execute the subsequent payload, "config.cat". The created task name is "MicrosoftUserInterfacePicturesUpdateTackMachine", which is disguised to appear as a legitimate Microsoft user interface or account picture-related task.
This scheduled task is configured to run repeatedly at one-minute intervals, utilizing "C:\Users\Public\AccountPictures\UserInerfacePicture\userscreen.exe" to execute the "config.cat" file in the same path.
"userscreen.exe" is the renamed "Pythonw.exe" file from the Python embedded package, and "config.cat" is a Python bytecode file with its extension disguised to appear as a legitimate Windows security catalog file.
Through this structure, the threat actor establishes persistence so that the subsequent Python payload based on "config.cat" is executed periodically, even if the user does not manually execute the file.
Furthermore, the execution path and filenames are configured to resemble Windows account picture and user interface components, making it difficult for both general users and administrators to immediately identify their malicious nature during manual inspection.
|
C:\Users\Public\AccountPictures\UserInerfacePicture\userscreen.exe C:\Users\Public\AccountPictures\UserInerfacePicture\config.cat |
[Table 2-1] Scheduled Task Execution Command
The header of the "config.cat" file contains magic bytes used in Python bytecode files. The beginning of the file includes the following header value: "6F 0D 0D 0A".
[Figure 2-4] Header Structure of the "config.cat" File
This matches the header structure used by the Python interpreter to identify compiled Python bytecode in .pyc format.
In addition, the header is followed by the value "0xE3", which indicates a Python code object. This shows that the file is not a simple data file or a legitimate Windows security catalog (.cat) file, but a compiled Python script based on Python bytecode.
In other words, the threat actor disguised the actual Python-based malicious payload with the ".cat" extension to make users mistake it for a legitimate system file and to make immediate identification more difficult during security analysis.
Decompilation of the file confirmed that it contains Python-based logic that leads to subsequent malicious activities, including additional payload loading, execution environment configuration, and preparation for C2 communication. Therefore, "config.cat" is not a simple configuration file, but a subsequent Python payload that is periodically executed through the scheduled task.
When executed, "config.cat" operates as a backdoor loader that connects to the "webhostingkorea[.]com" C2, receives command code, and executes it in memory. It then downloads and executes additional BAT files according to commands delivered by the C2.
Through this structure, the threat actor secures an operational framework that allows functions to be dynamically expanded or new malicious modules to be flexibly deployed even after infection.
[Figure 2-5] Decompiled Python Code
The decompiled results showed that the code inside "config.cat" applies multiple layers of string obfuscation to avoid exposing key strings directly. In typical Python code, module names, C2 addresses, and HTTP header names can be identified in plaintext. However, this file constructs strings character by character using the "chr()" function or places strings in reverse order and restores them using the "[::-1]" operation. This structure makes it difficult to identify key functions and communication information through static analysis tools or simple string searches alone.
The code also does not use common statements such as "import os" or "import base64" when loading required modules. Instead, it indirectly accesses the "__import__" function through getattr(__builtins__, "__import__"). This approach reduces explicit import statements in the code, making it difficult for threat analysts to quickly identify the modules being used. It is interpreted as an intentional obfuscation technique designed to hide the actual functionality of the malware.
Analysis confirmed that the code uses the "os", "base64", "urllib.request", "urllib.parse", "sys", and "io" modules. These modules are used for collecting the username, Base64 encoding and decoding, C2 communication, generating POST data, controlling standard output, and collecting execution results, respectively. In particular, key strings such as the C2 URL, "Cookie", "User-Agent", "data", and "utf-8" are also hidden using the same method. This shows that the file is not a simple configuration file, but a Python-based backdoor loader equipped with functions for receiving remote commands and transmitting execution results.
After "config.cat" was executed, Genians Security Center confirmed and successfully collected evidence that a subsequent file was created as "AccountConfig.cat" in the path "C:\ProgramData\GoogleDriveUpdateCheck".
The path and filename are configured to appear as a Google Drive update or account configuration file. This is assessed as an attempt to reduce user suspicion by disguising the file as a legitimate software component and to make identification more difficult during security inspection.
Threat analysts at Genians Security Center paid particular attention to the change in file size. While the initial "config.cat" file was 7,318 bytes, the subsequently created "AccountConfig.cat" file was confirmed to be 7,467,018 bytes. This suggests that the file is likely a subsequent component that goes beyond a simple configuration file and contains additional malicious functions or a large payload.
Although it is disguised with the same ".cat" extension, this file was also confirmed to be structured as a compiled Python script based on Python bytecode. Notably, it contains large-scale obfuscated code consisting of more than approximately 33,000 lines.
Internally, the file contains a Base64-encoded payload and a SHA-256-based key derivation routine. Here, the Key derivation function (KDF) does not use a single fixed string or secret value as-is. Instead, it generates a keystream of the required length by combining the salt and counter values. In other words, it expands a short seed value into a byte sequence long enough to restore the payload.
Analysis confirmed that the first 16 bytes of the Base64-decoded data are used as the salt, while the hardcoded string "aHAnLLtQrP8Ce" serves as the seed or key material. This routine sequentially concatenates the seed, salt, and a 4-byte big-endian counter, then repeatedly applies SHA-256 hashing to generate a keystream matching the length of the encrypted payload. It then restores the original payload by performing a byte-by-byte XOR operation between the generated keystream and the encrypted payload.
This is assessed to be a custom XOR decryption structure similar to a counter-based KDF.
[Figure 2-6] XOR Decryption Process
After XOR decryption, the MZ signature was identified at the beginning of the restored data. This confirms that the final PE-based payload is restored in memory.
The compile timestamp of the PE EXE was also confirmed as 2026-04-30 18:07:49 (KST). This indicates that the malware was built in the evening hours and suggests that the threat actor continued development and testing even after regular business hours.
Once decryption is complete, the malware directly calls Windows functions using Python’s "ctypes" module. In simple terms, it executes Windows APIs from within the Python code and runs the decrypted payload directly in memory without saving it as a separate file. This technique is generally classified as fileless execution or in-memory execution.
"ctypes" is one of Python’s standard libraries and allows Python code to directly call C-based functions contained in DLLs.
In other words, it enables the code to go beyond simple Python script functionality and directly control low-level functions of the Windows operating system. A typical Python program mainly performs high-level operations such as file handling, string processing, and network communication. However, when "ctypes" is used, the code can directly call functions inside system DLLs such as "kernel32.dll" and perform low-level operations such as memory manipulation and process control.
First, the malware calls the "VirtualAlloc()" API to allocate a new memory region. This process does not simply create space to store data. It also grants Read, Write, and Execute permissions to that memory region at the same time. This is commonly referred to as RWX memory and corresponds to the preparation stage for loading decrypted code into memory and executing it immediately.
Legitimate programs can also allocate memory, but creating memory that has both write and execute permissions is uncommon in typical applications. Therefore, memory allocation using the "PAGE_EXECUTE_READWRITE" attribute is known as one of the representative behaviors frequently observed in shellcode execution or in-memory malware loading.
The malware then uses the "RtlMoveMemory()" API to copy the decrypted payload directly into the previously allocated memory region. In other words, instead of creating and executing an executable file on disk, it places the executable code directly in memory. As a result, if a security product focuses only on file creation events or disk-based execution traces, the actual malicious payload may not be detected.
In the final stage, the malware uses "ctypes.CFUNCTYPE()" to convert the memory address where the payload is stored into an executable function and then calls it directly. In simple terms, it treats a specific memory address as the starting point of a function and transfers the execution flow to that location.
As a result, the final payload is not saved as a new executable file or executed as a separate process. Instead, it runs directly inside the memory of the currently running Python process. Therefore, it may appear externally as a legitimate Python-based program, while the actual malicious activity is performed inside memory.
[Figure 2-7] Python ctypes-based In-Memory Payload Execution Flow (Fileless)
This structure not only makes file-based detection difficult, but can also make it difficult to obtain the final payload from disk during analysis, which can work to the threat actor’s advantage.
From this point, this report analyzes the internal behavior of the final PE payload executed in memory, namely the NarwhalRAT main component. This payload was implemented not as a simple downloader, but as a multifunctional RAT (Remote Access Trojan) structure that integrates multiple information-stealing capabilities and remote control capabilities.
In the initial execution stage, the malware performs preparation steps such as environment checks, mutex creation, working directory configuration, and global setting initialization. First, the malware checks CPUID-based Hypervisor Vendor ID strings to determine whether it is running in VMware, VirtualBox, or another virtualized environment.
The code contains comparisons with the strings "VMwareVMware" and "VBoxVBoxVBox", as well as " lrpepyh vr".
In particular, the value " lrpepyh vr" is mentioned as an alternative vendor string used to identify Parallels environments. It accounts for cases where Parallels returns the string "prl hyperv" as " lrpepyh vr" due to endianness handling inconsistencies.
Therefore, this routine performs an Anti-VM function designed to detect not only VMware and VirtualBox, but also Parallels Desktop-based virtualization environments that run Windows on macOS.
|
while ( v9 ); v10 = strcmp((const char *)&v17, "VMwareVMware"); if ( v10 ) v10 = v10 < 0 ? -1 : 1; if ( !v10 ) break; v11 = strcmp((const char *)&v17, " lrpepyh vr"); if ( v11 ) v11 = v11 < 0 ? -1 : 1; if ( !v11 ) return 3; v12 = strcmp((const char *)&v17, "VBoxVBoxVBox"); |
[Table 2-2] Anti-VM Function
This is a representative anti-analysis technique that allows the malware to operate normally in a general user environment, while intentionally minimizing its behavior or interfering with analysis in virtual environments used for malware analysis. This technique is often used by APT malware and is intended to prevent actual malicious behavior from being collected in automated sandbox analysis environments.
After the environment check is complete, the malware creates a mutex to prevent duplicate execution. In the code, the string "i5zJH9FL10cVd3sSW9eyWWErPJ" is used as the mutex name. If the same mutex already exists, the process terminates immediately.
|
wcscpy(Name, L"i5zJH9FL10cVd3sSW9eyWWErPJ"); hMutex = CreateMutexW(nullptr, 0, Name); if ( !hMutex || GetLastError() == 183 ) return 0; |
[Table 2-3] Mutex Creation
This is a typical RAT structure designed to prevent conflicts caused by multiple instances running on the same system or situations that increase the user’s awareness of abnormal behavior.
The malware then creates the "%APPDATA%\naverwhale" path and assigns the Hidden and System attributes to it. This folder serves as a working directory for storing various types of collected data, including keylogs, screen capture images, microphone recordings, and files waiting to be uploaded.
In particular, the name "naverwhale" is designed to mimic the Naver Whale browser, which is commonly used by Korean users. This increases the likelihood that users or administrators will mistake the path for a legitimate browser-related folder even if they inspect the file path.
|
strcpy(v10, "naverwhale"); strcat(Destination, v10); FileAttributesA = GetFileAttributesA(Destination); if ( FileAttributesA == -1 || (FileAttributesA & 0x10) == 0 ) { CreateDirectoryA(Destination, nullptr); SetFileAttributesA(Destination, 6u); |
[Table 2-4] Creation of the "naverwhale" Directory
During analysis, it was also confirmed that NarwhalRAT does not use a simple fixed structure, but is designed to allow its settings to be changed dynamically at runtime. Internally, it contains a global configuration area of approximately 1,700 bytes. This area stores the C2 address, communication password, feature activation flags, upload paths, pCloud-related settings, and other configuration values.
In particular, the C2 address can be dynamically changed through the "cmserver:", "caserver:", and "cdserver:" commands.
|
strcpy(v115, "chcommpwd:"); v4 = sub_404EF0(v2, v115); strcpy(Source, "Change Comm Pwd Arg is not correct"); if ( v4 ) { v5 = (const char *)(v4 + 10); if ( v4 == -10 ) { v6 = Source; LABEL_28: sub_451D40(v6); sub_451A80(a1); return 11; } if ( !strlen((const char *)(v4 + 10)) || (v7 = strlen(v5), v7 > 0x1E) ) { v6 = v147; strcpy(v147, "Comm Pwd is Empty or too Long"); goto LABEL_28; } v8 = dword_499970 + 260; v105 = (char *)(dword_499970 + 260); *(_OWORD *)(dword_499970 + 260) = 0; *(_OWORD *)(v8 + 16) = 0; sub_404FA0(v7, v105, "%s", (char)v5); strcpy(v153, "Ch Comm Pwd Completed: "); sub_451D40(v153); v9 = (char *)(dword_499970 + 260); goto LABEL_33; } strcpy(v126, "cmserver:"); v10 = sub_404EF0(v2, v126); strcpy(v164, "Ch Man Server Arg is not correct"); |
[Table 2-5] Dynamic Modification of C2 Addresses or Communication Passwords
NarwhalRAT also implements a configuration persistence structure to maintain not only execution persistence but also the operational settings themselves.
If an ".ent" configuration file does not already exist, the malware uses "SHGetFolderPathA()" to obtain the "%LOCALAPPDATA%" path and then creates the "\Microsoft\Internet Explorer" directory under it.
It then generates a six-character random string, combines it with the ".ent" extension, and creates an encrypted configuration file in the format "%LOCALAPPDATA%\Microsoft\Internet Explorer\<random>.ent".
|
if ( SHGetFolderPathA(nullptr, 28, nullptr, 0, pszPath) < 0 ) return 0; v50 = 0; v48 = 0; v49 = 0; strcpy(v47, "\\Microsoft\\Internet Explorer"); v47[29] = 0; v0 = strlen(v47) + 1; v1 = &v42; while ( *++v1 ) ; qmemcpy(v1, v47, v0); FileAttributesA = GetFileAttributesA(pszPath); if ( FileAttributesA == -1 || (FileAttributesA & 0x10) == 0 ) SHCreateDirectoryExA(nullptr, pszPath, nullptr); v51 = 0; v52 = 0; v53 = 0; v54 = 0; sub_4050F0(&v51, 6); v44 = 'tne'; v46 = 0; strcpy(Format, "%s\\%s.%s"); v45 = 0; |
[Table 2-6] Creation of the ".ent" File
This path is disguised to appear as a legitimate Internet Explorer configuration file. Through this structure, the threat actor likely designed the malware to retain previous operational settings and C2 infrastructure information even after a system reboot.
The malware organizes its current operating status, communication password-related values, management C2 server address, data server address, alternative server address, and feature activation status into a single configuration data block. Specifically, whether major information-stealing capabilities such as keylogging, screen capture, and microphone recording are enabled is managed through separate flag values. When a specific function is enabled, that status is also stored in the configuration file.
This configuration data is not stored in plaintext but is encrypted using AES-128 based on Windows CryptoAPI. The internal hardcoded string used for encrypting the ".ent" configuration file was identified as "!221aeAescde##2aefseseppl^12". This string is not used directly as the AES key, but is derived into an AES-128 key through a SHA-256 hash and the "CryptDeriveKey()" process.
The ".ent" configuration file described above is not simply used for storage. It is used to restore the operational state after the malware is executed again. During the startup phase, the malware first checks whether an ".ent" file already exists. If the file exists, it decrypts the internal data and reloads it into the in-memory operational configuration area.
The decrypted configuration data includes the communication password, management C2 server address, data server address, alternative server address, and feature activation flags. It also restores the status of information-stealing capabilities such as keylogging, screen capture, and microphone recording that were enabled during the previous execution.
In contrast, in an initial infection environment where no ".ent" configuration file exists, the malware uses the default operational settings hardcoded within it. Analysis confirmed that the following C2 addresses were included as default values inside NarwhalRAT.
Taken together, these structures indicate that NarwhalRAT is not a RAT that simply relies on a single C2 server, but is equipped with a multi-channel operation model that combines local configuration file restoration with multiple C2 relays. In particular, if an existing configuration file is present, it restores the previous operational state as-is. Even if no configuration file exists, it is designed to immediately resume communication through the default C2 infrastructure hardcoded inside the malware.
The internal code also implements a secondary communication routine based on the pCloud API. Dedicated code that directly processes the "folderid=" and "auth=" parameters, as well as branching logic based on the "api.pcloud[.]com" string, was identified. This shows that the malware uses a legitimate cloud service as a secondary C2 channel in the form of a dead-drop resolver.
This is interpreted as an operational stability strategy intended to continue command delivery and data exfiltration through alternative routes even if a specific C2 server is blocked or seized. From a network perspective, this communication also appears as access to legitimate websites and cloud services, making it difficult for conventional security products to identify it as malicious communication.
After initialization and C2 configuration restoration are complete, NarwhalRAT interprets commands delivered from the C2 server through its internal command processing routine. It operates by comparing the beginning of the received string with specific command prefixes, then executing the corresponding function or changing related flag values.
This method does not parse the entire command through a complex protocol. Instead, it branches functions based on string prefixes such as "startkcap:", "startscap:", "usb2local:", "cmd:", and "cmdadm:". Therefore, the C2 server can activate specific functions or execute remote commands on the infected system by delivering relatively simple command strings.
The command system identified during analysis can be categorized into remote command execution, file upload and download, screen capture, keylogging, microphone recording, USB collection, remote clicking, status inquiry, and termination functions. For example, the screen capture function operates by changing the activation flag to "1" when the "startscap:" command is received, and disabling it again when the "endscap:" command is received.
|
rcpy(SubStr, "startscap:"); if ( sub_404EF0((char *)(v1 + 24), SubStr) ) { *(_BYTE *)(dword_499970 + 1104) = '1'; return 14; } strcpy(v121, "endscap:"); if ( sub_404EF0(v2, v121) ) { *(_BYTE *)(dword_499970 + 1104) = '0'; return 14; } strcpy(v130, "startscaph:"); if ( sub_404EF0(v2, v130) ) { *(_BYTE *)(dword_499970 + 1110) = '1'; return 14; } strcpy(v124, "endscaph:"); if ( sub_404EF0(v2, v124) ) { *(_BYTE *)(dword_499970 + 1110) = '0'; return 14; } strcpy(v118, "startlcap:"); if ( sub_404EF0(v2, v118) ) { *(_BYTE *)(dword_499970 + 1107) = '1'; return 14; |
[Table 2-7] Information-Stealing Command Routine
A command control system based on more than 30 command prefixes was implemented, designed to remotely control various functions, including screen capture, keylogging, microphone recording, file upload and download, USB collection, remote command execution, and C2 configuration changes.
[Figure 2-8] Prefix-based Command Control System
Notably, the USB and removable storage device collection function is performed through the "usb2local:" command.
This routine dynamically generates a command string to copy the target collection path under "C:\Users\Public\<random>" and internally uses the "xcopy /s /e /y /c /q /h /b" options.
This function can be viewed as an intermediate collection, or staging, structure that copies files from a USB device or a specified path to a local temporary collection path without drawing the user’s attention, before exfiltrating them during a later upload stage.
NarwhalRAT does more than simply record keystrokes. It also implements a function to collect active window and running window information to identify the user’s current working environment. The code shows an API call flow involving "GetForegroundWindow()", "GetWindowTextA()", "GetWindowThreadProcessId()", and "GetWindowPlacement()". Through this structure, the malware collects information such as whether a window is currently active, the window title, the process name, and the window state.
However, it does not record all window information as-is during collection. Instead, it filters out unnecessary system windows and input assistance processes.
Specifically, entries containing the strings "KakaoTalkEdgeWnd", "KakaoTalkShadowWnd", "Program Manager", "Microsoft Text Input Application", and "MSCTFIME UI", as well as the processes "ApplicationFrameHost.exe" and "TextInputHost.exe", are excluded from collection.
|
sub_404FA0(v7, (char *)v27, "%s", (char)v6); if ( GetWindowTextLengthA(TopWindow) ) { GetWindowTextA(TopWindow, (LPSTR)v26, 260); if ( !strstr((const char *)v26, "KakaoTalkEdgeWnd") && !strstr((const char *)v26, "KakaoTalkShadowWnd") && !strstr((const char *)v26, "Program Manager") && !strstr((const char *)v26, "Microsoft Text Input Application") && !strstr((const char *)v26, "MSCTFIME UI") && !strstr((const char *)v27, "ApplicationFrameHost.exe") && !strstr((const char *)v27, "TextInputHost.exe") ) { v31 = 0; v30 = 658803; strcpy(v32, "Focus"); v8 = v32; |
[Table 2-8] Exclusion Condition Filtering
The filtering appears intended to reduce noise in the collected data by removing irrelevant auxiliary windows or operating system components during the window list collection process. In particular, the fact that KakaoTalk-related identifier strings are handled separately suggests that the malware was likely developed with the Korean user environment in mind.
The window information generated by this function can also be stored together with screen capture results. When combined with keystroke data collected by a separate keylogging function, it can reveal which program or service the user was using. For example, by analyzing active window information and input data from web browsers, messengers, business systems, financial services, and other applications together, the threat actor can track user behavior more precisely.
The collected keystroke data is not immediately transmitted externally. Instead, it is temporarily stored under the internal working directory "%APPDATA%\naverwhale" and then transmitted sequentially by the upload routine. This method is similar to a typical RAT-style information-stealing technique that spreads network traffic over time and makes real-time detection more difficult.
During the analysis of this case, multiple similarities were identified with the report published by Genians Security Center on May 11, 2025. In the publicly disclosed case, a Python-based multi-stage malware infection chain was used, with key characteristics including LNK shortcut files, BAT-based obfuscation, a Python loader, and a multi-C2 structure.
The NarwhalRAT case also showed a high level of similarity to the previously disclosed case in terms of the initial infection flow, execution structure, obfuscation techniques, Python-based payload configuration, scheduled task persistence, and C2 operation method. In particular, the overlap was not limited to simple IoC reuse. A substantial portion of the attacker’s development habits and operational methods, or TTPs, were also found to match.
First, the creation method of the HWP decoy document used in the spear phishing stage was highly similar to that of the previous case. The "Cybercrime Reporting System (ECRM).hwp" document, which impersonated an investigator from the Korean National Police Agency, and the "Cybersecurity Advisory Notice (Regarding One-Time Password Abuse).hwp" document used in this attack were both confirmed to have the same last saved by value, "Lailey". In addition, comparison with the legitimate HWP document showed that only the title had been changed, while the overall body structure and content remained largely the same.
Furthermore, the title structures of the two documents also followed a similar pattern.
This suggests that the same threat actor likely reused a spear phishing decoy document by replacing only the title based on an existing legitimate document.
[Figure 3-1] Comparison of Decoy Documents
The initial execution structure based on LNK shortcut files also showed a high level of similarity. In both cases, string obfuscation using environment variable substitution was applied inside the batch files, and the Link Flags and Obfuscation Pattern were highly similar in terms of LNK structure. Furthermore, both cases used the same method of changing the BAT filename and the "curl.exe" filename to random strings.
[Figure 3-2] Comparison of LNK Settings
Furthermore, parts of the C2 server infrastructure overlapped. Although the BAT filename was changed from "GuFLjO7q.bat" to "KHjWFcsE.bat", the overall execution flow and obfuscation structure maintained the same pattern.
The payload structure also matched the previous case in many aspects. Both cases used a Python payload compiled into bytecode (.pyc) and disguised with the ".cat" extension, while implementing persistence through the Task Scheduler. The string obfuscation structure and decryption flow inside the Python bytecode also showed a highly similar form.
The use of pCloud infrastructure is also one of the characteristics repeatedly mentioned in past APT37-related activity. In particular, it shares similarities with a typical multi-C2 operation method designed to maintain operational continuity even after the primary communication channel is blocked.
NarwhalRAT also showed a structure strongly tailored to the Korean user environment, including the use of the "naverwhale" working directory, handling of KakaoTalk-related windows, C2 servers based on Korean websites, and HWP decoy documents.
Taken together, this case shares a high level of similarity with the previously disclosed Python backdoor attack case. Commonalities were identified particularly in Korean-targeted social engineering techniques, the Python-based loader structure, environment variable-based BAT obfuscation, a manually operated RAT structure, and the pCloud-based auxiliary communication structure.
|
No |
Analysis Area |
Correlation Evidence |
|
1 |
Overall Campaign Structure |
This case showed a high level of similarity to the Python-based backdoor threat case disclosed by Genians Security Center on May 11, 2025. |
|
2 |
Spear-phishing Lure Document |
The "Cybercrime Reporting System (ECRM).hwp" document used to impersonate an investigator from the Korean National Police Agency and the "Cybersecurity Advisory Notice (Regarding One-Time Password Abuse).hwp" document used in this attack were both confirmed to have the same last saved by value, "Lailey". |
|
3 |
Decoy Document Reuse Pattern |
In the HWP documents, only the title had been changed, while the overall body structure and content remained largely the same. This indicates that the threat actor reused a spear phishing decoy document by replacing only the title of an existing legitimate document. |
|
4 |
Social Engineering Theme |
The case used social engineering themes targeting Korean users, such as security alerts, and the overall configuration pattern was also highly similar. |
|
5 |
LNK Obfuscation Structure |
String obfuscation based on environment variable substitution was used inside the BAT file. In addition, the LNK structure itself matched in terms of Link Flags, Extra Blocks, Argument Shape, and Obfuscation Pattern. |
|
6 |
BAT / Utility Naming Pattern |
The BAT filename and "curl.exe" filename were also confirmed to be generated in the same random string format. |
|
7 |
C2 Infrastructure Similarity |
The case used Korean website-based C2 infrastructure, and some C2 server infrastructure overlapped or showed a highly similar operational method. |
|
8 |
Python Loader Payload Structure |
It used a Python payload compiled into bytecode (.pyc) and disguised with the ".cat" extension, and the Python loader-based execution structure and string obfuscation method were the same. |
|
9 |
Persistence Technique |
Persistence through the Task Scheduler was also implemented in the same way. |
|
10 |
Python Bytecode Obfuscation |
The string obfuscation and decryption routines inside the Python bytecode followed the same pattern, and the structure linked to the environment variable-based BAT execution flow also matched. |
|
11 |
Multi-C2 Operation |
In addition to general HTTP-based C2, a structure using multiple communication paths was identified. This is similar to an APT37-related operational method designed to maintain operational continuity even after a single infrastructure channel is blocked. |
|
12 |
pCloud Auxiliary Channel |
A pCloud-based auxiliary communication structure was also identified. This method of operating an auxiliary channel based on a legitimate cloud service is one of the characteristics repeatedly mentioned in past APT37-related activity. |
|
13 |
Korea-focused Targeting |
A structure strongly tailored to the Korean user environment was identified, including the use of the "naverwhale" working directory, handling of KakaoTalk-related windows, Korean website-based C2, and Korean-language HWP decoy documents. |
|
14 |
TTP-level Similarity |
Overall, a high level of TTP similarity was identified in the Python-based loader structure, environment variable-based BAT obfuscation, manually operated RAT structure, and pCloud-based auxiliary communication structure. |
[Table 3-1] Similarity Comparison Table
4. Conclusion
This report analyzed the full infection flow and internal operational structure of NarwhalRAT, a Python-based RAT malware assessed to primarily target Korean users.
Analysis confirmed that this threat goes beyond a simple information-stealing malware and has an advanced, manually operated RAT structure that integrates spear phishing-based initial access, a multi-stage download structure, BAT-based string obfuscation, a Python loader, in-memory execution (fileless execution), AES-based encrypted communication, a multi-C2 operational structure, and selective information-stealing capabilities.
In the initial infection stage, the threat actor used an LNK shortcut file inside a ZIP archive to induce user execution. The BAT script then dynamically restored the actual commands by using an environment variable substitution-based string reconstruction technique. During this process, PowerShell, "curl.exe", and the Python runtime were sequentially invoked, forming a multi-stage infection flow that ultimately downloads a Python payload compiled into bytecode and disguised with the ".cat" extension.
In particular, NarwhalRAT was confirmed to create an encrypted configuration file and store the management C2 server, data server, alternative server, communication password, and feature activation status using AES-128-based encryption. Through this structure, the threat actor likely designed the malware to restore the previous operational state and enabled collection functions even after the infected system is rebooted.
From a command processing perspective, a remote command system based on more than 30 prefixes was implemented. It included functions such as keylogging, screen capture, microphone recording, file upload and download, USB collection, remote command execution, remote clicking, and C2 configuration changes.
Overall, NarwhalRAT is assessed to be an advanced RAT malware that integrates a Python-based multi-stage loader, an in-memory execution structure, a multi-C2 operational framework, and selective information collection functions. This threat also shares a high level of structural and operational similarity with previously disclosed Python-based APT37 attack cases, and is likely to continue being used in similar variants in the future.
Therefore, organizations need to strengthen not only IOC-based detection, but also behavior-based detection for activities such as BAT-based environment variable obfuscation after LNK execution, abnormal memory execution based on the Python Runtime, RWX memory allocation, scheduled task creation, and abnormal pCloud-based communication.
This threat was confirmed to be a complex attack that combines multiple stages after spear phishing-based initial access targeting Korean users, including LNK shortcut files, BAT-based string obfuscation, a Python loader, in-memory (fileless) execution, Task Scheduler-based persistence, and a multi-C2 communication structure.
Notably, the final payload uses a Python ctypes-based in-memory execution structure and takes the form of a manually operated RAT that selectively activates keylogging, screen capture, microphone recording, and USB collection functions through C2 commands. Because of these characteristics, it is difficult to identify the full attack flow using a security framework focused only on simple file-based detection.
Therefore, an EDR (Endpoint Detection and Response)-centered integrated response framework is required to visualize the entire attack chain, encompassing initial access, execution, persistence, in-memory payload activity, C2 communication, and information-stealing activities, and to analyze and block threat activity based on correlations between events.
"Genian Insights E" is an integrated endpoint security platform based on a single agent. For Python-based multi-stage attacks such as NarwhalRAT, it provides the following behavior-based detection and response capabilities.
EDR can track and analyze the entire attack flow based on behavior, and can identify the following activities observed in this case.
Furthermore, Genian Insights E does not simply provide process creation events. It enables integrated analysis of parent-child process relationships (Process Tree), command lines, memory behavior, file creation, network connection events, and other related telemetry.
In addition, the LnkTarget information allows analysts to verify the original content of the obfuscated BAT file referenced by the shortcut (LNK) file, enabling analysis from the initial execution stage. Analysts can trace the actual commands executed after BAT obfuscation, providing visibility into the overall attack flow.
[Figure 4-1] Detection of a Suspicious LNK File Through EDR
The Attack Storyline feature of Genian Insights E allows analysts to easily identify, based on the command line, which batch file commands were executed by the LNK file.
This information can be useful for security administrators when analyzing the threat flow through EDR.
[Figure 4-2] powershell.exe Command Line Lookup Screen
When an obfuscated BAT command is executed through "cmd.exe", the command line executed by the subsequent "powershell.exe" process can be reviewed. This command abuses "curl.exe", a legitimate Windows utility, as a LoLBin, copies it to the Local path above TEMP under the name "TEMPuARKK20.exe", and then executes it. Through this method, the malware attempts to conceal its behavior by disguising the copied "curl.exe" as a different executable.
It then connects to the "webhostingkorea[.]com" C2 server, saves a legitimate HWP document to the TEMP path as a decoy file, and executes it. It also downloads and executes an additional batch file, "KHjWFcsE.bat", to perform follow-up malicious activities.
[Figure 4-3] C2 Connection Through PowerShell and curl.exe
Using this behavior-based analysis information, EDR administrators can intuitively trace the attack chain from the initial intrusion and execution to the download and execution of additional payloads. This enables them to not only identify the threat quickly and accurately but also comprehensively analyze the threat actor’s activity and its impact, allowing them to establish an effective response plan.
[Figure 4-4] Activity Screen of Pythonw.exe Disguised as userscreen.exe
The execution command line of "userscreen.exe" (i.e., Pythonw.exe), which is registered as a scheduled task for persistence, can be reviewed intuitively. This makes it easier to identify the malware’s execution path and behavior. The communication flow with the C2 server can also be observed.
3715092aa00f380cefe8b4d2eddb7d08
7cef19f9c4480adac0cd4702ff98f46c
7eb9cee1f696727752169f25cf79a338
b6b0602310bb2d4360c52685119aac1b
crwellfood[.]com
daehoat[.]com
fe01.co[.]kr
novel21.co[.]kr
webhostingkorea[.]com
121.254.222[.]10
121.254.222[.]80
211.239.157[.]126
218.150.78[.]198
218.150.78[.]231
61.100.9[.]206