CVE-2020-8558-跨主机访问127.0.0.1
字数 1896 2025-08-26 22:11:28
CVE-2020-8558漏洞分析与复现指南
漏洞概述
CVE-2020-8558是Kubernetes kube-proxy组件中的一个安全漏洞,允许容器内的恶意用户或同一局域网内的其他机器访问节点上仅绑定在127.0.0.1的服务。这种访问可能使攻击者能够访问监听在本地的"Kubernetes无需认证的apiserver",进而控制整个集群。
漏洞背景
在正常情况下,当服务仅绑定在127.0.0.1时,只有本地主机可以访问该服务。然而,在某些网络配置下,攻击者可以绕过这一限制:
- 在同一个局域网内的两台机器A和B
- 机器A运行
nc -l 127.0.0.1 8888监听本地端口 - 机器B理论上不应该能访问机器A上的这个服务
漏洞原理
攻击场景分析
攻击者可以构造一个恶意的SYN包,其数据包信息如下:
| 字段 | 值 |
|---|---|
| 源IP | 攻击者IP(ip_a) |
| 源MAC | 攻击者MAC(mac_a) |
| 目的IP | 127.0.0.1 |
| 目的MAC | 目标MAC(mac_b) |
| 目的端口 | 8888 |
| 源端口 | 随机端口(如44444) |
数据包流向:A -> 交换机 -> B
目标机器B的网卡处理流程:
- 链路层:发现目的MAC是自己,交给网络层
- 网络层:发现IP是本机网卡IP,交给传输层
- 传输层:发现有服务监听127.0.0.1:8888,准备回复SYN-ACK
SYN-ACK包信息:
| 字段 | 值 |
|---|---|
| 源IP | 127.0.0.1 |
| 源MAC | mac_b |
| 目的IP | ip_a |
| 目的MAC | mac_a |
| 目的端口 | 44444 |
| 源端口 | 8888 |
数据包流向:B -> 交换机 -> A
这样,攻击者就能完成TCP三次握手,访问到目标机器上仅绑定在127.0.0.1的服务。
可能失败的场景
- 交换机检查:某些交换机(如公有云的OVS)会检查并丢弃目的IP为127.0.0.1的数据包
- 内核协议栈限制:内核可能因为安全考虑丢弃这类特殊数据包
关键内核参数
三个关键内核参数影响此漏洞的利用:
-
route_localnet
- 默认情况下,当收到源IP或目的IP是127.0.0.0/8(环回地址)时,内核会认为是非法数据包并丢弃
- 设置
route_localnet=1会关闭这一检查 - 在
ip_route_input_slow函数中实现检查
-
rp_filter(反向路径过滤)
rp_filter=1时会严格验证源IP- 通过"反向检查"实现:交换源IP和目的IP后查找路由表,检查回包设备是否与收包设备一致
-
accept_local
- 允许接收源IP是本机IP的数据包
- 与
rp_filter配合使用
Docker网桥模式下的漏洞复现
环境要求
-
宿主机:
- 设置
net.ipv4.conf.all.route_localnet=1 - Docker网桥设备(docker0)默认不需要设置rp_filter和accept_local
- 设置
-
容器内:
- 需要设置:
net.ipv4.conf.all.accept_local=1net.ipv4.conf.all.rp_filter=0net.ipv4.conf.default.rp_filter=0net.ipv4.conf.eth0.rp_filter=0
- 需要设置:
复现步骤
-
在宿主机上启用route_localnet:
sysctl -w net.ipv4.conf.all.route_localnet=1 -
创建并进入容器:
docker run -d busybox tail -f /dev/null docker top <容器ID> # 获取容器PID nsenter -n -t <容器PID> # 进入容器网络命名空间 -
在容器网络命名空间内设置内核参数:
sysctl -w net.ipv4.conf.all.accept_local=1 sysctl -w net.ipv4.conf.all.rp_filter=0 sysctl -w net.ipv4.conf.default.rp_filter=0 sysctl -w net.ipv4.conf.eth0.rp_filter=0 -
在宿主机上启动本地服务:
nc -l 127.0.0.1 8888 -
在容器内访问宿主机服务:
curl 127.0.0.1:8888 --interface eth0
Kubernetes的修复方案
Kubernetes通过添加iptables规则来修复此漏洞:
-A KUBE-FIREWALL ! -s 127.0.0.0/8 -d 127.0.0.0/8 -m comment --comment "block incoming localnet connections" -m conntrack ! --ctstate RELATED,ESTABLISHED,DNAT -j DROP
这条规则会丢弃:
- 目的IP是环回地址(127.0.0.0/8)
- 源IP不是环回地址
- 连接状态不是RELATED,ESTABLISHED或DNAT
注意:此修复方案不能防止访问本地UDP服务。
总结与扩展
- 公有云VPC环境下,交换机可能已经做了限制,难以复现此漏洞
- Docker环境中,默认/proc/sys只读,难以修改容器内网络参数,利用难度较高
- 使用CNI插件(如Calico IPIP网络模型)时,节点间能否访问"仅绑定在127.0.0.1的服务"取决于具体网络配置
参考资源
- Linux内核网络参数文档
- Kubernetes相关PR和issue讨论
- 网络协议栈实现细节(可参考Linux内核源码)