Steganografia di rete: come implementare un canale nascosto su una macchina Windows

Introduzione

La steganografia consiste nella scienza di nascondere il trasferimento e l’archiviazione delle informazioni [1]. Essa non deve essere confusa con la crittografia: entrambe condividono l’obiettivo finale di proteggere le informazioni, ma la prima tenta di renderle “difficili da notare”, mentre la seconda cerca di confondere il messaggio per renderlo “difficile da leggere”. I dati crittografati possono attirare l’attenzione a causa della natura “stravolta” rispetto ad un messaggio in chiaro; la steganografia, invece, non altera in modo evidente il pattern dei dati, e le informazioni nascoste appaiono come un normale messaggio con altro significato. Come esempio, In Figura 1 facciamo riferimento alla classica comunicazione tra Alice e Bob, i cui messaggi sono però costantemente monitorati e analizzati da un warden (sorvegliante) con pieni poteri, il quale si può immediatamente rendere conto dello scambio di un messaggio cifrato [2].

Figura 1

Esempi di steganografia includono l’occultamento di informazioni nei media digitali come immagini di diverso formato, flussi audio e video. La steganografia di rete si distingue invece per la sua capacità di utilizzare il traffico di rete regolare come covert object, e cioè il carrier dati in cui si nasconde l’informazione inviata da un covert sender ad un covert receiver). Tale manipolazione non deve comunque inficiare il corretto scambio di informazioni su una rete.

La steganografia di rete può essere impiegata in varie applicazioni più o meno legittime. Alcuni esempi includono l’esfiltrazione di dati nello spionaggio e nell’intelligence, comunicazioni aziendali riservate, attività dannose (comunicazioni di malware o di Command-and-Control o C&C, per eludere gli Intrusion Detection Systems, o IDS), ed infine comunicazioni anonime e anti-censura.

Descrizione e implementazione di un covert channel

Come risultato di un esperimento eseguito nell’articolo in [3], in questo articolo proponiamo un canale nascosto (covert channel) e la sua implementazione nel sistema operativo Windows. Questo canale di archiviazione utilizza l’Initial Sequence Number di TCP per nascondere quattro caratteri di testo e il campo identificativo per “firmare” il messaggio e capire così se è stato alterato durante la trasmissione. Il segreto viene inviato dal mittente nel primo segmento SYN inviato per simulare l’apertura di una connessione, mentre una risposta ACK-RST conferma la ricezione da parte del ricevente, e al contempo simula la chiusura della connessione TCP. In questa risposta da parte del ricevente abbiamo inserito un codice per la correzione di eventuali errori, in modo da rendere il protocollo più robusto e in grado di gestire la perdita di pacchetti (IP) e errori di trasmissione. Infatti, per la costruzione di questo canale non ci affidiamo alla affidabilità fornita nativamente da TCP, ma spediamo in sequenza ciascuna parte del messaggio segreto con un semplice successivi segmenti SYN, e per ciascuno ci aspettiamo una risposta ACK-RST, che oltre alla conferma di avvenuta ricezione, ci può anche chiedere di ritrasmettere quella parte del messaggio o una precedente a causa di errori di trasmissione.

Un’implementazione in Python di mittente e destinatario presentati in questo articolo è disponibile all’indirizzo: https://github.com/Aldwyn47/TCPCovertChannel, ed è stata testata in ambiente Windows 10 e 11. Sia il mittente che il ricevente necessitano di essere eseguiti con i diritti di amministratore di sistema: Scapy[1], il package al cuore dello sviluppo, necessita infatti di manipolare i pacchetti a basso livello. La porta utilizzata per inviare il segmento da parte del mittente con SYN attivato è la 80, al fine di mimetizzare il più possibile la comunicazione all’interno di un normale traffico di rete che spesso include connessioni HTTP (ovviamente tala porta può essere modificata secondo necessità).

Di seguito elenchiamo numerandoli i passi principali, riassunti anche in Figura 2 e Figura 3:

  1. Il mittente crea un pacchetto TCP contraffatto e incorpora il messaggio segreto nel campo del numero di sequenza dell’intestazione TCP. Vengono incorporati fino a quattro caratteri ASCII utilizzando i 28 bit meno significativi del campo; i quattro bit più significativi vengono invece utilizzati per implementare codici di errore e codici di controllo interni al nostro canale, volti a migliorare la robustezza.
  2. Per migliorare la distribuzione dei valori, viene aggiunta anche una maschera di bit randomizzata a ciascun numero di sequenza contraffatto. Questa maschera si ottiene chiamando una determinata funzione casuale (nota sia al mittente che al ricevente) dopo che il suo seme è stato impostato per riflettere il valore di identificazione IP del pacchetto. Poiché ogni pacchetto ha un valore identificativo univoco, la maschera di bit randomizzata generata è sempre diversa.
  3. Detta maschera viene poi applicata al numero di sequenza “grezzo” tramite un’operazione XOR bit a bit.
  4. Il Mittente imposta quindi su 1 il flag SYN del pacchetto per far finta che il mittente stia tentando un nuovo handshake a tre vie con il ricevente.
  5. Il Mittente procede quindi alla consegna del pacchetto.
  6. Il ricevente ottiene il pacchetto ed estrae il valore del relativo campo Identificazione. Quindi utilizza questo valore per impostare il seme della stessa funzione casuale utilizzata dal mittente per ricreare la stessa maschera di bit randomizzata.
  7. Il ricevitore quindi estrae il numero di sequenza del pacchetto in entrata ed esegue uno XOR bit a bit con la maschera di bit appena ricreata. Lo XOR bit a bit del ricevente alla fine annulla quello del mittente, ripristinando così il numero di sequenza “grezzo” originale e consentendo al ricevente di estrarre il messaggio nascosto.
  8. Il ricevente imposta quindi il seme della funzione casuale su un valore corrispondente alla somma dei valori dell’identificazione IP e del numero di sequenza del pacchetto in entrata. L’output generato chiamando la funzione random sarà quindi una “firma” randomizzata determinata direttamente dai valori dei due campi.
  9. Infine, il ricevente assembla una risposta consistente in un altro pacchetto TCP. I flag RST e ACK di questo pacchetto sono impostati su 1 per far finta che il destinatario stia semplicemente tentando di rifiutare il tentativo del mittente di stabilire un handshake a tre vie. In realtà, il ricevente conferma la ricezione del pacchetto originale e ne passa la “firma” al mittente inserendola nel campo Identificazione della risposta.
  10. Il ricevente procede quindi a consegnare il suo pacchetto di risposta.
  11. Dopo aver ricevuto il pacchetto di risposta, il mittente imposta il seme della funzione casuale sulla somma dei valori dell’identificazione IP e del numero di sequenza del pacchetto originale. Quindi confronta l’output della funzione casuale con il campo Identificazione della risposta (ovvero la “firma” del destinatario). Se i due valori differiscono, significa che i campi dell’intestazione del pacchetto originale sono stati in qualche modo alterati dopo la partenza del pacchetto. Ciò significa che la trasmissione è fallita e deve essere interrotta. Altrimenti, il mittente può continuare la sua trasmissione e preparare il successivo pacchetto per spedire la parte rimanente del messaggio.
Figura 2
Figura 3

Test

Una possibile limitazione potrebbe consistere nella capacità di un warden di prevedere come un dato sistema operativo assegni nuovi valori per i numeri di sequenza TCP utilizzati dal nostro approccio, consentendo così di notare la differenza tra quelli legittimi e contraffatti. Nei moderni sistemi operativi però questi valori vengono generati in modo sufficiente casuale per motivi di sicurezza, e quindi questa limitazione risulta essere difficilmente applicabile. Più di successo risulta invece essere qualsiasi middlebox che operi da proxy TCP su tutte le connessioni in uscita della rete vittima. Alcune tecnologie router (ad esempio, CISCO ASA) sono per esempio in grado di riscrivere automaticamente il numero di sequenza e neutralizzare quindi il canale nascosto.

Siamo quindi ben lungi dal sostenere di avere una pallottola d’argento in grado di evitare qualsiasi forma possibile di difesa. D’altronde però, i test da noi effettuati dimostrano che è possibile comunicare attraverso il nostro canale segreto posizionando il mittente in i) una piccola/media rete aziendale, ii) una rete universitaria, iii) dietro un Internet Service Provider (ISP), mentre il ricevente riceve connettività da un ISP.

Infine, per attestare la stealthiness dell’implementazione, abbiamo effettuato vari test inviando messaggi segreti da 36 a 712 caratteri ciascuno e collezionando file .pcap di queste trasmissioni, mentre al contempo effettuavamo delle classiche operazioni come controllare la posta o navigare su Internet, cercando di includere sia traffico lecito che il nostro traffico manipolato. Né Suricata[2] (configurato con 47000 regole) né Zeek[3] (esteso con numerosi package, come icmp-exfil-detection) sono stati in grado di rilevare anomalie sui .pcap in questione. Alcuni dei tool più comuni di sicurezza disponibili liberamente non sono quindi in grado di riconoscere una comunicazione nascosta, e comunque un rilevamento necessiterebbe di analizzare tutto il traffico di rete nel dettaglio, un compito ben dispendioso dal punto di vista delle risorse, soprattutto se il traffico riguarda per esempio un ISP o comunque una rete di grandi dimensioni.

Conclusioni

L’implementazione presentata in questo articolo dimostra come sia possibile a tutt’oggi inviare informazioni segrete inserendole all’interno di pacchetti di rete opportunatamente modificati, senza destare allarmi nei sistemi più comuni per il monitoraggio della sicurezza di rete. Il traffico generato si perde insieme al rimanente traffico a livello trasporto come un tentativo di connessione andato a vuoto.

BIBLIOGRAFIA

[1] S. Wendzel, L. Caviglione, W. Mazurczyk, A. Mileva, J. Dittmann, C. Kr ̈atzer, K. Lamshoft, C. Vielhauer, L. Hartmann, J. Keller, and T. Neubert. A revised taxonomy of steganography embedding patterns. In ARES 2021: The 16th International Conference on Availability, Reliability and Security, pages 67:1–67:12. ACM, 2021.

[2] G. J. Simmons. The prisoners’ problem and the subliminal channel. In David Chaum, editor, Advances in Cryptology, Proceedings of CRYPTO, pages 51–67. Plenum Press, New York, 1983.

[3] S. Bistarelli, A. Imparato, F. Santini: A TCP-based Covert Channel with Integrity Check and Retransmission. 20th Annual International Conference on Privacy, Security and Trust, PST 2023: 1-7

Note

[1] Scapy: https://scapy.net

[2] Suricata: https://suricata.io

[3] Zeek: https://zeek.org

 

Articolo a cura di Francesco Santini

Profilo Autore

Francesco Santini è Professore Associato presso il Dipartimento di Matematica e Informatica dell’Università degli Studi di Perugia. Si occupa da quasi venti anni di Intelligenza Artificiale e Cybersecurity, con un approccio integrato. È docente di corsi riguardanti la sicurezza per corsi di laurea magistrale in informatica e in master universitari di primo livello su protezione del dato e forensics. È relatore di tesi sulle materie di insegnamento. Organizza il programma di training CyberChallenge.it per studenti di scuole superiori e laurea triennale, ed è membro del Cybersecurity National Lab. presso il nodo di Perugia.

Condividi sui Social Network:

Articoli simili