SYN端口扫描

/*
经典描器(全TCP连接)和SYN(半连接)扫描器

全TCP连接

全TCP连接是长期以来TCP端口扫描的基础。
扫描主机尝试(使用三次握手)与目的机指定端口建立建立正规的连接。
连接由系统调用connect()开始。对于每一个监听端口,connect()会获得成功,
否则返回-1,表示端口不可访问。
 这种扫描方法很容易检测出来,在日志文件中会有大量密集的连接和错误记录)。

TCP SYN扫描

在这种技术中,扫描主机向目标主机的选择端口发送SYN数据段。
如果应答是RST,那么说明端口是关闭的,按照设定就探听其它端口;
如果应答中包含SYN和ACK,说明目标端口处于监听状态。
由于所有的扫描主机都需要知道这个信息,传送一个RST给目标机从而停止建立连接。
由于在SYN扫描时,全连接尚未建立,所以这种技术通常被称为<半打开扫描>。
SYN扫描的优点在于即使日志中对扫描有所记录,但是尝试进行连接的记录也要比全扫描少得多。
缺点是在大部分操作系统下,发送主机需要<构造适用于这种扫描的IP包>,
通常情况下,构造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的规定(https://www.360docs.net/doc/052283493.html,/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 = gethostbyname((char*)LocalName)) == NULL) {
CheckSockError(SOCKET_ERROR, "gethostbyname()");
}



memcpy(&sa.sin_addr.S_un.S_addr,hp->

h_addr_list[0],hp->h_length);
sa.sin_family = AF_INET;
sa.sin_port = htons(7000);
iErrorCode = bind(sockListen, (PSOCKADDR)&sa, sizeof(sa));
CheckSockError(iErrorCode, "bind"); //设置SOCK_RAW为SIO_RCVALL,以便接收所有的IP包
DWORD dwBufferLen[10] ;
DWORD dwBufferInLen = 1 ;
DWORD dwBytesReturned = 0 ;
iErrorCode=WSAIoctl(sockListen, SIO_RCVALL,&dwBufferInLen, sizeof(dwBufferInLen), &dwBufferLen, sizeof(dwBufferLen),&dwBytesReturned , NULL , NULL );
CheckSockError(iErrorCode, "Ioctl"); //获得目标主机IP
memset(&dest,0,sizeof(dest));
dest.sin_family = AF_INET;
dest.sin_port = htons(atoi(argv[2]));
if((dest.sin_addr.s_addr = inet_addr(argv[1])) == INADDR_NONE) {
if((hp = gethostbyname(argv[1])) != NULL) {
memcpy(&(dest.sin_addr),hp->h_addr_list[0],hp->h_length);
dest.sin_family = hp->h_addrtype;
printf("dest.sin_addr = %s\n",inet_ntoa(dest.sin_addr));
} else {
CheckSockError(SOCKET_ERROR, "gethostbyname()");
}
} //填充IP首部
ip_header.h_lenver=(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=sa.sin_addr.s_addr; //32位源IP地址
ip_header.destIP=dest.sin_addr.s_addr; //32位目的IP地址 //填充TCP首部
tcp_header.th_sport=htons(7000); //源端口号
tcp_header.th_dport=htons(atoi(argv[2])); //目的端口号
tcp_header.th_seq=htonl(SEQ); //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校验和,计算校验和时需要包括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报文
iErro

rCode=sendto(sockRaw,SendBuf,datasize,0,(struct sockaddr*) &dest,sizeof(dest));
CheckSockError(iErrorCode, "sendto()"); //接收数据
DWORD timeout = 200000;//2000
DWORD start = GetTickCount();
while(true) { //计时,2s超时
if((GetTickCount() - start) >= timeout) break;
memset(RecvBuf, 0, sizeof(RecvBuf));
iErrorCode = recv(sockListen, RecvBuf, sizeof(RecvBuf), 0);
CheckSockError(iErrorCode, "recv");
if(int i = DecodeIPHeader(RecvBuf,iErrorCode)) {
if(i == 1) break;
tcp_header.th_flag=4; //RST 标志
//计算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报文
iErrorCode=sendto(sockRaw,SendBuf,datasize,0,(struct sockaddr*) &dest, sizeof(dest));
CheckSockError(iErrorCode, "sendto()");
break;
}
} //退出前清理
if(sockRaw != INVALID_SOCKET) closesocket(sockRaw);
WSACleanup();
getchar();
return 0;
}












相关文档
最新文档