Nmap具有强大的脚本引擎NSE(Nmap Scripting Engine),它允许用户编写(和共享)简单的脚本(使用lua编程语言)自动化各种网络任务。
本次实验目的在于掌握Nmap脚本的基本使用方法。
kali,IP地址:192.168.11.11
Linux,IP地址:192.168.11.21
Nmap提供的脚本相关命令行参数如下:
该步骤简单介绍脚本的相关使用。
在使用Nmap时,通过--script=脚本名
语句来调用脚本,而且Nmap自带众多脚本,路径如下:
这些脚本大致分为以下几种:
在调用脚本时,可以使用种类名来调用该分类下的全部脚本,如--scritp vuln
,但是比较费时间,在此就不演示,本次以 http-methods 脚本为例,來演示脚本的大致使用。
使用--script-help
脚本名来查看脚本的说明和用法,比如查看 http-methods.nse 脚本信息:
使用http-methods.nse脚本来对目标主机进行探测,用于得到目标支持的http请求方式
nmap --script-help=http-methods 192.168.11.21
可以看到探测出来目标主机支持的http请求有 GET、POST、HEAD、OPTIONS 四种。
因为所有的脚本都是以服务名来命名,比如 http 相关的脚本就是 http 开头,ssl 相关脚本是以 ssl开头:
因此在调用脚本时,可以使用通配符 *
来调用相关服务下的所有脚本,以mysql服务为例,所有mysql脚本如下:
使用语句 --script "mysql*"
来选择mysql相关的所有脚本,探测结果如下:
nmap --script "mysql*" 192.168.11.21
Nmap在使用脚本时,如果脚本支持,我们还可以通过 --script-args
传入参数。
已知一些网站会通过判断 user-agent
来判断请求是否合法,那Nmap在请求时有没有带上自己的特征呢?同样使用刚才的 http-methos.nse 脚本,打开wireshark抓包,启动以下命令:
nmap --script=http-methods.nse 192.168.11.21
可以看到在请求包的 User-Agent
字段信息包含 Nmap Scripting Engine
,也就是代表该请求来自 Nmap的脚本,如果目标主机对该请求进行了过滤,那么就无法成功探测。
因此需要加入一定的参数,来改变 User-Agent
字段信息,绕过过滤,使用 --script-args
修改 User-Agent 的值
命令如下:
nmap --script=http-methods --script-args http.useragent="Mozilla 42" 192.168.11.21
重新抓包,发现 User-Agent 字段内容已经更改
还有其他脚本参数,后续继续学习。
在使用脚本时,可以添加 --script-trace
参数来打印出所有交互数据包的细节
nmap --script=http-methods --script-trace 192.168.11.21
使用 -d1-9
来进入调试模式,查看扫描信息,数字越大,输出越详细,以 d2 为例:
nmap --script=http-methods -d2 192.168.11.21
Nmap脚本使用 lua 语言编写,采用严格的格式规范,一个完整的NSE包括以下几个部分:
依然以 http-methods.nse 脚本为例,来展示nse的组成:
1.引用API部分:使用 require 函数调用模块
2.description字段:脚本的介绍及描述
3.author字段:作者信息
4.categories字段:脚本分类信息
5.rule字段:描述脚本执行的规则,也就是确定脚本触发执行的条件,这个规则是一个lua函数,返回值只有true和false两种,只有返回true时,action中的函数才会执行
6.action字段:脚本具体的执行内容,当脚本通过rule字段的检查被触发执行时,就会调用action字段定义的函数
Nmap的扩展脚本语言都基于lua来开发的,执行也是调用了内部封装的lua解释器。正常情况下,调用任何一个扩展脚本会首先执行nse_main.lua,该脚本主要做了以下几件事:
加载一些Nmap的核心库(nselib文件夹中)
定义多线程函数
定义输出结果处理函数
读取、加载扩展脚本
定义扩展脚本函数接口
执行扩展脚本
扩展脚本执行的规则在nse_main.lua中有定义:
具体的执行规则如下:
可以编写一个nse文件进行简单的验证:
其中action函数是在 hostrule 或 portsule 返回 true 时,才会,因为 prerule 和 postrule 没有判断条件。
了解了这些后,我们试着编写一个简单的脚本,来体验一下NSE的功能。
在开始编写脚本之前,还应该对NSE中数据的传递做简单了解
在脚本引擎中,用户可以轻松访问Nmap已经了解的有关目标主机的信息。该数据作为参数传递给NSE脚本的 action 方法,参数 host 和 port 是 lua 表,其中包含脚本执行的目标的信息。
每个表里面所含有的变量:
host 表:
host:
该表作为参数传递给规则和操作功能。
host.os:
操作系统匹配表数组。
host.ip:
包含目标主机IP地址的字符串表示形式。
host.nam:
包含表示为字符串的扫描目标主机的反向DNS条目。
host.targetname:
包含在命令行上指定的主机名。
host.reason:
包含目标主机为何处于其当前状态的原因的字符串表示形式。
host.reason_ttl:
包含响应数据包的TTL值,用于确定目标主机到达时的状态。
host.directly_connected:
一个布尔值,指示目标主机是否直接连接到运行Nmap的主机(即与该主机处于同一网段)。
host.mac_addr:
MAC地址 目标主机的名称(六字节长的二进制字符串)(如果有),否则nil。
host.mac_addr_next_hop:
到主机的路由中第一跳的MAC地址,或者 nil如果不可用。
host.mac_addr_src:
我们自己的MAC地址,用于连接到主机(我们的网卡或(带有 --spoof-mac) 欺骗性地址)。
host.interface:
包含接口名称的字符串(dnet样式) 通过它向主机发送数据包。
host.interface_mtu:
MTU(最大传输单位)host.interface,如果未知,则为0。
host.bin_ip:
目标主机的IP地址为4字节(IPv4)或16字节(IPv6)字符串。
host.bin_ip_src:
我们主机的(正在运行的Nmap)源IP地址为4字节(IPv4)或16字节(IPv6)字符串。
host.times:
该表包含主机的Nmap时序数据。
host.traceroute:
这是使用该–traceroute选项时出现的traceroute跃点数组。
host.os_fp:
如果执行了OS检测,则这是一个字符串,其中包含主机的OS指纹。
port 表:
port.number:
目标端口的端口号。
port.protocol:
目标端口的协议,有效值为 “tcp"和"udp”。
port.service:
包含 port.numberNmap 服务检测所检测到的正在运行的服务的字符串表示形式 。
port.reason:
包含目标端口为何处于其当前状态的原因的字符串表示形式(由提供port.state)。
port.reason_ttl:
包含响应数据包的TTL值,用于确定目标端口到达时的状态。此响应数据包是也用于设置的数据包port.reason。
port.state:
包含有关端口状态的信息。服务脚本只能再次运行。
port.version相关:
此项是一个表,其中包含Nmap版本扫描引擎检索到的信息。
参考 Nmap官方文档:https://nmap.org/book/nse-api.html
了解了NSE中数据的传递,尝试写一个简单的脚本。
实现的功能是当发现目标开放端口后,便输出"IP *** open *** port"
的语句,严格按照格式来编写一个完整的脚本:
description = [[
this is my fisrt nmap script.
]]
author = {"wx"}
categories = {"default"}
portrule = function(host, port)
return true
end
action = function(host, port)
return string.format("IP <%s> open <%d> port", host.ip, port.number)
-- "IP".. host .."open".. port.number .."port"
end
运行结果:
那如果想在指定端口下输出结果呢?以 80 端口为例,此时代码如下:
只需要返回指定的端口,即当判断是 80 端口时,就会返回True,然后执行 action 函数。
本次实验了解了Nmap的脚本引擎NSE,学习了在Nmap中如何使用脚本以及脚本的编写,通过学习编写了简单的测试脚本。