这个实验是关于数据包的嗅探与伪造
1. Task Set 1
这部分主要是利用工具来嗅探数据包,这里用的是 scapy
。 可以用下面的命令进行安装。
sudo pip3 install scapy
简单测试一下,构造了一个IP数据包并打印其的一些信息
[07/02/21]seed@VM:~/.../Lab10$ sudo python3
Python 3.5.2 (default, Nov 17 2016, 17:05:23)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from scapy.all import *
>>> a = IP()
>>> a.show()
###[ IP ]###
version = 4
ihl = None
tos = 0x0
len = None
id = 1
flags =
frag = 0
ttl = 64
proto = hopopt
chksum = None
src = 127.0.0.1
dst = 127.0.0.1
\options \
Task 1.1 嗅探数据包
下面是使用 scapy
来嗅探数据包的一个例子
#!/usr/bin/python3
from scapy.all import *
def print_pkt(pkt):
pkt.show()
pkt = sniff(filter="icmp",prn=print_pkt)
Task 1.1A
先使用 chmod a+x sniffer.py
添加执行权限
先使用root权限运行上面的程序 sudo ./sniffer.py
, 结果如下,可以看到其成功嗅探到了不同协议的数据包,图中只包括ICMP包。
然后使用普通权限运行该程序 ./sniffer.py
。结果如下,可以看到报错了,提示无权限。
这说明嗅探包是一件拥有高权限才能做的事情,没有高权限,系统是不让你嗅探数据包的。
Task 1.1B
一般在嗅探包时我们只对特定类型的数据包感兴趣,所以我们需要对数据包进行一些过滤。scapy的过滤机制使用BPF的语法,这部分我们需要实现几个过滤的方法。
-
只捕捉ICMP数据包
上面的代码就是只捕捉icmp的数据包,略修改如下:
#!/usr/bin/python3
from scapy.all import *
def print_pkt(pkt):
return pkt.summary()
pkt = sniff(filter="icmp",prn=print_pkt)
print(pkt)
运行结果如下,可以看到捕获到了7个ICMP数据包
- 只捕捉来自特定IP,且目标端口号为23的TCP数据包
查看自己的IP地址如下:
这里随意拿个IP来测试, 我们使用10.0.2.11
, 嗅探代码如下:
#!/usr/bin/python3
from scapy.all import *
def print_pkt(pkt):
return pkt.summary()
pkt = sniff(filter="tcp and src host 10.0.2.11 and dst port 23",prn=print_pkt)
print(pkt)
发送数据包的代码如下:
#!/usr/bin/python3
from scapy.all import *
ip = IP()
ip.src = "10.0.2.11"
ip.dst = "10.0.2.1"
tcp = TCP()
tcp.dport = 23
send(ip/tcp)
运行嗅探的程序,再运行发送数据包的程序(可以多试几次), 结果如下:
3. 捕捉来自或发送到特定子网的数据包
这里我们使用的子网为128.230.0.0/16
.嗅探代码如下:
#!/usr/bin/python3
from scapy.all import *
def print_pkt(pkt):
return pkt.summary()
pkt = sniff(filter="net 128.230.0.0/16",prn=print_pkt)
print(pkt)
发送包的代码如下:
#!/usr/bin/python3
from scapy.all import *
ip = IP()
ip.src = "10.0.2.11"
ip.dst = "128.230.0.1"
tcp = TCP()
tcp.dport = 23
send(ip/tcp)
ip.src = "128.230.0.1"
ip.dst = "10.0.2.11"
send(ip/tcp)
嗅探结果如下,可以看到嗅探到了发送给子网128.230.0.0/16
和 该子网发送过来的数据包
Task 1.2
这部分主要是伪造任意的IP地址发IP包,这里我们用的是ICMP协议,使用的IP地址为 10.0.2.3
, 注意 在task 1.1B2中,我们查看了自己的IP地址为10.0.2.4
,也就是这里我们伪造成ip地址为 10.0.2.3
进行发包。
先启动wireshark,选择网卡,再运行发包的程序
发送的代码如下:
#!/usr/bin/python3
from scapy.all import *
ip = IP()
ip.src = "10.0.2.3"
ip.dst = "128.230.0.1"
icmp = ICMP()
send(ip/icmp)
在wireshark中可看到记录,伪造的包有了回复。
Task 1.3
这部分主要是实现traceroute来估计本机到指定IP之间的路由器的个数。
代码如下:
#!/usr/bin/python3
from scapy.all import *
import sys
def traceroute(target, minttl=1, maxttl=30, dport=80):
print("target: %s(port=%s)" % (target, dport))
ans, unans = sr(IP(dst=target, ttl=(minttl,maxttl),id=RandShort())/TCP(flags=0x2, dport=dport), timeout=10)
for snd,rcv in ans:
print(snd.ttl, rcv.src)
if __name__ == '__main__':
if len(sys.argv) <= 1:
traceroute("baidu.com")
else:
traceroute(sys.argv[1])
运行效果如下, 可以看到打印除了不同TTL对应的IP
注意如果出现,没有回复包,或者回复包过少,可能与环境优点关系,可以尝试VPS运行
Task 1.4
这部分主要是准备两个在同一个局域网的虚拟机,一个机器ping任意IP x,另一个机器伪造ICMP回复请求,使得其有回复,而IP x所对应的机器可能根本不存在。
我们准备的A机器 IP 地址为10.0.2.4,B机器IP地址为10.0.2.5. 我们用A机器去发送请求,B机器伪造响应。
代码如下:
#!/usr/bin/python3
from scapy.all import *
def print_pkt(pkt):
send(IP(src=pkt[IP].dst, dst=pkt[IP].src)/ICMP(type="echo-reply", code= 0, id=pkt[ICMP].id, seq=pkt[ICMP].seq))
pkt = sniff(filter="icmp[icmptype]==icmp-echo",prn=print_pkt)
测试ping baidu.com
结果如下,ttl=64为我们伪造的回复包,ttl=52的为正常的相应包。
在断网情况下,仍然可以ping通其他网段的IP
2. Task Set 2
这部分主要是使用pcap库写程序来嗅探和伪造包
Task 2.1
Task 2.1A
这部分主要是写一个打印捕获的包的源IP和目的IP地址。
代码如下:
#include <pcap.h>
#include <stdio.h>
#include <arpa/inet.h>
/* Ethernet header */
struct ethheader {
u_char ether_dhost[6]; /* destination host address */
u_char ether_shost[6]; /* source host address */
u_short ether_type; /* protocol type (IP, ARP, RARP, etc) */
};
/* IP Header */
struct ipheader {
unsigned char iph_ihl:4, //IP header length
iph_ver:4; //IP version
unsigned char iph_tos; //Type of service
unsigned short int iph_len; //IP Packet length (data + header)
unsigned short int iph_ident; //Identification
unsigned short int iph_flag:3, //Fragmentation flags
iph_offset:13; //Flags offset
unsigned char iph_ttl; //Time to Live
unsigned char iph_protocol; //Protocol type
unsigned short int iph_chksum; //IP datagram checksum
struct in_addr iph_sourceip; //Source IP address
struct in_addr iph_destip; //Destination IP address
};
void got_packet(u_char *args, const struct pcap_pkthdr *header,
const u_char *packet)
{
struct ethheader *eth = (struct ethheader *)packet;
if (ntohs(eth->ether_type) == 0x0800) { // 0x0800 is IP type
struct ipheader * ip = (struct ipheader *)
(packet + sizeof(struct ethheader));
printf(" From: %s\n", inet_ntoa(ip->iph_sourceip));
printf(" To: %s\n", inet_ntoa(ip->iph_destip));
/* determine protocol */
switch(ip->iph_protocol) {
case IPPROTO_TCP:
printf(" Protocol: TCP\n\n");
return;
case IPPROTO_UDP:
printf(" Protocol: UDP\n\n");
return;
case IPPROTO_ICMP:
printf(" Protocol: ICMP\n\n");
return;
default:
printf(" Protocol: others\n\n");
return;
}
}
}
int main()
{
pcap_t *handle;
char errbuf[PCAP_ERRBUF_SIZE];
struct bpf_program fp;
char filter_exp[] = "ip proto icmp";
bpf_u_int32 net;
// Step 1: Open live pcap session on NIC with name enp0s3
handle = pcap_open_live("enp0s3", BUFSIZ, 1, 1000, errbuf);
printf("listening on network card, ret: %p...\n", handle);
// Step 2: Compile filter_exp into BPF psuedo-code
printf("try to compile filter...\n");
pcap_compile(handle, &fp, filter_exp, 0, net);
printf("try to set filter...\n");
pcap_setfilter(handle, &fp);
// Step 3: Capture packets
printf("start to sniff...\n");
pcap_loop(handle, -1, got_packet, NULL);
pcap_close(handle); //Close the handle
return 0;
}
运行,并尝试ping baidu.com
,可以看到发送的包出现在结果中
Q1: 描述在你的嗅探程序中的库函数的调用
A1: 主要就是第一步,启动pcap监听网卡,第二步就是编译BPF过滤器并设置过滤器,第三步就是设置嗅探的处理函数,最后关闭嗅探即可。
**Q2: 为什么需要root权限才能运行嗅探程序?不使用root权限运行该程序会在哪里报错?
A2: 嗅探数据包是一个高权限的操作,因为涉及到隐私,安全相关问题。如果普通用户也能嗅探数据包,那么他就能窃取别人的隐私,甚至盗取账号密码等等。不使用root权限运行该程序。对比如下
可以看到在没有权限时第一步监听网卡就失败了。
**Q3: 打开嗅探程序的混杂模式。打开和关闭这个模式有什么区别?
A3: 使用混杂模式可以监听所在网段下其他机器的数据包,关闭则不能。如下所示,打开混杂模式,监听到了本网段另一机器 10.0.2.5
ping baidu.com
的数据包,关闭后则嗅探不到。
Task 2.1B
这部分主要是写一些过滤器。这部分还是复用 task 2.1A的代码,只是修改其中的过滤器而已
-
只捕捉两个特定主机之间的ICMP包
使用的过滤器为
icmp and src host 10.0.2.4 and dst host 10.0.2.5
, 只捕捉从 10.0.2.4 发送到 10.0.2.5的ICMP包。结果如下,可以看到全是从 10.0.2.4 发送到 10.0.2.5的ICMP包,没有其他类型的包。
-
捕捉目的端口在10到100之间的TCP包
使用的过滤器为
tcp and dst portrange 10-100
, 只捕捉从 10.0.2.4 发送到 10.0.2.5的ICMP包。结果如下,可以看到全是从 10.0.2.4 发送到 10.0.2.5的ICMP包,没有其他类型的包。
结果如下,用浏览器访问baidu.com
的包出现在结果中,用浏览器访问baidu.com:111
的包没有出现在结果中。
Task 2.1C
这部分是用嗅探去捕捉telent协议中的密码。我们使用scapy会更方便一些。
代码如下:
#!/usr/bin/python3
from scapy.all import *
def print_pkt(pkt):
pkt.show()
print(sniff(filter="tcp port 23", prn=print_pkt))
然后 使用telnet 10.0.2.5
,并输入账户密码远程登录。嗅探到的密码如下,其分成了几个包发送,如下:
所以输入的密码就是dees
。获得telnet输入的用户名同理。
Task 2.2
这部分主要是伪造包。用到的一些代码文件如下:
myheader.h
内容如下:
/* Ethernet header */
struct ethheader {
u_char ether_dhost[6]; /* destination host address */
u_char ether_shost[6]; /* source host address */
u_short ether_type; /* IP? ARP? RARP? etc */
};
/* IP Header */
struct ipheader {
unsigned char iph_ihl:4, //IP header length
iph_ver:4; //IP version
unsigned char iph_tos; //Type of service
unsigned short int iph_len; //IP Packet length (data + header)
unsigned short int iph_ident; //Identification
unsigned short int iph_flag:3, //Fragmentation flags
iph_offset:13; //Flags offset
unsigned char iph_ttl; //Time to Live
unsigned char iph_protocol; //Protocol type
unsigned short int iph_chksum; //IP datagram checksum
struct in_addr iph_sourceip; //Source IP address
struct in_addr iph_destip; //Destination IP address
};
/* ICMP Header */
struct icmpheader {
unsigned char icmp_type; // ICMP message type
unsigned char icmp_code; // Error code
unsigned short int icmp_chksum; //Checksum for ICMP Header and data
unsigned short int icmp_id; //Used for identifying request
unsigned short int icmp_seq; //Sequence number
};
/* UDP Header */
struct udpheader
{
u_int16_t udp_sport; /* source port */
u_int16_t udp_dport; /* destination port */
u_int16_t udp_ulen; /* udp length */
u_int16_t udp_sum; /* udp checksum */
};
/* TCP Header */
struct tcpheader {
u_short tcp_sport; /* source port */
u_short tcp_dport; /* destination port */
u_int tcp_seq; /* sequence number */
u_int tcp_ack; /* acknowledgement number */
u_char tcp_offx2; /* data offset, rsvd */
#define TH_OFF(th) (((th)->tcp_offx2 & 0xf0) >> 4)
u_char tcp_flags;
#define TH_FIN 0x01
#define TH_SYN 0x02
#define TH_RST 0x04
#define TH_PUSH 0x08
#define TH_ACK 0x10
#define TH_URG 0x20
#define TH_ECE 0x40
#define TH_CWR 0x80
#define TH_FLAGS (TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG|TH_ECE|TH_CWR)
u_short tcp_win; /* window */
u_short tcp_sum; /* checksum */
u_short tcp_urp; /* urgent pointer */
};
/* Psuedo TCP header */
struct pseudo_tcp
{
unsigned saddr, daddr;
unsigned char mbz;
unsigned char ptcl;
unsigned short tcpl;
struct tcpheader tcp;
char payload[1500];
};
checksum.c
内容如下:
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include "myheader.h"
unsigned short in_cksum (unsigned short *buf, int length)
{
unsigned short *w = buf;
int nleft = length;
int sum = 0;
unsigned short temp=0;
/*
* The algorithm uses a 32 bit accumulator (sum), adds
* sequential 16 bit words to it, and at the end, folds back all
* the carry bits from the top 16 bits into the lower 16 bits.
*/
while (nleft > 1) {
sum += *w++;
nleft -= 2;
}
/* treat the odd byte at the end, if any */
if (nleft == 1) {
*(u_char *)(&temp) = *(u_char *)w ;
sum += temp;
}
/* add back carry outs from top 16 bits to low 16 bits */
sum = (sum >> 16) + (sum & 0xffff); // add hi 16 to low 16
sum += (sum >> 16); // add carry
return (unsigned short)(~sum);
}
/****************************************************************
TCP checksum is calculated on the pseudo header, which includes
the TCP header and data, plus some part of the IP header.
Therefore, we need to construct the pseudo header first.
*****************************************************************/
unsigned short calculate_tcp_checksum(struct ipheader *ip)
{
struct tcpheader *tcp = (struct tcpheader *)((u_char *)ip +
sizeof(struct ipheader));
int tcp_len = ntohs(ip->iph_len) - sizeof(struct ipheader);
/* pseudo tcp header for the checksum computation */
struct pseudo_tcp p_tcp;
memset(&p_tcp, 0x0, sizeof(struct pseudo_tcp));
p_tcp.saddr = ip->iph_sourceip.s_addr;
p_tcp.daddr = ip->iph_destip.s_addr;
p_tcp.mbz = 0;
p_tcp.ptcl = IPPROTO_TCP;
p_tcp.tcpl = htons(tcp_len);
memcpy(&p_tcp.tcp, tcp, tcp_len);
return (unsigned short) in_cksum((unsigned short *)&p_tcp,
tcp_len + 12);
}
spoof.c
内容如下:
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include "myheader.h"
/*************************************************************
Given an IP packet, send it out using a raw socket.
**************************************************************/
void send_raw_ip_packet(struct ipheader* ip)
{
struct sockaddr_in dest_info;
int enable = 1;
// Step 1: Create a raw network socket.
int sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
printf("sock: %d\n", sock);
// Step 2: Set socket option.
setsockopt(sock, IPPROTO_IP, IP_HDRINCL,
&enable, sizeof(enable));
// Step 3: Provide needed information about destination.
dest_info.sin_family = AF_INET;
dest_info.sin_addr = ip->iph_destip;
// Step 4: Send the packet out.
sendto(sock, ip, ntohs(ip->iph_len), 0,
(struct sockaddr *)&dest_info, sizeof(dest_info));
close(sock);
}
Task 2.2A
这部分主要是伪造IP包。这里伪造是UDP包, 代码如下:
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include "myheader.h"
void send_raw_ip_packet (struct ipheader* ip);
/******************************************************************
Spoof a UDP packet using an arbitrary source IP Address and port
*******************************************************************/
int main() {
char buffer[1500];
memset(buffer, 0, 1500);
struct ipheader *ip = (struct ipheader *) buffer;
struct udpheader *udp = (struct udpheader *) (buffer +
sizeof(struct ipheader));
/*********************************************************
Step 1: Fill in the UDP data field.
********************************************************/
char *data = buffer + sizeof(struct ipheader) +
sizeof(struct udpheader);
const char *msg = "Hello Server!\n";
int data_len = strlen(msg);
strncpy (data, msg, data_len);
/*********************************************************
Step 2: Fill in the UDP header.
********************************************************/
udp->udp_sport = htons(12345);
udp->udp_dport = htons(9090);
udp->udp_ulen = htons(sizeof(struct udpheader) + data_len);
udp->udp_sum = 0; /* Many OSes ignore this field, so we do not
calculate it. */
/*********************************************************
Step 3: Fill in the IP header.
********************************************************/
ip->iph_ver = 4;
ip->iph_ihl = 5;
ip->iph_ttl = 20;
ip->iph_sourceip.s_addr = inet_addr("1.1.1.1");
ip->iph_destip.s_addr = inet_addr("8.8.8.8");
ip->iph_protocol = IPPROTO_UDP; // The value is 17.
ip->iph_len = htons(sizeof(struct ipheader) +
sizeof(struct udpheader) + data_len);
/*********************************************************
Step 4: Finally, send the spoofed packet
********************************************************/
send_raw_ip_packet (ip);
return 0;
}
使用gcc -o task22A task22A.c spoof.c -lpcap
编译,sudo ./task22A
运行,查看后台wireshark,可以看到我们伪造的UDP包
Task 2.2B
这部分是伪造ICMP Echo请求。伪造的代码如下, 其中源IP10.0.2.5
是局域网内另一个虚拟机的IP,
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include "myheader.h"
unsigned short in_cksum (unsigned short *buf, int length);
void send_raw_ip_packet(struct ipheader* ip);
/******************************************************************
Spoof an ICMP echo request using an arbitrary source IP Address
*******************************************************************/
int main() {
char buffer[1500];
memset(buffer, 0, 1500);
/*********************************************************
Step 1: Fill in the ICMP header.
********************************************************/
struct icmpheader *icmp = (struct icmpheader *)
(buffer + sizeof(struct ipheader));
icmp->icmp_type = 8; //ICMP Type: 8 is request, 0 is reply.
// Calculate the checksum for integrity
icmp->icmp_chksum = 0;
icmp->icmp_chksum = in_cksum((unsigned short *)icmp,
sizeof(struct icmpheader));
/*********************************************************
Step 2: Fill in the IP header.
********************************************************/
struct ipheader *ip = (struct ipheader *) buffer;
ip->iph_ver = 4;
ip->iph_ihl = 5;
ip->iph_ttl = 20;
ip->iph_sourceip.s_addr = inet_addr("10.0.2.5");
ip->iph_destip.s_addr = inet_addr("8.8.8.8");
ip->iph_protocol = IPPROTO_ICMP;
ip->iph_len = htons(sizeof(struct ipheader) +
sizeof(struct icmpheader));
/*********************************************************
Step 3: Finally, send the spoofed packet
********************************************************/
send_raw_ip_packet (ip);
return 0;
}
其中用到额外的文件,
使用gcc -o task22B task22B.c spoof.c checksum.c -lpcap
进行编译, sudo ./task22B
运行,查看后台的wireshark,如下:
,可以看到我们发送的源IP为10.0.2.5
, 目的IP为8.8.8.8
的ICMP包,并且还有回复
Q4: 能把IP包的长度设置为任意数值,而不管实际的包的大小吗?
A4: 将代码中设置长度该成下面的代码,运行可知其为28B,修改长度为10B,wireshark没有捕捉到包,说明没有发出去。
ip->iph_len = htons(10);
printf("iph_len: %d\n", sizeof(struct ipheader) +
sizeof(struct icmpheader));
修改成1000B,结果如下,可以看到正常发送出去,且收到了相应。说明可以调大length,不能调小length。
Q5: 使用 raw socket 编程, 我们要计算IP头部的checksum吗?
A5: 不用计算IP头部的checksum,但是需要计算ICMP头部的checksum。
Q6: 为什么使用raw socket 编程需要root权限?没有root权限执行时程序会在哪里报错?
**A6:**因为能任意读取发送包意味着很大的安全风险,所以需要root权限。使用普通权限运行结果如下:
可以看到返回的socket 描述符为-1, 说明创建raw socket失败了。
Task 2.3
准备两个在同一个局域网的虚拟机,这部分主要是同时嗅探和伪造包,实现一个机器ping任意IP x,另一个机器伪造ICMP回复请求,使得其有回复,而IP x所对应的机器可能根本不存在。
代码如下:
#include <pcap.h>
#include <stdio.h>
#include <arpa/inet.h>
#include "myheader.h"
void got_packet(u_char *args, const struct pcap_pkthdr *header,
const u_char *packet)
{
struct ethheader *eth = (struct ethheader *)packet;
if (ntohs(eth->ether_type) == 0x0800) { // 0x0800 is IP type
struct ipheader * ip = (struct ipheader *)
(packet + sizeof(struct ethheader));
printf("From: %s ", inet_ntoa(ip->iph_sourceip));
printf("To: %s ", inet_ntoa(ip->iph_destip));
if (ip->iph_protocol == IPPROTO_ICMP)
printf("protocal: ICMP\n");
else
printf("protocal: Others\n");
struct icmpheader *icmp_pkt = (struct icmpheader *)(packet + sizeof(struct ethheader)
+ sizeof(struct ipheader));
if (ip->iph_protocol == IPPROTO_ICMP) {
char buffer[1500];
memset(buffer, 0, 1500);
/*********************************************************
Step 1: Fill in the ICMP header.
********************************************************/
struct icmpheader *icmp = (struct icmpheader *)
(buffer + sizeof(struct ipheader));
icmp->icmp_type = 0; //ICMP Type: 8 is request, 0 is reply.
icmp->icmp_code = 0;
icmp->icmp_id = icmp_pkt->icmp_id;
icmp->icmp_seq = icmp_pkt->icmp_seq;
printf("icmp id: %d, seq: %d\n", ntohs(icmp_pkt->icmp_id), ntohs(icmp_pkt->icmp_seq));
// Calculate the checksum for integrity
icmp->icmp_chksum = 0;
icmp->icmp_chksum = in_cksum((unsigned short *)icmp,
sizeof(struct icmpheader));
/*********************************************************
Step 2: Fill in the IP header.
********************************************************/
struct ipheader *ipp = (struct ipheader *) buffer;
ipp->iph_ver = 4;
ipp->iph_ihl = 5;
ipp->iph_ttl = 64;
ipp->iph_sourceip.s_addr = ip->iph_destip.s_addr;
ipp->iph_destip.s_addr = ip->iph_sourceip.s_addr;
ipp->iph_protocol = IPPROTO_ICMP;
ipp->iph_len = htons(sizeof(struct ipheader) +
sizeof(struct icmpheader));
printf("send tt source :%s\n", inet_ntoa(ipp->iph_sourceip));
printf("send tt dest: %s\n", inet_ntoa(ipp->iph_destip));
/*********************************************************
Step 3: Finally, send the spoofed packet
********************************************************/
// icmp_pkt->icmp_type = 0;
// icmp_pkt->icmp_code = 0;
// icmp->icmp_chksum = 0;
// icmp->icmp_chksum = in_cksum((unsigned short *)icmp,
// sizeof(struct icmpheader));
send_raw_ip_packet (ipp);
}
}
}
int main()
{
pcap_t *handle;
char errbuf[PCAP_ERRBUF_SIZE];
struct bpf_program fp;
char filter_exp[] = "icmp[icmptype]==icmp-echo";
bpf_u_int32 net;
// Step 1: Open live pcap session on NIC with name enp0s3
handle = pcap_open_live("enp0s3", BUFSIZ, 1, 1000, errbuf);
printf("listening on network card, ret: %p...\n", handle);
// Step 2: Compile filter_exp into BPF psuedo-code
printf("try to compile filter...\n");
pcap_compile(handle, &fp, filter_exp, 0, net);
printf("try to set filter...\n");
pcap_setfilter(handle, &fp);
// Step 3: Capture packets
printf("start to sniff...\n");
pcap_loop(handle, -1, got_packet, NULL);
pcap_close(handle); //Close the handle
return 0;
}
使用 gcc -o task23 task23.c checksum.c spoof.c -lpcap
编译程序,sudo ./task23
运行
关闭网络,使用另一台机器ping 1.1.1.1
,此机器运行上面的程序,结果如下:
程序输出如下:
要注意的是,程序中使用的inet_ntoa
函数以字符串形式返回ip地址,该字符串存在函数内部的静态区域,下一次调用会刷新,之前的结果将会失效。
撒花完结。