Data over ICMP project:
...yet another protocol tunneling
1.1 Intro
Dunque,
dunque... era una notte buia e tempestosa... freddo e gelo fuori
dalla finestra. Era una di quelle serate in cui...
Uhm... No. A parte il fatto che non sono parole mie, l'intro stile
bfi non mi si addice proprio. Ricominciamo. :-)
Lo so. I 'data over protocol' non sono certo una novità.
Nel corso degli anni nella comunità cosidetta 'underground' si sono visti applicare stravolgimenti di ogni genere ai protocolli:
dall'HTTP tunneling a vere e proprie assurdità quali l''IP
over DNS, giusto per citarne una delle tante, e un progetto di questo
tipo non rappresenta di certo una novità, ma io che ci posso
fare? :-)
Era diverso tempo che l'ideuzza mi frullava nella testa: prendere
un protocollo utilizzato, in genere, per scopi ben precisi, modificarlo
a basso livello e fargli espletare compiti per i quali non è
stato progettato in origine.
Nel dettaglio l'idea iniziale era quella di 'costruire' da zero
i vari campi di cui è composto il pacchetto ICMP, editarne
il campo DATA posto in coda alla struttura e riempirlo di... dati,
appunto.
Certamente non nato come protocollo di trasporto quanto più
di controllo o 'diagnostica', ICMP torna assai utile in svariati
casi, primo fra tutti la verifica riguardo lo stato online/offline
di un host remoto (chi non ha mai usato il ping?).
La domanda 'perchè proprio ICMP?' in questo caso è
tanto scontata quanto lecita.
Un protocollo progettato specificatamente per il trasporto come
TCP, infatti, garantirebbe sicuramente una serie di vantaggi in
più, primo fra tutti la maggiore sicurezza nel recapito dei
dati.
La convenzione vuole che se esiste un posto affidabile in cui infilare
dei dati per spedirli in modo corretto, ed essere ragionevolmente
sicuri che essi arrivino a destinazione, quello sia proprio il campo
DATA di un pacchetto TCP.
Tale campo (payload), inoltre, sarebbe editabile direttamente per
mezzo dei più classici moduli socket in modo 'nativo' senza
andare a scomodare SOCKET_RAW, incappare di conseguenza in problemi
di privilegi, editare manualmente ogni singolo campo del pacchetto
e via dicendo.
Perchè complicarsi la vita con ICMP allora? Perchè
andare a gestire pacchetti grezzi e rischiare la perdita di pacchetti?
Il motivo è facilmente intuibile e presto detto: cercare
di far passare il più possibile inosservata la connessione
e cercare di evitare di farsi bloccare dal solito, immancabile firewall.
Inizializzare una connessione TCP 'costa' in termini di silenziosità.
Decisamente tanto...
Un semplicissimo netstat sarebbe sufficiente a rendere noti i due
socket comunicanti e l'immancabile firewall avrebbe non poco da
ridire riguardo una nuova connessione che fa capolino cercando di
comunicare con qualcuno all'esterno.
A riguardo molti potrebbero obbiettare facendo notare che la quasi
totalità dei firewall effettua di default un blocco per i
pacchetti TCP quanto per quelli ICMP, bisogna però considerare
il fatto che in ambito server si è soliti dare libero accesso
a ICMP praticamente quasi sempre (la prima prerogativa di un server
è appunto quella di essere raggiungibile). Un amministratore,
inoltre, potrebbe configurare il suo firewall affinchè non
accetti gli ICMP di tipo ECHO(request) in entrata ma lasci passare
quelli di tipo ECHOREPLY per poter usare il ping dalla propria macchina.
La verità è che ICMP è utile, specialmente
per i già menzionati motivi di diagnostica. Molto difficilmente
un amministratore vorrebbe farne a meno.
Questo è uno degli insoliti casi in cui un applicativo di
questo tipo ha più probabilità di funzionare su solide
macchine adibite a server anzichè client che possono essere
utilizzati sì da un'utenza meno esperta, ma proprio in quanto
tale non necessitante di un protocollo di questo tipo e solita a
lasciare un applicativo firewall con settaggi di default i quali
bloccano ICMP in modo sistematico (o perlomeno così accade
nella maggior parte dei casi).
Da qui l'idea di utilizzare un protocollo che proprio per il suo
quotidiano utilizzo amministrativo che ne permette solitamente il
passaggio a livello firewall e per la sua natura poco adatta al
trasporto, potrebbe rivelarsi un buon compromesso per muoversi nell'ombra,
dapprima recapitando del semplice testo e dopo... chissà?
Magari far eseguire dei comandi (whoops!).
Ma andiamo per ordine cominciando ad illustrare l'impiego più
semplice per creare una base di partenza per poi, via via, sperimentare
utilizzi più complessi e redditizi da integrare nel progetto
padre. Non so se avrò voglia e risorse tecniche sufficienti
per fare quello che mi sono prefissato di fare in seguito ma per
ora preferisco rimanere ancorato al presente e vedere che succede.
Si parte!
1.2 La pratica
Quello
che si andrà a sviluppare in questa sede sarà un semplice
applicativo client che recapiterà a una macchina remota dei
pacchetti ICMP con un payload da noi specificato. Dall'altra parte
ci dovrà essere un secondo applicativo ricevente in grado
di sniffare il contenuto di tali pacchetti e stamparlo a video.
Per payload (carico) si intende il blocco di dati (header escluso)
che il pacchetto si porta dietro, dall'host sorgente all'host di
destinazione. In questo caso il payload è rappresentato dalla
stringa di testo mandata dal client.
Il primo problema che appare evidente è il come distinguere
i pacchetti ICMP derivanti dal nostro applicativo client da tutti
gli altri pacchetti transitanti per la rete che possono venire ricevuti
dalla macchina remota (tra i piu noti, gli ECHO(request) derivanti
dai ping, ad esempio).
Tali pacchetti mandati 'lato client' si potrebbero differenziare
dagli ICMP convenzionali inserendo un determinato valore a noi noto
all'interno della stringa contenuta nel payload (es: il primo carattere
della stringa dovrà essere == '@' ). Una sorta di 'firma',
insomma.
Tramite l'utilizzo del modulo Impacket (chi conosce Python? :-))
verrà dapprima forgiata la struttura del pacchetto, e tramite
un socket di tipo RAW verrà spedito al mittente.
Per simulare uno stack (molto spartano) al tutto si aggiungerà
una funzione di frammentazione che lato client spezzetta i pacchetti
con campo DATA > 54 bytes, in singoli pacchetti da 54 ognuno.
Avendo una stringa di testo da 130 caratteri, ad esempio, si avranno
due pacchetti con campo DATA da 54 bytes e un terzo pacchetto da
22, il tutto ovviamente mandato in sequenza, incrementando di volta
in volta il valore del campo ID di ICMP.
Come tipo di ICMP ho optato per l'ECHOREPLY, almeno per ora, di
modo da non avere pacchetti di ritorno a sporcare lo sniffing. Un
ECHOREPLY ha, inoltre, statisticamente più probabilità
di valicare un firewall (leggasi i motivi sopra citati).
Il codice (txt):
All'analisi
di uno sniffer appare chiaro il risultato che si ottiene (screenshot).
L'applicativo ricevente sniffer, come detto in precedenza, dovrà
essere in grado di ricevere i pacchetti, ignorare quelli convenzionali
e stampare a video soltanto quelli aventi un payload firmato
'@', dal nostro client, with love.
Il codice (txt):
Anche
in questo caso uno screenshot
è più esplicativo di mille parole.
Per far funzionare il tutto si avrà bisogno di:
-
Un interprete Python (versione usata 2.4.1)
-
Le librerie libpcap o Winpcap
nel caso in cui si usi una piattaforma Windows.
-
La libreria impacket reperibile qui.
-
La libreria pcapy scaricabile da qui.
Se
nella vita avete di meglio da fare che installare moduli e interpreti
(posso capirlo), per comodità verso i Windows user non 'pitonati'
ho compilato due binari, comodamente eseguibili da shell, reperibili
qui.
Per eseguirsi non necessitano di alcun modulo o interprete aggiuntivo
salvo le librerie Winpcap che devono essere necessariamente installate.
1.5 Si, ma...
So bene quanto voi che un applicativo del genere è fondamentalmente
inutile, ma permettetemi di esporre alcune idee aggiuntive che potrebbero
rendere il progetto decisamente più interessante.
Prendete quanto detto fino ad ora come una base da cui poter implementare
qualcosa di più grande.
A look to the future: Command over ICMP
Anzitutto,
al posto di far viaggiare semplici ed inutili stringhe di testo
da far stampare allo sniffer perchè non mandare veri e propri
comandi da fare interpretare ed eseguire alla macchina remota?
E se oltre a far eseguire un comando ne facessimo anche recapitare
l'output alla macchina che lo ha richiesto? Si, direi che il tutto
comincia ad acquistare un nuovo significato. :-)
L'idea nella pratica: il client manderà il solito pacchetto
con un payload contenente il comando, lo sniffer posto
in remoto interpreterà la stringa, processerà il comando
in essa contenuto e infine impiegherà l'output del comando
in un pacchetto ICMP che farà ritornare al client.
Una specie di "command over ICMP" o "shell over ICMP"
a seconda dei gusti... (non che abbia scoperto qualcosa di nuovo,
si intende... ma qualcosa nella vita la dovrò pur fare, no?
:-)).
Spoofing
Un'altra possibile 'feature' da aggiungere potrebbe essere sicuramente
la possibilità di poter spoofare l'indirizzo ip sorgente.
Trattandosi del più classico e rozzo blind spoofing
non si avrebbero pacchetti di ritorno con cui permettere di visualizzare
l'output dei comandi, certo, ma la silenziosità in questo
caso comincerebbe a raggiungere livelli ragguardevoli, senza contare
che il comando verrebbe comunque eseguito dal server.
Controllo sul recapito
Una grande debolezza di tutto il meccanismo resta indubbiamente
quella intrinseca di ICMP data dall'impossibilità di assicurare
la comunicazione robusta e affidabile garantita da TCP, ma a pensarci
bene si potrebbe aggiungere una forma di controllo sul recapito
dei messaggi tramite l'accoppiata ICMP ECHO(request) e
ICMP ECHOREPLY.
Mi spiego meglio: entrambi i componenti non manderanno più
dei 'one way packets' di tipo ECHOREPLY ma dei pacchetti
di tipo ECHO(request) per mezzo dei quali si potrà
effettuare il controllo sul recapito attendendo il pacchetto di
ritorno.
Forse può non risultare chiarissimo:
-
A manda un pacchetto di tipo ECHO(request) a B, contenente
il comando.
-
A continua a mandare il pacchetto a B fino a quando B non risponderà
con un pacchetto ECHO_REPLY.
-
B processa il comando e ne incapsula l'output in un pacchetto
di tipo ECHO(request) che rimanderà ad A.
-
B continua a mandare il pacchetto fino a quando A non risponderà
con un pacchetto ECHOREPLY stante a indicare l'avvenuto recapito.
- Solo
allora B potrà continuare il ciclo di frammentazione mandando
il secondo pacchetto, il terzo, il quarto e cosi via... e ogni
nuovo ciclo adotterà ovviamente la stessa tecnica di verifica
sul recapito.
| client |
ICMP
type |
payload
(DATA) |
server |
| ---> |
ECHO(request) |
@netstat
|
--->
|
| <--- |
ECHO_REPLY |
@netstat |
<--- |
| <--- |
ECHO(request) |
@Connessioni
attive
Proto Indirizzo locale Indirizzo esterno Stato
TCP startdus:1111 irc.daxnet.no:6667 ESTABLISHED
TCP startdus:1124 64.12.28.152:5190 ESTABLISHED |
<--- |
| ---> |
ECHOREPLY |
@Connessioni
attive
Proto Indirizzo locale Indirizzo esterno Stato
TCP startdus:1111 irc.daxnet.no:6667 ESTABLISHED
TCP startdus:1124 64.12.28.152:5190 ESTABLISHED |
---> |
Una
sorta di TCP un po' spartano, insomma, ma il protocollo dopotutto
è quello che è...
Gia che siamo in vena di creatività potremmo anche crittografare
il payload sia in uscita che in entrata nel caso in cui
un amministratore notasse il traffico insolito (si insospettirebbe
comunque e chiunque vedendo del testo crittografato in una discreta
quantità di pacchetti ICMP come minimo mette subito mano
a iptables o chi per esso. Ma tant'è...)
Chiave privata? Chiave pubblica? Non lo so... non ho mai messo mano
a cose di questo tipo ma si può sempre provare, no?
Le possibilità di impiego, come si vede, sono molteplici
e l'unico limite è dato dalla fantasia di chi ha un po' di
tempo da spendere dietro al monitor. Quello che ho fatto non è
stato altro che prendere una manciata di idee, metterle su un piatto
e aspettare che mi venisse voglia a sufficienza per provare a metterle
in pratica.
Poi... chi sa cosa preserva il futuro?
Stay
tuned.
Argomenti
correlati
Shell
over ICMP project
billiejoex
EOF 31/08/2005 - hh 02:43AM
|