TCP描基本概念
首先介绍第一种扫描技术——TCP全开扫描。这种扫描的思想很简单,如果目标端口是开放的,那么在接到主机端口发出的SYN请求之后,就会返回一个SYN+ACK回应,表示愿意接受这次连接的请求,然后主机端口再回应一个ACK,这样就成功地和目标端口建立了一个TCP连接。 如果目标端口是关闭的,那么在连接到主机端口发出的SYN请求之后,就会返回一个RST回应,表示不接受这次连接的请求,这样就中断了这次TCP连接,这个过程就如下。 但是目标端口不开发还有另外一种情况,就是当主机端口发出SYN请求之后,没有收到任何的回应。多种原因都可能造成这种情况,例如,目标主机处于非活跃状态,这时当然无法进行回应,不过这也可以认为端口是关闭的。另外一些网络安全设备也会屏蔽掉对某些端口的SYN请求,这时也会出现无法进行回应的情况,在此暂时不考虑。
TCP端口扫描工具的编写
在前面已经写过很多关于Scapy中IP数据包和TCP数据包的格式,需要注意的是需要将TCP的flags参数设置为“S”,表明这是一个SYN请求数据包,然我们构造它并将它发送出去,我们可以像下面这样构造。
data = IP(dst="192.168.43.1") / TCP(dport=21, flags="S")
send = sr1(data, timeout=5)
if send:
print(send.summary())
else:
print("目标端口关闭!")
运行结果: 可以发现有回应的,就证明目标端口是开放的。
接下来要根据收到对应的应答包来判断目标端口的状态,这是会有以下三种情况。
- 如果此时send的值为空,就表示没有收到来自目标的回应。在程序中可以使用str(trpe(send))来判断这个是不是为空,当type(send)的值转化为字符串之后为“<class 'NoneType'>”时就表明send是空的,也就是没有收到任何数据包,直接判断该端口为closed。如果不是这个值,则说明send不为空,也就是hi收到了回应的数据包,那么就转到后面的第二种或者第三种。 其实也不用那么麻烦因为sr1只有一个回应,不像sr那样分为收到和没有接收到,所以直接用“if send”即可。
- 当收到了回应的数据包之后,需要判断一下这个数据包是“SYN+ACK”类型还是“RST”类型的。在Scapy中数据包的构造是分层的,可以使用haslayer(TCP)来判断,也可以使用getlayer(TCP)来读取其中某个字段的内容。例如,send.getlayer(TCP).flahs == 0x12 就表示目标端口是开放的。
- 如果send.getlayer(TCP).flags的结果不是0x12,而是0x14(表示RST),表明目标端口是关闭的。
这里大家在测试的时候,建议大家拿虚拟机进行测试,而且关闭防火墙,开始我拿自己的物理机测试的,发现一直都是RST,然后我用命令看了一下端口是开放的,最后我才知道我的杀毒软件给拦下来了。
我们可以通过这个图知道我虚拟机win7的IP:192.168.43.83,在使用命令“netstat -a -n”后看到了一些开发的端口。
接下来我们通过全开TCP连接进行一次端口探测。
from scapy.all import *
data = IP(dst="192.168.43.83") / TCP(dport=80, flags="S")
send = sr1(data, timeout=5)
print(send.summary())
flag = send[TCP].flags
if hex(int(flag)) == "0x12":
print("端口状态:" + hex(int(flag)))
print("[*] 目标端口处于开放状态!")
elif hex(int(flag)) == "0x14":
print("[*] 目标端口处于关闭状态!")
print("端口状态:" + hex(int(flag)))
else:
print("[*] 目标处于非活跃状态")
运行结果: 这里大家可能对SA不太理解,这里的SA表示的就是“SYN+ACK”的连接。但是有一点要注意,我不是像上面提到的使用getlayer()来进行判断它的flags的,我是直接提取TCP里的flags,而后出来的结果就是SA,我们将它转换成int类型,然后在使用hex()转为16进制。而后我们就得到了0x12表示“SYN+ACK”的连接。反之RA表示的就是“RST”,端口是关闭的。 这里我们再次回国头来看,我们需要判断send它是否有回应,如果没有回应我们这个程序必定报错,所以我们可以采用异常处理的方式,或者增加一个判断。
- 采用异常处理(这里我探测一个不存在的IP)
from scapy.all import *
data = IP(dst="192.168.4.83") / TCP(dport=22, flags="S")
send = sr1(data, timeout=5)
try:
print(send.summary())
flag = send[TCP].flags
if hex(int(flag)) == "0x12":
print("端口状态:" + hex(int(flag)))
print("[*] 目标端口处于开放状态!")
elif hex(int(flag)) == "0x14":
print("[*] 目标端口处于关闭状态!")
print("端口状态:" + hex(int(flag)))
except:
print("[!] 目标端口关闭!")
print("[!] 目标也也有可能处于非活跃状态!")
运行结果:
- 判断send为空
from scapy.all import *
data = IP(dst="192.168.4.83") / TCP(dport=21, flags="S")
send = sr1(data, timeout=5)
if str(type(send)) == "<class 'NoneType'>":
print("[!] 目标端口关闭!")
print("[!] 目标也也有可能处于非活跃状态!")
else:
print(send.summary())
flag = send[TCP].flags
if hex(int(flag)) == "0x12":
print("端口状态:" + hex(int(flag)))
print("[*] 目标端口处于开放状态!")
elif hex(int(flag)) == "0x14":
print("[*] 目标端口处于关闭状态!")
print("端口状态:" + hex(int(flag)))
运行结果: