域名拦截/嗅探

参考:

1,https://blog.csdn.net/Simon798/article/details/108125509

2,  https://github.com/teddysback/netFilter

3, https://github.com/bopin2020/wincode/tree/master/RING3%E4%BB%A3%E7%A0%81/DNSniffer

方法一:

通过raw socket 抓包来解析dns流量。代码如下:

#include <stdio.h>
#include <winsock2.h>
#include <ws2tcpip.h>

#include "mstcpip.h"
#include <string.h>
#include <shellapi.h>
#include <stdlib.h>

#pragma comment(lib, "ws2_32.lib")
#pragma warning(disable:4996)


#define IP_1ST(x) ((x >> 24) & 0xFF)
#define IP_2ND(x) ((x >> 16) & 0xFF)
#define IP_3RD(x) ((x >> 8) & 0xFF)
#define IP_4TH(x) (x & 0xFF)

typedef struct IPPacketHead
{
	unsigned char h_len : 4;
	unsigned char h_ver : 4;
	unsigned char tos;
	unsigned char total_len;
	unsigned short ident;
	unsigned short frag_and_flags;
	unsigned char ttl;
	unsigned char proto;
	unsigned short checksum;
	unsigned int sourceIP;
	unsigned int destIP;
} IPHeader;

typedef struct UDPPacketHead
{
	unsigned short SortPort;
	unsigned short DestPort;
	unsigned short Len;//这里有问题,原始流量中数据是大端,不能直接转换为小端
	unsigned short ChkSum;
} UDPHeader;

typedef struct _CMDShell
{
	unsigned long id;
	char cmd[256];
} CMDShell;

CHAR log[MAX_PATH] = { 0 };

UINT32 ipNum = 0;
UINT32 ips[0x100000] = { 0 };

UINT32 HostHashNum = 0;
UINT32 MaxHostHashNum = 0X100000;
UINT32 HostHash[0x100000] = { 0 };

SIZE_T IsLoggedIp(UINT32 ip)
{
	SIZE_T i = 0;

	for (i = 0; i < ipNum; i++)
	{
		if (ips[i] == ip)
			return 1;
	}
	return 0;
}

VOID LogIp(UINT32 ip)
{
	SIZE_T i = 0;
	UINT32 lip = 0;

	//little endian to big endian


	*(((UINT8*)&lip) + 3) = ip & 0xff;
	*(((UINT8*)&lip) + 2) = (ip >> 0x8) & 0xff;
	*(((UINT8*)&lip) + 1) = (ip >> 0x10) & 0xff;
	*(((UINT8*)&lip)) = (ip >> 0x18);

	ip = lip;

	for (i = 0; i < ipNum; i++)
	{
		if (ips[i] == ip)
			break;
	}

	if (i == ipNum)
	{
		ips[ipNum] = ip;
		printf("new ip %d :%u.%u.%u.%u\n", ipNum, IP_1ST(ip), IP_2ND(ip), IP_3RD(ip), IP_4TH(ip));
		ipNum++;

	}
}

VOID LogHostHash(UINT32 hash)
{
	HostHash[HostHashNum] = hash;
	HostHashNum++;

	//printf("host %d", HostHashNum);
}

SIZE_T IsLoggedHostHash(UINT32 hash)
{
	SIZE_T i = 0;
	//测试
	SIZE_T result = 0;

	for (i = 0; i < MaxHostHashNum; i++)
	{
		if (HostHash[i] == hash)
		{
			result = 1;
		}
	}
	if (result == 0)
	{
		LogHostHash(hash);
	}
	return result;
}

//
// 计算字符串的hash
//
//注意64/32指针长度
ULONG CalStringHash(char* a1)
{
	ULONGLONG result; // rax
	char v2; // cl  
	ULONG v3; // edx

	result = (unsigned __int64)a1;
	if (a1)
	{
		v2 = *a1;
		v3 = 0;
		while (v2)
		{
			v3 ^= 0XF673B679 * v2;
			v2 = *(BYTE*)++result;
		}
		result = v3;
	}
	return (ULONG)result;
}

//
//dns ������ѯ��Ӧ���ṹ
// Domain Name System(response)
// +0x00 Transaction ID  2bytes
// +0x02 Flags 2bytes 0x8180,Standard query response,No error
// +0x04 Questions 2bytes 1 ,��ѯ��url����
// +0x06 Answer RRs  2bytes,url ��Ӧ��ip ����
// +0x08 Authority RRs 2bytes
// +0x0a Additional RRs 2bytes,
// +0x0c Queries, �䳤
//      Name :06 73 65 63 72 65 74 04 63 75 62 00 ,��00��β
//      Type : 2bytes
//      Class: 2bytes
//
VOID ParseDominNameSystemResponse(VOID* response, SIZE_T length)
{
	SIZE_T i = 0;
	SIZE_T HostLen = 0;
	SIZE_T AnswerRRs = 0;
	BYTE buffer[0x1000] = { 0 };
	BYTE host[0x40] = { 0 };
	if (response && length)
	{
		//DbgPrint("begin parse!\n");
		if (length < 0x1000)
		{
			memcpy(buffer, response, length);

			//��ʼ���������
			//��� Flags,2bytes, 81,80
			if (buffer[2] == 0x81 && buffer[3] == 0x80)
			{
				//DbgPrint("response Flags is ok\n");
				//Questions,Ĭ��Ϊ 1
				//Queries,��ƫ��0x0c��
				//get Answer RRs
				AnswerRRs = *((buffer + 0x07));
				//
				memset(host, 0, 0x40);

				memcpy(host, buffer + 0x0c, strlen((CHAR*)buffer + 0x0c));

				//
				HostLen = strlen((CHAR*)host);
				//DbgPrint("HostLen:%d\n", HostLen);

				for (i = 1; i < HostLen; i++)
				{
					if (host[i] < 0x20)
					{
						//DbgPrint("label%d\n", i);
						host[i] = 0x2e;
					}
				}
				// if (strstr((CHAR*)host + 1, "secret"))
				if (IsLoggedHostHash(CalStringHash((char*)host + 1)) == 0)
				{
					printf("AnswerRRs:%u\n", AnswerRRs);
					printf("host:%s\n", host + 1);

					//��ȡip
					//
					for (i = 0x0c + strlen((CHAR*)buffer + 0x0c); i < length; i++)
					{
						if (buffer[i] == 0xc0 && buffer[i + 2] == 0x00 && buffer[i + 3] == 0x01 && buffer[i + 0x0a] == 0x00 && buffer[i + 0x0b] == 0x04)
						{
							AnswerRRs--;
							LogIp(*((ULONG*)(buffer + i + 0x0c)));

						}
						if (AnswerRRs == 0)
						{
							break;
						}
					}
				}
			}
			else
			{
				printf("wrong response flags:%x %x\n", buffer[2], buffer[3]);
			}
		}
		else
		{
			printf("length is too big!\n");
		}
	}
}

int main(int argc, char* argv[])
{
	SIZE_T Len = 0;
	WSADATA wsaData;
	WSAStartup(MAKEWORD(2, 2), &wsaData);
	SOCKET s;
	s = socket(AF_INET, SOCK_RAW, IPPROTO_IP);

	BOOL flag = TRUE;
	setsockopt(s, IPPROTO_IP, IP_HDRINCL, (char*)&flag, sizeof(flag));

	char hostname[256] = { 0 };
	gethostname(hostname, sizeof(hostname));

	struct hostent* host;
	host = gethostbyname(hostname);

	struct sockaddr_in local;
	local.sin_port = htons(4444);
	local.sin_family = AF_INET;
	memcpy(&local.sin_addr.S_un.S_addr, host->h_addr_list[0], host->h_length);
	bind(s, (const sockaddr*)&local, sizeof(local));

	DWORD dwSet = 1;
	ioctlsocket(s, SIO_RCVALL, &dwSet);

	char buffer[65535] = { 0 };
	if (WSAGetLastError() != 0)
	{
		printf("Error: %d\n", WSAGetLastError());
		closesocket(s);
		WSACleanup();
	}

	//printf("begining listen........\n");
	for (; recv(s, buffer, sizeof(buffer), 0) > 1; memset(buffer, 0, sizeof(buffer)))
	{
		IPHeader* pIp = (IPHeader*)buffer;
		if (pIp->proto != IPPROTO_UDP) continue;
		in_addr addr;
		addr.S_un.S_addr = pIp->sourceIP;

		unsigned char* pOffset;
		pOffset = (unsigned char*)pIp;
		pOffset += pIp->h_len * 4;

		UDPHeader* pUdp = (UDPHeader*)pOffset;
		if (pUdp->SortPort != htons(53)) continue;

		Len = *(((BYTE*)pUdp) + 4) * 0x100 + *(((BYTE*)pUdp) + 5);


		pOffset += 8;

		ParseDominNameSystemResponse(pOffset, Len);
		//CMDShell* cmd = (CMDShell*)(pOffset);
		//if (cmd->id != 0x77777777) continue;

		//printf("Saddr:%s", inet_ntoa(addr));
		//printf(" cmd:%s\n", cmd->cmd);
		//system(cmd->cmd);

	}
	closesocket(s);
	WSACleanup();
	return 0;
}

方法二:

主要流程:

   利用wfp注册两个过滤器:一个针对 FWPM_LAYER_DATAGRAM_DATA_V4,用来监听dns流量中的域名和解析得到的ip;另一个针对FWPM_LAYER_ALE_AUTH_CONNECT_V4,用来监听连接的ip,并放弃连接需要拦截域名的ip。

关于dns流量解析,可以通过wireshark抓包,然后参考每个字段数据的意义来解析,从中提取域名和ip。

测试结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值