questo scritto è lungo, confuso e denso di appunti, link e domande, se avete il caffè sul fuoco, toglietelo. è stato un lavoro sudato, speriamo vi piaccia.
parliamo di captatori informatici, sicurezza offensiva e il tentativo di normare questi trojan di stato.
per iniziare
siccome ci piace toccare con mano gli oggetti dei nostri ragionamenti, ci siamo procurati uno di questi “captatori informatici” e ne abbiamo documentato il setup completo per chi volesse sporcarsi le mani con noi (grazie al lab61 per averci messo la pulce nell’orecchio).
successivamente abbiamo infettato volontariamente un dispositivo con il malware per vederne il funzionamento da vicino, quali funzionalità presenta e quali difetti.
in ultimo, dal momento che nel tentativo di normare questi pericolosi strumenti leggiamo della “necessità di forti garanzie per essere inattacabile sul piano della veridicità dei dati acquisiti“, abbiamo provato a generare delle prove non valide per capire quanto sono affidabili questi malware (non contenti l’abbiamo fatto in due modi diversi).
la conclusione a cui siamo arrivati è che no, non esiste modo di garantire tecnicamente che le prove raccolte siano veritiere.
abbiamo anche fatto un’analisi tecnica della proposta di legge sottolineandone le criticità qui.
(legenda: le parti a sfondo bianco come questa sono per tutti i lettori,
quelle a sfondo nero sono più tecniche e interessanti per qualcuno, noiose per qualcun altro, vi assicuriamo che saltarle non pregiudicherà la lettura).
installare galileo
un piccolo disclaimer: vi potete fare male, noi non abbiamo mai fatto uscire nessuna delle installazioni su internet liberamente, suggeriamo di fare lo stesso.
siamo partiti da questo link, un tutorial per il setup, modificando alcuni passaggi.
in particolare abbiamo eliminato vari check della licenza per cui non è più necessario cambiare la data del sistema (molto scomodo su una macchina virtuale) ed è ora quindi possibile abilitare tutte le funzionalità.
il setup minimo necessita almeno di 4 macchine:
- un master (windows 7, almeno 4Gb di ram)
- un collector (windows 7, almeno 1Gb di ram)
- un anonymizer (suggerito centos solo cli, anche solo 300mb di ram, io ho usato un container con alpine via runc)
- un target (fate voi, una debian, un android, un mac)
se volete strafare, servirá anche una macchina che faccia da network tactical injector, cioè l’oggetto usato per infettare le vittime attraverso attacchi wifi.
le prime due voci le abbiamo installate in macchine virtuali su un portatile con 8Gb di ram usando virtualbox, ma se avete delle macchine da sacrificare è uguale.
per iniziare guardiamo uno schema di come funziona l’architettura:
ora decidiamo gli ip statici per ogni macchina:
master: 192.168.56.2
collector: 192.168.56.3
anonymizer: 192.168.56.4
master
- installo Windows 7 su una VM e imposto come ip dell’interfaccia
192.168.56.2
- installo rcs-setup-2015032102.exe
- installo rcs-exploits-2015032101.exe
- seleziono Master Node
- in CN metto
192.168.56.2
:
questo ip verra’ usato anche come CN del certificato https, potevo anche usare un nome ma poi toccava editare /etc/hosts
di windows
- metto la password con cui controllerò tutto:
RCSMaster1
- metto la licenza e a questo punto parte l’installazione.
- quando vedo “Remove previous master node files” sostituisco questo file in C:\RCS\bin\
- siccome ad ogni avvio ricontrolla la licenza, finita l’installazione devo sostituire anche questo file in C:\RCS\DB\lib\
- ora installo anche Adobe Air e la console
- a questo punto riavvio la macchina o i servizi e apro la console
- inserisco la loro CA come trusted dentro l’albero delle root CA
- inserisco le credenziali, vado dentro
monitor
e passo ad installare il collector
collector
- come sopra ma scelgo Collector invece di Master Node
- imposto l’ip come scelto in precedenza per il collector, quindi
192.168.56.3
- il common name del master richiesto sará quindi
192.168.56.2
- torno sul master
master #2
- dentro
System
della console dovrebbe a questo punto comparire un collector
- faccio un nuovo anonymizer a cui assegno come ip
192.168.56.4
-
collego l’anonymizer al collettore
-
creo il pacchetto per l’anonymizer premendo Download installer
anonymizer
- preparo una macchina per installare l’anonymizer (consigliano una centos)
- io ho usato un container (runc) a cui ho dato come ip
192.168.56.4
- prendo lo .zip creato sopra e installo l’anonymizer (bbproxy, lo mette dentro /opt)
- quando tutto funziona, in
System
della console vediamo questo:
a questo punto siamo pronti per studiare, ecco i manuali di riferimento:
- RCS_9.6_Admin_1.7_IT.pdf
- RCS_9.6-Analyst_1.9_IT.pdf
- RCS_9.6_SysAdmin_1.9_IT.pdf
- RCS_9.6_Technician_2.0_IT.pdf
usare un captatore informatico
dopo aver installato e letto i manuali d’uso di RCS, abbiamo voluto provare effettivamente cosa è in grado di fare questo captatore informatico.
abbiamo quindi volontariamente infettato una nostra macchina linux e testato il funzionamento del tutto.
per prima cosa apriamo un’indagine (Operations->New Operation) a cui aggiungiamo un indagato sul cui ipotetico computer d’ufficio vogliamo installare un agente:
l’agente
ora con una facile interfaccia punta e clicca possiamo selezionare le funzionalità del trojan da attivare
se invece vogliamo una configurazione particolare, come ad esempio limitare l’uso della batteria dell’agente
possiamo utilizzare la modalità avanzata:
qui sopra un esempio di come è possibile attivare determinati moduli solamente quando il dispositivo è in carica.
per completezza ecco l’elenco dei possibili eventi, delle possibili azioni e di tutti i moduli.
se volete studiare tutte le funzionalità, rimandiamo alla documentazione ufficiale.
ovviamente non tutte le funzionalità sono compatibili con tutti i sistemi operativi, per avere una lista delle compatibilità vi rimandiamo anche in questo caso alla documentazione ufficiale e a quella non ufficiale.
quando la configurazione ci soddisfa, procediamo con la creazione del vero e proprio agente premendo in alto a sinistra su Build
.
ora manca solo di scegliere come infettare la vittima:
i vettori
i vettori di infezione sono tanti, anche in questo caso la documentazione ufficiale ci viene in aiuto.
la scelta del vettore da usare dipende in gran parte dalla vicinanza del dispositivo da infettare:
accesso fisico
avendo accesso fisico al dispositivo (ad esempio in aereoporto, durante un controllo o una perquisizione) è possibile installare il malware via:
- Silent Installer: un programma da eseguire direttamente sul dispositivo della vittima
- Offline Installation: avvio del dispositivo da una pennetta usb
- U3 Installation: usa una chiave U3 per installare l’agente
- Persistent Installation: installa l’agente in maniera permanente (resistente ad una formattazione di windows o un factory reset di android)
vicinanza spaziale
se è possibile avvicinare la vittima (facendo ad esempio un appostamento fuori dall’abitazione) è possibile introdursi nella sua rete wireless o emularla attraverso una serie di attacchi usando quello che viene chiamato il Tactical Network Injector.
negli altri casi
- lo stesso strumento, chiamato in questo caso Network Injector, può venire utilizzato installandolo direttamente
dal provider/ISP (tim, wind, vodafone, ecc) dove attraverso dei filtri è possibile specificare chi infettare.
- inviando un’allegato (pdf, doc) via mail contenente uno zero-day.
noi purtroppo non abbiamo la possibilità di provare direttamente da un ISP l’installazione del Network Injector e avendo accesso fisico al dispositivo del fittizio indagato, ci infettiamo volontariamente con un Silent Installer per linux.
l’infezione
pubblichiamo l’agente venuto fuori dalla build per chi volesse sporcarsi le mani, SE NON SAPETE COSA STATE FACENDO, NON FATELO, SUL SERIO
NON SCARICARMI SE NON DEVI.zip
ovviamente non ci sarebbe bisogno di fare reverse engineering visto che abbiamo i sorgenti, ma siccome se non vediamo non crediamo, lo faremo ugualmente, non prima di vederlo in azione però.
se avete linux e avete paura di essere infetti da un paio d’anni e non potete aspettare, date un’occhio dentro ~/.config/autostart/.*
, /var/crash/.report*
e /var/tmp/.report*
ma non sperate di trovare qualcosa perchè nelle licenze italiane le funzionalità per infettare linux non sono state comprate.
ps. abbiamo ascoltato il traffico con wireshark ma sembra che non cerchi di andare altrove.
abbiamo le prove
attendiamo 5 minuti che l’agente raccolga i dati e ce li invii ed ecco i primi risultati in una comoda dashboard:
vediamo ora una carrellata delle possibilità, possiamo navigare il file system della vittima
possiamo inserire file, eseguirli e ovviamente scaricarli
possiamo inviare comandi e riceverne i risultati
e poi ovviamente guardare tutte le prove, quindi screenshoot (con supporto OCR)
un simpatico keylogger e tutti gli eventi del mouse
le foto dalla webcam con la frequenza scelta
la lista dei siti visitati
le password salvate da firefox e chrome
ovviamente con la possibilità di filtrare il materiale con filtri di tutto rispetto
ci fermiamo qui anche se ci sarebbero tanti altri moduli da provare, i messaggi, i contatti, i wallet bitcoin, l’infezione di un’android, il network tactical injector, gli exploits….
rompere un captatore informatico
ok, l’abbiamo installato e provato per poterlo analizzare meglio
e farci la seguente domanda: ma quanto sono sicuri questi captatori informatici?
sono veramente dei generatori di prove affidabili e veritiere come si vorrebbe sostenere?
come raccolgono le prove? proviamo ad immaginare come potremmo fare noi, prendendo a titolo di esempio i contatti skype:
i contatti skype sono presenti nel computer dentro un file
contentente una base dati.
questa base dati non è protetta in nessun modo, ed è direttamente accessibile da chiunque, sia da Skype che da un qualsiasi altro programma e ovviamente anche dai captatori informatici, che vanno a cercare dentro quella base dati la lista dei contatti e la nostra messaggistica.
dove si trova di preciso? la base dati di skype su linux si trova dentro ~/.Skype/<profiloutente>/main.db
proviamo allora a creare da noi questa base dati senza neanche avere skype installato sul computer e inserire dei contatti fittizi al suo interno. funzionerà?
falsi contatti
la base dati in questione è un sqlite, il cui schema è reperibile pubblicamente.
creiamo quindi dentro la macchina della vittima una directory per ospitare il nostro finto profilo skype al cui interno inseriamo il nostro db sqlite compatibile con lo schema skype:
mkdir -p ~/.Skype/fakeprofile/
sqlite3 ~/.Skype/fakeprofile/main.db
# creo i db 'Accounts' e 'Contacts'
# https://github.com/suurjaak/Skyperious/blob/master/skyperious/skypedata.py#L128
# creo un account
INSERT INTO Accounts (skypename, fullname, is_permanent) VALUES ('account falso', 'account falso', 1);
# inserisco dei contatti a piacimento
INSERT INTO Contacts (skypename, displayname, birthday, is_permanent) VALUES("contatto falso", "contatto falso",0,1);
.quit
a questo punto attendiamo che il captatore raccolga le nuove prove e ….
per i siti visitati attraverso chrome/firefox e altri browser vale lo stesso discorso, perchè questi vengono salvati all’interno di una base dati simile a quella usata da skype.
anche per il microfono, la webcam, gli screenshoot del monitor e in generale per ogni tipo di dato acquisito, non solo è difficile se non impossibile dire con certezza se i dati carpiti all’insaputa dell’utente siano veritieri o meno, ma è anche relativamente semplice falsificare questi dati da parte di terzi (pensiamo ad un’applicazione su android ad esempio).
è possibile evitarlo? no.
rompere un captatore informatico #2
ma quanto sono sicuri questi captatori informatici?
nel proseguire il nostro studio sull’argomento, vogliamo sottolineare una questione secondo noi importante. non divulgare le falle di sicurezza dei nostri dispositivi per avere la possibilità di poterli infettare mantiene inevitabilmente meno sicuri i dispositivi di tutti, compresi quelli di chi i captatori informatici li utilizza.
abbiamo visto come sia possibile falsificare le prove prima che vengano raccolte, cerchiamo ora di capire come funziona l’invio dei dati raccolti in RCS e vediamo se è possibile inviare delle prove create ad-hoc.
reverse engeenering
ed eccoci alla parte più interessante del nostro studio (nonchè la più divertente).
la descrizione del reverse engeenering che segue è molto piu’ lineare di come si è svolta nella realtà, abbiamo saltato le parti noiose e ripetitive (openssl l’abbiamo ricompilato almeno 6 volte) e cercato inoltre di rendere i ragionamenti sequenziali, quando nella realtà tante scelte sono state fatte intuitivamente.
siamo inoltre convinti che si poteva ottenere lo stesso risultato in altri N modi e che
quello da noi usato è sicuramente molto grezzo.
innanzitutto, ipotizziamo di avere solo il binario, il malware.
dobbiamo capire cosa fa e come si comporta. creiamo quindi un ambiente di studio, un container che lo isoli in un posto sicuro dove non puo’ fare danni e in cui è possibile studiarne il comportamento.
noi abbiamo usato runc usando come rootfs una debian
dentro una directory montata con loggedfs per controllare tutti i suoi movimenti sul file system (file creati, letti, etc…).
vediamo subito che si installa dentro /var/crash/.report*/whoopsie-report
e cerchiamo di capire di che file si tratta con un:
$ file whoopsie-report
whoopsie-report: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, stripped`
è un piccolo file statico di 77kb, un po’ troppo piccolo per essere veramente statico,
lo avviamo con strace ./whoopsie-report
e notiamo infatti che cerca di aprire parecchie librerie di sistema, tra cui:
- /lib/x86_64-linux-gnu/libpthread.so.0
- /lib/x86_64-linux-gnu/libc.so.6
- /usr/lib/x86_64-linux-gnu/libcurl-gnutls.so.4
- /usr/lib/x86_64-linux-gnu/libcrypto.so.1.0.0
- /usr/lib/x86_64-linux-gnu/libX11.so.6
e qui gia’ ci sarebbe spazio per divertirsi: libX11 viene sicuramente utilizzata per fare gli screenshot dello schermo, sarebbe possibile ricompilarla per fare in modo che per alcuni programmi dei metodi tornino cose inaspettate.
ad un certo punto notiamo che vengono creati dei files dentro /var/crash/.report*/.tmp*
, sono presumibilmente le prove raccolte, anche perchè ciclicamente si moltiplicano.
all’interno solo dati binari, controlliamo se sono solamente compressi, ma non ci sembra, saranno cifrati? ma come? per una cosa del genere a noi verrebbe da utilizzare le librerie standard, quindi openssl
, ma come possiamo esserne sicuri?
in effetti il malware accede a libssl
.
perdiamo un po’ di tempo provando con gdb
ma stufi di seguire tutti i thread, ci viene in mente di ricompilare libssl inserendo del debug che ci mostri come vengono cifrati i dati.
per ricompilare un pacchetto debian seguiamo questa guida, ci armiamo di pazienza e scarichiamo il tutto.
cercando come si cifra con openssl vediamo che ci sono parecchie chiamate differenti, quindi proviamo con ltrace
(con strace si vedono le syscall, con ltrace le libcall) a vedere se possiamo capire quale chiamata viene usata:
$ ltrace ./whoopsie-report
Couldn't find .dynsym or .dynstr in "/proc/30234/exe"
questo e’ parecchio strano ma smanettando un po’ troviamo con strings
la seguente stringa dentro il malware:
$ strings ./whoopsie-report
$Info: This file is packed with the UPX executable packer http://upx.sf.net $
leggiamo che upx è un packer che comprime binari, installiamo quindi upx-ucl
e proviamo un upx-ucl -d whoopsie-report
per fare il processo inverso e decomprimere il binario:
File size Ratio Format Name
-------------------- ------ ----------- -----------
261044 <- 77972 29.87% linux/ElfAMD whoopsie-report
ora abbiamo il binario “in chiaro” e riprovando con ltrace (qui siamo passati dentro una macchina virtuale con VirtualBox perchè dentro runc si bloccava per qualche motivo) otteniamo le chiamate usate dal malware, in particolare nel nostro interesse ricadono le seguenti:
dlsym(0x122f4c0, "EVP_get_cipherbyname")
dlsym(0x122f4c0, "BIO_set_cipher")
a questo punto cerchiamo quei metodi nei sorgenti di libssl e troviamo la prima chiamata in crypto/evp/names.c
linea 112 a cui aggiungiamo questo debug che scrive il cifrario usato dentro un file
const EVP_CIPHER *EVP_get_cipherbyname(const char *name)
{
const EVP_CIPHER *cp;
// DEBUG: scrivo il cifrario utilizzato dentro un file
FILE *f;
f = fopen("/tmp/debug_ciphername", "w"); // <- qui trovo il cifrario
fprintf(f, "%s", name);
fclose(f);
cp = (const EVP_CIPHER *)OBJ_NAME_get(name, OBJ_NAME_TYPE_CIPHER_METH);
return (cp);
}
e la seconda chiamata in crypto/evp/bio_enc.c
e anche qui aggiungiamo del debug:
void BIO_set_cipher(BIO *b, const EVP_CIPHER *c, const unsigned char *k,
const unsigned char *i, int e)
{
BIO_ENC_CTX *ctx;
// DEBUG: scrivo i parametri del cifrario su file
FILE *f;
f = fopen("/tmp/debug_cipher", "a+");
fprintf(f, "\n----\n");
fprintf(f, "block_size: %d, key_len: %d, iv_len: %d\nkey: ", c->block_size, c->key_len, c->iv_len);
for(int co=0; co<c->key_len; co++)
{
fprintf(f, "%02X",k[co]);
}
fprintf(f,"\n\niv: ");
for(int co=0; co<c->iv_len; co++) {
fprintf(f, "%02X", i[co]);
}
fprintf(f,"\n\n");
fclose(f);
....
ricompiliamo le librerie, installiamo e rilanciamo il malware.
dentro /tmp
troviamo ora il cifrario usato dal malware e la chiave:
$ cat /tmp/debug_ciphername
aes-128-cbc
$ cat /tmp/debug_cipher
----
block_size: 16, key_len: 16, iv_len: 16
key: 692CC9D0DC834E4663EF389470E445B4
iv: 00000000000000000000000000000000
(= a questo punto proviamo a decifrare i file salvati su disco dal malware, lo scopo è ovviamente tentare di scriverne noi uno ad-hoc, con la chiave a disposizione dovrebbe essere facile, invece perdiamo un sacco di tempo a capire come mai non riusciamo a decifrare la prima parte del file.
pensavamo fosse legato al vettore di inizializzazione e invece nel file c’e’ un header di qualche tipo, ovvero il blocco cifrato non comincia all’inizio (questo però ovviamente openssl non lo dice).
il punto è che la lunghezza del testo cifrato ogni tanto non è un multiplo del BLOCK_SIZE del cifrario a blocchi usato, il che significa che c’è qualcosa che non dovrebbe esserci.
abbiamo provato prima manualmente ad eliminare un po’ di bytes prima di tentare il decrypt ed effettivamente ha funzionato:
#!/usr/bin/python
from Crypto.Cipher import AES
import sys
key = "692cc9d0dc834e4663ef389470e445b4"
IV = "00000000000000000000000000000000"
encrypted = open(sys.argv[1]).read()
x = 16 - len(encrypted)%16 if len(encrypted)%16 else 0
x += 16*int(sys.argv[2])
encrypted = encrypted[x:]
aes = AES.new(key.decode('hex'), AES.MODE_CBC, IV.decode('hex'))
print aes.decrypt(encrypted)
$ chmod +x test.py
$ ./test.py .tmp-1491179387-220638-SJBo7P 10 > image.jpg
il file in questione (il .tmp-149..) è stato selezionato perchè dalle dimensioni poteva sembrare un’immagine, inoltre decifrandolo inizialmente c’erano stringhe che riconducevano al formato JPG (ma non trovavamo il magic byte DD F8!).
quel 10 invece indica che prima dell’inizio dell’immagine all’interno del file salvato su disco, ci sono ben 160 bytes di header.
il prossimo passo è cercare di scrivere noi l’immagine dentro uno dei file, quindi apriamo con gimp
l’immagine estratta in precedenza (quindi con il vero screenshot) in modo da mantenerne le proprietà (colori, dimensioni, ecc.) e sostituirla dentro il file di cui sopra.
#!/usr/bin/python
from Crypto.Cipher import AES
import sys
key = "692cc9d0dc834e4663ef389470e445b4"
IV = "00000000000000000000000000000000"
original_header = open(sys.argv[1]).read()[:168]
new_image = open('.tmp-1491179387-220638-SJBo7P','w')
# mantengo l'header come era prima senza indagare oltre
new_image.write(original_header)
fake_image = open(sys.argv[2]).read()
# padding
x = 16 - len(fake_image)%16 if len(fake_image)%16 else 0
fake_image += x*"\0"
# cifro l'immagine fake e la scrivo sul nuovo file
aes = AES.new(key.decode('hex'), AES.MODE_CBC, IV.decode('hex'))
new_image.write(aes.encrypt(fake_image))
new_image.close()
ora basta solo aspettare e….
Underscore _TO* Hacklab // underscore chiocciola autistici.org
Key fingerprint = 5DAC 477D 5441 B7A1 5ACB F680 BBEB 4DD3 9AC6 CCA9
gpg2 –recv-keys 0x9AC6CCA9
https://autistici.org/underscore