跳转到内容

EP02:Source IP 能证明发送者身份吗?

在上一篇中,我们明确了 IP 协议的一个重要职责边界:

IP 地址用于寻址和转发,但不能单独证明通信身份。

数据包中的 Source IP,本质上只是 IP Header 中的一个字段。

当 Bob 收到:

Source IP = 192.168.106.130

它只能说明:

这个数据包声称自己来自 192.168.106.130。

但仅凭这个字段,Bob 无法证明真正发送数据包的一定就是 Alice。

这个结论能不能通过实验直接看到?

本实验准备三台主机:

Alice:192.168.106.130
Kali :192.168.106.131
Bob  :192.168.106.132

我们先让真正的 Alice 向 Bob 发送一份 UDP 数据。

然后再让 Kali 构造另一份 UDP 数据包,但故意把 IP Header 中的 Source IP 写成:

192.168.106.130

也就是 Alice 的地址。

最后站在 Bob 的视角观察这两份数据包。

本实验只回答一个问题:

Bob 看到 Source IP = 192.168.106.130,能不能证明发送者一定是 Alice?


一、实验目标

整个实验只有两个阶段。

第一阶段:

Alice
192.168.106.130
        │
        │ 正常发送
        ▼
Bob
192.168.106.132

Source IP = 192.168.106.130

第二阶段:

Kali
192.168.106.131
        │
        │ 人为构造
        ▼
Bob
192.168.106.132

Source IP = 192.168.106.130

也就是说:

真实发送者不同

Alice
vs
Kali

但:

Source IP 相同

192.168.106.130

最终验证:

Source IP 表示数据包“声称从哪里来”,并不是经过身份认证之后得到的身份信息。


二、实验环境

继续复用整个 IPSec 专题使用的 VMware 实验环境。

角色操作系统实验 IP作用
AliceRocky Linux192.168.106.130正常发送数据
Kali / EveKali Linux192.168.106.131构造伪造 Source IP
BobRocky Linux192.168.106.132抓包观察
宿主机Windows 11—VMware Workstation

实验仍然遵循一个原则:

在能够清楚展示机制的前提下,尽量减少资源占用。

三台虚拟机不需要复杂的图形环境。

推荐资源:

CPU:1~2 vCPU
内存:1.5~2 GB

三、实验网络设计

为了既保留虚拟机互联网访问,又建立独立实验网络,三台虚拟机都使用双网卡。

网卡 1
NAT
用于访问互联网、安装软件

网卡 2
VMnet2
用于 IPSec 系列实验

实验网段:

192.168.106.0/24

形成:

                    VMnet2
               192.168.106.0/24

        Alice          Kali          Bob
        .130           .131          .132
          │              │             │
          └──────────────┼─────────────┘

实验网卡不需要配置默认网关。

因为三台主机处于同一个网段,可以直接进行二层通信。


四、确认实验网卡

不要直接假设实验接口叫:

eth1

不同 Linux 系统的接口名称可能不同。

例如 Rocky Linux 可能是:

ens160
ens192
ens37

Kali 可能是:

eth0
eth1

因此首先执行:

ip -br addr

更推荐使用:

ip route get <目标IP>

确认系统真正使用哪块接口。

例如 Alice:

ip route get 192.168.106.132

可能得到:

192.168.106.132 dev ens37 src 192.168.106.130

说明:

实验接口 = ens37

Kali:

ip route get 192.168.106.132

例如:

192.168.106.132 dev eth1 src 192.168.106.131

说明:

实验接口 = eth1

后面的 Scapy 和 tcpdump 都应该使用真正的实验接口。


五、配置实验 IP

如果前面的实验已经配置过这些地址,可以直接跳过本节。

假设:

Alice:ens37
Kali :eth1
Bob  :ens37

Alice

sudo ip link set ens37 up
sudo ip addr add 192.168.106.130/24 dev ens37

确认:

ip -br addr show ens37

Kali

sudo ip link set eth1 up
sudo ip addr add 192.168.106.131/24 dev eth1

确认:

ip -br addr show eth1

Bob

sudo ip link set ens37 up
sudo ip addr add 192.168.106.132/24 dev ens37

确认:

ip -br addr show ens37

需要注意:

ip addr add 配置的是临时地址,系统重启后会消失。

对于一次实验已经足够。

如果整个 IPSec 专题长期复用这套网络,再使用 NetworkManager 将地址永久保存即可。


六、验证网络可达

Alice:

ping -c 3 192.168.106.132

Kali:

ping -c 3 192.168.106.132

Bob:

ping -c 3 192.168.106.130
ping -c 3 192.168.106.131

确认:

Alice ↔ Bob

Kali ↔ Bob

都能够正常通信。

但注意:

到这里我们证明的仍然只是“网络可达”。

这并没有证明任何通信身份。


七、记录 Alice 和 Kali 的 MAC 地址

本实验还需要观察一个辅助字段:

Ethernet Source MAC

目的并不是把 MAC 当作可靠身份认证手段。

而是在当前这个同一二层网络的受控实验环境中,用它帮助区分:

数据帧实际由 Alice 的网卡发出,还是由 Kali 的网卡发出。

Alice:

ip link show <Alice实验接口>

例如:

link/ether 00:0c:29:aa:aa:aa

记录:

Alice MAC = 00:0c:29:aa:aa:aa

Kali:

ip link show <Kali实验接口>

例如:

Kali MAC = 00:0c:29:bb:bb:bb

实际地址以自己的实验环境为准。


八、准备实验工具

Bob 需要使用 tcpdump。

Rocky Linux:

sudo dnf install -y tcpdump

确认:

tcpdump --version

Alice 需要 Python 3:

python3 --version

如果没有:

sudo dnf install -y python3

Kali 使用 Scapy:

python3 -c "import scapy; print(scapy.__version__)"

如果没有安装:

sudo apt update
sudo apt install -y python3-scapy

这里使用 Scapy 的原因非常简单:

Scapy 允许我们自己构造 IP Header。

本实验最重要的就是人为指定:

IP(src="192.168.106.130")

九、Bob 开始抓包

首先确认 Bob 访问 Alice 时使用哪块接口:

ip route get 192.168.106.130

假设结果显示:

dev ens37

开始抓包:

sudo tcpdump -i ens37 -e -nn -s0 -vv -X \
'udp and dst host 192.168.106.132 and dst port 8080'

这里最值得关注的两个参数是:

-e

显示 Ethernet Header,也就是 MAC 地址。

以及:

-X

显示 Payload。

因此后面我们可以同时观察:

Ethernet Source MAC
IP Source Address
Payload

十、对照组:Alice 正常发送数据

首先建立正常数据包。

Alice 创建:

nano ep02_alice.py

写入:

import socket

ALICE_IP = "192.168.106.130"
BOB_IP = "192.168.106.132"

SOURCE_PORT = 40000
DESTINATION_PORT = 8080

payload = b"EP02 LEGITIMATE ALICE"

sock = socket.socket(
    socket.AF_INET,
    socket.SOCK_DGRAM
)

sock.bind(
    (ALICE_IP, SOURCE_PORT)
)

sock.sendto(
    payload,
    (BOB_IP, DESTINATION_PORT)
)

print("Legitimate packet sent")
print(f"Source      : {ALICE_IP}:{SOURCE_PORT}")
print(f"Destination : {BOB_IP}:{DESTINATION_PORT}")
print(f"Payload     : {payload.decode()}")

sock.close()

运行:

python3 ep02_alice.py

应该看到:

Legitimate packet sent
Source      : 192.168.106.130:40000
Destination : 192.168.106.132:8080
Payload     : EP02 LEGITIMATE ALICE

Bob 观察正常报文

Bob 的 tcpdump 中应该出现类似:

Alice-MAC > Bob-MAC

IP 192.168.106.130.40000 >
   192.168.106.132.8080

Payload:

EP02 LEGITIMATE ALICE

记录两个关键字段:

Ethernet Source
=
Alice MAC

以及:

IP Source
=
192.168.106.130

所以正常情况下:

实际发送主机:Alice

Ethernet Source:
Alice MAC

IP Source:
192.168.106.130

这就是后面伪造实验的对照组。


十一、实验组:Kali 伪造 Alice 的 Source IP

现在进入整个实验最关键的一步。

Kali 的真实地址是:

192.168.106.131

但是这一次,我们不让它使用自己的地址作为 Source IP。

而是人为构造:

Source IP = 192.168.106.130

也就是 Alice 的 IP。

在 Kali 创建:

nano ep02_spoof.py

写入:

from scapy.all import IP, UDP, Raw, send

ALICE_IP = "192.168.106.130"
KALI_IP = "192.168.106.131"
BOB_IP = "192.168.106.132"

SOURCE_PORT = 40000
DESTINATION_PORT = 8080

payload = b"EP02 SPOOFED BY KALI"

packet = (
    IP(
        src=ALICE_IP,
        dst=BOB_IP
    )
    /
    UDP(
        sport=SOURCE_PORT,
        dport=DESTINATION_PORT
    )
    /
    Raw(
        load=payload
    )
)

print("Kali real IP   :", KALI_IP)
print("Spoofed IP     :", ALICE_IP)
print("Destination    :", BOB_IP)
print()
print("Packet structure:")

packet.show()

send(
    packet,
    verbose=False
)

print()
print("Spoofed packet sent.")

关键代码只有一处

整个脚本中真正需要理解的是:

IP(
    src=ALICE_IP,
    dst=BOB_IP
)

而:

ALICE_IP = "192.168.106.130"

Kali 自己的真实 IP 明明是:

192.168.106.131

但构造 IP Header 时,我们直接把 Source Address 写成了:

192.168.106.130

也就是说:

IP Header 中的 Source Address 可以被发送者人为构造。


运行伪造脚本

Kali:

sudo python3 ep02_spoof.py

因为 Scapy 需要发送原始数据包,所以这里需要 root 权限。

输出类似:

Kali real IP   : 192.168.106.131
Spoofed IP     : 192.168.106.130
Destination    : 192.168.106.132

packet.show() 中还会看到:

###[ IP ]###
  src = 192.168.106.130
  dst = 192.168.106.132

###[ UDP ]###
  sport = 40000
  dport = 8080

###[ Raw ]###
  load = b'EP02 SPOOFED BY KALI'

此时形成了一个非常关键的事实:

运行脚本的机器:

Kali
192.168.106.131

但发出去的数据包:

Source IP
=
192.168.106.130

十二、Bob 观察伪造数据包

回到 Bob。

tcpdump 应该能够看到类似:

Kali-MAC > Bob-MAC

IP 192.168.106.130.40000 >
   192.168.106.132.8080

Payload:

EP02 SPOOFED BY KALI

现在出现了整个实验最关键的现象。

Ethernet 层:

Source MAC
=
Kali MAC

但是 IP 层:

Source IP
=
192.168.106.130

也就是 Alice 的 IP 地址。

因此真正的数据包关系是:

Kali
真实 IP:192.168.106.131
真实网卡:Kali MAC

        │
        │ 构造 IP Header
        ▼

┌──────────────────────────┐
│ Ethernet Source          │
│ Kali MAC                 │
│                          │
│ IP Source                │
│ 192.168.106.130          │
│                          │
│ Payload                  │
│ EP02 SPOOFED BY KALI     │
└──────────────────────────┘

        │
        ▼

Bob
192.168.106.132

十三、比较两份数据包

现在把实验结果放在一起。

字段Alice 正常报文Kali 伪造报文
实际发送主机AliceKali
主机真实 IP.130.131
Ethernet SourceAlice MACKali MAC
IP Source.130.130
UDP Source Port4000040000
Destination IP.132.132
Destination Port80808080
PayloadLEGITIMATE ALICESPOOFED BY KALI

最重要的一行就是:

IP Source

Alice 正常发送:

192.168.106.130

Kali 伪造发送:

192.168.106.130

两份报文在 IP 层都声称:

我来自 Alice。

但真正发送它们的主机并不是同一台机器。

至此,本实验已经完成。


十四、可选:保存完整 PCAP

如果希望把实验结果长期保存,可以再进行一次抓包。

Bob:

sudo tcpdump -i ens37 -e -nn -s0 \
-w ep02-source-ip-spoofing.pcap \
'udp and dst host 192.168.106.132 and dst port 8080'

然后依次运行:

Alice:

python3 ep02_alice.py

Kali:

sudo python3 ep02_spoof.py

回到 Bob:

Ctrl+C

得到:

ep02-source-ip-spoofing.pcap

重新查看:

tcpdump -e -nn -vv -X \
-r ep02-source-ip-spoofing.pcap

这样可以连续看到正常报文和伪造报文。

PCAP 可以作为 EP02 的原始实验材料保存。


十五、为什么会出现这种现象

现在重新回答开头的问题。

Bob 收到:

Source IP = 192.168.106.130

是否能够证明:

发送者一定是 Alice?

答案是:

不能。

原因并不复杂。

IP 协议负责的是:

寻址
路由
转发

而不是:

身份认证

IP Header 中存在:

Source Address
Destination Address

它们首先用于网络通信。

例如:

Source      192.168.106.130
Destination 192.168.106.132

告诉网络这个数据包:

声称从哪里来

以及

准备到哪里去

但普通 IP 协议并没有要求:

发送者在填写 Source Address 之前,必须提供密码学证据证明自己确实就是这个身份。

所以:

Source IP
    │
    ▼
网络层地址

不能直接变成:

Source IP
    │
    ▼
经过验证的身份

十六、为什么实验还观察了 MAC 地址

这里需要特别控制实验结论的边界。

本实验观察:

Alice MAC

和:

Kali MAC

只是为了在当前这个同一二层 VMware 实验网络里辅助证明:

两个 Source IP 都是 .130 的数据包,实际上来自不同虚拟机。

这绝不意味着:

IP 不可信
MAC 就可信

MAC 地址本身也不是密码学身份认证机制。

而且如果 Alice 和 Bob 之间经过路由器:

Alice
  │
Router
  │
Bob

Bob 在 Ethernet 层看到的 Source MAC 通常属于:

最后一跳路由器

而不是 Alice。

所以 MAC 在这里仅仅是:

实验观察手段。

而不是实验结论。

真正需要记住的仍然只有:

IP 地址
≠
身份认证

十七、本实验没有证明什么

Source IP 可以被伪造,并不意味着:

攻击者能够在任何网络中随意冒充任意 IP 完成完整通信。

真实网络中还可能部署:

ACL
防火墙
uRPF
源地址反欺骗
运营商过滤
交换机安全机制
其他网络访问控制

这些机制可能直接阻止伪造报文。

另外,伪造 Source IP 本身还有一个明显的问题。

例如 Kali 发送:

Source IP = Alice

Bob 如果进行回复:

Bob
  │
  │ Reply
  ▼
192.168.106.130

回复通常会发送给真正的 Alice,而不是 Kali。

所以:

能够伪造一个单向数据包,并不等于能够自动劫持完整的双向通信。

但是这些限制不会改变本实验已经证明的事实:

IP Source Address 本身没有提供身份认证能力。


十八、从实验回到安全通信

现在再考虑 Alice 和 Bob:

Alice
192.168.106.130

        ↕

Bob
192.168.106.132

Bob 不能简单地认为:

只要 Source IP 是
192.168.106.130

对方就一定是 Alice

因为我们刚刚亲手让:

Kali
192.168.106.131

发出了一份:

Source IP
=
192.168.106.130

的数据包。

于是一个新的问题自然出现:

如果地址本身不能证明身份,那么安全通信应该怎样确认对面到底是谁?

这就是后面会逐渐出现的:

身份认证

不过 EP02 到这里就应该停下来。

现在还不需要引入 IKE、PSK 或数字证书。

这一实验只需要建立一个清晰的认知边界:

Source IP 是地址,不是身份证。


实验总结

本实验使用三台主机:

Alice
192.168.106.130

Kali
192.168.106.131

Bob
192.168.106.132

首先由真正的 Alice 正常发送:

Source IP = 192.168.106.130

然后由 Kali 使用 Scapy 构造:

IP(
    src="192.168.106.130",
    dst="192.168.106.132"
)

Bob 最终观察到:

Alice 正常报文

Ethernet Source:
Alice MAC

IP Source:
192.168.106.130

而 Kali 伪造报文:

Ethernet Source:
Kali MAC

IP Source:
192.168.106.130

两个数据包的实际发送主机不同。

但是它们在 IP 层都声称:

Source IP = 192.168.106.130

因此我们最终验证了:

一个数据包声称自己来自 Alice,并不意味着发送者已经被证明就是 Alice。

换句话说:

IP 地址解决寻址
        ≠
IP 地址解决身份认证

或者更容易记:

Source IP 告诉你数据包“说自己是谁”,身份认证才负责证明“它到底是谁”。