NSE脚本编写
NES是nmap的脚本,在nmap/scripts文件夹下,语言为lua。这篇只记录我如何初识nse scripts,目前程序基础没跟上,后续还会再次学习,深入编写。
点开一个看看结构:
- local brute = require "brute"
- local creds = require "creds"
- local shortport = require "shortport"
- local stdnse = require "stdnse"
- local ftp = require "ftp"
- description = [[
- Performs brute force password auditing against FTP servers.
- Based on old ftp-brute.nse script by Diman Todorov, Vlatko Kosturjak and Ron Bowes.
- ]]
- ---
- -- @see ftp-anon.nse
- --
- -- @usage
- -- nmap --script ftp-brute -p 21 <host>
- --
- -- This script uses brute library to perform password
- -- guessing.
- --
- -- @output
- -- PORT STATE SERVICE
- -- 21/tcp open ftp
- -- | ftp-brute:
- -- | Accounts
- -- | root:root - Valid credentials
- -- | Statistics
- -- |_ Performed 510 guesses in 610 seconds, average tps: 0
- --
- -- @args ftp-brute.timeout the amount of time to wait for a response on the socket.
- -- Lowering this value may result in a higher throughput for servers
- -- having a delayed response on incorrect login attempts. (default: 5s)
- -- 06.08.16 - Modified by Sergey Khegay to support new brute.lua adaptability mechanism.
- author = "Aleksandar Nikolic"
- license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
- categories = {"intrusive", "brute"}
- portrule = shortport.port_or_service(21, "ftp")
- local arg_timeout = stdnse.parse_timespec(stdnse.get_script_args(SCRIPT_NAME .. ".timeout"))
- arg_timeout = (arg_timeout or 5) * 1000
- Driver = {
- new = function(self, host, port)
- local o = {}
- setmetatable(o, self)
- self.__index = self
- o.host = host
- o.port = port
- return o
- end,
- connect = function( self )
- self.socket = brute.new_socket()
- -- discard buffer, we'll create a new one over the BruteSocket later
- local realsocket, code, message, buffer = ftp.connect(self.host, self.port, {request_timeout=arg_timeout})
- if not realsocket then
- return false, brute.Error:new( "Couldn't connect to host: " .. (code or message) )
- end
- self.socket.socket = realsocket
- return true
- end,
- login = function (self, user, pass)
- local buffer = stdnse.make_buffer(self.socket, "\r?\n")
- local status, code, message = ftp.auth(self.socket, buffer, user, pass)
- if not status then
- if not code then
- return false, brute.Error:new("socket error during login: " .. message)
- elseif code == 530 then
- return false, brute.Error:new( "Incorrect password" )
- elseif code == 421 then
- local err = brute.Error:new("Too many connections")
- err:setReduce(true)
- return false, err
- else
- stdnse.debug1("WARNING: Unhandled response: %d %s", code, message)
- local err = brute.Error:new("Unhandled response")
- err:setRetry(true)
- return false, err
- end
- end
- stdnse.debug1("Successful login: %s/%s", user, pass)
- return true, creds.Account:new( user, pass, creds.State.VALID)
- end,
- disconnect = function( self )
- ftp.close(self.socket)
- return true
- end
- }
- action = function( host, port )
- local status, result
- local engine = brute.Engine:new(Driver, host, port)
- engine.options.script_name = SCRIPT_NAME
- status, result = engine:start()
- return result
- end
复制代码
接下来去看一看文档,指路:文档指路
脚本分类nmap脚本大概分为下列类别: NSE scripts define a list of categories they belong to. Currently defined categories are auth, broadcast, brute, default. discovery, dos, exploit, external, fuzzer, intrusive, malware, safe, version, and vuln. Category names are not case sensitive. The following list describes each category.
NSE脚本定义了它们所属的类别的列表。当前定义的类别 auth, broadcast, brute, default。 discovery, dos, exploit, external, fuzzer, intrusive, malware, safe, version,和 vuln。类别名称不区分大小写。以下列表描述了每个类别。
Auth:负责处理鉴权证书(绕过鉴权)
Broadcast:在局域网内探测更多服务的开启情况,如DHCP/DNS/SQLServer等。
Brute:针对常见的应用提供暴力破解方式,如HTTP/SMTP等。
Default:使用-sC或者-A选项扫描时默认的脚本,提供基本的脚本扫描能力。
Discovery:对网络进行更多信息的搜集,如SMB枚举,SNMP查询等。
DOS:用于拒绝服务攻击。
Exploit:利用已知的漏洞入侵系统。
External:利用第三方的数据库或者资源,如进行whois解析。
Fuzzer:模糊测试脚本,发送异常的包到目标机,探测潜在漏洞。
Intrusive:入侵性脚本,此类脚本可能引起对方IDS/IPS的记录或者屏蔽。
Malware:探测目标机是否感染了病毒、开启后门等信息。
Safe:与Intrusive相反,属于安全性脚本。
Version:负责增强服务与版本扫描功能。
Vuln:负责检测目标机是否有常见漏洞。 运行规则脚本运行在nmap扫描中的哪一阶段
Prerule scripts:包含一个prerule()函数,且prerule()函数不接受参数。
在扫描开始前,prerule()函数执行一次,并且整个流程只执行一次。 These scripts run before any of Nmap’s scan phases, so Nmap has not collected any information about its targets yet. They can be useful for tasks which don’t depend on specific scan targets, such as performing network broadcast requests to query DHCP and DNS SD servers. Some of these scripts can generate new targets for Nmap to scan (only if you specify the newtargets NSE argument). For example, dns-zone-transfer can obtain a list of IPs in a domain using a zone transfer request and then automatically add them to Nmap’s scan target list.
它们对于不依赖于特定扫描目标的任务很有用,例如执行网络广播请求以查询DHCP和DNS SD服务器。其中一些脚本可以为Nmap生成新目标进行扫描(仅当您指定newtargets NSE参数时)。例如,dns-zone-transfer 可以使用区域传输请求获取域中IP的列表,然后将其自动添加到Nmap的扫描目标列表中。
Host scripts:包含一个hostrule(host)函数。扫描完一个host目标执行一次,N个host执行N次。 Scripts in this phase run during Nmap’s normal scanning process after Nmap has performed host discovery, port scanning, version detection, and OS detection against the target host. This type of script is invoked once against each target host which matches its hostrule function. Examples are whois-ip, which looks up ownership information for a target IP, and path-mtu which tries to determine the maximum IP packet size which can reach the target without requiring fragmentation.
在此阶段的脚本在Nmap对目标主机执行了主机发现,端口扫描,版本检测和OS检测之后,在Nmap的正常扫描过程中运行。对与它的hostrule功能匹配的每个目标主机调用一次这种脚本。例子有whois-ip,它查找目标IP的所有权信息,而path-mtu 试图确定无需分段即可达到目标的最大IP数据包大小。
Service scripts:包含一个portrule(host, port)函数,扫描完一个主机的一个端口后执行一次,N个端口执行N次。 These scripts run against specific services listening on a target host. For example, Nmap includes more than 15 http service scripts to run against web servers. If a host has web servers running on multiple ports, those scripts may run multiple times (one for each port). These are the most commong Nmap script type, and they are distinguished by containing a portrule function for deciding which detected services a script should run against.
这些脚本针对在目标主机上侦听的特定服务运行。例如,Nmap包含超过15种针对Web服务器运行的http服务脚本。如果主机的Web服务器在多个端口上运行,则这些脚本可能会运行多次(每个端口一个)。这些是最常见的Nmap脚本类型,它们的区别在于包含portrule用于确定脚本应针对哪些检测到的服务运行的函数。
Postrule:包含一个postrule()函数,且postrule()函数不接受参数。全部扫描完之后运行一次,整个流程只执行一次。 These scripts run after Nmap has scanned all of its targets. They can be useful for formatting and presenting Nmap output. For example, ssh-hostkey is best known for its service (portrule) script which connects to SSH servers, discovers their public keys, and prints them. But it also includes a postrule which checks for duplicate keys amongst all of the hosts scanned, then prints any that are found. Another potential use for a postrule script is printing a reverse-index of the Nmap output—showing which hosts run a particular service rather than just listing the services on each host.
这些脚本在Nmap扫描完所有目标之后运行。它们对于格式化和显示Nmap输出很有用。例如,ssh- hostkey脚本连接到SSH服务器,发现其公共密钥并输出它们。但是它还包括一个规则,该规则检查所有扫描的主机中是否有重复的密钥,然后打印找到的所有密钥。postrule的另一个潜在用途是Nmap输出的反向索引-显示哪些主机在运行特定服务,而不仅仅是在每个主机上列出服务。
脚本格式description:描述了脚本要测试的内容以及用户应注意的任何重要说明。根据脚本的复杂程度,描述的长度可能从几句话到几段不等。
categories:定义了脚本所属的一个或多个类别,见上面脚本分类。类别不区分大小写,可以按任何顺序指定,以数组形式列出。
author:作者信息。
license:许可信息。一般格式为:
license = "Same as Nmap--See https://nmap.org/book/man-legal.html
license = "Simplified (2-clause) BSD license--See https://nmap.org/svn/docs/licenses/BSD-simplified
dependencies:元素是脚本名的数组,内部元素在这个脚本之前执行。如果省略该字段,则NSE将假定脚本没有依赖性。
rules:见上面的规则。
action:规则执行时的指令。Lua函数,它接受与规则相同的参数。
Environment Variables: 示例
local shortport = require "shortport"
description = [[a http server detected test demo]]
author = "reborn"
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
categories = {"default"}
portrule = function(host,port)
return port.protocol == "tcp" and port.number == 80 and port.service == "http" and port.state == "open"
end
action = function(host,port)
return "this is a web server"
end
放到/usr/share/nmap/scripts/nselib下,更新一下脚本库。
执行:
- nmap --script sample.nse 192.168.10.179
复制代码
类库
脚本通过包含类库,起到python类似import的作用。 试写一个库:
- function PortTest(port)
- return string.format("Port '%s' is open",port)
- end
复制代码 更新执行:
defcon2018上开发小哥写的探测动态ip摄像头的脚本:
- description = [[
- finds a webcam.
- ]]
- categories = {"safe", "discovery"}
- require("http")
- function portrule(host,port)
- return port.number == 80
- end
- function action(host,port)
- local response
-
- response = http.get(host,port,"/cam.jpg")
- if response.status and response.status ~= 404 and response.header["server"] and string.match(response.header["server"],"^thttpd") then
- return "webcam founnd."
- end
- end
复制代码- nmap -n -Pn -p 80 --open --script http-webcam 66.7.171.- -oN webcam.nmap -d
复制代码
|