0%

网络攻防-包嗅探和欺骗

网络攻防-假消息攻击1-包嗅探和欺骗,涉及实验:SEED Labs – Packet Sniffifing and Spoofifing Lab,代码见:https://github.com/Seanxz401/seed-labs

理论

NIC网络接口卡:机器和网络之间的物理或逻辑链路,检查数据包的目的MAC,如果与该卡的MAC地址匹配,则会进一步复制到内核的缓冲区中

混杂模式下,NIC将接收到的每个帧都传给内核

BPF包过滤器

通过setsockopt将编译好的BPF伪代码附加到套接字:setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &bpf, sizeof(bpf))。当内核收到数据包时,BPF将被调用。image-20221231143338498

使用套接字/原始套接字接收数据包的局限性:

  • 不能跨操作系统进行移植
  • 没有任何可以提高性能的优化
  • 设置过滤器不容易(需要编码)

使用pcap API的优点:

  • 在所有平台上都是标准的,隐藏了操作系统的细节
  • 允许使用可读的布尔表达式指定过滤规则

捕获到的数据包,通过结构体的类型转换可以得到各协议层的内容。

数据包欺骗:指数据包中的某些关键信息被伪造。

嗅探然后欺骗:先捕获数据包,根据情况伪造响应

网络字节序:大端存储

具体的流程和细节见实验

实验

Task1

1.1A sniffer.py

sniffer.py捕获指定网卡的ICMP包并打印信息:ICMP包可由ping任意主机产生

1
2
3
4
5
6
#!/usr/bin/env python3
from scapy.all import *
def print_pkt(pkt):
pkt.show()

pkt=sniff(iface='enp0s3',filter='icmp',prn=print_pkt)

赋予可执行权限:chmod a+x sniffer.py,以root权限执行:成功。

以seed用户权限执行:出现权限错误,因为创建原始套接字需要root权限

1.1B BPF

编写BPF过滤语法

  1. 只捕获ICMP

    1
    filter='icmp'

    ping www.baidu.comimage-20221121232806657

  2. 捕获特定源IP和目的端口的TCP包

    1
    filter='tcp and src net 10.0.2.15 and dst port 23'

    telnet IP 23通过telnet远程连接主机可以生成满足条件的包:image-20221121233217251

  3. 捕获源或目的IP属于某特定子网

    1
    filter='net 10.134.160.0/21'

    根据宿主机IP和子网掩码算出网络号如上,开始捕获后ping百度和宿主机,查看接收到的包只有目标为宿主机的icmp包:image-20221121233659805

1.2 Spoofing ICMP

spoof.py制作虚假源IP的ICMP包并发送:

1
2
3
4
5
6
7
from scapy.all import *
a=IP()
srcip=input('please input fake srcIP:')
a.src=srcip
b=ICMP()
p=a/b
send(p)

由用户输入虚假IP来设置ICMP包的源IP,默认目的地址是127.0.0.1,利用wireshark查看环回地址捕获到的ICMP包:image-20221121234313476

1.3 TTL

ttl.py 自动ttl增1并发送ICMP包

1
2
3
4
5
6
a=IP()
a.dst='...'
b=ICMP()
for i in range(1,65):
a.ttl=i
send(a/b)

ttl_sniff.py 捕获ICMP应答包并计算成功收到目标主机的应答前已经收到多少个路由器的错误反馈,根据此得出真正的ttl距离:

1
2
3
4
5
6
7
8
9
10
11
global ttl
ttl=0
def count_ttl(pkt):
global ttl
ttl=ttl+1
if(pkt[ICMP].type==0 and pkt[IP].src=='...'): # type=0是reply
print('get reply from target host while ttl='+str(ttl))
exit(0)

print('sniff...icmp reply')
sniff(iface='enp0s3',filter='icmp',prn=count_ttl)

启动ttl_sniff.py监听后开始发包,得到结果:image-20221122005716405

1.4 Sniff&Spoof

10.9.0.1(虚拟主机和attack都是)为主机A和B的网关,即10.9.0.1对应的网卡能接收到A和B的ICMP包。主机中运行嗅探和欺骗程序snsp.py:

1
2
3
4
5
def snsf(pkt):
a=IP(src=pkt[IP].dst,dst=pkt[IP].src)
b=ICMP(type='echo-reply',code=0,id=pkt[ICMP].id,seq=pkt[ICMP].seq)
p=a/b/pkt[Raw]
send(p)

Raw是应用层的数据,如果不加的话,被欺骗的主机能收到欺骗包,但是ping程序无法识别是响应包

容器hostA作为被欺骗者,分别ping:

  1. 互联网中不存在的主机1.2.3.4:hostA能接收到响应包image-20221123224606010
  2. 局域网中不存在的主机10.9.0.99:unreachable,hostA向局域网内的主机发包不会经过网关,因此攻击机不会收到ICMP包,也就不会返回欺骗包。由于hostA找不到10.9.0.99的MAC地址,导致包不可达。image-20221123224914878
  3. 互联网中存在的主机:虚拟主机。由于目标主机和攻击机都能收到ICMP包并做出响应,导致出现冗余包image-20221123225430511

Task2

2.1A sniff

sniff.c:嗅探局域网中的ICMP包,并打印源IP和目的IP。

Question1:

  • pcap_open_live:打开指定网卡设备
  • pcap_compile,pcap_setfilter:编译BPF过滤条件并绑定到本次处理;
  • pcap_loop:开始循环捕获,通过回调函数对捕获到的每一个包进行处理
  • pcap_close:关闭本次捕获

Question2:

对网卡设备(底层硬件)的操作需要root权限,从第一步打开网卡就需要权限:image-20221123232714044

Question3

混杂模式开启后能接收目的地址不是本机的数据包。用10.9.0.1的网卡设备作为嗅探设备,用hostA ping hostB,A和B在同一局域网,不会发给网关。

混杂模式开启时:10.9.0.1能接收到ICMP包image-20221123233416435

修改pcap_live_open参数中的1为0,关闭混杂模式:10.9.0.1不能接收到hostA ping hostB的ICMP包,但是可以接收到出局域网的包。image-20221123234308382

2.1B filter

1.捕获两个特定主机之间的ICMP数据包

1
filter="icmp and host 10.9.0.5 and host 10.9.0.6"

只捕获10.9.0510.9.0.6之间的,ping其他IP时则不会收到image-20221123235254708

2.捕获目标端口号在10到100范围内的TCP数据包。

1
filter="tcp and dst portrange 10-100"

用curl对多个端口发起请求,只有10-100之间的才可以被捕获到image-20221123235747895

2.1C telnet

嗅探TCP包中的敏感数据,以telnet为例:telnet远程连接,捕获其登录名和密码。image-20221124003818924

Telnet发送的数据固定在报文第66字节,可以直接输出内容

2.2A spoof IP

自定义报头结构体,根据需要指定字段内容:根据wireshark抓包可得,除了IP和ICMP的报文头,还有8个字节的时间戳和48个字节的填充数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//IP报头
typedef struct IP_HEADER {
#if defined(__LITTLE_ENDIAN_BITFIELD)
__u8 ihl:4, //4位头部长度 一位4个字节,,最多15*4个字节(可选项)
version:4; //4位版本号
#elif defined (__BIG_ENDIAN_BITFIELD)
__u8 version:4,
ihl:4;
#else
#error "Please fix <asm/byteorder.h>"
#endif
__u8 tos; //8位服务类型
__be16 tot_len; //16位总长度
__be16 id; //16位标识符
__be16 frag_off; //3位标志加13位片偏移
__u8 ttl; //8位生存时间
__u8 protocol; //8位上层协议号
__sum16 check; //16位校验和
__be32 saddr; //32位源IP地址
__be32 daddr; //32位目的IP地址
/*The options start here. */
} IP_HEADER;

//ICMP报头
typedef struct ICMP_HEADER
{
u_char type; //8位类型字段
u_char code; //8位代码字段
u_short cksum; //16位校验和
u_short id; //16位标识符
u_short seq; //16位序列号
} ICMP_HEADER;

使用原始套接字,根据数据包中的源IP构造对应的sockaddr_in,发送自定义IP数据包:

1
2
3
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_addr.s_addr=pIPHeader->daddr;

image-20221125151445579

修改源和目的IP,用wireshark查看结果:image-20221125151316253

2.2B spoof echo-request

构造ICMP包与2.1A类似,以局域网中不存在的主机为源IP向某存活主机发起request,由于源IP是不可达的,所以无法收到存活主机的reply

Question4:

可以随意设置IP报文头部的长度,但必须保证向socket发送的原始报文是正确的长度。

Question5:

必须要计算校验和,若校验不通过则该数据包会被丢弃。

Question6:

创建原始套接字需要root权限。若没有权限, socket(AF_INET, SOCK_RAW, IPPROTO_RAW);这一步就无法成功创建套接字。

2.3 Sniff&Spoof

结合以上的代码,实现在嗅探的同时发送欺骗响应包。

结果与Task1.4类似

总结

  • 用C语言构造报文头比python难很多,但是可操作性强,可自定义每一个字节的数据;
  • 接发包不只是要构造源和目的的地址,对于操作系统和特定程序来说,都有其必要的检验机制,如本次实验中ping检验了Raw数据。
  • 对C语言的数据类型及其在内存中的具体情况还不是很清楚。