L'exploit è facile. Sapere cosa cercare è difficile
PentestingDal team SwarmAttacker di JolocorpPubblicato 8 min di lettura

Ecco la cosa di cui nessuno ci aveva avvertito sul penetration testing automatizzato con un modello frontier attuale: scrivere l'exploit si è rivelato la parte facile. Punta SwarmAttacker su una web app vulnerabile e chiedigli di produrre un comando funzionante o una richiesta costruita ad hoc, e lo fa. In modo pulito. I problemi cominciano un passo prima, nella parte che non finisce mai in un tutorial: capire cosa stai davvero guardando.
Siamo tornati su ogni target che l'agente ha mancato, aspettandoci di trovare il modello che inciampava sulla sintassi o sceglieva la tecnica sbagliata. Non abbiamo trovato questo. Nemmeno una volta un target è sfuggito perché l'agente non riusciva a scrivere il codice. Quando ha fallito, ha fallito per una ragione più silenziosa: l'idea giusta non è mai stata formata, o non è mai stata inseguita abbastanza a fondo.
Classe giusta, tecnica sbagliata: dove si blocca il pentesting automatizzato
In tutta la suite, SwarmAttacker era quasi sempre nella zona giusta. Dava il nome corretto alla classe di vulnerabilità. Spesso metteva in piedi un appiglio funzionante. Sapeva che un form di login era probabilmente iniettabile, sapeva dove scorreva l'input dell'utente, conosceva la forma del problema. Ciò che non sempre riusciva a fare era arrivare alla tecnica esatta che il target richiedeva.
Sapere che un target ha una SQL injection non è la stessa cosa che sapere che è una blind, boolean-based.
Quel divario sembra piccolo. Non lo è. La distanza tra «qui c'è un'injection» e «ecco la tecnica precisa, blind, un bit alla volta, che estrae davvero i dati» è dove si è concentrata una buona parte dei nostri fallimenti. L'exploit era a portata di mano per tutto il tempo. La diagnosi era il muro.
Dove il muro è più alto: la blind SQL injection
Se vuoi vederlo in un solo numero, guarda la blind SQL injection. In tutta la suite è stata la classe peggiore che l'agente ha affrontato, risolta appena 1 su 3. Tutto il resto in quella famiglia, le vulnerabilità rumorose e loquaci, l'agente lo ha quasi spazzato via.
Il motivo è esattamente il problema della diagnosi, portato all'estremo. Un bug di cross-site scripting riflesso ti urla addosso: mandi una sonda, il payload rimbalza dritto nella pagina e il segnale è inconfondibile. La command injection è uguale: lanci una sonda e l'output stesso del target ti dice che ha funzionato. La blind SQLi non ha nessuna di queste cortesie. Non c'è niente da leggere. La pagina è identica sia che la tua ipotesi fosse giusta sia che fosse sbagliata. La risposta va ricostruita un'inferenza vero-o-falso alla volta, e quel ciclo lungo e fragile, chiedi, aspetta, interpreta una differenza così sottile che potrebbe essere rumore, correggi, chiedi di nuovo, è precisamente il punto in cui l'agente ha perso il filo più spesso.
I segnali rumorosi vengono spazzati via; quello cieco no
Le classi di vulnerabilità con una risposta evidente sono quasi perfette. La blind SQL injection, dove non c'è niente di visibile da leggere, è l'unico punto debole.
Perché la ricerca web non ha salvato i fallimenti difficili?
La soluzione ovvia è dare all'agente la ricerca web, e lo abbiamo fatto. Su questi fallimenti difficili ha salvato ben poco. Ci ha sorpreso finché non abbiamo guardato il perché. Il collo di bottiglia non è mai stato il modello che non conosceva la risposta: la risposta a «come si sfrutta una blind injection boolean-based» è scritta in cento posti. Il collo di bottiglia era l'agente incapace di formulare una domanda abbastanza precisa a partire dal proprio output torbido degli strumenti.
La ricerca premia una query precisa. «L'endpoint di reset della password restituisce 200 sia per i token validi sia per quelli non validi, e la lunghezza della risposta differisce di due byte» è una domanda a cui si può rispondere. «Qui c'è qualcosa che non torna» non lo è. Quando l'agente sapeva già articolare il problema, di solito non aveva bisogno di cercare. Quando non ci riusciva, nessuna quantità di ricerche aiutava, perché non aveva niente di preciso da cercare.
La risposta dello swarm: paziente, poi parallelo
Se la diagnosi è la parte difficile, allora la cosa peggiore che puoi fare è scagliare una folla di worker contro un target prima che qualcuno lo abbia capito. Cinquanta sonde parallele contro una vulnerabilità che nessuno ha letto correttamente producono solo cinquanta report sbagliati con grande sicurezza. Per questo SwarmAttacker è costruito per andare lento prima di sciamare.
Per i primi ~10 minuti di un'esecuzione mantiene deliberatamente ogni ondata piccola, solo 4 worker, così può osservare ogni sonda che rientra, leggerla e ripianificare spesso. È la fase di lettura, la parte in cui capisce cosa sta davvero guardando. Solo quando ha piste concrete si allarga, 6 worker per ondata, per sfruttare il vantaggio, tutto entro un limite rigido di 40 minuti.
Quel ritmo lascia un'impronta nei tempi. I tempi di risoluzione sono bimodali. C'è una grande gobba iniziale intorno ai 13–15 minuti, le catture in un colpo solo dove il segnale era forte e l'agente lo ha letto subito. Poi un secondo rialzo, più tardi, oltre i 20 minuti: i target che avevano bisogno di un secondo atto di inferenza attenta e paziente prima di cedere qualcosa. La mediana si ferma a 15 minuti, e la maggior parte delle risoluzioni arriva prima dei 20, ma la coda difficile, i target ciechi, silenziosi, pesanti di diagnosi, arriva lentamente.
I tempi di risoluzione sono bimodali
Una gobba iniziale intorno ai 13–15 minuti per le catture in un colpo solo, poi un secondo rialzo oltre i 20 minuti per i target che richiedono un secondo atto di inferenza attenta.
Cosa cambia
Per anni il modello mentale di un attaccante automatizzato è stato quello di una macchina da codice: il pericolo era che diventasse brava a scrivere exploit. Su un modello moderno quel treno è passato in silenzio, e non era la parte interessante. La parte interessante, ancora irrisolta, è la percezione: leggere l'output degli strumenti quando non sai che aspetto dovrebbe avere il segnale, e restringere una vaga sensazione di «qui c'è qualcosa» fino a una tecnica esatta.
È la scommessa che fa l'intera architettura. Se vuoi i dettagli sul perché l'abbiamo strutturata in ondate prima pazienti e poi parallele invece di un unico grande swarm, li trovi in come funziona. E se vuoi la suddivisione completa classe per classe, comprese quelle spazzate via e quelle che hanno opposto resistenza, è tutto nei risultati. In breve: il modello sa già scrivere l'exploit. Insegnargli a sapere cosa sta cercando è ora la frontiera.


