Di trojan di stato - details


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:

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:

schemarcs

ora decidiamo gli ip statici per ogni macchina:

master: 192.168.56.2
collector: 192.168.56.3
anonymizer: 192.168.56.4

master

  1. installo Windows 7 su una VM e imposto come ip dell'interfaccia 192.168.56.2
  2. installo rcs-setup-2015032102.exe
  3. installo rcs-exploits-2015032101.exe
  4. seleziono Master Node
  5. 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
  6. metto la password con cui controllerò tutto: RCSMaster1
  7. metto la licenza e a questo punto parte l'installazione.
  8. quando vedo "Remove previous master node files" sostituisco questo file in C:\RCS\bin\
  9. siccome ad ogni avvio ricontrolla la licenza, finita l'installazione devo sostituire anche questo file in C:\RCS\DB\lib\
  10. ora installo anche Adobe Air e la console
  11. a questo punto riavvio la macchina o i servizi e apro la console
  12. inserisco la loro CA come trusted dentro l'albero delle root CA
    root1 root2 root3 root4
  13. inserisco le credenziali, vado dentro monitor e passo ad installare il collector

collector

  1. come sopra ma scelgo Collector invece di Master Node
  2. imposto l'ip come scelto in precedenza per il collector, quindi 192.168.56.3
  3. il common name del master richiesto sará quindi 192.168.56.2
  4. torno sul master

master #2

  1. dentro System della console dovrebbe a questo punto comparire un collector
  2. faccio un nuovo anonymizer a cui assegno come ip 192.168.56.4
  3. collego l'anonymizer al collettore

    anon anon anon

  4. creo il pacchetto per l'anonymizer premendo Download installer

anonymizer

  1. preparo una macchina per installare l'anonymizer (consigliano una centos)
  2. io ho usato un container (runc) a cui ho dato come ip 192.168.56.4
  3. prendo lo .zip creato sopra e installo l'anonymizer (bbproxy, lo mette dentro /opt)
  4. quando tutto funziona, in System della console vediamo questo:

None

a questo punto siamo pronti per studiare, ecco i manuali di riferimento:

  1. RCS_9.6_Admin_1.7_IT.pdf
  2. RCS_9.6-Analyst_1.9_IT.pdf
  3. RCS_9.6_SysAdmin_1.9_IT.pdf
  4. 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:

newoperation newtarget newagent

l'agente

ora con una facile interfaccia punta e clicca possiamo selezionare le funzionalità del trojan da attivare

agentconfig

se invece vogliamo una configurazione particolare, come ad esempio limitare l'uso della batteria dell'agente possiamo utilizzare la modalità avanzata:

agentconfig2 agentconfigbattery agentconfigac agentconfig2

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:

build vector

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:

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

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

agentinfection

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:

dashboard

vediamo ora una carrellata delle possibilità, possiamo navigare il file system della vittima

fs

possiamo inserire file, eseguirli e ovviamente scaricarli

updown files

possiamo inviare comandi e riceverne i risultati

commands

e poi ovviamente guardare tutte le prove, quindi screenshoot (con supporto OCR)

screenshoot screenshoot

un simpatico keylogger e tutti gli eventi del mouse

keylogger

le foto dalla webcam con la frequenza scelta

camera

la lista dei siti visitati

www

le password salvate da firefox e chrome

password

ovviamente con la possibilità di filtrare il materiale con filtri di tutto rispetto

filtri

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 ....

fake_contact fake_contact2

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:

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:

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....

fake_screenshot1 fake_screenshot2

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

Related Post