
Impianto di canale nascosto DNS per Red Teams.
WEASEL è un piccolo impianto in memoria che utilizza Python 3 senza dipendenze. Il beacon client invia una piccola quantità di informazioni identificative sul suo host a una zona DNS che controlli. Il server WEASEL può incaricare i client di eseguire comandi preconfigurati o arbitrari.
WEASEL è un payload di stage 1, pensato per essere difficile da rilevare e utile per riguadagnare l'accesso quando i tuoi stage rumorosi e ricchi di funzionalità vengono scoperti.
Stato
Consulta l'uso nel README del client e nel README del server per istruzioni specifiche.
Per avviare il server o il client, esegui gli script direttamente o passali all'interprete Python.
Assicurati che i domini C2 abbiano ciascuno un record NS con l'indirizzo IP dell'host che esegue server.py.
WEASEL richiede Python 3.6+.
Il client è autonomo e utilizza solo librerie standard, quindi può essere eseguito su macOS, Linux, ecc.
Il server ha alcune dipendenze da pip, incluse nel requirements.txt del server. Il server dovrebbe essere eseguito su Linux, ma nulla impedisce di eseguirlo su macOS o altri *nix.
Non è necessario offuscare e minimizzare il beacon in questo caso. Le istruzioni print vengono preservate. Come per l'Utilizzo sopra, assicurati che i record NS per i domini in servers in beacon.py puntino all'indirizzo IP di server.py.
Sull'host del server:
sudo python3 server.py
Sull'host vittima (può essere lo stesso del server):
python3 beacon.py
Non è necessario capire nulla di questo per usare WEASEL.
Il beacon comunica tramite DNS utilizzando query e risposte AAAA. Non utilizza record TXT perché sono noti per essere utilizzati da malware e tunnel DNS. I blue team spesso hanno rilevamenti di tunneling DNS che avvisano su grandi query TXT.
Il lato client non necessita di root per funzionare, non utilizza socket raw e non crea pacchetti DNS malformati. Utilizza interfacce regolari fornite dal sistema e dal linguaggio per effettuare richieste DNS. Le informazioni sono codificate + crittografate nei record stessi.
Questo beacon è pensato per essere lento e a bassa larghezza di banda. Dovrebbe dirci su quali host si trova e fornirci un modo per lanciare ulteriori stage secondo necessità, e niente di più. Sebbene supporti comandi arbitrari, non è destinato a essere utilizzato come shell interattiva regolare o canale di comunicazione.
WEASEL è uno stage 1 che lasci in esecuzione, garantendo l'accesso continuo mentre i tuoi stage completi (e quindi più rumorosi) vengono scoperti.
WEASEL era inizialmente mirato a server con elevato uptime dove avevamo un vettore di sfruttamento/accesso affidabile. Eludere le indagini forensi era una priorità alta. Di conseguenza, non ha funzionalità di persistenza nativa.
Puoi renderlo persistente aggiungendo la sua esecuzione alla tua tecnica di persistenza preferita, che è lasciata come esercizio al lettore :)
Una richiesta (dal client) è una singola query AAAA per un nome formattato come:
<preambolo><dati>.<flusso>.<sessione>.dominio.tld
Il preambolo è di 2 byte. Preambolo[0] è il numero di sequenza di quel pacchetto. Preambolo[1] è il numero totale di pacchetti in quel flusso.
I dati sono limitati a 50 byte (configurabili) e contengono il payload. Il payload è codificato in base32 con un alfabeto personalizzato.
In primo luogo, tutti i caratteri 'w' vengono sostituiti con '-'.
Successivamente, il carattere di padding viene sostituito da '=' a 'w' per conformarsi al set di caratteri DNS: [a-z0-9] e [-].
Non sostituiamo '=' con '-' direttamente perché il padding sarà sempre alla fine della stringa, e terminare un nome host con '---' è sia sospetto che contrario all'RFC DNS. In questo modo, quando una stringa ha del padding, terminerà con 'www', che è sia meno sospetto che conforme all'RFC.
Una risposta (dal server) è composta da una o più risposte AAAA.
Ogni risposta AAAA è un payload crittografato di 16 byte rappresentato come un indirizzo IPv6 utilizzando socket.inet_ntop. Le risposte in una risposta DNS non mantengono il loro ordine durante il transito, quindi vengono sequenziate e riassemblate come le richieste del client.
Il payload di trasporto è una stringa di elementi di dati separati dal carattere ^.
Richieste e risposte seguono questo formato:
<tipo>|<dati>
| Tipo | Significato (mittente) | AKA | Dati |
|---|---|---|---|
| 0 | Riconosciuto | ACK | Hex casuale |
| 1 | Check-in (client) | PING | Hex casuale |
| 2 | Terminati (server), mi termino (client) | FIN | |
| 3 | Messaggio di inizializzazione (client) | SYN | `versione |
| 4 | Riconnessione (server) | RST | |
| 5 | Imposta intervallo di callback (server) | secondi | |
| 6 | Ottieni dati interfaccia di rete | eth0 1.2.3.4/24\neth1 fe80:::/64\n... | |
| 8 | Eval codice Python3 arbitrario fino a 666 byte (server), restituisce i primi 400 byte di output (client) | EVAL | script oneliner python3 |
| 9 | Esegui comando arbitrario fino a 666 byte (server), restituisce i primi 400 byte di output (client) | EXEC | comando bash |
Le sessioni sono di lunga durata: un client avvia una sessione quando il beacon viene eseguito per la prima volta e quella sessione dovrebbe durare per tutto il tempo in cui il beacon è attivo su quel client. Nota che poiché il beacon è in memoria e non persistente, i dati della sessione sono memorizzati nella memoria del processo Python. Qualsiasi nuova invocazione del beacon avvierà una nuova sessione.
L'avvio di una sessione comporta che il client crei un messaggio con un preambolo non dati che identifica in modo univoco (per segnalare al server che si tratta di una nuova sessione): la concatenazione di una chiave pubblica Diffie-Hellman di 32 byte e un IV AES casuale di 16 byte.