识别出目标主机操作系统的类型和版本,可以大量减少不必要的测试版本,缩小测试范围,更精确地针对目标进行渗透测试
但是判断目标地操作系统并非一件简单的事情。因为现在的操作系统类型繁多,仅 Windows 和 Linux 就包含了许多衍生系统,同时,现今的防火墙、路由器、智能设备等都有其自带的操作系统,所以需要精确判断目标操作系统的类型并非易事。目前主要通过 "指纹识别" 的方式来对目标的操作系统来进行猜测。检测方法一般分为两种:主动式探测和被动式探测。
主动式探测:向目标主机发送一段特定的数据包,根据目标主机对数据包做出的回应进行分析,判断目标主机中可能的操作系统类型。和被动探测比起来,主动的方式肯定更为准确,但也同时因为是直接对目标主机进行发送而更容易触发目标安全系统的警报

被动式探测:通过工具嗅探、记录、分析数据包流。根据数据包信息来分析目标主机的操作系统。与主动探测相比,被动探测的结果虽然可能没有那么精确,但是不容易被目标主机的安全系统察觉

主机识别的原理:Windows 操作系统与 Linux 的操作系统的 TCP/IP 实现方式并不一样,导致对特定格式数据包的回应也不相同,包括响应数据中的内容、响应时间等,就形成了操作系统的指纹。通常的情况下,可以对主机进行 ping 之后根据返回的 TTL 值来判断系统类型

Windows TTL 起始值:128

Linux TTL 起始值:64

每经过一条路由,TTL 值 - 1

这里就不做界面演示了,可以直接去找 Windows 和 Linux 的机子去 ping 一下看看 TTL 值

接下来就使用返回 TTL 值的原理来用 python 程序实现自动化探测主机系统类型

导入程序代码所应用的模块:optparse、os 和 re。optparse 用于生成命令行参数;os 用于执行系统命令;re 为正则表达式模块,用于匹配返回的 TTL 值

1
2
3
from optparse import OptionParser
import os
import re

利用 optparse 模块生成命令行参数化形式,对用户输入的参数进行接收和批量处理,最后将处理后的 IP 地址传入 ttl_scan () 函数

1
2
3
4
5
6
7
8
9
10
def main():
parser = OptionParser("Usage:%prog -i <target host>") #输出帮助信息
parser.add_option('-i',type='string',dest='IP',help='specify target host')
#获取IP地址参数
options,args = parser.parse_args()
ip = options.IP
ttl_scan(ip)

if __name__ == "__main__":
main()

调用 os.popen () 函数执行 ping 命令,并将返回的结果通过正则表达式识别,提取出 TTL 值。当 TTL 值小于等于 64 时,操作系统为 Linux 类型,输出 "xx.xx.xx.xx
is Linux/UNIX",否则输出"xx.xx.xx.xx is Windows"。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def ttl_scan(ip):
ttlstrmatch = re.compile(r'ttl=\d+')
ttlnummatch = re.compile(r'\d+')
result = os.popen("ping -c 1 " + ip)
res = result.read()
for line in res.splitlines():
result = ttlstrmatch.findall(line)
if result:
ttl = ttlnummatch.findall(line)
if int(ttl[0]) <= 64: # 判断目标主机响应包中TTL值是否小于等于64
print("%s is Linux/UNIX" % ip) # TTL<=64时为Linux/UNIX系统
else:
print("%s is Windows" % ip) # 反之则为Windows系统
else:
pass

一个简易的检测脚本就完成了,使用方法:

1
python3 ./host.py -i IP

一般来说,主动的主机系统类型探测就是向目标主机发送特定数据包,然后用目标主机的回应包中的数据与指纹库来进行对比,从而得出主机系统类型,这里的脚本化简了这一流程。直接通过 ping 和返回的 TTL 值来对主机系统类型进行一个判断