SYN(半连接)扫描

TCP SYN 扫描是使用最为广泛的扫描方式,其原理就是像带扫描端口发送SYN 数据包。

如果能够收到SYN+ACK 数据包,则代表此端口开放,

如收到RST 数据包,则证明此端口关闭,

如未收到任何数据包,且确定该主机存在,则证明该端口被防火墙等安全设备过滤。

由于SYN 扫描并不会完成TCP 连接的三次握手过程,所以SYN 扫描又叫做半开放扫描。
SYN 扫描的最大优点就是速度,

在Internet 上,如果不存在防火墙,SYN 扫描每秒钟可以扫描数千个端口,

但是SYN 扫描由于其扫描行为较为明显,容易被入侵检测系统发现,

也容易被防火墙屏蔽,且构造原始数据包需要较高系统权限。

VC++实现

#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <time.h>
#include "mstcpip.h"
#pragma comment(lib,"ws2_32.lib")
#define SEQ 0x28376839
SOCKET sockRaw = INVALID_SOCKET,
sockListen = INVALID_SOCKET;
struct sockaddr_in dest;

BOOL ScanOK=FALSE;
char *DEST_HOST;
int DEST_PORT;
int DEST_PORTEND;
int play=0;
clock_t start,end;//程序运行的起始和结束时间
float costtime;//程序耗时
 
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;

//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解包程序
bool DecodeIPHeader(char *buf, int bytes)
{
IP_HEADER *iphdr;
TCP_HEADER *tcphdr;
unsigned short iphdrlen;
iphdr = (IP_HEADER *)buf;
iphdrlen = sizeof(unsigned long) * (iphdr->h_lenver & 0xf);
tcphdr = (TCP_HEADER*)(buf + iphdrlen);
//是否来自目标IP
if(iphdr->sourceIP != dest.sin_addr.s_addr) return false;
//序列号是否正确
if((ntohl(tcphdr->th_ack) != (SEQ+1)) && (ntohl(tcphdr->th_ack) != SEQ)) return false;
//if(tcphdr->th_flag == 20)return true;
//SYN/ACK - 扫描到一个端口
if(tcphdr ->th_flag == 18)
{
printf("/t%d/t open /n",ntohs(tcphdr->th_sport));
return true;
}
return true;
}
void usage(void)
{
printf("/t===================SYN portscaner======================/n");
printf("/t============gxisone@hotmail.com     2004/7/6===========/n");
printf("/tusage: synscan DomainName[IP] StartPort-EndPort/n");
printf("/tExample: synscan www.163.com 1-139/n");
printf("/tExample: synscan 192.168.1.1 8000-9000/n");
}
 
DWORD WINAPI RecvThread(LPVOID para)//接收数据线程函数
{
int iErrorCode;
struct hostent *hp;
char RecvBuf[65535]={0};
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[1],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");
memset(RecvBuf, 0, sizeof(RecvBuf));
//接收数据
for(;;)
{
iErrorCode = recv(sockListen, RecvBuf, sizeof(RecvBuf), 0);
//CheckSockError(iErrorCode, "recv");
DecodeIPHeader(RecvBuf,iErrorCode) ;
}
if(ScanOK)
{
 closesocket(sockListen);
 return 0;
}
}
void playx(void)  // 定义状态提示函数 
{ 
// 进度条 
char *plays[12]= 
{ 
 " | ", 
 " / ", 
 " - ", 
 " // ", 
 " | ", 
 " / ", 
 " - ", 
 " // ", 
 " | ", 
 " / ", 
 " - ", 
 " // ", 
}; 
printf(" =%s=/r", plays[play]);
play=(play==11)?0:play+1;
Sleep(2);
}
//主函数
int main(int argc,char **argv)
{
char *p;
if(argc!=3)
{
usage();
return 0;
}
p=argv[2];//处理端口参数
    if(strstr(argv[2],"-"))
    {    DEST_PORT=atoi(argv[2]);
        for(;*p;)
            if(*(p++)=='-')break;
        DEST_PORTEND=atoi(p);
        
        if(DEST_PORT<1 || DEST_PORTEND>65535)
        {    printf("Port Error!/n");
            return 0;
        }
    }

DEST_HOST=argv[1];
usage();
int iErrorCode;
int datasize;
struct hostent *hp;
IP_HEADER ip_header;
TCP_HEADER tcp_header;
char SendBuf[128]={0};
//初始化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[1],hp->h_length);
sa.sin_family = AF_INET;
sa.sin_port = htons(7000);
iErrorCode = bind(sockListen, (PSOCKADDR)&sa, sizeof(sa));
CheckSockError(iErrorCode, "bind");
 
//获得目标主机IP
memset(&dest,0,sizeof(dest));
dest.sin_family = AF_INET;
dest.sin_port = htons(DEST_PORT);
if((dest.sin_addr.s_addr = inet_addr(DEST_HOST)) == INADDR_NONE)
{
if((hp = gethostbyname(DEST_HOST)) != NULL)
{
memcpy(&(dest.sin_addr),hp->h_addr_list[1],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()");
}
}
//开启监听线程
HANDLE Thread=CreateThread(NULL,0,RecvThread,0,0,0);

//填充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_lenres=(sizeof(TCP_HEADER)/4<<4|0); //TCP长度和保留位
tcp_header.th_win=htons(16384);
 
 
//填充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));

Sleep(500);
printf("/n");
printf("Scaning %s/n",DEST_HOST);
start=clock();//开始计时
for(;DEST_PORT<DEST_PORTEND;DEST_PORT++)
{
playx();
tcp_header.th_dport=htons(DEST_PORT); //目的端口号
tcp_header.th_ack=0; //ACK序列号置为0
tcp_header.th_flag=2; //SYN 标志
tcp_header.th_seq=htonl(SEQ); //SYN序列号
tcp_header.th_urp=0; //偏移
tcp_header.th_sum=0; //校验和
//计算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()");
}
end=clock();//计时结束
ScanOK=TRUE;
printf("Closeing Thread...../n");
WaitForSingleObject(Thread,5000);
CloseHandle(Thread);
costtime= (float)(end - start) / CLOCKS_PER_SEC;  //转换时间格式
printf("Cost time:%f Sec",costtime);//显示耗时
//退出前清理
if(sockRaw != INVALID_SOCKET) closesocket(sockRaw);
WSACleanup();
return 0;
}

转载于:https://my.oschina.net/u/2317401/blog/382913

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SYN连接扫描是一种常见的端口扫描方法,攻击者可以利用它来探测目标主机上开放的端口和服务,从而进行后续的攻击。SYN连接扫描的过程如下: 1. 攻击者向目标主机发送SYN包,但是不完整地建立TCP连接,而是发送一个SYN标志位,并等待目标主机的响应。 2. 如果目标主机的端口是关闭的,那么它会发送一个RST包作为响应,攻击者可以根据这个响应判断目标主机上的端口是关闭的。 3. 如果目标主机的端口是开放的,那么它会发送一个SYN/ACK包作为响应,攻击者可以根据这个响应判断目标主机上的端口是开放的。 4. 攻击者在接收到目标主机的响应后,会将连接关闭,以避免留下不必要的痕迹。 SYN连接扫描是一种隐蔽性较强的端口扫描方法,因为它不会完整地建立TCP连接,而只是发送一个SYN包,从而减少了被检测到的风险。为了防范SYN连接扫描,可以采取以下措施: 1. 配置防火墙:配置防火墙可以限制非法流量的访问,减少服务器受到攻击的风险。 2. 使用入侵检测系统:使用入侵检测系统可以监控网络流量,及时发现和防御SYN连接扫描等攻击。 3. 限制TCP连接:限制TCP连接可以减少攻击者使用SYN连接扫描的风险,例如可以限制单个IP地址的TCP连接数。 4. 更新操作系统和应用程序:更新操作系统和应用程序可以修补安全漏洞,增强系统的安全性和可用性,减少受到攻击的风险。 综上所述,SYN连接扫描是一种常见的端口扫描方法,我们应该采取相应的防范措施,增强系统的抗攻击能力,保护系统的安全和稳定性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值