天天看點

網絡安全之tcp阻截引擎 (一)1、tcp協定的缺陷2 、抓包3、建立線程,查詢流經資料包3.2 解析IP包4 、包分析和阻斷流程5、IP 校驗算法6、制作界面

1、tcp協定的缺陷

任何協定都有缺陷,tcp協定同樣如此,tcp協定的三次握手是有一個不能輕易發現的缺陷,這個缺陷容易引起旁路中斷,引起中間人攻擊,可以讓中間人篡改資料包,Man-in-the-MiddleAttack,我們先看下圖,看懂了,就可以繼續了。

網絡安全之tcp阻截引擎 (一)1、tcp協定的缺陷2 、抓包3、建立線程,查詢流經資料包3.2 解析IP包4 、包分析和阻斷流程5、IP 校驗算法6、制作界面

    實際上,這個缺陷就是在伺服器和客戶機真正建立連接配接之前,我們可以發送RST包,先告訴伺服器斷開,然後我們模拟伺服器給用戶端發包,直接串入到他們的網絡中間。

    在TCP層,tcp的意思是傳輸控制協定,有個FLAGS字段,這個字段有以下幾個辨別:SYN, FIN, ACK, PSH, RST, URG. 對于我們日常的分析有用的就是前面的五個字段,SYN,建立連接配接,FIN包的意思是finish 關閉連接配接,ACK是回答響應,而RST表示我異常中斷,連結重置,PSH才是真正的資料傳送。對于我們來說,關鍵的截斷就在于RST 和 FIN,我們選取RST包。

2 、抓包

2.1 抓包方式1 交換機鏡像

    這種方式是直接從交換機鏡像端口複制資料,可以抓該交換機口路徑下的所有包,缺點是不能抓所有包。在網絡安全中,為了友善對一個或多個網絡接口的流量進行分析(如IDS 入侵檢測、網絡分析儀等),可以通過配置交換機或路由器來把一個或多個端口(VLAN)的資料轉發到某一個端口,這就是端口鏡像,來實作對網絡的監聽。

2.2 抓包方式2 網橋

    在路由器和交換機之間串入網橋,抓所有包,這種方式是可以抓所有包,缺點是流量更大。通常的網橋做法,可以使用兩個網卡,在兩個網卡之間既可以用旁路方式,也可以使用串入方式,在傳輸層這一層,既可以抓取tcp包,也可以抓取udp包,這取決于需求。

2.3 抓包方式3 網關

    網關方式是比較安全的方式,一般是純軟體旁路方式抓包。旁路方式抓包是不能阻截udp的,除非我們動用arp 協定,在網絡中下毒arp,讓所有主機誤認為我們發放病毒的機器是網關,這種方式不可取,本身具有arp防火牆的主機是不會受幹擾的。

為了友善示範,顯然我們制作一個網關,在網關上旁路抓包是比較安全的,下面是建立RAW SOCKET,抓取所有流經網關的原始資料包,然後一層一層往下走,代碼其實是适應各種環境的,無論交換機鏡像,還是旁路抓包都是這麼寫,網橋的方式不一樣,可以通過linux核心子產品流經處理的方式發送到使用者态去分析,這裡暫時不讨論這種方式。一下是旁路方式抓包。

if((m_helperSocket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW))==SOCKET_ERROR)
		{		
			return 0;
		}

		if(setsockopt(m_helperSocket, IPPROTO_IP, IP_HDRINCL, (char *)&optval, sizeof(optval))==SOCKET_ERROR)
		{		
			return 0;
		}
		if((m_sniffSocket = socket(AF_INET, SOCK_RAW, IPPROTO_IP))==SOCKET_ERROR)
		{		
			return 0;
		}
		PIP_ADAPTER_INFO pAdapterInfo = m_pAdapterInfo;		
		u_long in = 0;
		do 
		{
			if (strcmp (in_szSourceDevice, pAdapterInfo->AdapterName ) == 0)
			{
				break;
			}
			in++;
			pAdapterInfo = pAdapterInfo->Next;    // Progress through
		}
		while(pAdapterInfo);  
		

		struct sockaddr_in src;
		memset(&src, 0, sizeof(src));
		src.sin_addr.S_un.S_addr = inet_addr (pAdapterInfo->IpAddressList.IpAddress.String);		
		src.sin_family      = AF_INET;
		src.sin_port        = 0;
		if (bind(m_sniffSocket,(struct sockaddr *)&src,sizeof(src)) == SOCKET_ERROR)
		{			
			return 0;
		}

		int j=1;

		if (WSAIoctl(m_sniffSocket, SIO_RCVALL, &j, sizeof(j), 0, 0, &in,0, 0) == SOCKET_ERROR)
		{			
			return 0;
		}		
           

3、建立線程,查詢流經資料包

一個最大的IP包為64K,因為一個包是由兩個位元組來表示的,建立64K資料包緩存,下面隻是樣例寫法,實際上需要建立緩存連結清單,逐次分析每個包。

3.1 抓取IP

int ThreadHandler(void * in_pParam)
{
		
 //    libnet_t *LibnetHandle; 
	//char *DestAddr = "192.168.1.178";
 //   char *SourAddr = "192.168.1.1";
	
	
	//LibnetHandle = libnet_init(LIBNET_LINK, g_DevName, NULL);
 //   if (LibnetHandle == NULL)
 //   {
 //      
 //      return -1;
 //   }
 //   unsigned int DestAddrNumber = libnet_name2addr4(LibnetHandle, DestAddr, LIBNET_RESOLVE);
 //   unsigned int SourAddrNumber = libnet_name2addr4(LibnetHandle, SourAddr, LIBNET_RESOLVE);

	cprocess* _this = (cprocess*)in_pParam;	

	int  res = 0;
	char *pkt_data = (char *)malloc(65536); //64K的緩存!	
	char					m_pLogString[256];		
	Packet					p;
	
	if (pkt_data == NULL)
	{		
		return 0;
	}

	SetEvent(_this->m_hThrdReadyEvent);
	
	// Capture packet
	string strName;
	do
	{
       //#define GET_IP(x,buf) sprintf(buf,"%d,%d,%d,%d", x&0xFF, (x>>8)&0xFF, (x>>16)&0xFF, (x>>24)&0xFF)
		res = recvfrom(_this->m_sniffSocket,pkt_data,65536,0,0,0); //
		if(res > 0)	
		{			
			ZeroMemory(&p, sizeof (Packet));
			unsigned int Number = _this->DecodeIP((u_int8_t*)pkt_data, res, &p);
			if (p.banned == 1)
			{
				_this->FilterHttpRequestXP(&p);
				char ip_string_src[17];
				char ip_string_dst[17];
				memcpy (ip_string_src, inet_ntoa(p.iph->ip_src), 17);
				memcpy (ip_string_dst, inet_ntoa(p.iph->ip_dst), 17);

				sprintf (m_pLogString,
					"關鍵詞 \'%s\' 被偵測從 %s 到 %s. 暗影聯盟日志", 
					p.matched, ip_string_src, ip_string_dst);
				_this->m_pFilterLog->AddLog(m_pLogString);
			}
		}
	} 
	while (res > 0);
	free(pkt_data);
	return 1;
}
           

3.2 解析IP包

unsigned int  DecodeIP(u_int8_t * pkt, const u_int32_t len, Packet * p)
{
	u_int32_t ip_len;			/* length from the start of the ip hdr to the pkt end   ip包長度*/
	u_int32_t hlen;             /* ip header length  ip標頭長度 一個IP包如tcp包即使隻有一個位元組的應用層資料也是要大于40位元組的 */
	/* lay the IP struct over the raw data  */
	p->iph = (IPHdr *) pkt;
	/* 小于一個IP標頭的長度立刻退出 */
	if(len < IP_HEADER_LEN)
	{		
		p->iph = NULL;
		return -1;
	}
	if(IP_VER(p->iph) != 4)
	{
		p->iph = NULL;
		return -1;
	}
	/* set the IP datagram length */
	ip_len = ntohs(p->iph->ip_len);
	/* set the IP header length */
	hlen = IP_HLEN(p->iph) << 2;
	/* header length sanity check */
	if(hlen < IP_HEADER_LEN)
	{
		p->iph = NULL;
		return -1;
	}

	//抓包後分析的包長度
	if (ip_len > len) 
	{
		 ip_len = len;
	}

	if(ip_len < hlen)
	{
		 p->iph = NULL;
		 return -1;
	}

	/* test for IP options */
	p->ip_options_len = hlen - IP_HEADER_LEN;

	if(p->ip_options_len > 0)
	{
		p->ip_options_data = pkt + IP_HEADER_LEN;		
	}


	/* set the remaining packet length */
	ip_len -= hlen;

	/* check for fragmented packets */
	p->frag_offset = ntohs(p->iph->ip_off);

	/* 
	* get the values of the reserved, more 
	* fragments and don't fragment flags 
	*/
	p->rf = (u_int8_t)((p->frag_offset & 0x8000) >> 15);
	p->df = (u_int8_t)((p->frag_offset & 0x4000) >> 14);
	p->mf = (u_int8_t)((p->frag_offset & 0x2000) >> 13);

	/* mask off the high bits in the fragment offset field */
	p->frag_offset &= 0x1FFF;

	if(p->frag_offset || p->mf)
	{
		/* set the packet fragment flag */
		p->frag_flag = 1;	
	}

	/* if this packet isn't a fragment  如果不是一個分片代碼*/
	if(!(p->frag_flag))
	{
		if(p->iph->ip_src.S_un.S_addr == g_SelfIPAddress)
		//iphdr *pip = (iphdr *) pkt;
		{
			//這個包是從本地發出去的ip包
			g_Direction = 0;
		}
		else
		{
			if(p->iph->ip_dst.S_un.S_addr == g_SelfIPAddress)
			{
				//這個包是個進來的ip包
				g_Direction = 1;
			}
			else g_Direction = -1;//内網位址
		}
		
		//2013-02-01 注釋,做家長行為管理,不進行協定分析
        if(g_Direction >=0)
		{
			//unsigned int t = time(NULL);
			//return Analyze_Protocol(pip,t,g_Direction);
		}
		//2009-04-7 先進行協定分析,以下屏蔽
		//2013-02-01 又重新打開,做家長行為管理
		/* Decode only TCP headers */
		if (p->iph->ip_proto == IPPROTO_TCP)
		{
			DecodeTCP(pkt + hlen, ip_len, p);
		}

	}
	else
	{
		/* set the payload pointer and payload size */
		p->data = pkt + hlen;
		p->dsize = (u_short) ip_len;
		return -1;
	}


	return -1;
}
           

3.3 解析tcp

///解析tcp包,pkt傳進來的是ip包

void DecodeTCP(u_int8_t * pkt, const u_int32_t len, Packet * p)
{
	u_int32_t hlen;            /* TCP header length */
	
	if(len < 20)
	{
		  p->tcph = NULL;
		  return;
	}

	/* lay TCP on top of the data cause there is enough of it! */
	p->tcph = (TCPHdr *) pkt;

	/* multiply the payload offset value by 4 */
	hlen = TCP_OFFSET(p->tcph) << 2;

	if(hlen < 20)
	{
		p->tcph = NULL;
		return;
	}

	if(hlen > len)
	{
		p->tcph = NULL;
		return;
	}

	/* if options are present, decode them */
	p->tcp_options_len = hlen - 20;

	if(p->tcp_options_len > 0)
	{	
		p->tcp_options_data = pkt + 20;	
	}


	/* set the data pointer and size */
	p->data = (u_int8_t *) (pkt + hlen);

	if(hlen < len)
	{
		p->dsize = (u_short)(len - hlen);
	}
	else
	{
		p->dsize = 0;
	}
	
	if (p->tcph->th_flags & TH_ACK && p->tcph->th_flags & TH_PSH)
	{
		if(p->tcph->th_dport != htons(80) &&
			p->tcph->th_dport != htons(443) )
			return ;


		DecodeHTTP(p->data, p->dsize, p);

	}
	
	return;
}
           

上面的的流程就是一層一層往下解析,我們還要做的就是建立資料特征向量,分析資料,儲存資料,同樣可以完成資料回放。

4 、包分析和阻斷流程

網絡安全之tcp阻截引擎 (一)1、tcp協定的缺陷2 、抓包3、建立線程,查詢流經資料包3.2 解析IP包4 、包分析和阻斷流程5、IP 校驗算法6、制作界面

5、IP 校驗算法

在發送IP包的過程中,需要用到校驗算法

unsigned short CalcIPSum(unsigned short * w, int blen)
{
	unsigned int cksum;

	/* IP must be >= 20 bytes */
	cksum  = w[0];
	cksum += w[1];
	cksum += w[2];
	cksum += w[3];
	cksum += w[4];
	cksum += w[5];
	cksum += w[6];
	cksum += w[7];
	cksum += w[8];
	cksum += w[9];

	blen  -= 20;
	w     += 10;

	while( blen ) /* IP-hdr must be an integral number of 4 byte words */
	{
		cksum += w[0];
		cksum += w[1];
		w     += 2;
		blen  -= 4;
	}

	cksum  = (cksum >> 16) + (cksum & 0x0000ffff);
	cksum += (cksum >> 16);

	return (unsigned short) (~cksum);
}
           

6、制作界面

制作一個簡單的界面,從網卡上抓包,這裡其實做實驗可以從本地做,如果做好了,可以做一個網關,區域網路中的所有網絡主機填寫網關位址為本網關,就可以從網卡上以原始資料包方式抓取所有包。例如linux和windows server系列是可以抓包和發送原始資料包的,但是windows7 和 10 這種系列沒有權限發送原始資料包,隻能抓取,ok,原理已經清楚了,我們一步一步建立這樣的界面和程式。

網絡安全之tcp阻截引擎 (一)1、tcp協定的缺陷2 、抓包3、建立線程,查詢流經資料包3.2 解析IP包4 、包分析和阻斷流程5、IP 校驗算法6、制作界面

下一節我們繼續探讨網絡中抓到包以後如何把包解析出來。

繼續閱讀