2、目标探测
作者: Refdom, EmaiL: Refdom@263.net 2002/1/17
确定目标并收集相关的周边信息之后,更直接地要接触目标的手段的就是进行探测了。探测一台主机包括是否活动、主机系统、正在使用哪些端口、提供了哪些服务、相关服务的软件版本等等 对这些内容的探测就是为了“对症下药”。
探测也就是大家所说的扫描,应该说扫描是最多使用工具的一个步骤,现在扫描工具也非常的多,从一般的Port Scanner到可以穿透防火墙的Scan 工具,比如强大的nmap,国内的X-Scanner、流光等等。在这里,我不是来介绍工具使用的,而主要是看看这些扫描工具到底是怎么来实现的。如果你喜欢上一个工具的话,也就表示你丧失了一次进步的机会。 这里都是一些简单的小程序,功能非常有限,只是为了说明实现原理而写的。有兴趣的可以自己做更广泛的修改,而实现更多的功能。
ICMP协议——PING是最常用的,也是最简单的探测手段,用来判断目标是否活动。实际上Ping是向目标发送一个要求回显(Type = 8)的ICMP数据报,当主机得到请求后,再返回一个回显(Type = 0)数据报。而且Ping 程序一般是直接实现在系统内核中的,而不是一个用户进程。我们也可以很容易实现一个Ping程序,这里我列出我写的一个简单Ping程序。
#include #include
typedef struct ip_hdr //定义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;
typedef struct icmp_hdr { BYTE i_type; // ICMP报文类型 BYTE i_code; // ICMP代码 USHORT i_cksum; // 校验和 USHORT i_id; // 标志符 USHORT i_seq; // 序号 ULONG timestamp; // 时间戳 } ICMP_HEADER;
//CheckSum:计算校验和的子函数 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); }
void useage() { printf("******************************************\n"); printf("ICMPPing\n"); printf("\t Written by Refdom\n"); printf("\t Email: refdom@263.net\n"); printf("Useage: ICMPPing.exe Target_ip \n"); printf("*******************************************\n"); }
void DecodeHeader(char*, int);
void main(int argc, char* argv[]) { ICMP_HEADER icmpHeader; int rect; WSADATA WSAData; SOCKET sock; SOCKADDR_IN addr_in,addr_from; char recvbuf[1024];
useage(); if (argc!=2) { exit(0); }
if (WSAStartup(MAKEWORD(2,2), &WSAData) != 0 ) { printf ("WSAStartup Error!\n"); exit(0); }
sock= socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); int nTimeOut = 2000; setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char*)&nTimeOut, sizeof(nTimeOut)); setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&nTimeOut, sizeof(nTimeOut)); memset(&addr_in, 0, sizeof(addr_in)); addr_in.sin_family = AF_INET; addr_in.sin_addr.S_un.S_addr = inet_addr(argv[1]);
if (addr_in.sin_addr.S_un.S_addr == INADDR_NONE) { struct hostent *host = NULL; if ((host = gethostbyname(argv[1])) != NULL) { memcpy(&(addr_in.sin_addr), host->h_addr, host->h_length); } } // memset(&icmpHeader, 0, sizeof(icmpHeader)); icmpHeader.i_type = 8; icmpHeader.i_code = 0; icmpHeader.i_cksum = 0; icmpHeader.i_id = (USHORT)GetCurrentProcessId(); icmpHeader.i_seq = 0; icmpHeader.timestamp = GetTickCount(); icmpHeader.i_cksum = checksum((USHORT*)&icmpHeader, sizeof(icmpHeader));
rect = sendto(sock, (char*)&icmpHeader, sizeof(icmpHeader), 0, (sockaddr*)&addr_in, sizeof(addr_in)); int addr_from_len; addr_from_len = sizeof(addr_from); rect = recvfrom(sock, recvbuf, sizeof(recvbuf), 0, (sockaddr*)&addr_from, &addr_from_len); DecodeHeader(recvbuf, rect); closesocket(sock); WSACleanup(); }
void DecodeHeader(char* buf, int len) { ICMP_HEADER *icmpHeader; IP_HEADER *ipHeader; IN_ADDR addr; icmpHeader = (ICMP_HEADER*)(buf+20); DWORD Time1;
Time1 = GetTickCount(); ipHeader = (IP_HEADER*)malloc(20); memcpy(ipHeader, buf, 20); addr.S_un.S_addr = ipHeader->sourceIP; if (icmpHeader->i_type != 0) { printf("No replay!\n"); } if (icmpHeader->i_id != (USHORT)GetCurrentProcessId()) { printf("other pocket!\n"); } printf("Reply from %s: Bytes= %d ", inet_ntoa(addr), len); printf("TTL = %d Time= %d ms.\n", ipHeader->ttl, Time1-icmpHeader->timestamp ); } (其中去掉了一些错误判断的地方,呵呵,节约空间) PING得到的结果包括字节数、反应时间、以及生存时间。Ping程序通过在ICMP报文数据中存放发送请求的时间来计算返回时间。当应答返回时,根据现在时间减去报文中存放的发送时间就得到反应时间了。生存时间(TTL),本来就存放在IP数据报的头部,直接就能够获取。我们能够根据TTL时间来大致判断目标主机的系统类型,以及我们需要到达目的地需要经过几个路由器等等。 但是普通的Ping命令只能对一台主机进行探测,如果是要判断一个大类的网络是否有哪些活动的机器的话,就需要制作一个用来大面积Ping的工具,当然,你可以改进上面的基本程序,或者使用多线程并发来满足大面积Ping的需要。
上一页 1 2 3 下一页 |