6133cd0b2a8a7a1ecf353ae072c1e64934bfbeb0693cb7dc59d6d55173d6e0a7xenorat: 6133cd0b — moom825 build, LZNT1 compression, async node C2
Executive Summary
PE32 .NET Framework 4.8 RAT authored by moom825 and internally named xeno rat client.exe. Heavy use of C# async/await state machines, LZNT1 compression via native NT APIs, and a parent-child "Node" C2 architecture with DDoS-capable recv loops. OpenCTI co-label dcrat is a false positive; static evidence unambiguously points to XenoRAT.
What It Is
- File: 119 kB PE32 GUI .NET assembly, 3 sections ^[file.txt]
- Runtime: .NET Framework v4.0.30319 / target v4.8 ^[strings.txt:5,458]
- Timestamp: fabricated Fri Sep 10 2083 ^[pefile.txt]
- Version info masquerade: "Windows Updater for a better version", Company
Microsoft, OriginalFilenameWindows Update.exe^[exiftool.json] - True identity: InternalName
xeno rat client.exe, namespacexeno_rat_client, developer labelmoom825^[exiftool.json] ^[strings.txt:4,201,389] - Unsigned, not packed, not obfuscated — standard MSBuild output ^[rabin2-info.txt]
How It Works
Entry is an async Program+<Main>d__11 state machine that bootstraps a Handler instance and begins C2 lifecycle. The Handler owns a Node (primary C2 socket) and zero or more subNodes (child / proxy sockets), enabling a hub-and-spoke or chained topology ^[strings.txt:128-129,328].
Network I/O is fully async: ConnectSubSockAsync, ReceiveAsync, SendAsync, AuthenticateAsync ^[strings.txt]. Authentication implies a shared secret or token exchanged before command dispatch. Commands are typed: Type0Receive, Type1Receive, Type2Receive, plus a debug menu and info-updater ^[strings.txt:195-197].
The SocketHandler implements two receive variants: RecvAllAsync_ddos_safer and RecvAllAsync_ddos_unsafer, suggesting built-in DDoS/stress modes ^[strings.txt:305-306]. Traffic is compressed with RtlCompressBuffer / RtlDecompressBuffer in COMPRESSION_FORMAT_LZNT1 and encrypted via .NET AES + MD5 integrity checks ^[strings.txt:204,312-313] ^[capa.txt].
Plugin architecture uses CurrentDomain_AssemblyResolve to reflectively load missing assemblies at runtime — no disk touch for plugin DLLs ^[strings.txt:198-199]. A dedicated DllHandler / DllNodeHandler pair routes binary plugin payloads over the C2 stream.
Persistence is dual-path: non-admin via startup folder and admin via registry Run key, plus schtasks scheduling ^[strings.txt:264-265] ^[capa.txt]. Uninstall and self-removal routines are present (RemoveStartup, Uninstall) ^[strings.txt].
System discovery is thorough: WMI ManagementObjectSearcher for AV and hardware enumeration, GetWindowsVersion, processor count, idle time, active window caption, and machine/user name ^[strings.txt:268,366]. Console output is captured and exfiltrated via CapturingConsoleWriter ^[strings.txt:325].
Decompiled Behavior
Ghidra analysis incomplete at time of writing (CIL backend queued). radare2 function list confirms the async state machine surface: 240 functions, dominated by <MoveNext> and SetStateMachine stubs for TaskAwaiter-driven coroutines ^[rabin2]. The actual logic is IL bytecode inside .text; meaningful pseudo-C requires a .NET decompiler (dnSpy/ILSpy) rather than Ghidra/r2 CIL backends.
C2 Infrastructure
No hardcoded IP, domain, or port recovered from static strings. ServerIp and ServerPort fields exist in the Node class but values are runtime constants or builder-configured — not present in string artifacts ^[strings.txt:290,404]. C2 protocol is raw TCP with LZNT1 + AES framing. subServer field suggests multi-hop / proxy chaining.
Interesting Tidbits
- Author
moom825appears raw in the string table with no obfuscation — open-source project confidence ^[strings.txt:4] - LZNT1 via
RtlCompressBufferis unusual; most commodity RATs use gzip or zlib. This uses the Windows kernel compression engine directly ^[strings.txt:312-313] - Two hardcoded SHA-256-like hashes:
1D1CC35EA6...and630DCD2966...— likely AES key or config integrity checks ^[strings.txt:61,93] - GUID
$310fc5be-6f5e-479c-a246-6093a39296c0in the manifest — possibly builder-generated ^[strings.txt:456] - AssemblyResolve hook for plugin loading is a textbook .NET reflective loading pattern ^[strings.txt:198]
- No ConfuserEx, no SmartAssembly, no obfuscation — the builder trusts compilation artefacts alone
How To Mess With It (Homelab Replication)
- Toolchain: Visual Studio 2022 + .NET Framework 4.8 target
- Build a C# WinForms/Console app with
System.Net.Sockets.TcpClient,System.IO.Compression, andSystem.Security.Cryptography.AesManaged - Implement async
ReceiveAsync/SendAsyncwrappers withTaskAwaiterpatterns - Add
AppDomain.CurrentDomain.AssemblyResolve += ResolveHandlerfor in-memory DLL loading - Compress test payloads with
RtlCompressBuffervia P/Invoke tontdll.dll(or useSystem.IO.Compression.DeflateStreamas a stand-in) - Verify: run
capaon the reproducer; expect hits forcommunication/socket/tcp,data-manipulation/compression,data-manipulation/encryption/aes,load-code/dotnet
Deployable Signatures
YARA
rule XenoRAT_moom825
{
meta:
author = "PacketPursuit"
description = "XenoRAT by moom825 — .NET RAT with LZNT1 and async node C2"
family = "xenorat"
strings:
$a1 = "moom825" ascii wide nocase
$a2 = "xeno rat client" ascii wide nocase
$a3 = "xeno_rat_client" ascii wide
$b1 = "RecvAllAsync_ddos_safer" ascii wide
$b2 = "RecvAllAsync_ddos_unsafer" ascii wide
$b3 = "COMPRESSION_FORMAT_LZNT1" ascii wide
$b4 = "RtlCompressBuffer" ascii wide
$b5 = "RtlDecompressBuffer" ascii wide
$c1 = "CurrentDomain_AssemblyResolve" ascii wide
$c2 = "DllNodeHandler" ascii wide
$c3 = "ConnectSubSockAsync" ascii wide
condition:
uint16(0) == 0x5A4D and
(any of ($a*)) and
(2 of ($b*)) and
(2 of ($c*))
}
Behavioral fingerprint
.NET PE with mscoree IAT only, .rsrc containing large icon, async MoveNext state machines, AES+MD5 crypto classes, and P/Invoke to ntdll.dll for RtlCompressBuffer / RtlDecompressBuffer. On execution: TCP socket to ServerIp:ServerPort, AuthenticateAsync handshake, LZNT1-compressed traffic, WMI AV query, registry Run-key persistence.
IOC list
- SHA-256:
6133cd0b2a8a7a1ecf353ae072c1e64934bfbeb0693cb7dc59d6d55173d6e0a7 - Mutex seed string:
mutex_string^[strings.txt:223] - Install path field:
Install_path^[strings.txt:230] - Startup name field:
startup_name^[strings.txt:149] - Version-info masquerade:
Windows Update.exe,Windows Updater for a better version
Detection Signatures From capa static:
- T1547.001 — Registry Run Keys / Startup Folder
- T1053.005 — Scheduled Task
- T1047 — Windows Management Instrumentation
- T1082 — System Information Discovery
- T1087 — Account Discovery
- T1033 — System Owner/User Discovery
- T1057 — Process Discovery
- T1012 — Query Registry
- T1083 — File and Directory Discovery
- T1213 — Data from Information Repositories
- T1560.002 — Archive via Library
- T1140 — Deobfuscate/Decode Files or Information
- T1027 — Obfuscated Files or Information
- T1620 — Reflective Code Loading
- T1497.001 — VM Detection (capa low-confidence flag)
References
- Author:
moom825(GitHub) - OpenCTI artifact:
b511b9a2-d480-40be-9e6d-cc3c08529317 - Family page: xenorat
- Technique page: dotnet-assemblyresolve-plugin-loader
Provenance Static analysis only; CAPE skipped — no Windows guest available. Artifacts: file.txt, exiftool.json, pfile.txt, strings.txt, capa.txt, binwalk.txt, rabin2-info.txt, triage.json. Tools: radare2 (CIL backend limited), Ghidra (analysis incomplete). floss CLI misfired on arg parsing; no decoded strings output.