Skip to main content

One post tagged with "keylogger"

View All Tags

Deconstructing a Multi-Stage Snake Keylogger PowerShell Campaign

· 6 min read

Overview​

This post details the static analysis and decryption of two malicious scripts: eecrypted.ps1 (documented on URLhaus #3906259) and ugcrypted.ps1 (documented on URLhaus #3906260), both hosted on the malicious staging server 178.16.53.176.

The initial hex-encoded XOR payload loader decrypts and runs the reflective loading helper (RACE.EXECUTE) that hollows out aspnet_compiler.exe to run Snake Keylogger.


Methodology​

To statically analyze this threat chain safely without execution, the following manual steps can be performed.

1. Safe Acquisition​

To prevent accidental execution, retrieve the staging payloads using curl with the output redirected to a safe, non-executable text format:

curl -s -o ./eecrypted_payload.txt http://178.16.53.176/DVB/eecrypted.ps1
curl -s -o ./ugcrypted_payload.txt http://178.16.53.176/DVB/ugcrypted.ps1

2. Manual Layer 1 Decryption (Hex-XOR)​

The payload loader starts with a hex-encoded block ($encryptedHexData) and a hex-encoded XOR key ($decryptionHexKey). Extract the blobs from the file and decrypt them interactively in a Python shell (python3):

import re

# 1. Read the raw powershell crypter file
with open('./ugcrypted_payload.txt', 'r', encoding='utf-8') as f:
text = f.read()

# 2. Extract the hex payload and the 32-byte XOR key using regex
hex_data = re.search(r'\$encryptedHexData\s*=\s*@\'\s*(.*?)\s*\'@', text, re.DOTALL).group(1)
hex_key = re.search(r'\$decryptionHexKey\s*=\s*@\'\s*(.*?)\s*\'@', text, re.DOTALL).group(1)

# 3. Clean up the hex string and convert both to raw byte streams
cipher_bytes = bytes.fromhex(hex_data.replace('\n', '').replace('\r', ''))
key_bytes = bytes.fromhex(hex_key)

# 4. Perform the XOR loop
plain_bytes = bytes(b ^ key_bytes[i % len(key_bytes)] for i, b in enumerate(cipher_bytes))

# 5. Save the output as a decrypted PowerShell script
with open('layer1_decrypted.ps1', 'wb') as out:
out.write(plain_bytes)

3. Manual Layer 2 Decryption (Base64-XOR)​

The decrypted Layer 1 output contains a base64-encoded $encodedData block decrypted using a hardcoded string key: "NIJAcoder76@@".

To extract and decrypt it:

import base64
import re

# 1. Read the decrypted Layer 1 script
with open('layer1_decrypted.ps1', 'r', encoding='utf-8') as f:
l1_text = f.read()

# 2. Extract the Base64 cipher text block
b64_cipher = re.search(r"\$encodedData\s*=\s*'(.*?)'", l1_text, re.DOTALL).group(1)
clean_b64 = re.sub(r'\s+', '', b64_cipher) # Remove whitespaces

# 3. Decode the base64 string
cipher_bytes = base64.b64decode(clean_b64)

# 4. XOR decrypt using the key bytes of "NIJAcoder76@@"
key_bytes = b"NIJAcoder76@@"
plain_bytes = bytes(b ^ key_bytes[i % len(key_bytes)] for i, b in enumerate(cipher_bytes))

# 5. Save the plain text (which is a base64 string of the final PE DLL)
with open('layer2_b64.txt', 'wb') as out:
out.write(plain_bytes)

4. Manual Layer 3 Decoding (Base64 to PE Injection DLL)​

The decrypted Layer 2 output is the base64-encoded string representing the reflective helper DLL (RACE.EXECUTE). Decode it into a binary DLL:

import base64

# 1. Read the base64 string
with open('layer2_b64.txt', 'r', encoding='utf-8') as f:
b64_pe = f.read().strip()

# 2. Base64 decode to retrieve the raw Portable Executable (PE) bytes
pe_bytes = base64.b64decode(b64_pe)

# 3. Save as the DLL executable
with open('injection_helper.dll', 'wb') as out:
out.write(pe_bytes)

5. Final Snake Keylogger Payload Extraction​

The actual payload bytes are stored inside layer1_decrypted.ps1 as a raw array of integers under [Byte[]]$payloadBytes = (77, 90, 144, ...). To convert this array to a binary executable:

import re

# 1. Read the decrypted Layer 1 script
with open('layer1_decrypted.ps1', 'r', encoding='utf-8') as f:
l1_text = f.read()

# 2. Extract the byte array string
byte_array_str = re.search(r'\[Byte\[\]\]\$payloadBytes\s*=\s*\((.*?)\)', l1_text, re.DOTALL).group(1)

# 3. Parse the string into a list of integers
byte_vals = [int(x) for x in re.split(r',|\s+', byte_array_str) if x.strip()]

# 4. Save the integers directly to file as raw bytes
with open('snake_payload.exe', 'wb') as out:
out.write(bytes(byte_vals))

6. Manual Strings Audit​

Once you have extracted snake_payload.exe, you can statically audit its strings to find C2 domains, target DLLs, and exfiltration endpoints.

Using Unix Command Line:​

Use the built-in strings utility. Since Windows .NET binaries store strings in both 8-bit ASCII and 16-bit UTF-16le formats, run the command with different encoding flags:

# Extract ASCII strings
strings -n 4 snake_payload.exe | grep -E -i "http|bot|\.php|dns"

# Extract UTF-16 Little-Endian strings (common in .NET binaries)
strings -n 4 snake_payload.exe | grep -E -i "http|bot|\.php|dns"

Using Python (Cross-Platform):​

To automate this, run a Python script to scan the binary for both encodings and print suspicious keywords:

import re

# 1. Read binary data
with open('snake_payload.exe', 'rb') as f:
data = f.read()

# 2. Match ASCII and UTF-16 strings (minimum 4 characters)
ascii_strings = re.findall(b"[a-zA-Z0-9/\\-:.,_$ %'\"@]{4,}", data)
unicode_strings = re.findall(b"(?:[a-zA-Z0-9/\\-:.,_$ %'\"@]\x00){4,}", data)

# 3. Decode and compile
all_strings = []
for s in ascii_strings:
all_strings.append(s.decode('ascii', errors='ignore'))
for s in unicode_strings:
all_strings.append(s.decode('utf-16le', errors='ignore'))

# 4. Filter and display C2 indicators
suspicious = [s.strip() for s in all_strings if any(k in s.lower() for k in ["http", "bot", ".php", "telegram", "dns", "kozow"])]
for s in sorted(list(set(suspicious))):
print(s)

Tools Used​

  • Custom Python decryption scripts (for multi-layer XOR/base64 decoding)
  • Local file strings extraction and regex analysis
  • Public Threat Intelligence databases (URLhaus, Abuse.ch, etc.)

Investigation​

Payload Analysis: Snake Keylogger​

Statically auditing the strings of the hollowed executables reveals typical indicators of Snake Keylogger (also known as 404 Keylogger):

  • Credential Theft Targets: Searches for Firefox data files (nss3.dll, mozglue.dll), Foxmail credentials (Foxmail.exe), and other local credentials.
  • Geolocation & IP Probing: Queries http://checkip.dyndns.org/ and https://reallyfreegeoip.org/xml/ to resolve host coordinates.
  • Command & Control Infrastructure: Exfiltrates credentials and keystrokes to the following C2 endpoints:
    • http://varders.kozow.com:8081
    • http://aborters.duckdns.org:8081
    • http://anotherarmy.dns.army:8081
    • http://51.38.247.67:8081/_send_.php (exfiltration receiver script)
    • https://api.telegram.org/bot (Telegram Bot exfiltration fallback)

Snake Keylogger embedded C2 domains and exfiltration PHP/Telegram endpoints in strings output


IOCs​

Indicator TypeValueDescription
Loader SHA256fb6a0d07d6de377ba92277430cde62f40ea0ab1f63b3d5fe8df2c93b2261ab67eecrypted_payload.exe (Snake Keylogger)
Loader SHA25603d0c0eb7322d749f6ed52f631b46af9e413aa5eba6515210a9c6a956aef497cugcrypted_payload.exe (Snake Keylogger)
Injection DLLa2e9d433046aac0c29337843a2cdae31e9d20f8aecb4b2fa2229c32fbdba22f7RACE.EXECUTE reflective DLL injection helper
C2 Domainvarders.kozow.comPrimary Snake Keylogger C2
C2 Domainaborters.duckdns.orgSecondary Snake Keylogger C2
C2 Domainanotherarmy.dns.armyBackup Snake Keylogger C2
C2 IP51.38.247.67C2 Exfiltration Host (Port 8081)
Staging Server178.16.53.176Powershell script staging server

Detection Logic​

IF
Process = powershell.exe
AND Command Line contains "bxor" AND ("GetString" OR "FromBase64String")
THEN
Automated PowerShell Obfuscated Loader Download/Execution Detected
IF
Process = aspnet_compiler.exe
AND Network Connection established on Port 8081 OR to api.telegram.org
AND Process load list includes "mozglue.dll" OR "nss3.dll" (without Firefox parent)
THEN
Snake Keylogger Process Injection & Exfiltration Detected

Observations & Conclusions​

  1. Multi-Layer Decryption: The PowerShell loader utilizes successive layers of XOR hex-ciphers and base64 arrays to evade signature-based endpoint detection.
  2. Process Hollowing Injection: By targeting built-in .NET tools like aspnet_compiler.exe, the malware runs in-memory under a trusted Windows binary name, neutralizing standard process-tree audits.
  3. Snake Keylogger C2: Network exfiltration relies on multi-homed dynamic DNS domains (duckdns, kozow, dns.army) alongside direct IP targets on custom ports.
Indicators of Compromise (IOCs)
IOCs (domains, IP addresses, files, hashes, etc.) from this analysis are available on GitHub.
View on GitHub →