0x00:端口识别
在检测防火墙是否对一个端口过滤还是关闭,可通过发送两个类型的数据包来判断,第一个是 syn 包,第二个是 ack 包。分别根据这两个包的返回来进行确认。正常的请求过程是发 syn,回 syn/ack,发 ack,回 fin/ack。两个发两个回,所以可以通过两回来确认。这里分为四种情况。
第一种是最简单的,端口是开放状态,走的是正常的流程,所以 syn 应回 syn/ack,ack 应回 rst。因为 ack 是单独发的,所以回 rst。
第二种是关闭状态,syn 没有结果返回,ack 也没有结果返回。都没有结果返回时,则可证明端口是关闭的。
第三种是过滤状态,端口被过滤,有两种情况,第一个是 syn 正常返回,ack 不正常。第二个是 syn 不正常返回,ack 却正常。也就是两个包只有其中一个是正常的,另一个是不正常,则可判定为端口被过滤。先看第一种,syn 返回了 syn/ack,ack 却没有结果返回,则端口被过滤。
第四种是过滤状态,也就是上面说的另外一个,syn 没有返回结果,ack 却返回了 rst,则端口被过滤。
0x01:scapy 探测
了解了以上过程,可以通过 scapy 来分别发送 syn 和 ack,python 脚本如下:
#!/usr/bin/python
import sys
import logging
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
from scapy.all import *
if len(sys.argv) != 3:
print "./firewall.py 1.1.1.1 1"
sys.exit()
ip = sys.argv[1]
port = int(sys.argv[2])
ACK_response = sr1(IP(dst=ip)/TCP(dport=port,flags='A'),timeout=1,verbose=0)
SYN_response = sr1(IP(dst=ip)/TCP(dport=port,flags='S'),timeout=1,verbose=0)
if (SYN_response[TCP].flags == 18) and (ACK_response[TCP].flags == 4):
print "port is open or unfiltered"
elif (SYN_response == None) and (ACK_response == None):
print "port is closed or host down"
elif (SYN_response[TCP].flags == 18) and (ACK_response == None):
print "port is filtered"
elif (SYN_response == None) and (ACK_response[TCP].flags == 4):
print "port is filtered"
else:
print "port is closed or host down"
上面脚本就是通过 scapy 发 syn 包和 ack 包,然后利用返回结果来做出的判断,依据就是之前的那张表。其中 18 则代表 syn/ack,4 则代表 rst,flags 内容从下往上数,是从 1 开始倍数增加的,1,2,4,8,16,32 这种,把为 1 的字段的值相加即可知道 flags 返回的内容。
syn/ack:
ack:
运行结果如下:
0x03:nmap
既然是发 syn 包和 ack 包,则 nmap 必然也可以,nmap 默认识别端口时就是 syn 的方式,如果要发 ack 则可用参数 sA,然后根据两个包返回的结果对比刚开始的表,进行判断即可。
syn 可以使用 sS 参数,ack 可以使用 sA 参数,一般 nmap 的 sS 扫描就会直接出端口的结果,也可以拿 ack 和 syn 的结果和表格做对比。
0x04:总结
防火墙识别其实就是判断目标服务器过滤了哪些端口,可以使用 nmap 直接扫描端口得出结果。但通过 scapy 写脚本实现自己构造数据包发包判断返回信息的过程,更有利于了解其原理和过程。
公众号回复数字“8”领取CIS加固全套手册。
微 信:fageweiketang,朋友圈不定期干货分享,欢迎讨论。
公众号:发哥微课堂,专注于代码审计、WEB渗透、网络安全。