>>> 为了写这一系列的文章,我用这段时间学习了 Lua语言,学习了Nmap的API,翻译了NSE库的部分源码,希望给喜欢Nmap的小伙伴带来惊喜吧!
0x01 启动过程
主机发现 -- 端口识别 -- 服务发现 -- 系统识别 -- 漏洞/认证/...
-sn ——> -sA/-sS/-sT/-sU ——> -sV ——> -O ——> --script
在服务发现过程中才会开始自动调用 NSE 脚本 详细启动过程参考
https://nmap.org/book/nse-implementation.html
0x02 脚本分类
- auth 认证相关
- broadcast 广播
- brute 暴力破解
- default 默认
- discovery 发现相关
- dos 拒绝服务
- exploit 漏洞利用
- external 外部
- fuzzer 模糊测试
- intrusive 侵入性
- malware 恶意软件
- safe 安全地
- version 版本信息
- vuln 有漏洞的
- all 所有的
结果很长,这里只是选择了一小部分
0x03 脚本操作
0x031 脚本调用
Nmap的指定脚本调用使用的是 --script 参数
--script=xxx
有时候会用到 来进行屏蔽原本的端口服务识别的结果,可以用在修改了默认端口的一些服务上 比如 --script ms-sql-config
以下这些格式也是非常常用
- --script default,safe
- --script smb-os-discovery
- --script default,banner,/home/user/customscripts
- --script "http-*"
- --script "not intrusive"
- --script "default or safe"
- --script "default and safe"
- --script "(default or safe or intrusive) and not http-*"
0x032 脚本参数
脚本参数使用 --script-args
--script-args 的参数是key,value形式的,被存储在 nmap.registry.args 中,可以通过 stdnse.get_script_args 来进行获取 nmap -sC --script-args 'user=foo,pass=",{}=bar",paths={/admin,/cgi-bin},xmpp-info.server_name=localhost'
使用 local server_name = stdnse.get_script_args("xmpp-info.server_name") 来进行获取值
0x033 查看脚本帮助文档
--script-help=
0x034 脚本运行追踪
--script-trace
可以通过这个参数来监控脚本运行情况
0x035 升级脚本库
--script-updatedb
0x04 脚本规则
Nmap NSE定义了四种规则
- prerule 开始运行Nmap时调用
- hostrule 为扫描完一个主机调用
- portrule 为扫描完一个开放端口调用
- postrule 为扫描结束调用
action 函数是在hostrule 或 portrule返回true 时才被调用
0x041 prerule
这个规则对应的是脚本开始运行时才调用,我们自己写一个最简单的脚本来测试一下
代码语言:javascript复制local stdnse = require "stdnse"
local shortport = require "shortport"
local nmap = require "nmap"
description = [[
This is a test for http.lua's functions
]]
author = "test94"
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
categories = {"default"}
prerule = function()
print("functest running")
end
hostrule = function() end
portrule = function() end
postrule = function() end
action = function() end
可以看到四种规则外加 action 函数都在,在prerule 中打印输出,测试一下
可以看到,在扫描之前执行了
0x042 hostrule
这个规则对应扫描完一个主机才调用
代码语言:javascript复制local stdnse = require "stdnse"
local shortport = require "shortport"
local nmap = require "nmap"
description = [[
This is a test for http.lua's functions
]]
author = "test94"
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
categories = {"default"}
prerule = function()
print("functest running")
end
hostrule = function()
print("I am hostrule")
end
portrule = function() end
postrule = function() end
action = function() end
这里在之前的脚本中在 hostrule 中加入了打印输出
可以看到,成功输出
0x043 portrule
portrule 是端口规则,当扫描完一个开放端口后进行输出
代码语言:javascript复制local stdnse = require "stdnse"
local shortport = require "shortport"
local nmap = require "nmap"
description = [[
This is a test for http.lua's functions
]]
author = "test94"
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
categories = {"default"}
prerule = function()
print("functest running")
end
hostrule = function()
print("I am hostrule")
end
portrule = function()
print("I am portrule")
end
postrule = function() end
action = function() end
测试一下
可以看到成功输出,在这里我们只扫描了一个 443 端口,所以只输出了一次,那么我多扫描几个呢?
可以看到,扫描了三个端口,其中有两个是开放的,所以打印了端口规则两次。不过看到这里大家肯定会有些奇怪:
一个端口的时候打印顺序是 先主机规则再端口规则
两个端口的时候打印顺序是 先端口规则,再主机规则
为了验证我的猜想,我多次执行
可以看到,打印顺序不是固定的,所以应该是多线程打印的事
0x044 postrule
在脚本执行完毕前调用此规则
代码语言:javascript复制local stdnse = require "stdnse"
local shortport = require "shortport"
local nmap = require "nmap"
description = [[
This is a test for http.lua's functions
]]
author = "test94"
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
categories = {"default"}
prerule = function()
print("functest running")
end
hostrule = function()
print("I am hostrule")
end
portrule = function()
print("I am portrule")
end
postrule = function()
print("I am postrule")
end
action = function() end
测试一下
可以看到成功执行此规则
0x045 action
这个函数只有在 hostrule 或 portrule 返回 true 时才执行
代码语言:javascript复制local stdnse = require "stdnse"
local shortport = require "shortport"
local nmap = require "nmap"
description = [[
This is a test for http.lua's functions
]]
author = "test94"
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
categories = {"default"}
prerule = function()
print("functest running")
end
hostrule = function()
print("I am hostrule")
return true
end
portrule = function()
print("I am portrule")
end
postrule = function()
print("I am postrule")
end
action = function()
print('I am action')
end
测试一下
我们让 hostrule 和 portrule 都返回 true 试试
代码语言:javascript复制local stdnse = require "stdnse"
local shortport = require "shortport"
local nmap = require "nmap"
description = [[
This is a test for http.lua's functions
]]
author = "test94"
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
categories = {"default"}
prerule = function()
print("functest running")
end
hostrule = function()
print("I am hostrule")
return true
end
portrule = function()
print("I am portrule")
return true
end
postrule = function()
print("I am postrule")
end
action = function()
print('I am action')
end
测试一下
可以看到,action函数执行了三遍
0x05 host
host 是一个对象(表),其中有非常多的属性,非常重要
- host.os
- host.ip
- host.name
- host.targetname
- host.reason
- host.resion_ttl
- host.directly_connected
- host.mac_addr
- 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
- host.os_fp
local stdnse = require "stdnse"
local shortport = require "shortport"
local nmap = require "nmap"
description = [[
This is a test for http.lua's functions
]]
author = "test94"
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
categories = {"default"}
prerule = function()
print("functest running")
end
hostrule = function()
return true
end
action = function(host, port)
print('I am action')
local output = stdnse.output_table()
output.host_os = host.host or "null"
output.host_ip = host.ip or "null"
output.host_name = host.name or "null"
output.host_targetname = host.targetname or "null"
output.host_reason = host.reason or "null"
output.host_resion_ttl = host.resion_ttl or "null"
output.host_directly_connected = host.directly_connected or "null"
output.host_mac_addr = host.mac_addr or "null"
output.host_mac_addr_next_hop = host.mac_addr_next_hop or "null"
output.host_mac_addr_src = host.mac_addr_src or "null"
output.host_interface = host.interface or "null"
output.host_interface_mtu = host.interface_mtu or "null"
output.host_bin_ip = host.bin_ip or "null"
output.host_bin_ip_src = host.bin_ip_src or "null"
output.host_times = host.times or "null"
output.host_traceroute = host.traceroute or "null"
output.host_os_fp = host.os_fp or "null"
return output
end
测试一下
经过几个目标的测试,可以得到以下结论
0x051 host.os
操作系统匹配表数组, OS匹配项由易于理解的名称和一系列OS类组成。每个OS类包括一个供应商,OS系列,OS生成,设备类型以及该类的CPE条目数组,具体结构如下:
代码语言:javascript复制host.os = {
{
name = <string>,
classes = {
{
vendor = <string>,
osfamily = <string>,
osgen = <string>,
type = <string>,
cpe = {
"cpe:/<...>",
[More CPE]
}
},
[More classes]
},
},
[More OS matches]
}
加入匹配到的目标信息为
代码语言:javascript复制Fingerprint Linux 2.6.32 - 3.2
Class Linux | Linux | 2.6.X | general purpose
CPE cpe:/o:linux:linux_kernel:2.6
Class Linux | Linux | 3.X | general purpose
CPE cpe:/o:linux:linux_kernel:3
那么在 host.os 中存储如下:
代码语言:javascript复制host.os = {
{
name = "Linux 2.6.32 - 3.2",
classes = {
{
vendor = "Linux",
osfamily = "Linux",
osgen = "2.6.X",
type = "general purpose",
cpe = { "cpe:/o:linux:linux_kernel:2.6" }
},
{
vendor = "Linux",
osfamily = "Linux",
osgen = "3.X",
type = "general purpose",
cpe = { "cpe:/o:linux:linux_kernel:3" }
}
},
}
}
0x052 host.ip
目标主机的IP地址,如果给定的目标是域名,则会返回域名解析后的IP
0x053 host.name
反向DNS查询后的域名信息,如果查询不到,则返回空
0x054 host.targetname
目标域名,如果目标是域名形式,则为这个域名;如果给定的是IP,则为空
0x055 host.reason
判断依据,如果是正常返回的就是 echo-reply ; 如果是被防火墙拦截等则返回 user-set;如果在内网返回
0x056 host.resion_ttl
包含响应数据包的TTL值,用于确定目标主机到达时的状态。此响应数据包是也用于设置host.reason的数据包
0x057 host.directly_connected
判断是否与Nmap运行的主机在同一个网段,是一个布尔值
0x058 host.mac_addr
目标主机的mac地址, 一般只有目标主机在内网才会有这个值,而且只有做原始网络帧扫描时候才会有结果
0x059 host.mac_addr_next_hop
到主机的路由中第一跳的MAC地址,如果不可用,则为nil
0x0510 host.mac_addr_src
我们自己的MAC地址,该地址用于连接到主机(我们的网卡的地址,或(与--spoof-mac一起使用的)欺骗地址)
0x0511 host.interface
我们发送数据包的接口名称
0x0512 host.interface_mtu
host.interface的MTU(最大传输单位),如果未知,则为0
0x0513 host.bin_ip
目标主机的IP地址,为4字节(IPv4)或16字节(IPv6)字符串
0x0514 host.bin_ip_src
我们的主机的IP地址,为4字节(IPv4)或16字节(IPv6)字符串
0x0515 host.times
该表包含主机的Nmap时序数据。它的键是srtt(平滑的往返时间),rttvar(往返时间变化)和timeout(探测超时),所有这些都以浮点秒为单位
0x0516 host.traceroute
这是一个跟踪路由跃点数组,在使用--traceroute选项时出现。每个条目都是一个主机表,其中包含字段名称,ip和srtt(往返时间)。给定条目在表中的位置,该条目的TTL是隐式的。空表表示超时跳
0x0517 host.os_fp
如果执行了OS检测,则这是一个字符串,其中包含主机的OS指纹
很多字段在演示过程中都没有得到体现,大家在测试端口,服务,系统识别等方面可以进行多多测试,来确定每一个字段的值的存储形式
0x06 port
port 也是一个对象(表),其中有非常多的属性,非常重要
- port.number
- port.protocol
- port.service
- port.reason
- port.reason_ttl
- port.version
- name
- name_confidence
- product.version,extrainfo,hostname,ostype,devicetype
- service_tunnel
- service_fp
- service_dtype
- cpe
- port.state
local stdnse = require "stdnse"
local shortport = require "shortport"
local nmap = require "nmap"
description = [[
This is a test for http.lua's functions
]]
author = "test94"
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
categories = {"default"}
prerule = function()
print("functest running")
end
hostrule = function() end
portrule = function()
return true
end
action = function(host, port)
print('I am action')
local output = stdnse.output_table()
output.port_number = port.number or "null"
output.port_protocol = port.protocol or "null"
output.port_service = port.service or "null"
output.port_reason = port.reason or "null"
output.port_reason_ttl = port.reason_ttl or "null"
output.port_version = port.version or "null"
output.port_state = port.state or "null"
return output
end
测试一下
0x061 port.number
端口号
0x062 port.protocol
协议类型
0x063 port.service
端口服务类型
0x064 port.reason
判断依据
0x065 port.reson_ttl
包含响应数据包的TTL值,用于确定目标端口到达时的状态。此响应数据包是也用于设置port.reason的数据包
0x066 port.version
此项是一个表,其中包含Nmap版本扫描引擎检索到的信息。即使未执行版本扫描,Nmap仍可能检索某些值(例如服务名称,服务类型可信度和与RPC相关的值)。未确定的值默认为nil
- name 服务名
- name_confidence 评估Nmap对名称准确性的置信度,从1(最低置信度)到10。如果port.version.service_dtype为“ table”,则为3
- product.version,extrainfo,hostname,ostype,devicetype 版本相关的 5 个变量
- service_tunnel 根据Nmap是否使用SSL隧道检测服务,包含字符串“ none”或“ ssl”。
- service_fp 服务指纹信息
- service_dtype 根据Nmap是否从nmap-services文件或服务探测器匹配推导出port.version.name来包含字符串“ table”或“ probed”
- cpe 检测到的服务的CPE代码列表。如官方CPE规范中所述,这些字符串都以cpe:/前缀开头
0x067 port.state
端口状态
0x07 registry
脚本可以通过将值存储在注册表中来共享信息,该注册表是可以被所有脚本访问的特殊表。有一个名为 nmap.registry 的全局注册表,由所有脚本共享。每个主机还具有自己的注册表,称为 host.registry,其中host是传递给脚本的主机表。注册表中的信息不存储在Nmap执行之间
全局注册表会在整个扫描会话中持续存在。脚本可以使用它来存储例如稍后将由脚本规则脚本显示的值。另一方面,每个主机的注册表仅在扫描主机时存在,它们可用于将信息从一个脚本发送到在同一主机上运行的另一个脚本。如果可能,请使用每个主机的注册表。这不仅使您不必在各个主机之间使键名唯一,而且还使注册表不再需要时可以回收注册表所使用的内存
使用另一个脚本结果的脚本必须使用 dependencies 变量声明它,以确保较早的脚本先运行(至于dependencies 变量我们稍后会介绍)
0x08 环境变量
- SCRIPT_PATH 脚本路径
- SCRIPT_NAME 脚本名称
- SCRIPT_TYPE "脚本执行类型"
- 这个脚本主要是debug的时候进行使用,这个脚本可以返回 prerule、hostrule、portrule、postrule 四个规则中哪一个被执行了
local stdnse = require "stdnse"
local shortport = require "shortport"
local nmap = require "nmap"
description = [[
This is a test for http.lua's functions
]]
author = "test94"
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
categories = {"default"}
prerule = function()
print("functest running")
end
hostrule = function()
return true
end
action = function(host, port)
print('I am action')
local output = stdnse.output_table()
output.SCRIPT_NAME = SCRIPT_NAME
output.SCRIPT_TYPE = SCRIPT_TYPE
output.SCRIPT_PATH = SCRIPT_PATH
return output
end
测试一下输出
0x09 NSE脚本编写规范
NSE 脚本由很多部分组成,这样才能够保证脚本顺利运行,当然很多部分可以缺失,根据实际需要更改吧
先看一个例子吧 ,以 http-backup-finder.nse 为例
代码语言:javascript复制local coroutine = require "coroutine"
local http = require "http"
local httpspider = require "httpspider"
local shortport = require "shortport"
local stdnse = require "stdnse"
local table = require "table"
local url = require "url"
description = [[
Spiders a website and attempts to identify backup copies of discovered files.
It does so by requesting a number of different combinations of the filename (eg. index.bak, index.html~, copy of index.html).
]]
---
-- @usage
-- nmap --script=http-backup-finder <target>
--
-- @output
-- PORT STATE SERVICE REASON
-- 80/tcp open http syn-ack
-- | http-backup-finder:
-- | Spidering limited to: maxdepth=3; maxpagecount=20; withindomain=example.com
-- | http://example.com/index.bak
-- | http://example.com/login.php~
-- | http://example.com/index.php~
-- |_ http://example.com/help.bak
--
-- @args http-backup-finder.maxdepth the maximum amount of directories beneath
-- the initial url to spider. A negative value disables the limit.
-- (default: 3)
-- @args http-backup-finder.maxpagecount the maximum amount of pages to visit.
-- A negative value disables the limit (default: 20)
-- @args http-backup-finder.url the url to start spidering. This is a URL
-- relative to the scanned host eg. /default.html (default: /)
-- @args http-backup-finder.withinhost only spider URLs within the same host.
-- (default: true)
-- @args http-backup-finder.withindomain only spider URLs within the same
-- domain. This widens the scope from <code>withinhost</code> and can
-- not be used in combination. (default: false)
--
author = "Patrik Karlsson"
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
categories = {"discovery", "safe"}
portrule = shortport.http
local function backupNames(filename)
local function createBackupNames()
local dir = filename:match("^(.*/)") or ""
local basename, suffix = filename:match("([^/]*)%.(.*)$")
local backup_names = {}
if basename then
table.insert(backup_names, "{basename}.bak") -- generic bak file
end
if basename and suffix then
table.insert(backup_names, "{basename}.{suffix}~") -- emacs
table.insert(backup_names, "{basename} copy.{suffix}") -- mac copy
table.insert(backup_names, "Copy of {basename}.{suffix}") -- windows copy
table.insert(backup_names, "Copy (2) of {basename}.{suffix}") -- windows second copy
table.insert(backup_names, "{basename}.{suffix}.1") -- generic backup
table.insert(backup_names, "{basename}.{suffix}.~1~") -- bzr --revert residue
end
local replace_patterns = {
["{filename}"] = filename,
["{basename}"] = basename,
["{suffix}"] = suffix,
}
for _, name in ipairs(backup_names) do
local backup_name = name
for p, v in pairs(replace_patterns) do
backup_name = backup_name:gsub(p,v)
end
coroutine.yield(dir .. backup_name)
end
end
return coroutine.wrap(createBackupNames)
end
action = function(host, port)
local crawler = httpspider.Crawler:new(host, port, nil, { scriptname = SCRIPT_NAME } )
crawler:set_timeout(10000)
-- Identify servers that answer 200 to invalid HTTP requests and exit as these would invalidate the tests
local status_404, result_404, known_404 = http.identify_404(host,port)
if ( status_404 and result_404 == 200 ) then
stdnse.debug1("Exiting due to ambiguous response from web server on %s:%s. All URIs return status 200.", host.ip, port.number)
return nil
end
-- Check if we can use HEAD requests
local use_head = http.can_use_head(host, port, result_404)
local backups = {}
while(true) do
local status, r = crawler:crawl()
-- if the crawler fails it can be due to a number of different reasons
-- most of them are "legitimate" and should not be reason to abort
if ( not(status) ) then
if ( r.err ) then
return stdnse.format_output(false, r.reason)
else
break
end
end
-- parse the returned url
local parsed = url.parse(tostring(r.url))
-- handle case where only hostname was provided
if ( parsed.path == nil ) then
parsed.path = '/'
end
-- only pursue links that have something looking as a file
if ( parsed.path:match(".*%.*.$") ) then
-- iterate over possible backup files
for link in backupNames(parsed.path) do
local host = parsed.host
local port = parsed.port or url.get_default_port(parsed.scheme)
-- the url.escape doesn't work here as it encodes / to /
-- which results in 400 bad request, so we simple do a space
-- replacement instead.
local escaped_link = link:gsub(" ", "% ")
local response
if(use_head) then
response = http.head(host, port, escaped_link, {redirect_ok=false})
else
response = http.get(host, port, escaped_link, {redirect_ok=false})
end
if http.page_exists(response, result_404, known_404, escaped_link, false) then
if ( not(parsed.port) ) then
table.insert(backups,
("%s://%s%s"):format(parsed.scheme, host, link))
else
table.insert(backups,
("%s://%s:%d%s"):format(parsed.scheme, host, port, link))
end
end
end
end
end
if ( #backups > 0 ) then
backups.name = crawler:getLimitations()
return stdnse.format_output(true, backups)
end
end
这么长看起来不直观,下面我们来分解分析一下
0x091 导包
代码语言:javascript复制local coroutine = require "coroutine"
local http = require "http"
local httpspider = require "httpspider"
local shortport = require "shortport"
local stdnse = require "stdnse"
local table = require "table"
local url = require "url"
0x092 description
代码语言:javascript复制description = [[
Spiders a website and attempts to identify backup copies of discovered files.
It does so by requesting a number of different combinations of the filename (eg. index.bak, index.html~, copy of index.html).
]]
这一部分是描述信息,基本上都是以 [[ some words ]] 这种形式的,所以尽量大家也不要变成其他形式的注释
0x093 NSEDoc
代码语言:javascript复制---
-- @usage
-- nmap --script=http-backup-finder <target>
--
-- @output
-- PORT STATE SERVICE REASON
-- 80/tcp open http syn-ack
-- | http-backup-finder:
-- | Spidering limited to: maxdepth=3; maxpagecount=20; withindomain=example.com
-- | http://example.com/index.bak
-- | http://example.com/login.php~
-- | http://example.com/index.php~
-- |_ http://example.com/help.bak
--
-- @args http-backup-finder.maxdepth the maximum amount of directories beneath
-- the initial url to spider. A negative value disables the limit.
-- (default: 3)
-- @args http-backup-finder.maxpagecount the maximum amount of pages to visit.
-- A negative value disables the limit (default: 20)
-- @args http-backup-finder.url the url to start spidering. This is a URL
-- relative to the scanned host eg. /default.html (default: /)
-- @args http-backup-finder.withinhost only spider URLs within the same host.
-- (default: true)
-- @args http-backup-finder.withindomain only spider URLs within the same
-- domain. This widens the scope from <code>withinhost</code> and can
-- not be used in combination. (default: false)
--
这一部分一般包括 @usage、@output、@args等,其实也是写不写都行,但是作为一个半吊子的coder,我还是经常喜欢写的,规范咱们就遵守嘛
0x094 author
代码语言:javascript复制author = "Patrik Karlsson"
作者信息
0x095 license
代码语言:javascript复制license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
这个所有的脚本都是一样的
0x096 categories
代码语言:javascript复制categories = {"discovery", "safe"}
目录表,这个脚本属于哪些个目录,就在这里填写哪些就好了
0x097 dependencies
代码语言:javascript复制dependencies = {"smb-brute"}
依赖性区域,是一个列表,在这个列表中列出来的脚本如果在本次执行中也进行了调用,那么先调用列表中的文件,之后再执行我们的脚本 其中我们的脚本可以调用列表中脚本的执行结果
一般smb的脚本都会先调用smb-brute (5.10beta2版本后,依赖区域不再使用,而是手动使用 runlevel 区域)
其实在接下来的部分中可能穿插着用户自定义的函数与代码
0x098 rules
- prerule()
- hostrule(host)
- portrule(host, port)
- postrule()
0x099 action()
当 hostrule 和 portrule 返回 true 时才会执行
0x010 NSEDoc
为了让所有开发者都能看懂这些脚本,一个NSEDoc是必要的,所以单拿出来讲解
下面是 stdnse.print_debug() 函数文档
代码语言:javascript复制---
-- Prints a formatted debug message if the current verbosity level is greater
-- than or equal to a given level.
--
-- This is a convenience wrapper around
-- <code>nmap.log_write</code>. The first optional numeric
-- argument, <code>level</code>, is used as the debugging level necessary
-- to print the message (it defaults to 1 if omitted). All remaining arguments
-- are processed with Lua's <code>string.format</code> function.
-- @param level Optional debugging level.
-- @param fmt Format string.
-- @param ... Arguments to format.
0x0101 规范:
- 文档注释以三个 - 开始,之后就是针对一下代码的说明
- 第一段应该是一个简短的总结,接下来的段落进行详细说明
- 特殊的标签要以 @ 开头来划分出文档的一部分
- 比如 @param 是用来描述每个功能参数的标签 之间的会呈现出一个等宽字体,这个应该被用在变量,函数名以及多行注释
- 如果一个序列行从字符 * 开始,他们将作为项目符号列表呈现,每个列表项都必须完全在同一个物理行
代码语言:javascript复制推荐每一个module和每一个每一个table都有一个注释文件 下面是 comm module的一个注释
---
-- Common communication functions for network discovery tasks like
-- banner grabbing and data exchange.
--
-- These functions may be passed a table of options, but it's not required. The
-- keys for the options table are <code>"bytes"</code>, <code>"lines"</code>,
-- <code>"proto"</code>, and <code>"timeout"</code>. <code>"bytes"</code> sets
-- a minimum number of bytes to read. <code>"lines"</code> does the same for
-- lines. <code>"proto"</code> sets the protocol to communicate with,
-- defaulting to <code>"tcp"</code> if not provided. <code>"timeout"</code>
-- sets the socket timeout (see the socket function <code>set_timeout</code>
-- for details).
--
-- @author Kris Katterjohn 04/2008
-- @copyright Same as Nmap--See https://nmap.org/book/man-legal.html
description = [[
Maps IP addresses to autonomous system (AS) numbers.
The script works by sending DNS TXT queries to a DNS server which in
turn queries a third-party service provided by Team Cymru
(team-cymru.org) using an in-addr.arpa style zone set up especially for
use by Nmap. The responses to these queries contain both Origin and Peer
ASNs and their descriptions, displayed along with the BGP Prefix and
Country Code. The script caches results to reduce the number of queries
and should perform a single query for all scanned targets in a BGP
Prefix present in Team Cymru's database.
Be aware that any targets against which this script is run will be sent
to and potentially recorded by one or more DNS servers and Team Cymru.
In addition your IP address will be sent along with the ASN to a DNS
server (your default DNS server, or whichever one you specified with the
<code>dns</code> script argument).
]]
---
-- @usage
-- nmap --script asn-query [--script-args dns=<DNS server>] <target>
-- @args dns The address of a recursive nameserver to use (optional).
-- @output
-- Host script results:
-- | asn-query:
-- | BGP: 64.13.128.0/21 | Country: US
-- | Origin AS: 10565 SVCOLO-AS - Silicon Valley Colocation, Inc.
-- | Peer AS: 3561 6461
-- | BGP: 64.13.128.0/18 | Country: US
-- | Origin AS: 10565 SVCOLO-AS - Silicon Valley Colocation, Inc.
-- |_ Peer AS: 174 2914 6461
author = "jah, Michael"
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
categories = {"discovery", "external", "safe"}
0x0102 NSE 文档标签如下
- @param 一个函数的每一个参数都应该有一个描述
- @see 添加一个交叉引用到另一个函数或表
- @return 描述一个函数返回值,可能多次用于多个返回值
- @usage 描述一个函数的使用方法或者nmap命令等
- @name 函数或者表的名字,一般没啥必要
- @class 定义类,方法,或者模块,通常自动推断出来
- @field 一般在表中用来描述指定字段的值
- @args --script-args option 中定义的参数,一般@args后面跟的第一个参数为 参数名称,之后是这个参数的描述
- @output 一个脚本的输出样式
- @xmloutput XML格式化输出的一个样式
- @author 作者
- @copyright 著作权声明