Unraveling Not AZORult but Koi Loader: A Precursor to Koi Stealer

eSentire’s TRU investigated a phased infection initially attributed to AZORult but determined to involve a C++/.NET-era Koi Loader that stages and deploys a Koi Stealer. The campaign uses phishing via a CAPTCHA-protected Google Sites page, a .lnk→.bat→PowerShell chain with AMSI bypass, anti-VM checks, process injection, XOR-decrypted payloads, and HTTP-based C2 exfiltration. #KoiLoader #KoiStealer #AZORult #eSentire

Keypoints

  • Detection: eSentire TRU found a stealer infection late March 2024 originally linked to AZORult but analyzed as Koi Loader/Koi Stealer variants.
  • Initial vector: phishing email pointing to a Google Sites page with CAPTCHA that serves a ZIP (chasebank_statement_mar.zip) containing a malicious .lnk shortcut.
  • Execution chain: .lnk downloads a .bat via curl to %TEMP%, .bat launches a JS (agent.js) that self-replicates to %programdata%, sets a mutex and creates scheduled tasks to maintain persistence.
  • Download and execution: PowerShell scripts (agent1.ps1, agent3.ps1) perform AMSI bypass, fetch a C++ Koi loader and shellcode which allocates memory and transfers execution to the loader.
  • Loader capabilities: XOR decryption of embedded payloads, language and anti-VM/sandbox checks (display adapters, file/name heuristics, memory thresholds), mutex generation and scheduled-task persistence, and process injection.
  • Koi Stealer: sd2.ps1/sd4.ps1 decrypt the final stealer with XOR, collect browser cookies/history/credentials, generate Curve25519 keys, GZip then XOR-encrypt harvested data, and exfiltrate via HTTP POST to C2 (example IP 91.202.233[.]209).

MITRE Techniques

  • [T1566.002] Phishing – Attack began with a phishing email containing an embedded link to a Google Sites page that served the payload (‘phishing email about an unauthorized transaction on the sender’s debit card containing an embedded link’).
  • [T1204.002] User Execution: Malicious File – The delivered ZIP contains a shortcut file that initiates the chain (‘the ZIP archive includes a shortcut file (.lnk) named “chasebank_statement_mar.lnk” … which downloads the next stage payload … using curl’).
  • [T1053.005] Scheduled Task/Job – Persistence is achieved by creating scheduled tasks to run the dropped agent.js (‘establishes persistence on the system by creating a Scheduled Task named “0BAduEnQZG9POyK”’).
  • [T1059.001] Command and Scripting Interpreter: PowerShell – PowerShell is used to fetch and execute follow-on payloads (‘The download batch file … contains the PowerShell command … fetching another payload … “WLXUL6LWXQPB.js”’).
  • [T1059.003] Command and Scripting Interpreter: Windows Command Shell – Batch scripts are used to download and launch subsequent stages (‘downloads the next stage payload from the server, “m8hHxtkVLYPw.bat”’).
  • [T1562.001] Impair Defenses – AMSI Bypass – A PowerShell one-liner performs AMSI bypass to evade runtime scanning (‘agent1.ps1 … contains a one-liner command that is responsible for AMSI bypass’).
  • [T1055] Process Injection – Loader supports injecting payloads into explorer.exe or certutil.exe or executing from %TEMP% (‘Performs process injection into either explorer.exe or certutil.exe … or writes the payload to %TEMP% folder and directly executes it’).
  • [T1497.001] Virtualization/Sandbox Evasion: System Checks – The loader performs multiple anti-VM and environment checks (display adapter strings, VirtualBox files, file-name/size heuristics, memory thresholds) (‘uses EnumDisplayDevicesW … searching for device strings that match known virtual machine display adapters’).
  • [T1027] Obfuscated Files or Information – Payloads and final binaries are XOR-obfuscated in resources and decrypted at runtime (‘final loader payload is extracted and decrypted using XOR from the resource section’).
  • [T1071.001] Application Layer Protocol: Web Protocols (HTTP/S) – C2 communication and payload retrieval occur over HTTP POST requests to C2 servers (‘sends the following to the C2 … 101|{GUID}|VoYGkc5R|pNL/…’).
  • [T1005] Data from Local System – Koi Stealer gathers browser cookies, history and login information from the host (‘Koi Stealer copies sensitive data, including cookies, history, and login information, to the %AppData% folder’).
  • [T1041] Exfiltration Over C2 Channel – Collected data is compressed, encrypted with a shared secret and sent to C2 via HTTP POST (public key + delimiter + encrypted data) (‘compresses the harvested data using GZip and encrypts it with XOR, employing the shared secret … sends the data to the C2 server’).

Indicators of Compromise

  • [File hash] Payload hashes seen in samples – chasebank_statement_mar.zip MD5: 8751223ced55a2079e876b893917a0f3, WLXUL6LWXQPB.js MD5: 48c7fd278ac590c9bd896ad9c7850c3a (and additional MD5s for agent1/agent3/sd2/sd4).
  • [Filenames] Malicious filenames observed – chasebank_statement_mar.lnk, agent.js (JS self-replication filename copied to %programdata%).
  • [Scheduled Task] Persistence artifacts – Scheduled Task names “0BAduEnQZG9POyK” and “Firefox Default Browser Agent 458046B0AF4A39CB”.
  • [Domain/IP] Command-and-control and key retrieval – hxxp://91.202.233[.]209/index.php?id=$guid&subid=px8eIkut (C2/key URL), plus payload hosting on Google Sites (CAPTCHA-protected page serving ZIP).
  • [Mutex] Runtime mutex identifier – ‘7z2LKLJ62LPA’ used by the JS/agent to prevent multiple instances.

The technical execution begins with a phishing link to a CAPTCHA-protected Google Sites page that serves a ZIP containing a .lnk shortcut; that shortcut downloads a .bat (via curl) into %TEMP% which then calls a JavaScript stage (agent.js). The JS attempts self-replication into %programdata% as agent.js, establishes a mutex, hides the file, and creates scheduled tasks to maintain persistence while invoking PowerShell to retrieve additional scripts and payloads.

PowerShell stages (agent1.ps1 and agent3.ps1) perform an AMSI bypass, download a C++ Koi loader and associated shellcode, and allocate memory to transfer execution to the loader. The loader decrypts embedded payloads with XOR, performs extensive anti-analysis and anti-VM checks (display adapters, known VM files, memory thresholds, filename/size heuristics, and language checks), computes a mutex based on volume serial calculations, and supports process injection or direct execution of fetched payloads. It communicates with C2 using initial and secondary POST formats (e.g., ‘101|{GUID}|VoYGkc5R|…’ and ‘111|{GUID}|{XOR’ed host information}’) and uses a modified XOR+MD5 scheme for host fingerprinting.

Depending on detected .NET compilers, the loader fetches sd2.ps1 or sd4.ps1 which XOR-decrypt the final Koi Stealer binary. The stealer repeats anti-VM checks, harvests browser cookies, history, and credentials (copying them to %AppData% temporarily), generates a Curve25519 keypair and shared secret, compresses harvested data with GZip, XOR-encrypts the blob with the shared secret, and exfiltrates the result to the C2 (POST begins with the public key + delimiter 0x4b followed by the encrypted data). For full context and indicators, consult the original analysis.

Read more: https://www.esentire.com/blog/unraveling-not-azorult-but-koi-loader-a-precursor-to-koi-stealer