Hello,各位小伙伴晚上好~
最后让我们一起来看看如何利用TCP/UDP进行四层主机探测吧~
Part.1
TCP主机探测
TCP探测
利用TCP协议,在未进行TCP三次握手的情况下,直接向目标主机发送ACK报文。
如果对端回复RST重置连接,则认为对端上线。
优点:可以跨网段进行扫描。
缺点:ACK报文可能被防火墙拦截。
TCP协议
在开始之前,我们先来看看什么是TCP协议。
TCP是一种面向连接的、可靠的传输层通信协议。
TCP在通信之前必须先与目标主机指定的服务端口建立连接,进行TCP三层握手,流程如下:
等到连接建立完成之后,再进行数据传输,如下:
以HTTP为例,访问网页61.151.166.139,同时使用wireshark抓包。
可以看到主机先向目标网站80端口(HTTP服务)发起TCP三层握手:
等到连接建立成功后,再发起数据交互:
当收到对端的数据包后,还会通过ACK报文进行确认:
如果发送数据后,一定时间内没有收到对端的确认包,就会进行重传。
这就是TCP的确认、重传机制,可以保证对端一定能收到数据,因此TCP是一种可靠的传输协议。
但也因为发送的每个数据包都要确认,TCP传输的速率低于UDP,但可靠性一定高于UDP。
Part.2
TCP探测脚本
需求说明
通过python编写一个四层主机探测脚本,发送TCP ACK 报文进行探测。
脚本需要从外部传入参数:
今天的脚本依然是使用scapy模块,忘记的小伙伴先去补补课哦:
模块引入
首先引入我们需要的模块,如下:
具体调用模块的什么功能,我们在后面用到的时候说明。
sweep()函数
首先我们来定义一个sweep()函数,来向指定IP地址发送SYN ACK报文。
//接收的参数ip表示我们需要探测的主机地址。
使用scapy定义一个SYN ACK报文:
这里针对flags字段进行说明:
A表示ACK,F表示FIN,S表示SYN,R表示RST, 默认值是SYN。也可以用数值表示:F为1,S为2,R为4,A为16。
使用sr1进行三层发包,仅接收1个应答报文,超时时间为1s,且不显示详细信息。将收包结果赋值给result,通过if判断flags字段是否为4(RST),进而判断目标主机是否存活。
如果响应包flags字段为RST,就判断主机存活,打印“IP online”。
time.sleep(0.2)用于进行短暂停顿,避免多线程导致输出乱序。
最后再添加try/except异常处理功能,说明如下:
主函数main()
接下来我们来定义主函数main(),如下:
(1)首先通过optparse模块,通过选项向脚本传递所需的参数:
相关代码如下:
说明如下:
(2)判断用户是否传参
判断filename和address参数是否同时为空:
如果同时为空则打印报错信息,报错后通过sys.exit()函数直接退出程序。
(3)通过 -f 文件名传参
代码如下:
(4)通过 -i IP地址传参
代码如下:
Part.3
TCP探测脚本测试
脚本测试
接下来我们对脚本进行测试。
(1)查看帮助信息
输入 -h 查看帮助信息:
(2)不传入任何参数
当不传参时,脚本提示报错并退出:
(3)通过 -i 传入IP地址
成功探测到存活主机:
(4)通过 -f 传入文件
创建ip.txt文件如下:
通过 -f 传入ip.txt,成功探测存活主机:
(5)完整代码
Part.4
UDP主机探测
基本原理
除了使用TCP以外,我们还可以通过UDP进行主机探测。
与TCP不同,UDP是向目标主机一个没有开放的端口发送数据,目标主机会返回一个目的端口不可达的ICMP报文,以此来判断主机是否在线。
注意:如果主机不在线,或者目标端口开放,UDP探测是不会收到响应包的。
目标主机响应的ICMP报文如下:
因此,我们通过判断应答报文proto字段是否为1,进而判断主机是否上线。
代码实现
sweep()函数代码修改如下:
监测一个未开放的非知名端口,例如56789。
通过判断应答报文的proto字段是否为1,来确认主机是否上线。
代码其他部分与前面的TCP一致,这里就不再进行赘述。简单测试如下,成功探测上线主机:
Part.5
结语
好啦,截至今日,主机的二层、三层、四层探测就全部讲解完毕了。大家都明白了吗?
Peace!