还有一个Tracert 命令,也非常有用,可以参考以前写的,这里就不再罗嗦了。 关于ICMP协议的其他使用,比如,ICMP拒绝服务攻击等等,以后再讨论。
由于现在一些防火墙对ICMP进行控制,所以,实际上用ping来做判断已经非常不可靠了。即使是个人防火墙,你也Ping不进去了。 当然,我们有更多探测的方式,我们可以不使用ICMP协议,而使用更普通的TCP协议来进行探测,而且进行对方开放端口的扫描。普通的TCP探测是直接用connect()进行的,但是,在对方有防火墙情况下,Connect() 探测得出的结果也是不能确信的,如果熟悉更多关于TCP/IP协议的内容,我们就可以通过TCP/IP协议的特点尽可能地绕过防火墙。这就是大家所说得半开式扫描,其原理也就是不直接使用Connect进行对方端口得连接,而是发送TCP的标志位来实现,而且这样根本就不用同目标主机进行实际的连接。 在X-Scanner也有使用SYN探测的一项,也就是通过下面这些原理来做的。
SYN PING SYN位表示一个TCP连接的开始,也就是三次握手的第一步,向远端主机某端口发送一个只有SYN标志位的TCP数据报,如果主机反馈一个SYN || ACK数据包,那么,这个主机正在监听该端口,如果反馈的是RST数据包,说明,主机没有监听该端口。
ACK PING 在三次握手中,ACK来表示确认握手过程,但是,如果根本没有进行SYN的请求,而去确认连接,目标主机就会认为一个错误发生了,而发送RST位来中断会话。发送一个只有ACK标志的TCP数据报给主机,如果主机反馈一个TCP RST数据报来,那么这个主机是存在的。ACK探测更容易通过一些 stateless型的防火墙。
FIN ping 因为FIN标志表示一个结束,但是目标主机根本就没有这个连接记录,所以,根据TCP/IP协议,目标主机就要发送一个RST标志的数据包来中断这个会话。对某端口发送一个TCP FIN数据报给远端主机,如果主机没有任何反馈,那么这个主机是存在的,而且正在监听这个端口;主机反馈一个TCP RST回来,那么说明该主机是存在的,但是没有监听这个端口。
NULL Ping 即发送一个没有任何标志位的TCP包,根据RFC793,如果目标主机的相应端口是关闭的话,应该发送回一个RST数据包。
后两种办法可以绕过一些防火墙,而得到防火墙后面的主机信息。即使在ICMP包被过滤的情况下,一般TCP探测还是能够成功的。当然,是在不被欺骗的情况下的。
下面这段程序就是一个TCP/IP半开探测的例子,当然,并没有做得完美,因为没有接收部分,而在WIN2000下实际就是一个选择性的SNIFFER,呵呵,大家可以使用其他的SNIFFER来实现同样的目的。
#include #include #include
#define SOURCE_PORT 7234 #define MAX_RECEIVEBYTE 255
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地址 }IPHEADER;
typedef struct tsd_hdr //定义TCP伪首部 { unsigned long saddr; //源地址 unsigned long daddr; //目的地址 char mbz; char ptcl; //协议类型 unsigned short tcpl; //TCP长度 }PSDHEADER;
typedef struct tcp_hdr //定义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位紧急数据偏移量 }TCPHEADER;
//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("TCPPing\n"); printf("\t Written by Refdom\n"); printf("\t Email: refdom@263.net\n"); printf("Useage: TCPPing.exe Target_ip Target_port \n"); printf("*******************************************\n"); }
int main(int argc, char* argv[]) { WSADATA WSAData; SOCKET sock; SOCKADDR_IN addr_in; IPHEADER ipHeader; TCPHEADER tcpHeader; PSDHEADER psdHeader;
char szSendBuf[60]={0}; BOOL flag; int rect,nTimeOver;
useage();
if (argc!= 3) { return false; }
if (WSAStartup(MAKEWORD(2,2), &WSAData)!=0) { printf("WSAStartup Error!\n"); return false; }
if ((sock=WSASocket(AF_INET,SOCK_RAW,IPPROTO_RAW,NULL,0,WSA_FLAG_OVERLAPPED))==INVALID_SOCKET) { printf("Socket Setup Error!\n"); return false; } flag=true; if (setsockopt(sock,IPPROTO_IP, IP_HDRINCL,(char *)&flag,sizeof(flag))==SOCKET_ERROR) { printf("setsockopt IP_HDRINCL error!\n"); return false; }
nTimeOver=1000; if (setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char*)&nTimeOver, sizeof(nTimeOver))==SOCKET_ERROR) { printf("setsockopt SO_SNDTIMEO error!\n"); return false; } addr_in.sin_family=AF_INET; addr_in.sin_port=htons(atoi(argv[2])); addr_in.sin_addr.S_un.S_addr=inet_addr(argv[1]);
// // //填充IP首部 ipHeader.h_verlen=(4<<4 | sizeof(ipHeader)/sizeof(unsigned long)); // ipHeader.tos=0; ipHeader.total_len=htons(sizeof(ipHeader)+sizeof(tcpHeader)); ipHeader.ident=1; ipHeader.frag_and_flags=0; ipHeader.ttl=128; ipHeader.proto=IPPROTO_TCP; ipHeader.checksum=0; ipHeader.sourceIP=inet_addr("本地地址"); ipHeader.destIP=inet_addr(argv[1]);
//填充TCP首部 tcpHeader.th_dport=htons(atoi(argv[2])); tcpHeader.th_sport=htons(SOURCE_PORT); //源端口号 tcpHeader.th_seq=htonl(0x12345678); tcpHeader.th_ack=0; tcpHeader.th_lenres=(sizeof(tcpHeader)/4<<4|0); tcpHeader.th_flag=2; //修改这里来实现不同的标志位探测,2是SYN,1是FIN,16是ACK探测 等等 tcpHeader.th_win=htons(512); tcpHeader.th_urp=0; tcpHeader.th_sum=0;
psdHeader.saddr=ipHeader.sourceIP; psdHeader.daddr=ipHeader.destIP; psdHeader.mbz=0; psdHeader.ptcl=IPPROTO_TCP; psdHeader.tcpl=htons(sizeof(tcpHeader));
//计算校验和 memcpy(szSendBuf, &psdHeader, sizeof(psdHeader)); memcpy(szSendBuf+sizeof(psdHeader), &tcpHeader, sizeof(tcpHeader)); tcpHeader.th_sum=checksum((USHORT *)szSendBuf,sizeof(psdHeader)+sizeof(tcpHeader));
memcpy(szSendBuf, &ipHeader, sizeof(ipHeader)); memcpy(szSendBuf+sizeof(ipHeader), &tcpHeader, sizeof(tcpHeader)); memset(szSendBuf+sizeof(ipHeader)+sizeof(tcpHeader), 0, 4); ipHeader.checksum=checksum((USHORT *)szSendBuf, sizeof(ipHeader)+sizeof(tcpHeader));
memcpy(szSendBuf, &ipHeader, sizeof(ipHeader));
rect=sendto(sock, szSendBuf, sizeof(ipHeader)+sizeof(tcpHeader), 0, (struct sockaddr*)&addr_in, sizeof(addr_in)); if (rect==SOCKET_ERROR) { printf("send error!:%d\n",WSAGetLastError()); return false; } else printf("send ok!\n");
closesocket(sock); WSACleanup();
return 0; }
上面这个程序不光是一个Ping的程序,也可以更改成为一个比connect()更优秀的端口扫描器。
上面这个程序实际上就是通过原始套接字发送自己构造的TCP和IP数据头,如果对这个程序作修改,也很容易改为一个SYN FLOOD的工具。SYN位前面说了,是三次握手过程的第一步,表示发出一个连接请求,这时目标主机同意的时候就会返回一个ACK SYN的数据报,来确认客户端的连接,然后需要客户端进行最后一次ACK的确认,来建立这个连接。但是,如果客户步发送一个ACK来确认,那么,服务器端就有一个缓冲来等待这个确认。当有大量的SYN缓冲等待的时候,正常的连接请求就会被放在一大堆队列中,从而影响正常用户的正常连接。同样相似的,就是RST拒绝服务了。
进行上面的探测应该是探测的第一步,比如主机活动状态,端口。接来下应该针对相应端口进行更详细的判别,以及探测主机系统。 上一页 1 2 3 |