简单实现SYN端口扫描

0x00

最近也在学习Linux开发,尤其是网络编程这块。今天就share下前几天写的简易SYN端口扫描的代码,与其说简易,不如说是简陋,不过确实收获不少。

我这里就不介绍全面端口扫描,SYN扫描不同于全连接的扫描,由于这种扫描不需要建立连接,所以扫描的速度会比全连接的扫描速度快很多,附一张图说明:

简单实现SYN端口扫描_第1张图片

TCP建立连接的时候需要进行三次握手,总的来说就是SYN--------->SYN+ACK------------>ACK,只要进行了三次握手,那么连接双方就会为这次连接分配相应的资源,如缓冲区等。而SYN扫描明显不是建立全连接,当第二次消息为SYN+ACK,就代表服务端可以进行连接,或者说端口开放着,这次发送一个RST将连接断开即可,因为我们已经获知端口开放的情况。这样进行扫描,速度快是自然的。


0x01

实现的思路就是自己构造相应flag的TCP报文进行发送,如果收到SYN+ACK说明这个端口开放,这时候要再发送一个RST断开连接来避免消耗被扫主机的资源。如果是RST+ACK,说明端口没有开发,继续扫描其它端口。

实现中我也查阅了不少的资料,其中实现的最重要的基础就是基于原始套接字进行发包,就是要自己构造相应的IP或者TCP报文,然后发送,因为使用系统的bind connect 那一套是不能操作TCP首部字段的。关于原始套接字的编程基础我也不打算介绍了,因为网上实在很多优秀的博客。这里就直接分享代码了。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include
#include 
#include 
#include
#include
/*
 * Author:Exploit
 * 这是一个SYN极速扫描的demo
 * 存在的问题:发包的速度要控制    不然丢包很严重
 * 但是在60个端口的范围内有效
 *
 * */


//定义TCP伪报头
typedef struct psd_hdr
{
	unsigned long saddr; //源地址
	unsigned long daddr; //目的地址
	char mbz; char ptcl; //协议类型
	unsigned short tcpl; //TCP长度

}PSD_HEADER;

//定义TCP报头
typedef struct _tcphdr
{
	unsigned short th_sport; //16位源端口
	unsigned short th_dport; //16位目的端口
	unsigned int th_seq; //32位序列号
	unsigned int th_ack; //32位确认号
	unsigned char th_lenres; //4位首部长度/4位保留字
	unsigned char th_flag; //6位标志位
	unsigned short th_win; //16位窗口大小
	unsigned short th_sum; //16位校验和
	unsigned short th_urp; //16位紧急数据偏移量

} TCP_HEADER;


//定义IP报头
typedef struct _iphdr
{
	unsigned char h_lenver ; //长度加版本号
	unsigned char tos;
	unsigned short total_len;
	unsigned short ident;
	unsigned short frag_and_flags;
	unsigned char ttl;
	unsigned char proto;
	unsigned short checksum;
	unsigned int sourceIP;
	unsigned int destIP;

} IP_HEADER;

/**
 * 计算校验和
 */
unsigned short checksum(unsigned short *addr,int len){
		int nleft=len;
	   int sum=0;
	   unsigned short * w=addr;
	   unsigned short answer=0;

	   while (nleft>1)
	   {
	     sum+=*w++;
	     nleft-=2;
	   }

	   if (nleft==1)
	   {
	     *(unsigned char *)(&answer)=*(unsigned char *)w;
	     sum+=answer;
	   }

	   sum=(sum>>16)+(sum & 0xffff);
	   sum+=(sum>>16);
	   answer=~sum;
	   return(answer);
}

/* 攻击目标*/
struct sockaddr_in target;
struct sockaddr_in myaddr;
int sockfd ;
pthread_t pth ;

void TCP_Send(int port,unsigned char flag);
void* recvpackage(void*arg) ;

int main(int args,char* argv[]){

	//参数检查
	if(args < 4){
		printf("Usage:shit targetIP startPort endPort\n") ;
		exit(-1) ;
	}

	char IP[32] ; //目标IP
	strcpy(IP,argv[1]) ;
    int startPort = atoi(argv[2]) ;
	int endPort = atoi(argv[3]) ;

	if((endPort - startPort) > 60){
		printf("The port range must be within 60 considering your bandwith....\n") ;
		exit(-1) ;
	}

	target.sin_family = AF_INET ;
	target.sin_addr.s_addr = inet_addr(IP) ;

	myaddr.sin_family = AF_INET ;
	myaddr.sin_port = htons(60000) ;
	myaddr.sin_addr.s_addr = inet_addr("10.10.10.132") ;

	//TCP报文的socket
	sockfd = socket(AF_INET,SOCK_RAW,IPPROTO_TCP) ;

	if(sockfd == -1){
		printf("socket error:%s\n",strerror(errno)) ;
		exit(-1) ;
	}

	int i ,count=1;
	for(i=startPort;ith_dport) != 60000){
			continue ;
		}

		if(testtcp->th_flag == 20){
			printf("%d 端口未开放\n",ntohs(testtcp->th_sport)) ;
			continue ;
		}
		if(testtcp->th_flag == 18){
			TCP_Send(ntohs(testtcp->th_sport),4) ;
			printf("%d 端口开放!ACK + SYN....\n",ntohs(testtcp->th_sport)) ;
			continue ;
		}
	}

}

这里有个很大的缺陷就是会产生很多丢包现象(1M网络,使用wireshark实验)。按说TCP应该会自动控制发包的速度???如果你知道如何更好的控制并能达到最好的效果,请留言。


0x02

测试下效果:

简单实现SYN端口扫描_第2张图片

利用原始套接字可以做很多事情,比如实现ping隧道窃取信息,再比如实现大规模的漏扫,确实应该好好深究下~

如果有不对的地方,还望留言指正。


你可能感兴趣的:(安全编程)