
NAT Slipstreaming permite que um invasor acesse remotamente qualquer serviço TCP/UDP vinculado a uma máquina vítima, contornando o NAT/firewall da vítima, apenas com alguém na rede da vítima visitando um site
NAT Slipstreaming permite que um atacante acesse remotamente qualquer serviço TCP/UDP vinculado a qualquer sistema atrás do NAT da vítima, ignorando o NAT/firewall da vítima (controle remoto arbitrário de abertura de firewall), apenas com a vítima visitando um site.
v1 desenvolvido por: @SamyKamkar // https://samy.pl
v2 desenvolvido por: Samy Kamkar && (Ben Seri && Gregory Vishnipolsky da Armis).
Leia a excelente descrição técnica de Ben e Gregory sobre v2 aqui que se aprofunda em suas atualizações da v2 com muitos detalhes adicionais.
v1 lançado: 31 de outubro 👻, 2020
v2 lançado: 26 de janeiro, 2021
Código fonte: https://github.com/samyk/slipstream
versão animada aqui gerada com meu fork do draw.io, permitindo fluxo de contexto de borda exportável e controle em animações
NAT Slipstreaming explora o navegador do usuário em conjunto com o mecanismo de rastreamento de conexão Application Level Gateway (ALG) incorporado em NATs, roteadores e firewalls, encadeando extração de IP interno via ataque de tempo ou WebRTC, descoberta remota automatizada de MTU e fragmentação IP, ajuste de tamanho de pacote TCP, uso indevido de autenticação TURN, controle preciso de limite de pacote e confusão de protocolo através de abuso do navegador. Como é o NAT ou firewall que abre a porta de destino, isso ignora quaisquer restrições de porta baseadas no navegador.
Este ataque tira proveito do controle arbitrário da porção de dados de alguns pacotes TCP e UDP sem incluir cabeçalhos HTTP ou outros; o ataque realiza esta nova técnica de injeção de pacote em todos os principais navegadores modernos (e antigos), e é uma versão modernizada da minha técnica original NAT Pinning de 2010 (apresentada na DEFCON 18 + Black Hat 2010). Além disso, novas técnicas para descoberta de endereço IP local estão incluídas.
Este ataque requer que o NAT/firewall suporte ALG (Application Level Gateways), que são obrigatórios para protocolos que podem usar múltiplas portas (canal de controle + canal de dados) como SIP e H323 (protocolos VoIP), FTP, IRC DCC, etc.
Em alto nível, NAT Slipstreaming funciona assim:
.local mDNS/Bonjour apresentado não será útil para o ataque)img ocultas para todos os gateways comuns (ex: 192.168.0.1) são carregadas em segundo planoonerror/onsuccess anexados às tags imgUsamos NATs (Network Address Translation) por várias razões. A característica mais útil do NAT é que permite que um único endereço IP público seja compartilhado entre múltiplos sistemas. Isso é feito criando uma rede local, fornecendo endereços IP locais para todas as máquinas que se conectam, e quando um desses sistemas sai para a Internet, ele reescreve os pacotes de saída para usar o IP público, de modo que as respostas voltem para o NAT, e vice-versa, reescrevendo o IP de destino para o IP específico do cliente.
É responsabilidade do NAT diferenciar conexões para os mesmos endereços/portas (google.com:443) de hosts internos, pois, no final, a porta de saída, o IP de destino e o IP de origem serão os mesmos. Se dois pares internos diferentes tentarem se conectar da mesma porta de origem, NATs modernos alterarão uma das portas de origem (algumas redes fazem isso com todas as portas de origem TCP/UDP).

De Wikipedia ala Wikiwand:``` One of the important features built on top of the Netfilter framework is connection tracking. Connection tracking allows the kernel to keep track of all logical network connections or sessions, and thereby relate all of the packets which may make up that connection. NAT relies on this information to translate all related packets in the same way, and iptables can use this information to act as a stateful firewall.
Se uma máquina atrás do seu NAT envia um pacote para fora e o seu roteador espera que o host remoto possa responder, ele mantém controle das informações, especificamente as portas de origem e destino, endereços IP de origem e destino, e seu IP interno, então retorna quaisquer pacotes correspondentes de volta para o seu IP interno.
Se outro host na sua LAN tentar fazer a mesma conexão com as mesmas portas de origem e destino + IPs, o seu NAT não conseguiria discriminá-lo (os IPs de origem são diferentes na sua LAN, mas são reescritos para o mesmo IP público no lado WAN), então ele altera a porta de origem, mas a reescreve ao enviar de volta para você.
### Gateway de Nível de Aplicação
Os ALGs permitem que o NAT rastreie um protocolo de múltiplas portas como o FTP para sair do seu sistema para um servidor FTP, então rastreia quando você solicita que um arquivo seja enviado para o seu IP interno em uma porta específica, o ALG pode reescrever o pacote para incluir seu IP público e, em seguida, encaminhar a conexão do servidor FTP de volta para você. Se não tivesse reescrito seu IP, o servidor FTP tentaria se conectar de volta a você no seu IP interno (ou nem tentaria se esperar que o IP de origem seja o mesmo da conexão de sinalização).
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.
Primeiramente, gostaria de ver como os gateways comuns realmente tratam pacotes e protocolos de múltiplas portas, como FTP, SIP, etc. Para isso, vamos querer fazer engenharia reversa do firmware de roteadores comuns. Poderíamos extrair a flash de roteadores físicos, no entanto, se conseguirmos firmware não criptografado dos fabricantes, poderemos investigar mais modelos de roteadores e de forma muito mais rápida.
Começaremos com um roteador comum, o Netgear Nighthawk R7000. Uma pesquisa rápida nos ajuda a encontrar um artigo da Netgear com firmware recente. Depois de baixar o firmware e descompactar, encontramos um arquivo de 30MB chamado 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

O comando `file` não detecta nenhuma [informação mágica](https://www.wikiwand.com/en/Magic_number_(programming)), então podemos usar [`binwalk`](https://github.com/ReFirmLabs/binwalk) para escanear o arquivo em busca de dados aninhados.```sh
tigerblood:~c/ng$ binwalk R7000-V1.0.9.64_10.2.64.chk
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
58 0x3A TRX firmware header, little endian, image size: 31703040 bytes, CRC32: 0xBEF1BB2F, flags: 0x0, version: 1, header size: 28 bytes, loader offset: 0x1C, linux kernel offset: 0x21E3F0, rootfs offset: 0x0
86 0x56 LZMA compressed data, properties: 0x5D, dictionary size: 65536 bytes, uncompressed size: 5436416 bytes
2221098 0x21E42A Squashfs filesystem, little endian, version 4.0, compression:xz, size: 29475437 bytes, 1988 inodes, blocksize: 131072 bytes, created: 2018-12-26 04:15:38

Uso macOS e o binwalk depende de alguns aplicativos Linux prontos para uso, o que faria com que binwalk -e (que extrai arquivos) falhasse, então extraio manualmente (e eu <3 perl golf).```sh
tigerblood:~c/ng$ perl -ne'$@.=$_}{print+substr$@,2221098' R7000-V1.0.9.64_10.2.64.chk > squash.fs
Ou use [`inout`](https://github.com/samyk/samytools/blob/master/inout), por exemplo `inout R7000-V1.0.9.64_10.2.64.chk 2221098`.
Você poderia usar `dd`, no entanto você iria querer um `bs` (tamanho de bloco) grande para que a saída seja rápida, por exemplo 1024, porém o atributo `skip` (para indicar para começar na localização do blob squashfs) respeitaria o tamanho do bloco e 2221098 não é obviamente divisível por nada rapidamente de cabeça além de 2...agora estou curioso.```sh
tigerblood:~c/ng$ time dd if=R7000-V1.0.9.64_10.2.64.chk skip=$((2221098/2)) bs=2 of=squash.fs2
14741000+0 records in
14741000+0 records out
29482000 bytes transferred in 78.363403 secs (376222 bytes/sec)
real 1m18.385s
user 0m12.553s
sys 1m4.451s
Agora vamos descompactar o sistema de arquivos squash. Criei um fork de um fork do squashfs-tools que roda no macOS e tem suporte a lzo. Você pode precisar instalar xz e lzo também. Alternativamente, você pode usar o sasquatch no Linux.```sh
tigerblood:~c/ng$ sudo port install xz lzo
...
tigerblood:~c/ng$ git clone https://github.com/samyk/squashfs-tools && cd squashfs-tools/squashfs-tools && make && sudo make install && cd ../..
E finalmente podemos descompactar o 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
Agora temos o SO bruto para explorar!
Agora vamos ver se conseguimos encontrar quaisquer arquivos relevantes para FTP, já que era um protocolo muito utilizado, então o suporte a ALG será abundante em roteadores. Eu uso minha g tool que é apenas um wrapper conveniente para 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 interessante, então vamos `g` para arquivos binários cujo conteúdo corresponda a /ftp/, ignorando alguns arquivos que não nos importam.```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 verifica recursivamente o diretório de trabalho atual por padrão. -l serve para imprimir apenas nomes de arquivos (já que estes serão principalmente binários), -a para escanear arquivos binários, ftp para o texto a corresponder, e -v '\.(html?|js|gif)$|www/|bin/' para ignorar arquivos web e executáveis (localizados em (s)bin/).
Quaisquer arquivos lib/lib*.{a,so}{.*,} (formato bash) são desinteressantes, então vamos escanear novamente com menos:```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 Funções Potencialmente Úteis
Ok, dois arquivos de interesse -- `lib/modules/tdts.ko` pode estar relacionado, e `lib/modules/2.6.36.4brcmarm+/kernel/lib/br_dns_hijack.ko` provavelmente não está relacionado, mas parece interessante! Pode ser que investigue isso mais 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
Legal! Um objeto de kernel (.ko) com funções ftp, e com palavras como "port", provavelmente está relacionado a um ALG de FTP. O FTP RFC 959 explica o significado do 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.
### Portas / Serviços para Investigar
Embora tenhamos encontrado algumas funções FTP, estamos mais interessados em portas que podemos usar. Navegadores modernos impedem conexões HTTP(S) de saída para várias [portas restritas](https://github.com/samyk/chromium/blob/2d57e5b8afc6d01b344a8d5b3470d46b35845c5/net/base/port_util.cc#L20-L90), incluindo FTP, então abusar do FTP ALG provavelmente não é viável.
Em 2010, quando [demonstrei pela primeira vez o NAT Pinning](https://samy.pl/natpin/), usei a porta 6667 (IRC) através das mensagens DCC CHAT/FILE. Rapidamente, os fornecedores de navegadores bloquearam a porta 6667... embora alguns usassem um uint32 (inteiro sem sinal de 32 bits) para armazenar a porta, verificar se a porta estava bloqueada e, se não estivesse, conectar. Para contornar isso, é importante notar que as portas TCP têm 16 bits de comprimento, então se você adicionar 2**16 (65536) à porta "restrita" escolhida, neste caso 65536+6667=72203, o navegador armazenaria 72203, passaria na restrição de porta (72203 != 6667) e então seria enviado para a pilha TCP onde seria truncado para 16 bits, que é a porta restrita que queríamos!
Minha simples [`base calculator, 3`](https://github.com/samyk/samytools/blob/master/3) mostra isso (db = dec -> bin):```sh
tigerblood:/Users/samy/d$ 3 db 65536 6667 65536+6667
000000010000000000000000
000000000001101000001011
000000010001101000001011
Podemos ver melhor com a minha ferramenta diffbits, uma ferramenta simples para visualizar semelhanças e diferenças entre strings de bits, bem como entre múltiplos grupos de strings de bits, útil para engenharia reversa de protocolos binários proprietários.

Vá em frente e abra seu desassemblador de escolha. Eu usei o Ghidra dos nossos amigos da NSA, pois é gratuito e de código aberto.
Algumas das funções que vimos em tdts.ko através de strings foram ftp_decode e ftp_decoder, então é possível que outros ALGs tenham uma função _decode. Vamos ver...

Certo, várias funções _decode...rolando para baixo, uma interessante é sip_decode.

Verificando as portas restritas do nosso navegador, vemos que a porta 5060, a porta padrão do SIP, não é restrita no Chrome :)
O SIP vive na porta TCP/UDP 5060, mas a mídia como RTP (áudio) é enviada em portas alternativas que são geradas dinamicamente. Ao enviar uma requisição para uma chamada SIP, seu cliente SIP escolhe uma porta aleatória, abre-a e a inclui no cabeçalho SIP. Seu NAT também deve vê-la e abri-la, assumindo que o ALG SIP esteja ativado (e está ativado na maioria dos roteadores por padrão).
Assumindo que NATs leem pacotes SIP linha por linha (SIP é baseado em linhas como HTTP e não é um protocolo binário), talvez ele ignore o cabeçalho HTTP e, ao chegar nos dados do POST, leia o REGISTER e acredite que é um pacote SIP. Isso funcionou na nossa versão de 2010 para o IRC DCC. O NAT ignorou o cabeçalho HTTP e apenas analisou o comando IRC DCC.
Engraçado, isso também nos permitiu fazer com que usuários que visitassem nosso site se conectassem a um servidor IRC legítimo, entrassem em um canal e enviassem uma mensagem a partir do IP deles sem que soubessem! :P Demonstrei essa técnica para enviar e-mails para servidores de correio com endereços IP de clientes antes da porta 25 ser bloqueada pelos navegadores e antes dos registros SPF serem comuns... loucura.
Agora, em um teste rápido, enviar um pacote SIP REGISTER pela porta 5060 através de um POST HTTP parece não funcionar... talvez estejamos perdendo algo no pacote.```javascript // our sip message var sipmsg = 'REGISTER sip:samy.pl;transport=TCP SIP/2.0\r\n' + 'Contact: sip:[email protected]:1234;transport=TCP\r\n\r\n'
// load form in an iframe so user doesn't see it var iframe = document.createElement('iframe') iframe.name = 'iframe' iframe.style.display = 'none' // hide the iframe
// create form var form = document.createElement('form') form.setAttribute('target', 'iframe') // load into iframe form.setAttribute('method', 'POST') // need the POST area where we can add CRLFs form.setAttribute('action', 'http://samy.pl:5060') // "http" server on SIP port 5060 form.setAttribute('enctype', 'multipart/form-data') // ensure our data doesn't get encoded
var textarea = document.createElement('textarea') textarea.setAttribute('name', 'textname') // required textarea.innerHTML = sipmsg form.appendChild(textarea) document.body.appendChild(iframe) document.body.appendChild(form) form.submit()
Se farejarmos, vemos (analisado 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--
No entanto, isso não abre a porta, nem o IP é reescrito como esperaríamos (mais sobre isso adiante), então deve estar faltando algo.
Vamos continuar investigando o objeto do kernel. No desassembly, vemos a tag "SIP/2.0" de um pacote SIP, então é provável que esteja fazendo parsing aqui (o que "decode" parece indicar).

Ah, é por isso que falhamos. Parece que está executando strncasecmp em INVITE (parsing semelhante no REGISTER) — comparando (case-insensitive, o que é interessante, já que INVITEs SIP estão em maiúsculas) a palavra "INVITE" no início do pacote e branches if not equal (assembly ARM bne) para 0, ou seja, se as palavras coincidirem, a ordem lexicográfica será 0 e continuaremos para ct_sip_get_header, o que parece divertido, e parece abortar caso contrário.
Este é o problema... embora possamos usar um navegador web para criar sockets de saída (TCP via HTTP(S), UDP via TURN com WebRTC), não temos controle suficiente sobre o navegador para iniciar a porção de dados TCP com a palavra "INVITE", que este módulo espera. Na versão IRC de 2010, o ALG IRC apenas analisava linha por linha, ignorando todos os dados do cabeçalho HTTP, usando linhas novas nos dados POST para enviar um "IRC DCC" válido. No entanto, este ALG SIP é muito mais restritivo e controlar o início do pedido não é possível. Se usar TLS, o cabeçalho encriptado iniciará o pacote. Se usar HTTP, o método HTTP começará o pacote (GET, POST, etc). Podemos explorar isso de outra forma?
Para entender melhor o rastreamento de conexão e os Gateways de Nível de Aplicação, podemos ver como eles se comportam no netfilter, a pilha de rede do Linux. Criei um gráfico dos ALGs mais comuns e como eles se comportam com base na análise do código fonte do Linux.

A partir deste gráfico, os mais interessantes (que o Chrome não bloqueia) são sane (backup), sip (voip), pptp (vpn) e h323 (voip). Vamos escolher SIP, pois é um dos protocolos mais ubíquos destes, e já o vemos em alguns firmwares de roteadores.
O Linux especificamente tem arquivos nf_conntrack_*.c para lidar com o rastreamento de conexão por protocolo, e nf_nat_*.c para manipulação (modificação) de pacotes.
Vamos dar uma olhada rápida no módulo de rastreamento de conexão SIP
module_init(nf_conntrack_sip_init) inicializa este rastreador de conexão, chamando nf_conntrack_sip_initnf_ct_helper_init(...AF_INET, IPPROTO_TCP, "sip", SIP_PORT...) esperamos que a sinalização venha de IPv4 AF_INET TCP IPPROTO_TCP porta 5060 SIP_PORT...isto ocorre para UDP, TCP, IPv4 e IPv6sip_help_tcp(...) chamado quando um pacote TCP SIP correspondente chega
process_sip_msg(...) se isto parece um potencial pacote SIP
Pelo que sabemos, não podemos fazer com que o navegador force uma conexão TCP de saída com o tráfego que quisermos, e é necessário criarmos um pacote TCP/UDP começando com um método SIP como REGISTER ou INVITE.
O Flash costumava permitir sockets de saída, mas estava num formato sobre o qual não tínhamos controlo total. Java requer permissão. WebSockets ainda são HTTP. TLS está encriptado. WebRTC (RFC 7742) está encriptado. STUN (RFC 3489) e TURN (RFC 5766) estão em formatos fixos, e TURNS (RFC 7065) está encriptado.
Num nível alto, não podemos controlar o início do pacote TCP, mas e se enviarmos um pacote demasiado grande? Deve haver um tamanho máximo de pacote... ponto em que um pacote tem de ser fragmentado em vários pacotes. Se conseguirmos exceder o tamanho do pacote TCP e controlar precisamente parte dos dados, poderíamos causar segmentação de pacotes e ter os nossos dados no início do nosso próximo pacote excedido?
Bem, precisaríamos saber quantos dados o navegador enviará, o que será diferente por navegador, e até mesmo por utilizador, pois podem enviar cabeçalhos HTTP diferentes. HTTPS não funcionará, pois a maior parte do conteúdo está encriptado, enquanto um HTTP POST permite-nos controlar uma grande porção do cabeçalho.
Para obter o tamanho geral do pacote, enviamos um HTTP POST grande (6000 bytes) com um ID e dados de enchimento com um formulário web oculto para o nosso http://our.attack.server:5060/pktsize. No servidor de ataque, executamos um sniffer de pacotes que procura as fronteiras do nosso pacote para determinar o tamanho MTU (Maximum Transmission Unit), tamanho do cabeçalho IP, potenciais opções IP, tamanho do cabeçalho TCP, potenciais opções TCP, tamanho do pacote de dados, e que porção do pacote controlamos.
Também executamos um servidor personalizado que escuta na porta TCP 5060 e responde com tráfego HTTP para aplacar o navegador, de modo que nada pareça suspeito no lado do cliente (um servidor com uma resposta malformada causaria erros na consola, ou um servidor a responder incorretamente manteria o spinner de estado ativo).

Tentamos ainda controlar o tamanho dos dados do pacote TCP enviando uma opção TCP Maximum Segment Size (mss) durante a resposta SYN inicial para manipular os tamanhos dos pacotes de saída da vítima (RFC 793 x3.1). Isto diz à máquina da vítima para manter os pacotes TCP com um determinado tamanho.

Pode fazer isto no Linux anexando advmss <size> ao ip route. Usaremos 1500.```sh
ip route replace default via [gateway] dev eth0 advmss 1500
Assim que obtivermos os pacotes, enviamos os dados de tamanho de volta ao cliente vítima através de um POST separado, que envia o ID da vítima para podermos correlacioná-lo com a requisição original da vítima. Neste ponto, o cliente tem uma boa noção de como preencher pacotes para fazer com que dados arbitrários cheguem a qualquer localização específica em um pacote TCP.
### Fragmentação IP com UDP e TURN
Alguns NATs permitem acesso a portas UDP apenas se a conexão SIP foi originalmente UDP, então usamos TURN neste caso. TURN é um protocolo que suporta relay para comunicação peer-to-peer como SIP e WebRTC. TURN é UDP enquanto TURNS (TURN+TLS) é TCP. Navegadores modernos suportam TURN para WebRTC caso não consigam estabelecer uma conexão direta peer-to-peer entre si para compartilhamento de mídia.
TURN permite autenticação via nome de usuário e senha, onde o nome de usuário é enviado em texto claro. Curiosamente, o nome de usuário não é limitado por tamanho ou caracteres, então podemos usar isso para realizar o mesmo tipo de overflow de pacote.
Como TURN é sobre UDP, o próprio pacote IP será fragmentado se exceder o tamanho MTU (UDP não suporta segmentação). O segundo pacote não terá apenas a porção de dados sob nosso controle, mas também o cabeçalho UDP! Isso não é importante para nosso ataque, mas é interessante e pode definitivamente produzir ataques alternativos. No final, podemos realizar o mesmo ataque via UDP alinhando nosso limite de pacote com base no tamanho MTU calculado, em vez do tamanho MSS, fazendo com que nosso pacote SIP UDP viva no limite do segundo pacote (com um cabeçalho UDP falso anexado), permitindo-nos encaminhar portas UDP de volta para nossa vítima.
## Ataque de Temporização TCP / Descoberta de Sub-rede Interna e IP
Ah, isso ainda não vai funcionar! Para que o ALG trate como um pacote SIP legítimo, o endereço IP que você está solicitando que os dados retornem (na linha [`Contact`](https://tools.ietf.org/html/rfc2543#section-6.13) do SIP) deve ser o IP interno (vítima) de onde o pacote SIP veio, o qual não conhecemos. Apenas o endereço IP público do roteador é transmitido para nosso servidor (pois o NAT reescreve o IP de origem quando ele sai pelo lado público).
Vemos esta verificação no `process\_sip\_request` do Linux em `nf_conntrack_sip.c` ([link](https://github.com/samyk/linux/blob/ea2cec24c8d429ee6f99040e4eb6c7ad627fe777/net/netfilter/nf_conntrack_sip.c#L1260)):

Em [2010](https://samy.pl/natpin/), usamos [LiveConnect](https://developer.mozilla.org/en-US/docs/Archive/Web/LiveConnect) que permitia executar código Java sob algumas condições a partir de Javascript, extraindo o IP local do usuário. Isso se tornou obsoleto rapidamente.
Em alguns navegadores (Chrome, Firefox), podemos usar [WebRTC](https://www.w3.org/TR/webrtc/) para obter o endereço IP interno da vítima via [ICE](https://tools.ietf.org/html/rfc5245) (que usa apenas STUN/TURN/TURNS). Estes são protocolos para ajudar peers atrás de NATs a determinarem informações sobre si mesmos. Ironicamente, nenhum servidor precisa ser usado na "requisição" ICE, pois o navegador já conhece seu IP interno, e um servidor STUN/TURN remoto não saberia disso a menos que o cliente o enviasse em primeiro lugar. O problema é que nem todos os navegadores fornecem este mecanismo.
Atualmente, usar WebRTC para obter o endereço IP local no Chrome, em vez de um endereço `.local` mDNS/Bonjour, requer HTTPS, mas HTTP é necessário para o restante dos ataques, então primeiro detectamos se estamos em HTTP e, se não, redirecionamos para HTTPS. Então tentamos usar WebRTC para extrair o endereço IP local. De qualquer forma, redirecionamos de volta para HTTP com o(s) IP(s) anexado(s) à URL para contornar restrições de origem cruzada via outros métodos de comunicação.
### Ataque de Temporização
Se usar Safari, IE <= 11 ou outros que não suportam WebRTC ou intencionalmente não revelam IP interno (Safari), podemos usar um ataque de temporização web para revelar o endereço IP interno da vítima.
Conseguimos isso primeiro produzindo tags `` HTML ocultas na página, todas para gateways comuns (192.168.*.1, 10.0.0.1 e [outros](https://github.com/samyk/slipstream/blob/main/server#L159)), juntamente com eventos Javascript `onsuccess` e `onerror`. Cada vez que uma img é escrita na página, um temporizador é iniciado e, se o `onsuccess` carregar, isso significa que o IP respondeu com um servidor web; se nenhum servidor web estiver rodando mas o IP estiver na rede, ele enviará um TCP RST (reset, significando porta não aberta) de volta, acionando o `onerror`. Se nenhum IP existir, nenhum RST é enviado e a resposta levará > 1 segundo, momento em que sabemos que o IP não existe em nossa rede.
Assim que vemos um desses eventos disparar, sabemos uma potencial sub-rede interna em que estamos; então realizamos o mesmo ataque para cada IP na sub-rede (ex: 192.168.0.[2-255]), e desta vez realizamos uma temporização mais precisa para determinar qual IP responde **mais rápido**. Este é provavelmente nosso próprio IP interno (vítima), pois nem precisamos sair da interface de rede. Mesmo que não sejamos os primeiros por algum motivo, ainda tentamos nosso ataque em todos os IPs que responderam na rede.
## Confusão de Protocolo do Navegador
Assim que o cliente obtém os tamanhos dos pacotes e o endereço IP interno, ele constrói um formulário web especialmente criado que preenche os dados POST até acreditarmos que o pacote será fragmentado, momento em que nosso SIP REGISTER contendo o endereço IP interno é anexado. O formulário é submetido via Javascript sem consentimento da vítima. :)
[](img/pinpkt.png)
### Alteração de Pacote ao Vivo no Navegador
Em nosso servidor de ataque, como podemos ver os pacotes chegando, verificamos se o pacote SIP foi reescrito com o endereço IP público. Se não foi, comunicamos de volta ao cliente (automaticamente) que o pacote SIP não estava no limite de pacote esperado e não foi reescrito, e fornecemos a nova posição do limite a partir do nosso sniffer.
O código cliente ajusta automaticamente seu tamanho de pacote para o novo tamanho apenas após duas falhas consecutivas. Alguns navegadores (Firefox) às vezes terão um tamanho de pacote ligeiramente diferente devido ao multipart-boundary que geram para o formulário, que, ao contrário da maioria dos outros navegadores, não tem um comprimento fixo. Acho que após cerca de 10 tentativas, o mesmo tamanho será usado e o ataque será bem-sucedido.
Assim que o pacote SIP cair no limite de pacote, o NAT será enganado, acreditando que é um registro SIP legítimo e de um cliente SIP na máquina da vítima. Uma vez que nosso servidor responda com uma resposta SIP adequada (aninhada dentro de uma resposta HTTP apropriada para que o navegador não detecte nada suspeito), o NAT abrirá a porta no pacote original que fizemos a vítima enviar, e o roteador agora **encaminhará qualquer porta que o atacante escolher de volta para a vítima interna, tudo simplesmente navegando para um site**.
Ataque completo. O atacante pode agora se conectar a serviços TCP/UDP arbitrários em execução na vítima.
# Outras Descobertas
Estas não são usadas neste ataque, mas são interessantes e poderiam potencialmente ser usadas para outros ataques.
- A fragmentação IP permite controle total de todos os dados na seção de dados IP, significando controle total de um cabeçalho UDP incluindo portas de origem/destino no pacote com overflow
- A pilha IP da vítima remonta e não analisará os dados, no entanto o NAT pelo qual o pacote passa será suscetível
- Permite contornar firewall do navegador ou do sistema, pois apenas a porta UDP que é inspecionada é o pacote original, não o pacote fragmentado com overflow
- DoS em um cliente SIP enviando `Expires: 0` e removendo o conntrack de outra pessoa
- Se uma porta já está ocupada, a porta ouvida é incrementada até que a porta transborde para 0
- STUN não tem autenticação implementada em nenhum navegador moderno
# Download
Obrigado por ler! Você pode baixar o código de prova de conceito do meu [github do NAT Slipstream](https://github.com/samyk/slipstream).
# Contato
**Ponto de Contato:** [@SamyKamkar](https://twitter.com/samykamkar)
Encontre mais dos meus projetos em <https://samy.pl> ou entre em contato via <[email protected]>.
username do TURN preenchido
username especialmente criado, forçando fragmentação IP e controle preciso de limiteusername é "preenchido" até o tamanho exato do segmento TCP / limite do pacote, em seguida, o “pacote H.323” anexado e postado via formulário webprocess_sip_request(...)strncasecmp(*dptr, handler->method, ...) o handler abortará a menos que o método (ex., REGISTER) ocorra no início da porção de dados do pacote (TCP ou UDP) como vimos com INVITE acima...REGISTER é apenas outro comando SIPprocess_register_request(...)nf_ct_expect_init(...) via sip_handlers inicializamos o pinhole de firewall (porta para permitir que uma pessoa remota se conecte de volta), mas ainda não abrimosnf_nat_sip_hooks -> nf_nat_sip(...) o NAT também manipula (reescreve) o endereço IP interno do cliente para o IP público do NAT para que o destino possa alcançá-lo adequadamentesip_help_tcp(...) -> process_sip_msg(...) ->
process_sip_response(...) agora estamos olhando para a resposta SIP do servidor SIP
process_register_response(...) -> refresh_signalling_expectation(...) a porta é encaminhada pelo NAT apenas depois que uma resposta SIP válida é enviada pelo servidor SIP