简单实现SYN端口扫描

来源:互联网 发布:北风网 人工智能很贵 编辑:程序博客网 时间:2024/06/05 17:37

0x00

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

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


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


0x01

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

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

#include <stdlib.h>#include <stdio.h>#include <errno.h>#include <string.h>#include <unistd.h>#include <netdb.h>#include <sys/socket.h>#include <sys/types.h>#include <netinet/in.h>#include <netinet/ip.h>#include<errno.h>#include <arpa/inet.h>#include <linux/tcp.h>#include<pthread.h>#include<fcntl.h>/* * 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] ; //目标IPstrcpy(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报文的socketsockfd = 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;i<endPort;i++){TCP_Send(i,2);}pthread_create(&pth,NULL,recvpackage,NULL) ;pthread_join(pth,NULL) ;close(sockfd) ;return 0 ;}void TCP_Send(int port,unsigned char flag){//设置目标端口target.sin_port = htons(port) ;//构造包char buffer[256] ;memset(buffer,0,256) ;struct _tcphdr tcpHeader ;struct psd_hdr psdHeader ;//填充TCP//目的端口tcpHeader.th_dport = htons(port) ;//源端口tcpHeader.th_sport = htons(60000) ;//序列号??tcpHeader.th_seq = htonl(0x1245678);//确认号tcpHeader.th_ack = 0;//(4位首部长度/4位保留字)tcpHeader.th_lenres = (sizeof(tcpHeader) / 4 << 4 | 0);//SYN标志tcpHeader.th_flag = flag ;//SYN//滑动窗口tcpHeader.th_win = htons(16384) ;//16位紧急数据偏移量tcpHeader.th_urp = 0;//16位校验和tcpHeader.th_sum = 0;//psdheaderpsdHeader.saddr = myaddr.sin_addr.s_addr;psdHeader.daddr = target.sin_addr.s_addr;psdHeader.mbz = 0;  // mbz = must be zero, 用于填充对齐psdHeader.ptcl = IPPROTO_TCP ;  //8位协议号psdHeader.tcpl = htons(sizeof(tcpHeader)) ;//set checksum 使用伪头计算TCP校验和memcpy(buffer,&psdHeader,sizeof(psdHeader)) ;memcpy(buffer+sizeof(psdHeader),&tcpHeader,sizeof(tcpHeader)) ;tcpHeader.th_sum = checksum((unsigned short*)buffer,sizeof(psdHeader)+sizeof(tcpHeader)) ;//最终的组包(TCP+IP)memcpy(buffer,&tcpHeader,sizeof(tcpHeader)) ;//发送的过程   由于IP协议是无连接的协议   所以可以使用sendtoint ret = sendto(sockfd,buffer,sizeof(tcpHeader),0,(struct sockaddr*)&target,sizeof(target)) ;if(ret == -1){printf("send error!:%s\n",strerror(errno)) ;exit(-1);}else{//printf("send OK\n") ;}}/* * 线程的回调函数 * */void* recvpackage(void*arg){//接收的过程recvfromprintf("Thread starting...\n") ;struct _tcphdr* testtcp ;char msg[1024] ;int len = sizeof(myaddr);int count ,size;while(1){memset(msg,0,1024) ;size = recvfrom(sockfd,msg,sizeof(msg),0,(struct sockaddr*)&myaddr,&len) ;if (size == -1) break ;//这里的指针是指向IP头部第一个字段的   所以得到TCP头部时要加上相应的偏移量20bytetesttcp = (struct _tcphdr*)(msg + sizeof(struct _iphdr)) ;if (size < (20 + 20)){/*读出的数据小于两个头的最小长度的话continue*/continue;}if(ntohs(testtcp->th_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

测试下效果:



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

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


0 1
原创粉丝点击