Nmap脚本引擎原理
Nmap脚本引擎原理
一、NSE介绍
虽然Nmap内嵌的服务于版本探测已足够强大,但是在某些情况下我们需要多伦次的交互才能够探测到服务器的信息,这时候就需要自己编写NSE插件实现这个功能。NSE插件能够完成网络发现、复杂版本探测、脆弱性探测、简单漏洞利用等功能。
转载请注明出处:http://www.cnblogs.com/liun1994/
在文章 "Nmap脚本文件分析(AMQP协议为例)" 中会将版本探测,NSE脚本原理联系起来,具体分析Nmap探测的执行过程。
在文章 " 编写自己的NSE脚本" 中将以一个简单的例子说明NSE的编写。
脚本扫描通过选项被激活
-sC: 使通用scripts生效
--script: 指定自己的脚本文件
--script-trace: 查看脚本执行过程
-A: 同时进行版本探测和脚本扫描 为了不进行主机发现也不进行端口扫描,直接使用自定义的脚本探测。可以使用下面的选项:
-Pn -sn --script --script-args和--script-args-file,指定脚本要读入的参数
nmap --script snmp-sysdescr --script-args snmpcommunity=admin example.com nmap --script default,safe 加载default和safe类脚本。
参考: https://nmap.org/book/nse-usage.html#nse-categories
脚本文件分类:brute、default、dos、safe、exploit等,具体的可查看:https://nmap.org/book/nse-usage.html#nse-categories
根据脚本的运行阶段不同分为四类:Prerule scripts、Host scripts、Service scripts、Postrule scripts。
应用最多的就是Service scripts,Post scripts对Nmap输出进行格式化输出,Host scripts这个阶段在Nmap运行完主机发现、端口扫描、版本探测、OS侦测后执行;Prerule scripts执行一些资源操作,先于各探测执行。
二、Nmap执行原理图

由上图可以看到四类脚本的运行阶段,以及他们的功能。
1)在nmap_main里面,调用init_main()进行详细的初始化过程,加载Lua标准库与Nmap扩展库,准备参数环境,加载并执行nse_main.lua文件;这个文件加载用户选择的脚本文件,执行完之后返回函数对象给init_main(),被保存到Lua注册表中。
2)在nse_main.lua中,定义两个核心的类,Script和Thread,Script用于管理NSE脚本,当新的脚本被加载时,调用 Script.new创建脚本对象,该对象被保存下来在后续的扫描过程中使用;Thread用于管理脚本的执行,该类中也包含对脚本健全性的检查。在脚本执行时,如果脚本之间存在依赖关系,那么会将基础的无依赖的脚本统一执行完毕,再执行依赖性的脚本。
3)执行脚本扫描时,从nmap_main()中调用script_scan()函数。在进入script_scan()后,会标记扫描阶段类型,然后进入到初始化阶段返回的main()函数(来自nse_main.lua脚本中的main)中,在函数中解析具体的扫描类型。
4)main()函数负责处理三种类型的脚本扫描:预扫描(SCRIPT_PRE_SCAN)、脚本扫描(SCRIPT_SCAN)、后扫描 (SCRIPT_POST_SCAN)。预扫描即在Nmap调用的最前面(没有进行主机发现、端口扫描等操作)执行的脚本扫描,通常该类扫描用于准备基本的信息,例如到第三服务器查询相关的DNS信息。而脚本扫描,是使用NSE脚本来扫描目标主机,这是最核心的扫描方式。后扫描,是整个扫描结束后,做一些善后处理的脚本,比如优化整理某些扫描。
5)在main()函数中核心操作由run函数负责。而run()函数的本身设计用于执行所有同一级别的脚本(根据依赖关系划分的级别),直到所有线程执行完毕才退出。run()函数中实现三个队列:执行队列(Running Queue)、等待队列(Waiting Queue)、挂起队列(Pending Queue),并管理三个队列中线程的切换,直到全部队列为空或出错而退出。
三、Nmap API
数据传递
nmap.luadoc是与nmap内部函数交互和数据结构化的API,API提供目标主机的详细信息例如端口状态和版本探测结果;同时API也提供与Nsock交互的接口,这样方便我们自己写NSE脚本与服务器交互,目前文件中共48个函数。
在脚本引擎中,用户可以轻松访问Nmap已经了解的有关目标主机的信息。该数据作为参数传递给NSE脚本的action方法,参数host和port是lua表,其中包含脚本执行的目标的信息。下面介绍每个表里面所含有的变量。
nmap使用注册表来共享信息,每个脚本之间共享nmap.registry,每个主机还有自己的注册表名为host.registry;在整个扫描会话中,全局注册表始终存在。脚本可以使用它,例如,存储稍后将由postrule脚本显示的值。机注册表仅在主机被扫描时存在。它们可以用于将信息从一个脚本发送到另一个脚本。例如:1)ssh-hostkey脚本的portrule收集SSH密钥指纹,并将其存储在全局nmap.registry中,以便稍后可以由postrule打印。2)ssl-cert脚本收集SSL证书并将其存储在每个主机注册表中,以便ssl-google-cert-catalog脚本可以使用它们,而无需再次连接到服务器。nmap.registry是全局的,因此key选择很重要;使用另一个脚本结果的脚本必须使用dependencies变量来声明它,以确保先前的脚本首先运行。
host.ip
host.name 通过dns反向查询的主机名,如果没查到则为空串
host.targetname
host.reason: 给出host处于现在这个状态的解释
host.reason_ttl
host.mac_addr
host.directly_connected
host.mac_addr_next_hop
host.mac_addr_src
host.interface
host.interface_mtu
host.bin_ip
host.bin_ip_src
host.times
host.traceroute port.number
port.protocol: 有效值为tcp、udp
port.service: 字符串表示的运行在端口号上的服务,该服务由服务探测阶段探测出,如果 port.version.service_dtype字段是table,那么Nmap基于端口号猜测服务;如果不是table,那么版本探测阶段能够确定是什么服务,这个字段的值被设定为port.version.name
port.reason: 字符串解释处于port.state状态的原因。
port.reason_ttl
port.version: 这个字段是一个表格,包含版本探测阶段返回的全部信息,包括:name;name_confidence;等,具体可参考官方文档版本探测章节。
port.state 参考:https://nmap.org/book/nse-api.htm
Network I/O API
require("nmap")
-- 简单的使用Nsock连接服务器的例子
local socket = nmap.new_socket()
socket:set_timeout()
try = nmap.new_try(function() socket:close() end)
try(socket:connect(host.ip, port.number))
try(socket:send("login"))
response = try(socket:receive())
socket:close()
除此之外还有receive_bytes方法,receive_lines方法,receive_buf方法,可查看nmap.luadoc文件
除了Network的方式还有行包连接的方式:参考https://nmap.org/book/nse-api.html
四、编写自己的脚本的建议
编写NSE脚本,需要根据Nmap规范编写description,author,license,categories,rule,action字段的内容,其中主要是action字段的编写;如果rule函数返回结果为真,那么执行编写的action函数。
The Rule
这部分决定是否执行action函数,A prerule or a postrule 类型的脚本总是执行;在端口规则脚本里面,NSE仅给我们当前扫描端口的信息,比如一个脚本要执行,但是必须保证当前端口开启并且113端口开启,为了检测113端口是否开启,我们使用nmap.get_port_state这个函数,如果113端口没有被扫描,函数将返回nil。
portrule = function(host, port)
local auth_port = { number=, protocol="tcp" }
local identd = nmap.get_port_state(host, auth_port)
return identd ~= nil
and identd.state == "open"
and port.protocol == "tcp"
and port.state == "open"
end
The Action
脚本首先连接到我们探测的端口,通过调用nmap.new_socket创建两个套接字选项。接下来,我们定义一个错误处理捕获功能,如果检测到故障,则关闭这些套接字。此时我们可以安全地使用诸如打开,关闭,发送和接收的对象方法来在网络套接字上操作。在这种情况下,我们调用connect来建立连接。 NSE的异常处理机制用于避免过多的错误处理代码。 try用来包围可能出错的代码,如果有任何问题,这将调用catch函数。如果两个连接成功,我们构造一个查询字符串并解析响应,最后返回解析结果。
action = function(host, port)
local owner = ""
local client_ident = nmap.new_socket()
local client_service = nmap.new_socket()
local catch = function()
client_ident:close()
client_service:close()
end
local try = nmap.new_try(catch)
try(client_ident:connect(host.ip, ))
try(client_service:connect(host.ip, port.number))
local localip, localport, remoteip, remoteport =
try(client_service:get_info())
local request = port.number .. ", " .. localport .. "\r\n"
try(client_ident:send(request))
owner = try(client_ident:receive_lines())
if string.match(owner, "ERROR") then
owner = nil
else
owner = string.match(owner,
"%d+%s*,%s*%d+%s*:%s*USERID%s*:%s*.+%s*:%s*(.+)\r?\n")
end
try(client_ident:close())
try(client_service:close())
return owner
end
五、参考文献
https://nmap.org/changelog.html#7.50 Nmap各版本更新内容
https://nmap.org/book/nse-tutorial.html NSE编写指南
https://nmap.org/book/nse-api.html Nmap API
https://nmap.org/ Nmap官网
Nmap脚本引擎原理的更多相关文章
- Nmap脚本文件分析(AMQP协议为例)
Nmap脚本文件分析(AMQP协议为例) 一.介绍 上两篇文章 Nmap脚本引擎原理 编写自己的Nmap(NSE)脚本,分析了Nmap脚本引擎的执行过程,以及脚本文件的编写,这篇文章将以解析AMQ ...
- Nmap源码分析(脚本引擎)
Nmap提供了强大的脚本引擎(NSE),以支持通过Lua编程来扩展Nmap的功能.目前脚本库已经包含300多个常用的Lua脚本,辅助完成Nmap的主机发现.端口扫描.服务侦测.操作系统侦测四个基本功能 ...
- nmap 使用脚本引擎进行扫描
1.下载nmap(nmap官网). 2.安装nmap. 3.编辑环境变量(windows下所需),保存.
- nmap脚本扫描使用总结
nmap的脚本默认目录为:/usr/share/nmap/scripts/ Nmap提供的命令行参数如下 -sC: 等价于--script=default,使用默认类别的脚本进行扫描 可更换其他类别 ...
- C#脚本引擎 CS-Script 之(三)——如何部署
本文不但介绍了CS-Script如何部署,还介绍了CS-Script的部署后面的原理,并用一个框图详细介绍了部署中的各种细节. 一.获取资源 1.从官网上下载编译好的csscript资源:cs-scr ...
- 脚本AI与脚本引擎
Scripted AI and Scripting Engines 脚本AI与脚本引擎 This chapter discusses some of the techniques you can us ...
- nmap脚本使用总结
0x00 前言: nmap的基本介绍和基本使用方法,在乌云知识库中已经有人提交过,讲的比较详细,在此文中就不再讲述. 具体链接:http://drops.wooyun.org/tips/2002 本文 ...
- nmap脚本nse的使用
nmap脚本(nse)使用总结 0x01 nmap按脚本分类扫描 nmap脚本主要分为以下几类,在扫描时可根据需要设置--script=类别这种方式进行比较笼统的扫描: auth: 负责处理鉴权证书( ...
- nmap脚本(nse)使用总结
nmap脚本主要分为以下几类,在扫描时可根据需要设置--script=类别这种方式进行比较笼统的扫描: auth: 负责处理鉴权证书(绕开鉴权)的脚本 broadcast: 在局域网内探查更多服务 ...
随机推荐
- 分针网—IT教育:调皮的JavaScript
JavaScript是一门有趣的语言,不仅有趣而且调皮,不同的内核的浏览器在解析的时候表现会有些差异,今天主要是抛砖引玉,和大家一起讨论一些在实际开发中比较常见但同时可能并没有过于在意的JavaScr ...
- OC类的介绍
类的本质 类的本质其实也是一个对象(类对象) 类对象 类对象再程序运行时一直存在 类对象是一种数据结构,存储类的基本信息:类大小,类名称,类的版本以及消息与函数的映射表等 类对象所保存的信息在程序编译 ...
- Docker- 创建支持SSH服务的容器镜像
示例 - CentOS7 [root@CentOS-7 ~]# cat ssh-centos7 FROM centos:centos7 MAINTAINER anliven "anliven ...
- c#实现windows远程桌面连接程序
c#实现windows远程桌面连接程序 使用winform制作windows远程桌面连接程序,windows自带了远程桌面连接,我们需要将远程桌面连接集成 到自己的winform程序,并实现管理远程主 ...
- LeetCode:60. Permutation Sequence,n全排列的第k个子列
LeetCode:60. Permutation Sequence,n全排列的第k个子列 : 题目: LeetCode:60. Permutation Sequence 描述: The set [1, ...
- 大数的加法运算,杭电oj-1002
原题地址:http://acm.hdu.edu.cn/showproblem.php?pid=1002 [Problem Description] I have a very simple pro ...
- 【转】c++ new操作符的重载
基本概念: 1. 操作符重载:C++支持对某个操作符赋予不同的语义 2. new操作符:申请内存,调用构造函数 关于c++ new操作符的重载 你知道c++ 的new 操作符和operator new ...
- 安卓TextView限定行数最大值,点击按钮显示所有内容
问题展示 如上图所示,在普通的TextView中,要求: 最多显示3行 超过三行显示展开按钮 且点击展开按钮显示完整内容 这个需求看似简单,但解决起来会遇到两个较为棘手的问题:1,如何判断是否填满了前 ...
- ArrayList源码解析(三)
1.isEmpty() 如果此列表中没有元素,则返回 true /** * Returns <tt>true</tt> if this list contains no el ...
- Js判断是否是直接进入本页面的
今天带来一个Js的小示例,用来判断当前页面的链接来路.很多人应该可以用到,这个虽然非常简单,但是用到的地方却还是挺多的 首先新建一个index.html,代码如下 <!DOCTYPE html& ...