
Abordagem de iniciante para hacking de firmware
Este documento é o relato da minha experiência pessoal como novato em engenharia reversa e exploração de firmware.

Para demonstração, analisaremos e reproduziremos a CVE-2023-27216.
Para explorar qualquer firmware, existem os seguintes passos:
gdbserver estaticamente para depurar.Normalmente, um arquivo binário de firmware contém um bootloader (uBoot), um arquivo de kernel, um cabeçalho de kernel para o bootloader (uImage), um sistema de arquivos compactado (geralmente no formato SquashFS), uma tabela CRC/MD5 (para verificar a integridade dos arquivos) e outros arquivos diversos.
Primeiro, encontre uma maneira de analisar o firmware, faça algumas pesquisas e reúna alguns recursos:

Extraia o firmware usando o binwalk: binwalk -Me DSL-3782_A1_EU_1.01_07282016.bin

Obtive a pasta squashfs-root extraída e alguns arquivos estranhos.

Bônus: Se você não vir a pasta squashfs-root, use unsquashfs em qualquer arquivo ".squashfs" que encontrar. Eles são como arquivos zip 😅.
Verifique a arquitetura e o endianness do firmware. Isso pode ser verificado analisando alguns binários extraídos do firmware. Verifique a arquitetura e o firmware: file <binary>

Aqui podemos quase confirmar que o firmware roda na arquitetura MIPS de 32 bits MSB. O motivo do "quase" é que alguns firmwares podem rodar em uma arquitetura diferente com MIPS Compatible, como Lexra.
Verifiquei a pasta squashfs-root e encontrei alguns arquivos interessantes:
usr/etc/init.d/rcS => Este é o script que executa quando o firmware iniciausr/etc/passwd => Este é o arquivo que contém as informações dos usuáriosuserfs/romfile.cfg => Existe uma credencial admin:adminVerifiquei o arquivo rcS e encontrei um código interessante:
echo "admin:$1$$iC.dUsGpxNNJGeOm1dFio/:0:0:root:/:/bin/sh" > /usr/etc/passwd
passwdBoa é um servidor web antigo, usado principalmente em dispositivos embarcados como roteadores nos anos 2000. No entanto, o servidor Boa interrompeu seu desenvolvimento em 2005! Mesmo estando morto há quase 20 anos, ele ainda vive até hoje graças ao nosso fornecedor.

Recomendo usar um sistema operacional baseado em Debian para o processo de emulação, como Ubuntu ou Kali. Existe outro sistema operacional focado em hacking de firmware chamado AttifyOS. Neste documento, usei Kali Linux. Começando pelo processo de emulação, existem 2 ferramentas:

Vamos ver como usar o FAT para emular completamente um firmware. Primeiro, clonamos o repositório do GitHub para sua máquina Kali. E passamos pelo processo de configuração. Você também precisa alterar o arquivo fat.config, caso contrário não funcionará.
git clone https://github.com/attify/firmware-analysis-toolkit.git
cd firmware-analysis-toolkit
./setup.sh
vi fat.config # Modify to your sudo password.
Em seguida, copiamos o binário do firmware (o que baixamos do fabricante) para a pasta do FAT em nossa máquina Kali e o executamos.
./fat.py DSL-3782_A1_EU_1.01_07282016.bin
Nota: Durante o processo de configuração do FAT, podemos encontrar erros. Ele pode dizer que não há libmagic.

Basta executar
pip unistall python-magic
pip install python-magic
Isso deve resolver o seu problema; em seguida, executamos o comando de compilação novamente. Agora deve funcionar perfeitamente.

Pressione Enter para executar. O processo de emulação deve funcionar bem, e você pode acessar http://192.168.1.1 (na máquina Kali) para verificar se funciona.

Você também pode fazer login no console se tiver as credenciais. Aqui está admin:admin.

Se você decidir desligar o firmware emulado, basta pressionar Ctrl+A X. Quando precisar executar novamente, não rode fat.py outra vez, pois o firmware já foi transformado em uma imagem. Você só precisa executar o script que já foi gerado.
cd firmadyne/scratch/<Image-ID>
./run.sh

Compile gdbserver para fins de depuração. Existem muitas maneiras de compilar gdbserver. Você também pode baixar um servidor compilado estaticamente. Há um repositório que armazena alguns binários compilados estaticamente. No entanto, prefiro compilar o gdbserver eu mesmo, pois os do repositório do GitHub são bastante antigos e podem apresentar problemas de compatibilidade.
Consulte esta postagem do blog como referência: https://sheran.sg/blog/cross-compile-gdb-for-mips/. O blog foi publicado em 30 de julho de 2024, pouco antes deste projeto, então funciona perfeitamente.
Nota: O blog foi feito para MIPS x32 LSB, mas precisamos de MIPS x32 MSB. Precisamos mudar mipsel-linux-gnu para mips-linux-gnu.
Precisamos instalar a toolchain para MIPS. Felizmente, o pacote do Debian já a possui.
**apt update && apt upgrade -y
apt install -y build-essential m4 gcc-mips-linux-gnu g++-mips-linux-gnu**
Para compilar gdbserver para MIPS, há alguns pacotes que precisamos compilar e instalar. Aqui está onde obtenho o código-fonte.
Obtenha o código-fonte
wget https://sourceware.org/pub/gdb/releases/gdb-15.1.tar.xz
wget https://gmplib.org/download/gmp/gmp-6.3.0.tar.xz
wget https://www.mpfr.org/mpfr-current/mpfr-4.2.1.tar.xz
Compile as bibliotecas com a toolchain É crucial ter privilégio de root ao compilar essas bibliotecas. Primeiro precisamos compilar a GMP, pois ela é um requisito para compilar a MPFR.
tar xvf gmp-6.3.0.tar.xz && cd gmp-6.3.0
./configure --host=mips-linux-gnu
make -j$((`nproc`+1))
make install
cd ..
Depois compilamos a MPFR:
tar xvf mpfr-4.2.1.tar.xz && cd mpfr-4.2.1
./configure --host=mipsel-linux-gnu --with-gmp-build=<YOUR-FOLDER>/gmp-6.3.0
make -j$((`nproc`+1))
make install
cd ..
Agora podemos finalmente compilar o gdbserver:
tar xvf gdb-15.1.tar.xz && cd gdb-15.1
./configure --host=mipsel-linux-gnu --with-gmp-lib=/usr/local/lib --with-mpfr-lib=/usr/local/lib --with-gmp-include=<YOUR-FOLDER>/gmp-6.3.0 --with-mpfr-include=<YOUR-FOLDER>/mpfr-4.2.1/src
make -j$((`nproc`+1)) LDFLAGS=-static
O binário compilado gdbserver deve estar na pasta gdb-15.1/gdbserver.
O firmware emulado não possui wget, nc, curl, /dev/tcp, ... Não podemos hospedar um servidor HTTP Python para transferir arquivos. Também não temos ssh. No entanto, ainda podemos colocar nosso gdbserver na máquina emulada montando a imagem.
sudo ./scripts/mount.sh 1gdbserver compilado estaticamente para qualquer lugar na pasta montada.sudo ./scripts/umount.sh 1./run.sh novamente apenas para garantir).

A partir de agora, você pode realizar depuração e hacking dentro da máquina Kali. No entanto, podemos ir além, encaminhando as portas da máquina emulada para nossa máquina host (Windows ou Mac).
Vamos primeiro verificar a rede usando ifconfig.

O resultado nos mostra que existem 2 interfaces: eth0 e tap1_0. Pelo que sabemos, a interface eth0 é a rede compartilhada com o host, e tap1_0 é a interface da máquina de firmware emulada.
Para facilitar o entendimento, a rede eth0 é como uma rede pública, onde podemos acessar a máquina Kali a partir do host. A tap1_0 é como uma rede privada, onde só podemos acessar a partir da máquina Kali. Precisamos encaminhar a conexão de eth0 para a porta 192.168.1.1:80 na interface tap1_0.
Existem muitas ferramentas que podem nos ajudar com isso. No entanto, iptables parece funcionar melhor, se você souber como configurá-lo, é claro.
Devemos permitir o encaminhamento de portas primeiro. Execute este comando:
echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward
Isso se aplica apenas a uma sessão. Se quiser aplicar permanentemente, modifique o conteúdo de /etc/sysctl.conf.
net.ipv4.ip_forward=1 # Find this line, uncomment it.
Salve e feche o arquivo quando terminar.
Em seguida, aplique as configurações deste arquivo. Execute o seguinte comando:
sudo sysctl -p
sudo sysctl --system
Normalmente, podemos executar vários comandos iptables. Mas seria tedioso demais 😵💫. Podemos instalar a ferramenta iptables-persistent. Ela permite gravar um arquivo de configuração, carregá-lo em um arquivo ou extrair chains para um arquivo. Tudo pode ser feito rapidamente.
apt install iptables-persistent
O arquivo de configuração que queremos modificar aqui é /etc/iptables/rules.v4. Alteramos o conteúdo do arquivo para o conteúdo abaixo.
*filter
:INPUT ACCEPT [37:22880]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [35:2330]
# Forward HTTP Port
-A FORWARD -i eth0 -o tap1_0 -p tcp --dport 80 -d 192.168.1.1 -j ACCEPT
-A FORWARD -i tap1_0 -o eth0 -p tcp --sport 80 -s 192.168.1.1 -j ACCEPT
# Forward Debugger port
-A FORWARD -i eth0 -o tap1_0 -p tcp --dport 31337 -d 192.168.1.1 -j ACCEPT
-A FORWARD -i tap1_0 -o eth0 -p tcp --sport 31337 -s 192.168.1.1 -j ACCEPT
COMMIT
# Completed on Wed Aug 7 09:32:11 2024
# Generated by iptables-save v1.8.10 (nf_tables) on Wed Aug 7 09:32:11 2024
*nat
:PREROUTING ACCEPT [60:5405]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [1096:50947]
-A PREROUTING -i eth0 -p tcp -j DNAT --to-destination 192.168.1.1
-A POSTROUTING -o tap1_0 -p tcp -d 192.168.1.1 -j MASQUERADE
Atenção: Permitir todas as portas gera uma série de problemas de segurança. Recomenda-se
DROPem todas as portas e depois apenasFORWARDpara algumas, de acordo com sua necessidade.
Salve e renove a chain do iptables.
service netfilter-persistent reload
Agora você pode acessá-lo de fora do host.

Existem vários endpoints para explorar. Dois deles estão dentro do binário cfg_manager. Vou demonstrar apenas um deles; o outro deixo para você descobrir sozinho.
Jogue o binário no seu decompilador favorito, procure por todos os comandos system, e você pode ver isto. O comando executa um arquivo chamado /etc/lanconfig.sh.

Procurando outros lugares que possam usar esse arquivo, encontrei um lugar onde podemos gravá-lo.

Explicando o que ele faz:
/etc/lanconfig.shmxmlElementGetAttr, que eu suponho que encontra um atributo de um objeto, podendo ser direta ou indiretamente de uma requisição HTTP, possivelmente XML.sprintf para criar uma string a partir dos atributos obtidos de mxmlElementGetAttr.fputs para gravar no arquivo.Imediatamente, procurei por qualquer coisa na pasta web boaroot relacionada a IP, netmask e encontrei isto. A documentação do servidor web Boa é extremamente limitada; só posso supor que ele coloca o parâmetro POST lan_ip1 nos parâmetros IP de um XML que é chamado pelo binário.

Na interface, podemos encontrar a requisição que aciona o bug. Ela está em Settings > Network.

Intercepte a requisição com o Burpsuite quando pressionarmos Save.

O payload 192.168.1.1;utelnetd -p 8090 -l /bin/sh; é um reverse shell. Podemos executá-lo e nos conectar a ele.

Semelhante, pode ser melhor que o FAT, ainda não testei -> FirmAE.
O Binary Ninja custa apenas 74$ se você tiver status de estudante. A licença pode ser compartilhada com qualquer pessoa.
Outros bugs relacionados ao CVE:

Isso também pode levar a RCE; deixarei você fazer isso sozinho. A memória nesse local data_4c0160 pode ser injetada em algum lugar 🫡.

