
SYN端口扫描.docx
9页SYN端口扫描 /* 经典描器(全TCP连接)和SYN(半连接)扫描器 全TCP连接 全TCP连接是长期以来TCP端口扫描的基础扫描主机尝试(使用三次握手)与目的机指定端口建立建立正规的连接连接由系统调用connect()开始对于每一个监听端口,connect()会获得成功,否则返回-1,表示端口不可访问 这种扫描方法很容易检测出来,在日志文件中会有大量密集的连接和错误记录) TCP SYN扫描 在这种技术中,扫描主机向目标主机的选择端口发送SYN数据段如果应答是RST,那么说明端口是关闭的,按照设定就探听其它端口;如果应答中包含SYN和ACK,说明目标端口处于监听状态由于所有的扫描主机都需要知道这个信息,传送一个RST给目标机从而停止建立连接由于在SYN扫描时,全连接尚未建立,所以这种技术通常被称为 SYN扫描的优点在于即使日志中对扫描有所记录,但是尝试进行连接的记录也要比全扫描少得多缺点是在大部分操作系统下,发送主机需要,通常情况下,构造SYN数据包需要超级用户或者授权用户访问专门的系统调用 一个TCP头包含6个标志位它们的意义分别为: SYN: 标志位用来建立连接,让连接双方同步序列号。
如果SYN=1而ACK=0,则表示该数据包为连接请求,如果SYN=1而ACK=1则表示接受连接FIN: 表示发送端已经没有数据要求传输了,希望释放连接 RST: 用来复位一个连接RST标志置位的数据包称为复位包一般情况下,如果TCP收到的一个分段明显不是属于该主机上的任何一个连接,则向远端发送一个复位包 URG: 为紧急数据标志如果它为1,表示本数据包中包含紧急数据此时紧急数据指针有效 ACK: 为确认标志位如果为1,表示包中的确认号时有效的否则,包中的确认号无效 PSH: 如果置位,接收端应尽快把数据传送给应用层 端口扫描技术(port scanning) 端口扫描就是通过连接到目标系统的TCP或UDP端口,来确定什么服务正在运行一般来说端口扫描有三个用途: * 识别目标系统上正在运行的TCP和UDP服务 * 识别目标系统的操作系统类型(Windows 9x, Windows NT,或UNIX,等) * 识别某个应用程序或某个特定服务的版本号 端口扫描技术: 1. TCP connect scan:这种方法最简单,直接连到目标端口并完成一个完整的三次握手过程(SYN, SYN/ACK, 和ACK)。
缺点是容易被目标系统检测到 2. TCP SYN scan: 这种技术也叫“半开式扫描”(half-open scanning),因为它没有完成一个完整的TCP连接这种方法向目标端口发送一个SYN分组(packet),如果目标端口返回SYN/ACK,那么可以肯定该端口处于检听状态;否则,返回的是RST/ACK这种方法比第一种更具隐蔽性,可能不会在目标系统中留下扫描痕迹 3. TCP FIN scan:这种方法向目标端口发送一个FIN分组按RFC793的规定( /rfc/rfc0793.txt),对于所有关闭的端口,目标系统应该返回RST标志这种方法通常用在基于UNIX的TCP/IP堆栈 4. TCP Xmas Tree scan:这种方法向目标端口发送一个含有FIN, URG,和PUSH标志的分组根据RFC793,对于所有关闭的端口,目标系统应该返回RST标志 5. TCP Null scan:这种方法向目标端口发送一个不包含任何标志的分组根据RFC793,对于所有关闭的端口,目标系统应该返回RST标志 6. UDP scan:这种方法向目标端口发送一个UDP分组如果目标端口以“ICMP port unreachable”消息响应,那么说明该端口是关闭的;反之,如果没有收到“ICMP port unreachable”响应消息,则可以肯定该端口是打开的。
由于UDP协议是面向无连接的协议,这种扫描技术的精确性高度依赖于网络性能和系统资源另外,如果目标系统采用了大量分组过滤技术,那么UDP扫描过程会变得非常慢如果你想对Internet进行UDP扫描,那么你不能指望得到可靠的结果 另外,有某种系统的IP协议是这样实现的,对于所有扫描的端口,不管他们处于关闭或者监听状态,都返回RST标志(我们知道,这不符合RFC793的规定)因此,扫描这种系统时,用不同的扫描技术可能得到不同的扫描结果 */#include "stdio.h" #include "winsock2.h"#include "WS2TCPIP.H"#include "mstcpip.h" #pragma comment(lib,"ws2_32") #define SEQ 0x28376839 //ip数据包的首部数据结构 typedef struct _iphdr { unsigned char h_lenver; //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 _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; struct //定义TCP伪首部{ unsigned long saddr; //源地址 unsigned long daddr; //目的地址 char mbz; char ptcl; //协议类型 unsigned short tcpl; //TCP长度 }psd_header; SOCKET sockRaw = INVALID_SOCKET, sockListen = INVALID_SOCKET; struct sockaddr_in dest; //SOCK错误处理程序 void CheckSockError(int iErrorCode, char *pErrorMsg) { if(iErrorCode==SOCKET_ERROR) {printf("%s Error:%d\n", pErrorMsg, GetLastError()); closesocket(sockRaw); ExitProcess(-1); } } //计算检验和 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解包程序 int DecodeIPHeader(char *recvbuf, int bytes) { IP_HEADER *iphdr; TCP_HEADER *tcphdr;unsigned short iphdrlen; iphdr = (IP_HEADER *)recvbuf; iphdrlen = sizeof(unsigned long) * (iphdr->h_lenver & 0xf); tcphdr = (TCP_HEADER*)(recvbuf + iphdrlen); //是否来自目标IP if(iphdr->sourceIP != dest.sin_addr.s_addr) return 0; //序列号是否正确 if((ntohl(tcphdr->th_ack) != (SEQ+1)) && (ntohl(tcphdr->th_ack) != SEQ)) return 0; //RST/ACK - 无服务 if(tcphdr->th_flag == 20) { printf("RST+ACK 无服务.\n"); return 1; } //SYN/ACK - 扫描到一个端口 if(tcphdr ->th_flag == 18) { printf("%d\n",ntohs(tcphdr->th_sport));return 2; } return true; } //主函数 int main(int argc,char *argv[]) { int iErrorCode; int datasize;struct hostent *hp; IP_HEADER ip_header; TCP_HEADER tcp_header; char SendBuf[128]={0}; char RecvBuf[65535]={0};printf("Useage: SYNPing.exe Target_ip Target_port \n"); //if (argc!=3) { return false; } //初始化SOCKET WSADATA wsaData; iErrorCode = WSAStartup(MAKEWORD(2,2),&wsaData); CheckSockError(iErrorCode, "WSAStartup()"); sockRaw = socket(AF_INET , SOCK_RAW , IPPROTO_IP); CheckSockError(sockRaw, "socket()"); sockListen = socket(AF_INET , SOCK_RAW , IPPROTO_IP); CheckSockError(sockListen, "socket"); //设置IP头操作选项 BOOL bOpt = true; iErrorCode = setsockopt(sockRaw,IPPROTO_IP,IP_HDRINCL,(char *)&bOpt,sizeof(bOpt)); CheckSockError(iErrorCode, "setsockopt()"); //获得本地IP SOCKADDR_IN sa; unsigned char LocalName[256]; iErrorCode = gethostname((char*)LocalName,sizeof(LocalName)-1); CheckSockError(iErrorCode, "gethostname()"); if((hp = gethostbyna。












