Post

Anatomía de una infección Bigpanzi: mi Android TV trabajaba para una botnet

cadena de infección

Hay incidentes que te eligen. Este empezó con un correo raro de mi ISP avisando de que mi IP aparecía en una lista negra, y terminó conmigo sentado frente a un Android TV de 2017 que llevaba 14 meses ejecutando un backdoor como root y alquilando mi conexión a terceros.

Esta es la historia completa, con la metodología, el protocolo C2 que logré recuperar y todo lo que haría distinto. Todo el análisis se hizo sobre mi propia red y mi propio dispositivo, en modo lectura, y sin interactuar con la infraestructura del atacante.

Los datos personales (IP pública, cuenta de Google, MAC) están enmascarados. Los IOC de red sí están completos: son infraestructura del atacante y sirven para que otros puedan detectarla.

Resumen en 30 segundos

Qué Detalle
Dispositivo Android TV KII PRO (p20x, Amlogic)
Sistema Android 5.1.1, SDK 22, build userdebug de 2017
Malware pandoraspearrk — familia Pandora / BADBOX 2.0
Grupo Bigpanzi (botnet de TV boxes, activa desde ~2015)
Persistencia supervisord como watchdog root, autorestart=true
C2 45.56.117.139:9999 y otras 3 IPs en el puerto 9999
Efecto Proxy residencial + shell root + nodo DDoS
Consecuencia IP pública listada en DroneBL (Class 6, fuente CBL)

Herramientas y recursos usados

Técnica Herramienta Objetivo
Reputación de IP DroneBL, Spamhaus Confirmar el listado
Descubrimiento arp-scan, nmap, mDNS Mapear la LAN
Acceso al device adb (root) Enumeración autorizada
Forense volátil /proc/net/tcp, netstat, ss Socket → proceso
Análisis de artefactos file, strings, aapt, readelf Identificar binarios y APKs
Sinkhole iptables DNAT + listener Python Capturar el protocolo C2
Ingeniería inversa Unicorn, Capstone, Ghidra Entender el empaquetado
Captura tcpdump Evidencia de red

1. La señal: una IP en una lista negra

La primera pista no fue técnica, fue administrativa. Un aviso indicaba que la IP pública del hogar estaba listada en DroneBL, incidente con clasificación Class 6 — Unknown worm or spambot, alimentada por CBL.

Esa clasificación casi nunca es un falso positivo accidental: la CBL detecta patrones de spam, escaneos o proxying saliente. En una casa con tres móviles, una PC y una TV, la pregunta era obvia: ¿quién está generando ese tráfico?

2. Barrido de la red local

Con la máquina de análisis en la misma LAN, lo primero es tener inventario real, no el que uno cree tener.

1
2
sudo arp-scan -I eth0 --localnet
sudo nmap -sn 192.168.18.0/24 -oG hosts

El barrido devolvió router, un Ubiquiti, la PC de análisis, los móviles y 192.168.18.11, un dispositivo que se anunciaba por mDNS como reproductor AirPlay (ATV_11). Era el Android TV.

El paso siguiente fue mirar qué puertos exponía:

1
sudo nmap -p- -sS -sV -Pn 192.168.18.11 -oN tv_ports

Resultado incómodo: 5555/tcp abierto, el puerto de ADB, sin autenticación. En la LAN. Cualquier dispositivo de la red podía conectarse con adb connect y obtener shell.

1
2
3
adb connect 192.168.18.11:5555
adb root
adb shell

ADB expuesto en red es una de las puertas traseras más comunes en TV boxes baratas. No es una vulnerabilidad exótica: viene activado de fábrica en muchos firmwares.

3. Dentro del dispositivo

Ya con shell root, el objetivo es responder tres preguntas: qué corre, qué habla con Internet y qué sobrevive a un reinicio.

1
2
3
ps -A -o PID,USER,NAME,ARGS
cat /proc/net/tcp
netstat -antp

Tres procesos destacaron de inmediato:

Proceso PID Rol
/system/bin/pandoraspearrk 3805 Backdoor principal, mantiene el C2
/data/data/com.waxrain.airplaydmr/files/wdog2 4454 Proxy + ejecución remota root
/system/bin/supervisord 3793 Watchdog root que relanza el backdoor

Y la conexión que lo confirmaba todo:

1
192.168.18.11:60267 -> 45.56.117.139:9999  ESTABLISHED   (/system/bin/pandoraspearrk)

Un binario en /system/bin (partición de solo lectura en teoría), corriendo como root, con una conexión persistente al puerto 9999 de un VPS en Linode. No había mucho margen para interpretaciones.

3.1 Artefactos encontrados

Fichero Función
/system/bin/pandoraspearrk Backdoor (Android.Pandora.2)
/system/bin/supervisord Watchdog empaquetado con UPX
/data/supervisord.tar.gz Kit de infección completo
/data/data/com.waxrain.airplaydmr/files/wdog2 Proxy / exec root
/data/data/com.waxrain.airplaydmr/lib/libpreloader.so Payload auxiliar (timestamp falso: 1979)
/data/local/tmp/server.apk APK com.cetusplay.remoteservice
/system/etc/hosts DNS secuestrado (58 dominios)

El kit de persistencia era el hallazgo más interesante:

1
2
adb shell tar tzvf /data/supervisord.tar.gz
# pandoraspearrk  supervisord  s.conf  curl  arp  tar

Y dentro, s.conf:

1
2
3
4
5
6
7
[supervisord]
logfile=/data/sp.log
pidfile=/data/sp.pid

[program:pd]
command = /data/pandoraspearrk
autorestart=true

Ahí está el diseño. supervisord corre como root y relanza pandoraspearrk cada vez que muere. En sp.log había 2.012 reinicios entre el 2025-07-03 y el 2026-09-27. Matar el proceso a mano no sirve de nada: vuelve en segundos.

4. El secuestro de DNS

El /system/etc/hosts había sido reescrito con 58 dominios apuntando a 37 IPs de la infraestructura. No es un detalle menor: con eso el malware se asegura de que, incluso si el usuario cambia el DNS del router, el dispositivo siga resolviendo los dominios del atacante a sus propias IPs.

1
adb pull /system/etc/hosts hosts.modificado

Un extracto representativo:

1
2
3
4
5
6
7
8
173.255.212.243 apz.pdonno.com
173.255.212.243 ok3.mflve.com
173.255.212.243 pcn.panddna.com
139.144.201.58  pandorabackup-1322908155.us-west-2.elb.amazonaws.com
23.12.198.13    ageniustv1.cc
54.149.89.70    eumk.wak2p.com
71.19.250.244   www.htvmarket.com
127.0.0.1       pcdnbus-bk.a2k3v.com

Los dominios no son aleatorios: pertenecen a un ecosistema de IPTV/streaming pirata (agenius*, htvmarket, qicicloud, wak2p). El negocio y el vector de infección son la misma cosa.

La línea 127.0.0.1 pcdnbus-bk.a2k3v.com apunta al downloader a localhost: el malware bloquea su propia vía de actualización una vez que ya no la necesita, para que nadie más lo actualice.

5. El C2

Cuatro IPs respondían en el puerto 9999:

1
2
3
4
45.56.117.139     Linode/Akamai (US)   <- conexión observada
173.255.212.243   Linode/Akamai (US)
173.255.221.98    Linode/Akamai (US)
71.19.252.14      eSecureData (CA)

Y una segunda capa de infraestructura en velia.net (DE), GorillaServers (US) y un ELB de AWS con el nombre pandorabackup-.... La separación entre “C2 principal” y “backup” es deliberada: si tumbas uno, el bot tiene a dónde volver.

6. Sinkhole local: cortar el mando sin tocar al atacante

Aquí hay una decisión ética y legal importante. No hay que conectarse al C2 del atacante. Lo que hice fue redirigir el tráfico del propio dispositivo hacia una máquina de mi red, usando iptables en el propio TV (root) con DNAT:

1
2
3
4
iptables -t nat -A OUTPUT -p tcp -d 45.56.117.139   --dport 9999 -j DNAT --to-destination 192.168.18.14:9999
iptables -t nat -A OUTPUT -p tcp -d 173.255.212.243 --dport 9999 -j DNAT --to-destination 192.168.18.14:9999
iptables -t nat -A OUTPUT -p tcp -d 173.255.221.98  --dport 9999 -j DNAT --to-destination 192.168.18.14:9999
iptables -t nat -A OUTPUT -p tcp -d 71.19.252.14    --dport 9999 -j DNAT --to-destination 192.168.18.14:9999

El sinkhole es un listener TCP que solo escucha:

1
2
3
4
5
6
7
8
9
10
11
12
13
import socket

srv = socket.socket()
srv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
srv.bind(("0.0.0.0", 9999))
srv.listen(5)
print("sinkhole 9999 escuchando")

while True:
    conn, addr = srv.accept()
    data = conn.recv(4096)
    print(addr, len(data), data[:80])
    conn.close()

Efecto secundario útil: mientras las reglas están puestas, el bot no alcanza su C2 real. Es contención sin modificar el malware ni atacar a nadie.

1
2
# revertir siempre al terminar
iptables -t nat -D OUTPUT -p tcp -d 45.56.117.139 --dport 9999 -j DNAT --to-destination 192.168.18.14:9999

Esta contención es temporal y reversible. No sustituye a desconectar el equipo. Si tienes dudas legales sobre tocar el dispositivo, habla con tu CERT antes.

7. El protocolo C2, recuperado

Aquí está la parte que más valor tiene del análisis. Con el sinkhole pasivo se capturó el handshake completo:

formato del beacon

  • Mensajes de 1024 bytes exactos.
  • Payload útil de 60 caracteres, relleno de 0x00 hasta 1024.
  • Codificación base64 con alfabeto propio: A-Za-z0-9./ (usa . en vez de +).
  • Al decodificar: 45 bytes = 36 B de ID estable + 9 B de nonce.

El ID estable es oro para detección: es el mismo en todos los beacons del dispositivo.

1
2
ID    : d92936f3e05db722f56867f063ece82a9d3f304edc934f05faa1f4c67378d743a8f5f4f4
nonce : cambia en cada beacon (9 bytes)

Y el comportamiento temporal:

1
2
3
19:02:27  connect -> beacon inmediato
19:04:32  close  (~125 s esperando respuesta)
19:05:08  reconnect

Un beacon cada ~2,5 minutos, con ~2 minutos de espera. Si el servidor no contesta, cierra y reintenta.

7.1 Experimentos de interacción

Con el sinkhole activo probé qué acepta el bot como respuesta del C2:

# Respuesta enviada Tamaño Reacción
0 echo de su propio paquete 1024 B cierra en ~20 ms
1 1024 bytes de ceros 1024 B espera >120 s (equivale a “sin comando”)
2 su token ASCII devuelto 60 B cierra a los ~30 s
3 "OK" 2 B cierra a los ~30 s

Conclusiones:

  1. El bot valida el contenido de la respuesta: un echo se rechaza al instante.
  2. Cualquier respuesta menor de 1024 B provoca un timeout corto.
  3. El C2 real responde con 1024 B con un formato concreto (probablemente cifrado).
  4. Para replicarlo hay que reversar el binario. Eso quedó pendiente.

8. Ingeniería inversa del binario

pandoraspearrk es un ELF de 32 bits, ARM, estáticamente enlazado y stripped. Lo interesante aparece al mirar la estructura:

1
readelf -h pandoraspearrk
  • Entropía global 7,85 / 8 → empaquetado o cifrado.
  • Tabla de secciones eliminada (solo .shstrtab y .ARM.attributes).
  • Cabecera ELF no estándar: dos segmentos LOAD, ambos desde offset 0.
  • Entry point en 0x38584c, fuera de cualquier sección normal.

El entry point es un stub de descompresión: lector de bits, copia de literales, copia de coincidencias. Un unpacker clásico.

En ejecución, /proc/<pid>/maps confirma el patrón:

1
2
3
aaac3000-aacee000 r-xp   (código descomprimido, ~2.3 MB, sin fichero)
aacee000-aad00000 r--p   (rodata)
aad00000-aad29000 rw-p   (datos)

El fichero en disco solo aparece mapeado como una página r--p. Todo el código real se descomprime en memoria anónima. Por eso los antivirus basados en firma de fichero tienen tan poco que rascar.

8.1 Lo que no funcionó

Intenté volcar memoria desde el propio dispositivo:

1
2
dd if=/proc/3805/mem of=/data/dump.bin bs=1M
# -> I/O error

Falla también para init, con CapEff completo y SELinux en Permissive: no es DAC ni SELinux, es una restricción del kernel. Core dumps deshabilitados (Max core file size = 0). Los tombstones que había no eran del malware.

8.2 Emulación con Unicorn

Construí un emulador ARM (Unicorn + Capstone) que mapea los segmentos, implementa syscalls (open/read/lseek/mmap/brk/mprotect) y ejecuta desde el entry point. En la v5 reconstruí la pila inicial estilo kernel (argc/argv/envp/auxv con AT_PHDR, AT_ENTRY, AT_PAGESZ, AT_EXECFN), que es lo que el loader PIE necesita.

El loader avanzó: open(/proc/self/exe), mmap2, mprotect, readlink… pero no completó el desempaquetado limpio. Es un loader PIE propio, de los que usan los packers de Android. Se extrajo una segunda etapa de ~2968 B con una rutina de copia inversa y escritura de = y espacios compatible con base64, pero el formato del paquete de comando del C2 quedó sin recuperar.

Conclusión honesta: con Unicorn puro no merece la pena forzarlo. Lo correcto es Qiling con rootfs ELF32, o ejecutar el loader en un laboratorio aislado con qemu-arm y red deshabilitada. El objetivo defensivo principal ya estaba cubierto: el protocolo de registro está íntegramente caracterizado.

9. Quién está detrás

El binario corresponde a Android.Pandora.2 (nomenclatura Dr.Web) y encaja con el malware pandoraspear + downloader pcdn del grupo Bigpanzi:

  • Sindicato de ciberdelito activo desde ~2015, con origen en China/sudeste asiático.
  • Reportes públicos hablan de ~800.000 nodos activos diarios.
  • QiAnXin Xlabs observó ~170.000 dispositivos al interceptar dos de sus dominios C2.
  • El FBI publicó un PSA en 2025 sobre BADBOX 2.0 en dispositivos IoT domésticos.

El modelo de negocio es claro: proxy residencial (vender tu IP y tu ancho de banda a terceros), nodos DDoS y fraude publicitario con apps llenas de SDKs de anuncios.

10. Línea temporal

timeline

Fecha Evento
2017-08-03 Build del firmware (Android 5.1.1)
2025-04-21 Instalación de Downloader + aparición de supervisord.tar.gz
2025-07-03 → 2026-09-27 Actividad del backdoor (2.012 reinicios)
2025-12-26 mtime de pandoraspearrk (actualización del backdoor)
2026-01-24 IP listada en DroneBL (CBL)
2026-10-05 Análisis, contención y recolección de evidencia

Ocho meses entre el listado en la lista negra y el análisis. Ese es el coste real de no mirar.

11. Impacto

  • Uso fraudulento de la IP y el ancho de banda: la IP pública se alquilaba a terceros.
  • Reputación comprometida: listas negras, posible bloqueo de servicios legítimos.
  • Riesgo de pivote: un dispositivo con root en la LAN es una posición de salida hacia el resto.
  • Exposición de la cuenta de Google asociada al dispositivo.

12. Qué hice mal (y qué haría distinto)

Ser honesto con los errores es la parte útil de un writeup:

  1. Compré una TV box barata con Android 5.1.1 en 2017 y nunca la actualicé. Sin parches de seguridad desde hace casi una década. Un dispositivo sin soporte no es un electrodoméstico, es deuda técnica.
  2. Instalé APKs de fuentes externas para tener “más canales”. Ese es el vector.
  3. Nunca revisé los puertos abiertos de mi propia red. ADB en 5555 llevaba años ahí.
  4. Tardé meses en reaccionar al aviso de la lista negra.

Lo que sí funcionó: aislar el dispositivo primero, recolectar evidencia con hashes antes de tocar nada, y no intentar “limpiar” un sistema con root en /system.

13. Cómo saber si tu dispositivo está infectado

Checklist rápido, en orden:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 1. ¿Hay ADB abierto?
nmap -p 5555 192.168.1.0/24

# 2. Procesos raros como root
adb shell ps -A -o PID,USER,NAME | grep -Ei "supervisor|pandora|pcdn|wdog"

# 3. Conexiones al puerto 9999
adb shell cat /proc/net/tcp | grep -i ":270F"   # 9999 en hex

# 4. ¿hosts secuestrado?
adb shell cat /system/etc/hosts

# 5. ¿Watchdog persistente?
adb shell ls -l /data/supervisord.tar.gz /data/sp.log

Señales de alarma en el día a día:

  • La TV va lenta sobre todo cuando está “apagada” (en standby sigue encendida por dentro).
  • Consumo de subida alto en el router sin explicación.
  • La IP aparece en DNSBL (DroneBL, Spamhaus).
  • Dominios de IPTV pirata resolviendo a IPs que no son las del proveedor.

14. Remediación: lo que realmente funciona

  1. Desconectar de Internet ahora, aislar en el router o VLAN.
  2. Bloquear los IOC en router, Pi-hole o firewall.
  3. Desactivar UPnP y revisar el port forwarding (nunca exponer 5555).
  4. No confiar en borrar ficheros: el watchdog y las modificaciones en /system sobreviven.
  5. factory reset no garantiza nada si el malware tiene root en /system o si el firmware ya venía infectado.
  6. Reflashear firmware limpio de fuente oficial o reemplazar el equipo. En mi caso, reemplazar.
  7. Cambiar credenciales de los servicios usados en el dispositivo.
  8. Revisar el resto de la LAN.
  9. Solicitar la retirada de la lista negra después de confirmar el cese del tráfico.

15. IOC principales

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# C2 activos (puerto 9999)
45.56.117.139      173.255.212.243
173.255.221.98     71.19.252.14

# Infra secundaria
207.38.87.205  209.239.115.206  199.189.87.86
209.126.116.211  50.30.37.108  192.200.112.10
139.144.201.58

# Dominios (extracto)
panddna.com  pdonno.com  mflve.com  bv1tpvdco.com
ageniustv1.cc  ageniusapp.cc  ageniusvod.cc
htvmarket.com  qicicloud.xyz  wak2p.com  tenlsi1.club
pandorabackup.lftpdo.com  pcdnbus-bk.a2k3v.com  pcdnfuc.ou2sv.com
Fichero SHA-256
pandoraspearrk 52c4d4fc0d883bd9841db4b7673f26f28ccb80a4c959824349453960b6fcb34c
supervisord 17ea3b1459382a4f1812e1bb6d17f9b68842107e5ca46019b5b97e77267ddd19
supervisord.tar.gz 4379cd89bd87155c09c1e799586df8f6b4bdd8c1d26e3cdb361d4cadaef40bf8
wdog2 e4cd104694f1676791cd23747b532320e21c0012ed8998ab37dfaaedf758d770
libpreloader.so de351e0e3bca13425d1472b39dd9c0a88bfe7ba503be0e330a024e76684d2251
server.apk cb483cdb56de41523495e128df22489c53863a1e856ebd7d444bafd0b07be4a8

16. Conclusiones

  1. El IoT doméstico es superficie de ataque real. Una TV box de 30 dólares con Android de 2017 puede convertir tu casa en infraestructura criminal sin que notes nada.
  2. Los avisos de listas negras son señales de incidente, no spam administrativo.
  3. La persistencia es el verdadero problema. El malware no es sofisticado: es terco.
  4. El sinkhole pasivo es la técnica más rentable para entender un C2 sin cruzar líneas rojas.
  5. El empaquetado gana la partida a corto plazo. Si no puedes desempaquetar, documenta el protocolo de red: eso ya te permite detectar y contener.

Y la lección que me llevo: si un dispositivo ya no recibe parches, no es un dispositivo, es un riesgo con enchufe.

Referencias

  • QiAnXin Xlabs — Bigpanzi Exposed: The Hidden Cyber Threat Behind Your Set-Top Box
  • Dr.Web — Android.Pandora.2
  • BleepingComputer — Bigpanzi botnet infects 170,000 Android TV boxes
  • FBI IC3 PSA (2025-06-05) — Home Internet Connected Devices (BADBOX 2.0)
  • Kaspersky — Is your TV box renting out your network?
  • DroneBL — https://dronebl.org

Gracias por leer.

This post is licensed under CC BY 4.0 by the author.

Comments powered by Disqus.