1,使用scapy实现TCP端口扫描原理:实现TCP连接最重要的就是三次握手的建立,所以通过scapy构造一个
SYN数据包,发送之后如果收到目的主机的SYN+ACK数据包,就说明目的主机的端口是开放的。
2,TCP三次握手过程分析
第一个数据包,客户端向服务端发送一个SYN数据包,其数据包有一个Sequence(包序列)数值,TCP协议
头部信息中flags的SYN位置为1(代表发送一个SYN请求)。
可以看到,这里的Seq为0,TCP头部的flags中SYN的标志位为1,flags共8位,所以这里的SYN数值就是2。
第二个数据包,服务器向客户端回复的数据包,是一个SYN+ACK的数据包,这个包也有一个Sequence
数值,这里的ACK的数值就为第一个SYN包的Seq数值+1,所以这里ACK的数值是1,而且TCP头部中的
SYN和ACK位都置为了1,flags的数值就为18。
可以看到,这里的syn和ack位都为1,且ack的数值为1,即为第一个包的seq+1。
第三个数据包,客户端向服务器回复的ack确认包,当这个包发送之后,双方之间就可以互相传送
数据了。
这里的ack数值就是第二个包的seq+1。它自己的seq序号应该为客户端序号的增序,
因为客户端第一次发送
的时候,seq为0,所以这里就是1。
3,使用scapy构造syn数据包
这里构造syn数据包的时候,只需要将tcp头部中的flags标志的值填成2,就代表将syn位
置为1,而且这里
使用scapy构造数据包的填写dport(目的端口)时候,可以直接写一个
范围。
syn=IP(dst='192.168.219.1')/TCP(dport(int(1),int(1024)),flags=2,timeout=1)
这就构造了一个syn数据包,因为这里传入的是一个端口范围,所以要接收多个回复,所以应该使用sr发送
数据包。
result_raw=sr(syn)
因为result_raw是一个元组,第一部分为收到结果的包,第二部分为未收到结果的包,所以提取result_raw
的第一部
分,且将其做成一个清单。
result_list=result_raw[0].res
然后依次分析清单中的数据包就可以得到目的端口是否开放,result_list中的数据包分为发送的和回复的,
result_list[i][1]就表示第i个数据包的回复部分,使用haslayer(TCP)就可以判断是否有TCP头部信息,
如果有,就提取TCP头部信息。
TCP_Fields=result_list[i][1].getlayer(TCP).fields
然后判断TCP_Fields中的flags字段的值是否为18就可以判断端口的开放情况。
if TCP_Fields['flags']==18:
端口开放的
4,TCP端口扫描
#!/usr/bin/python3.4
# _*_ coding=utf-8 _*_
import logging
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
from scapy.all import *
def ping_one(host):
ip_id=randint(1,65535)
icmp_id=randint(1,65535)
icmp_seq=randint(1,65535)
packet=IP(dst=host,ttl=64,id=ip_id)/ICMP(id=icmp_id,seq=icmp_seq)/b'ylp'
ping=sr1(packet,timeout=2,verbose=False)
if ping:
return 0
else:
return -1
def syn_scan(hostname,lport,hport):
ping_res=ping_one(hostname)
if ping_res==-1:
print('设备'+hostname+'不可达')
else:
syn=IP(dst=hostname)/TCP(dport=(int(lport),int(hport)),flags=2)
result_raw=sr(syn,timeout=1,verbose=False)
#取出收到结果的数据包,做成一个清单
result_list=result_raw[0].res
for i in range(len(result_list)):
#判断清单的第i个回复的接受到的数据包,并判断是否有TCP字段
if(result_list[i][1].haslayer(TCP):
#得到TCP字段的头部信息
TCP_Fields=result_list[i][1].getlayer(TCP).fields
#判断头部信息中的flags标志是否为18(syn+ack)
if TCP_Fields['flags']==18:
print('端口号: '+str(TCP_Fields['sport'])+' is Open!!!'
if __name__=='__main__':
host=input('请输入扫描主机的IP地址:')
port_low=input('请输入扫描端口的最低端口号')
port_high-input('请输入扫描端口的最高端口号')
syn_scan(host,port_low,port_high)