Prendo spunto da un post di Forbes per chiarire (spero) qual’è il problema del TCP split handshake, detto anche Sneak-ACK attack. Buona parte dei chiarimenti sulla parte più tecnica si possono trovare qui. Sappiamo che parlando di TCP si parla abitualmente di three ways handshake: SYN, SYN/ACK, ACK, con i corrispondenti scambi di numero di sequenza fra mittente e destinatario.Ma l’RFC 793, in realtà dice una cosa molto più generale: a pag. 27 dice che: The synchronization requires each side to send it’s own initial
sequence number and to receive a confirmation of it in acknowledgment from the other side. Each side must also receive the other side’s initial sequence number and send a confirming acknowledgment.
1) A –> B SYN my sequence number is X
2) A <– B ACK your sequence number is X
3) A <– B SYN my sequence number is Y
4) A –> B ACK your sequence number is Y
Dato che i passi 2 e 3 possono essere uniti in un unico pacchetto grazie al “piggybacking”, e non c’è motivo di non farlo, normalmente abbiamo il three ways handshake. “Normalmente” è la parola chiave. Niente vieterebbe di mantenere separati i due pacchetti dei passi 2 e 3, ed in questo caso avremmo un SYN senza ACK che va dal server al client. L’assenza di SYN singoli da server a client è alla base dei meccanismi di filtraggio stateless, che però sono i più primitivi: un meccanismo stateful può essere disegnato per tenere conto anche di questo caso, verificando l’ordine temporale dei due SYN (quello da server a client è una risposta a quello da client a server, quindi viene necessariamente dopo). Se si ha presente il problema naturalmente, il che non è ovvio. Il rischio comunque sembra solo che una connessione potenzialmente legittima non vada a buon fine, nel momento in cui il SYN singolo da server a client viene scartato. Viceversa, un meccanismo stateless che volesse premettere questo tipo di connessione non sarebbe in grado di distinguere la direzione della connessione.
Per completezza, l’RFC 793, alla sez. 3.4, fig. 8, considera anche la possibilità che le due parti tentino di aprire la stessa connessione contemporaneamente. Con questo si intende che l’host A dalla porta a provi una connessione all’host B porta b, mentre host B dalla porta b provi una connessione all’host A porta a. Non si tratta di una cosa che possa succedere nell’uso abituale di Internet: l’unico caso che mi viene in mente erano i vecchi server DNS che facevano connessioni da porta 53 a porta 53, e che due server provassero ad esempio un zone transfer (quindi TCP) contemporaneamente. In questo caso, entrambi inviano un SYN “contemporaneamente” (dal punto di vista dell’automa a stati finiti che descrive lo stato della connessione), ognuno con il proprio numero di sequenza. La fig. 8 dell’RFC dice chiaramente che entrambi rispondono con un SYN/ACK, completando l’apertura della connessione in due soli passi, seppure con quattro scambi di pacchetti. Curiosamente, questo sembra più un handshake “peer-to-peer” che client/server.
Qual’è la parte interessante di tutta la faccenda? Che essendo casi particolari, non è detto che siano implementati correttamente. È possibile una sequenza:
1) A –> B SYN my sequence number is X
2) A <– B SYN my sequence number is Y
3) A –> B SYN/ACK your sequence number is Y
4) A <– B ACK your sequence number is X
O anche una sequenza:
1) A –> B SYN my sequence number is X
2) A <– B ACK my sequence number is Y
3) A <– B SYN my sequence number is Y
4) A –> B SYN/ACK your sequence number is Y
5) A <– B ACK your sequence number is X
Una considerazione un po’ “accademica”: ho letto che questa sequenza “differisce radicalmente” da quanto descritto nell’RFC, ma non vedo perché: escludendo il passo 5, che comunque da un punto di vista di pacchetti è la normale continuazione della sessione da lì in poi, la differenza sarebbe nel passo 4, in cui A risponde con un SYN/ACK anziché con un ACK. Di principio, per quanto ne so un host può ritrasmettere un pacchetto quante volte vuole, almeno entro i tempi previsti (è il meccanismo del TCP keepalive, dopotutto). Se consideriamo che A stia semplicemente ritrasmettendo il primo SYN, e che usi il piggyback per unirlo all’ACK che dovrebbe mandare in risposta al SYN di B, ecco che abbiamo proprio questa sequenza, in modo legittimo. Ma torniamo alla sostanza.
Si vede che qui i passaggi da 3 a 5 corrispondono a un’apertura di connessione da B ad A. Sembra che un firewall/IDS possa essere confuso, “buttare via” i primi pacchetti e ritenere che sia appunto B a connettersi ad A (uso il condizionale perché il report originale costa 3500 $). In particolare, alcuni attacchi sembra che riescano a superare questi firewall/ids perché i relativi controlli vengono fatti sulla direzione sbagliata del flusso.
Qualche considerazione. La prima è che le parti dei sistemi e delle reti che sembrano non poter più riservare alcuna sorpresa (in questo caso l’handshake TCP), ogni tanto riescono a tirare fuori qualche nuovo problema anche su cose così basilari. Vecchi problemi ritornano: penso anche al recente advisory sulla GNU libc.
La seconda è che a livello TCP/IP la vulnerabilità mi sembra più che altro teorica, ma magari mi sbaglio. A livello TCP, il problema si dovrebbe porre se le ACL permettono una connessione da B ad A ma non da A a B, ma in questo caso il primo SYN dovrebbe essere scartato, quindi l’handshake non dovrebbe proprio funzionare. Se viceversa vengono fatti passare i primi due SYN, vuole dire che la connessione è comunque autorizzata. Ma se la connessione da A a B è permessa, l’handshake anomalo non cambia niente, perché a livello TCP il concetto di client e server finisce non appena la connessione è completata. Il problema si pone quindi quando la connessione da B ad A è consentita ma verificata a livello applicativo (es. una connessione verso un server web interno): se la connessione viene interpretata nella direzione sbagliata (connessione uscente dal server web) i controlli a livello applicativo falliscono.
La terza considerazione è che una vulnerabilità a un problema di questo tipo non me la sarei aspettata almeno da alcuni dei prodotti citati. Il fatto che i controlli vengano fatti nella direzione sbagliata vuole dire che quasi certamente siamo di fronte a banalissimo pattern matching su blacklist, con un default permit, senza nessun reale riconoscimento o tantomeno enforcement del protocollo applicativo. Altrimenti, per fare un esempio banale, se in una sessione http invece di vedere il client iniziare la sessione con un GET, lo vedo fare al server, l’enforcement della correttezza dell’http dovrebbe rilevare subito la cosa. Per i protocolli la cui direzionalità non sia così facile da riconoscere, necessariamente i controlli dovrebbero essere fatti in entrambe le direzioni.
Una quarta riguarda il test in sè. Le reazioni di diversi produttori degli oggetti testati sono sul tono: “Non è vero che siamo vulnerabili, se ci aveste consultati vi avremmo spiegato quali sono i settaggi opportuni”. Almeno tre prodotti hanno in effetti delle protezioni disponibili, anche se non abilitate di default e magari non specifiche. Cisco non ha confermato i risultati del test. Queste cose non vanno mai molto a favore di chi fa il test; d’altra parte, se di sei oggetti testati solo uno o due hanno un problema, probabilmente un laboratorio ha difficoltà sia a pubblicare il test che a trovare qualcuno che lo compri per 3500 $ 😉
L’ultima considerazione riguarda il fatto che tutte queste aperture anomale di connessioni vengano chiamate “attacchi” o “spoofing”. Da un punto di vista pragmatico non può che essere così, visto che si tratta di una caratteristica del TCP che al momento non ha altri usi. Eppure, quando una funzionalità prevista da uno standard viene marchiata con il nome di attacco, ho sempre la sensazione che ci sia qualcosa che non va.