
sgn v1.0.0-rs
Codificatore binario polimorfico per payload di sicurezza offensiva. Codifica shellcode con loop di feedback basato su LFSR, iniezione di istruzioni spazzatura e offuscamento a iterazioni multiple per eludere il rilevamento statico.
SGN è un codificatore binario polimorfo per scopi di sicurezza offensiva, come la generazione di payload binari staticamente non rilevabili. Utilizza un ciclo di feedback additivo per codificare le istruzioni binarie fornite, simile a LFSR. Questo progetto è la reimplementazione dell'originale Shikata ga nai in golang con molti miglioramenti.
[!WARNING]
Il progetto è stato recentemente portato in Rust. Questo porting mantiene il design e il comportamento originali, ma sostituisce l'assemblatore testuale keystone con l'assemblatore puro Rusticed-x86, quindi non ci sono dipendenze da librerie native — viene compilato con un semplicecargo build. Dai un'occhiata al branch sgn-go per la versione legacy in Go.
Perché?
Per la comunità della sicurezza offensiva, l'implementazione originale del codificatore shikata ga nai è considerata il miglior codificatore di shellcode (fino ad ora). Ma nel corso degli anni i ricercatori di sicurezza hanno trovato diverse insidie per rilevare staticamente lo stub del decodificatore (lavoro correlato articolo FireEye). La motivazione principale di questo progetto è stata quella di creare un codificatore migliore che codifichi il binario fornito al punto da renderlo identico a dati completamente casuali e che non sia possibile rilevare la presenza di un decodificatore.
- Supporto 64 bit.
Finalmente shellcode x64 codificati correttamente! - Nuovo stub decodificatore più piccolo.
Chiave LFSR ridotta a 1 byte - Stub codificato con schema pseudo-casuale.
Anche lo stub decodificatore è codificato con uno schema pseudo-casuale - Nessuna condizione di ciclo visibile
Lo stub si decodifica da solo SENZA usare alcuna condizione di ciclo!! - Offuscamento dello stub decodificatore.
Generatore casuale di istruzioni spazzatura aggiunto con keystone - Opzione registro sicuro.
Nessun registro viene sovrascritto (preambolo opzionale, può ridurre il polimorfismo)
Come funziona
Ogni passaggio di codifica:
- (opzionale) aggiunge un suffisso di ripristino dei registri (modalità sicura);
- antepone istruzioni spazzatura casuali che preservano il valore;
- cifra il payload con la cifratura ADFL (ciclo di feedback additivo) e antepone uno stub decodificatore senza loop che lo inverte in fase di esecuzione;
- a meno che non venga specificato
--plain, crittografa lo stub stesso con un cifrario a schema casuale per esecuzione (XOR/ADD/SUB/ROL/ROR/NOTsu DWORD) e antepone un decodificatore dello schema che si auto-localizza, così anche il decodificatore sembra dati casuali; - opzionalmente ripete
--encvolte con seed freschi; - (opzionale) antepone un prefisso di salvataggio dei registri (modalità sicura).
Installazione
cargo install sgn
Puoi anche ottenere i binari precompilati QUI.
Utilizzo
-h è abbastanza autoesplicativo, usa -v se vuoi vedere cosa succede dietro le quinte ( ͡° ͜ʖ ͡°)_/¯
__ _ __ __ _
___ / / (_) /_____ _/ /____ _ ___ ____ _ ___ ___ _(_)
(_-</ _ \/ / '_/ _ `/ __/ _ `/ / _ `/ _ `/ / _ \/ _ `/ /
/___/_//_/_/_/\_\\_,_/\__/\_,_/ \_, /\_,_/ /_//_/\_,_/_/
========[Author:-Ege-Balcı-]====/___/=======v2.0.2=========
┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ (ノ ゜Д゜)ノ ︵ 仕方がない
sgn [OPZIONI]
Opzioni:
-i, --input <INPUT> Percorso del binario in input
-o, --out <OUT> Nome del binario codificato in output (default: <input>.sgn)
-a, --arch <ARCH> Architettura del binario (32/64) [default: 64]
-c, --enc <ENC> Numero di volte per codificare il binario [default: 1]
-M, --max <MAX> Byte massimi per blocco di istruzioni spazzatura [default: 50]
--plain Non codificare lo stub del decodificatore
--ascii Genera un payload completamente stampabile in ASCII (lento)
-S, --safe Preserva tutti i valori dei registri (nessuna sovrascrittura)
--badchars <BADCHARS> Evita questi byte, formato hex (es. \x00\x0a)
-v, --verbose Modalità verbosa
-h, --help Stampa aiuto
-V, --version Stampa versione
Esempio:
sgn -i shellcode.bin -o encoded.bin -a 64 --badchars '\x00\x0a\x0d'
Flusso di esecuzione
L'immagine seguente è un diagramma di base del flusso di lavoro per il codificatore. Tieni presente che le dimensioni, le posizioni e l'ordine delle istruzioni spazzatura, dei decodificatori e dei decodificatori di schema cambieranno a ogni iterazione.
L'LFSR stesso è piuttosto potente in termini di spazio di probabilità. Per un polimorfismo ancora maggiore, le istruzioni spazzatura vengono aggiunte all'inizio del payload grezzo non codificato. L'immagine seguente mostra la matrice compagna del polinomio caratteristico dell'LFSR e, denotando il seme come vettore colonna, lo stato del registro nella configurazione di Fibonacci dopo k passi.
Utilizzo come libreria
use sgn::Encoder;
let shellcode = std::fs::read("payload.bin")?;
let mut encoder = sgn::Encoder::new(64)?;
let encoded = encoder.encode(&shellcode)?;
println!("encoded {} bytes", encoded.len());
Vedi examples/encode_binary.rs.
Test
cargo test
La suite include test unitari di andata e ritorno della cifratura più test di esecuzione reali:
lo shellcode x64 codificato viene mappato come eseguibile e eseguito in-process, mentre lo shellcode x86
viene eseguito tramite un harness helper cc -m32 (saltato automaticamente se non è presente una
toolchain a 32 bit). Entrambe le architetture vengono esercitate attraverso le modalità plain, schema,
multi-layer e safe-register, incluso un ciclo di stress randomizzato.
Note sul porting
- La generazione di istruzioni utilizza l'API assemblatore tipizzata di
iced-x86invece del testo assembly di keystone; gli stub decodificatore sono stati ricostruiti attorno all'indirizzamento RIP-relativo (x64) e a uno schema a due passicall/pop(x86). - Il cifrario a schema è espresso direttamente nella vista nativa little-endian DWORD della CPU, che è equivalente ma più chiara dell'aritmetica mista big/little-endian dell'originale.
- Il codice morto dell'originale (la tabella del set di istruzioni di ~3k linee inutilizzata e il generatore di "spazzatura non sicura" che non veniva mai chiamato) è stato rimosso.
- Piccole correzioni:
random_byteora copre l'intero intervallo0..=255e il budget di dimensione per la spazzatura (--max) viene applicato in modo coerente come limite per blocco.