漏洞扫描 --编写Nmap脚本 |
2006年12月份,Nmap4.21 ALPHA1版加入脚本引擎,并将其作为主线代码的一部分。NSE脚本库如今已经有400多个脚本,覆盖了各种不同的网络机制(从SMB漏洞检测到Stuxnet探测,及中间的一些内容)。NSE的强大,依赖它强大的功能库,这些库可以非常容易的与主流的网络服务和协议,进行交互。 |
实现 |
Nmap 引擎脚本,由Lua编程语言、NmapAPI、系列强大的NSE库实现。为了达到本文的目的,现假设某个应用中存在一个叫ArcticFission漏洞。与许多其他的web应用程序类似,可以通过探测特定的文件,假设这个文件就是/arcticfission.html,用正则表达式提取文件内容中的版本号,与有漏洞的值进行对比.听起来好像很简单,让我们开始吧! |
NSE脚本主要由三部分组成: |
The Head Section 该部分包含一些元数据,主要描述脚本的功能,作者,影响力,类别及其他。 |
The Rule Section 该部分定义脚本执行的必要条件。至少包含下面列表中的一个函数: 此案例中,重点介绍portrule。portrule能够在执行操作前,检查host和port属性。portrule会利用nmap的API检查TCP80端口。 |
The Action Section 该部分定义脚本逻辑。此处案例中,检测到开放80端口,则打印“HelloWorld”。脚本的输出内容,会在nmap执行期间显示出来。 |
root@security:/home/offensive/nmap_nse# nmap -sS -p 22,80,443 --script /home/offensive/nmap_nse/http-vuln-check.nse www.exploit-db.com Starting Nmap 6.47 ( http://nmap.org ) at 2014-09-29 10:39 EDT Nmap scan report for www.exploit-db.com (192.99.12.218) Host is up (0.47s latency). Other addresses for www.exploit-db.com (not scanned): 198.58.102.135 rDNS record for 192.99.12.218: cloudproxy71.sucuri.net PORT STATE SERVICE 22/tcp filtered ssh 80/tcp open http |_http-vuln-check: Hello world ! 443/tcp open https |
调用脚本库 |
优秀的库集合,促使其变的强大。例如,可调用现有库中的函数,针对http端口创建portrule。此处用到了shortport. |
local shortport = require "shortport" -- The Rule Section -- portrule = shortport.http -- The Action Section -- action = function(host, port) return "Hello world!" end |
同样的扫描,产生了不同的结果 |
root@security:/home/offensive/nmap_nse# nmap -sS -p 22,80,443 --script /home/offensive/nmap_nse/http-vuln-check_shortport.nse www.exploit-db.com Starting Nmap 6.47 ( http://nmap.org ) at 2014-09-29 10:36 EDT Nmap scan report for www.exploit-db.com (192.99.12.218) Host is up (0.46s latency). Other addresses for www.exploit-db.com (not scanned): 198.58.102.135 rDNS record for 192.99.12.218: cloudproxy71.sucuri.net PORT STATE SERVICE 22/tcp filtered ssh 80/tcp open http |_http-vuln-check_shortport: Hello world! 443/tcp open https |_http-vuln-check_shortport: Hello world! Nmap done: 1 IP address (1 host up) scanned in 6.32 seconds |
该脚本对443执行了类似80端口的操作。主要是因为shortport.http表示类似HTTP的端口(80,443,631,7080,8080,8088,5800,3872,8180,8000),也就是说,nmap会探测服务http、https、ipp、http-alt、vnc-http、oem-agent、soap、http-proxy非标准端口,如果想要获取更多的信息,请查阅shortport的文档. |
服务探测 |
让我们把注意力放到action 部分的逻辑上。上述漏洞的检测,首先需要探测页面”/arcticfission.html” |
local shortport = require "shortport" local http = require "http" -- The Rule Section -- portrule = shortport.http -- The Action Section -- action = function(host, port) local uri = "/arcticfission.html" local response = http.get(host, port, uri) return response.status end |
上述代码用到了库http处理web页面, |
root@security:/home/offensive/nmap_nse# nmap -sS -p 22,80,443 --script /home/offensive/nmap_nse/http-vuln-check_shortport2.nse www.exploit-db.com Starting Nmap 6.47 ( http://nmap.org ) at 2014-09-29 11:16 EDT Nmap scan report for www.exploit-db.com (192.99.12.218) Host is up (0.48s latency). Other addresses for www.exploit-db.com (not scanned): 198.58.102.135 rDNS record for 192.99.12.218: cloudproxy71.sucuri.net PORT STATE SERVICE 22/tcp filtered ssh 80/tcp open http |_http-vuln-check_shortport2: 403 443/tcp open https |_http-vuln-check_shortport2: 400 |
上述输出表明,两个服务器端口不存在对应页面”arcticfission.html”,注意'http'库会自动在http与https端口切换,因此你不需要考虑去实现TLS/SSL。 |
如果只想输出存在该页面的web应用,可以如下操作: |
local shortport = require "shortport" local http = require "http" -- The Rule Section -- portrule = shortport.http -- The Action Section -- action = function(host, port) local uri = "/arcticfission.html" local response = http.get(host, port, uri) if (response.status == 200) then return response.body end end |
上述代码,返回状态码为200的页面内容。 |
注意:如果没有数据返回或返回数据为空,将导致无输出显示. |
版本检测的另一种方法,生成Hash与有漏洞的页面对比。为了实现此效果,此处调用了openssl库。 |
local shortport = require "shortport" local http = require "http" local stdnse = require "stdnse" local openssl = require "openssl" -- The Rule Section -- portrule = shortport.http -- The Action Section -- action = function(host, port) local uri = "/arcticfission.html" local response = http.get(host, port, uri) if (response.status == 200) then local vulnsha1 = "398ffad678f17a4f16ccd00b1914ca986d0b9258" local sha1 = string.lower(stdnse.tohex(openssl.sha1(response.body))) if ( sha1 == vulnsha1 ) then return "Vulnerable" else return "Not Vulnerable" end end end |
从上面的跟踪看,NSE的'http'库使用的默认User-Agent是“Mozilla/5.0(compatible; Nmap Scripting Engine;http://nmap.org/book/nse.html)”. 可能由于某些安全原因,你需要更改user-agent,可使用下面方法. |
offensive@security:~/nmap_nse$ nmap -p 80,443 --script /home/offensive/nmap_nse/http-vuln-check_openssl.nse --script-args="http.useragent='Mozilla/5.0 (compatible [offensive@security])'" --script-trace 192.168.1.105 Starting Nmap 6.47 ( http://nmap.org ) at 2014-09-30 06:08 EDT NSOCK INFO [0.2590s] nsi_new2(): nsi_new (IOD #1) NSOCK INFO [0.2600s] nsock_connect_tcp(): TCP connection requested to 192.168.1.105:80 (IOD #1) EID 8 NSOCK INFO [0.2610s] nsock_trace_handler_callback(): Callback: CONNECT SUCCESS for EID 8 [192.168.1.105:80] NSE: TCP 192.168.1.106:59923 > 192.168.1.105:80 | CONNECT NSE: TCP 192.168.1.106:59923 > 192.168.1.105:80 | 00000000: 47 45 54 20 2f 61 72 63 74 69 63 66 69 73 73 69 GET /arcticfissi 00000010: 6f 6e 2e 68 74 6d 6c 20 48 54 54 50 2f 31 2e 31 on.html HTTP/1.1 00000020: 0d 0a 48 6f 73 74 3a 20 31 39 32 2e 31 36 38 2e Host: 192.168. 00000030: 31 2e 31 30 35 0d 0a 55 73 65 72 2d 41 67 65 6e 1.105 User-Agen 00000040: 74 3a 20 4d 6f 7a 69 6c 6c 61 2f 35 2e 30 20 28 t: Mozilla/5.0 ( 00000050: 63 6f 6d 70 61 74 69 62 6c 65 20 5b 6f 66 66 65 compatible [offe 00000060: 6e 73 69 76 65 40 73 65 63 75 72 69 74 79 5d 29 nsive@security]) 00000070: 0d 0a 43 6f 6e 6e 65 63 74 69 6f 6e 3a 20 63 6c Connection: cl 00000080: 6f 73 65 0d 0a 0d 0a ose NSOCK INFO [0.2610s] nsock_trace_handler_callback(): Callback: WRITE SUCCESS for EID 19 [192.168.1.105:80] NSE: TCP 192.168.1.106:59923 > 192.168.1.105:80 | SEND NSOCK INFO [0.2610s] nsock_read(): Read request from IOD #1 [192.168.1.105:80] (timeout: 8000ms) EID 26 NSOCK INFO [0.2640s] nsock_trace_handler_callback(): Callback: READ SUCCESS for EID 26 [192.168.1.105:80] (392 bytes) NSE: TCP 192.168.1.106:59923 < 192.168.1.105:80 | 00000000: 48 54 54 50 2f 31 2e 31 20 32 30 30 20 4f 4b 0d HTTP/1.1 200 OK 00000010: 0a 44 61 74 65 3a 20 54 75 65 2c 20 33 30 20 53 Date: Tue, 30 S 00000020: 65 70 20 32 30 31 34 20 31 30 3a 30 38 3a 32 34 ep 2014 10:08:24 00000030: 20 47 4d 54 0d 0a 53 65 72 76 65 72 3a 20 41 70 GMT Server: Ap 00000040: 61 63 68 65 2f 32 2e 32 2e 32 32 20 28 44 65 62 ache/2.2.22 (Deb 00000050: 69 61 6e 29 0d 0a 4c 61 73 74 2d 4d 6f 64 69 66 ian) Last-Modif 00000060: 69 65 64 3a 20 54 75 65 2c 20 33 30 20 53 65 70 ied: Tue, 30 Sep 00000070: 20 32 30 31 34 20 30 37 3a 33 30 3a 33 33 20 47 2014 07:30:33 G 00000080: 4d 54 0d 0a 45 54 61 67 3a 20 22 65 31 31 38 31 MT ETag: "e1181 00000090: 2d 37 34 2d 35 30 34 34 33 35 62 64 38 36 62 30 -74-504435bd86b0 000000a0: 32 22 0d 0a 41 63 63 65 70 74 2d 52 61 6e 67 65 2" Accept-Range 000000b0: 73 3a 20 62 79 74 65 73 0d 0a 43 6f 6e 74 65 6e s: bytes Conten 000000c0: 74 2d 4c 65 6e 67 74 68 3a 20 31 31 36 0d 0a 56 t-Length: 116 V 000000d0: 61 72 79 3a 20 41 63 63 65 70 74 2d 45 6e 63 6f ary: Accept-Enco 000000e0: 64 69 6e 67 0d 0a 43 6f 6e 6e 65 63 74 69 6f 6e ding Connection 000000f0: 3a 20 63 6c 6f 73 65 0d 0a 43 6f 6e 74 65 6e 74 : close Content 00000100: 2d 54 79 70 65 3a 20 74 65 78 74 2f 68 74 6d 6c -Type: text/html 00000110: 0d 0a 0d 0a 3c 68 74 6d 6c 3e 0a 3c 68 65 61 64 <html> <head 00000120: 3e 0a 3c 74 69 74 6c 65 3e 41 72 63 74 69 63 46 > <title>ArcticF 00000130: 69 73 73 69 6f 6e 20 31 2e 30 3c 2f 74 69 74 6c ission 1.0</titl 00000140: 65 3e 0a 3c 2f 68 65 61 64 3e 0a 3c 62 6f 64 79 e> </head> <body 00000150: 3e 0a 3c 68 31 3e 57 65 6c 63 6f 6d 65 20 74 6f > <h1>Welcome to 00000160: 20 41 72 63 74 69 63 46 69 73 73 69 6f 6e 20 31 ArcticFission 1 00000170: 2e 30 3c 2f 68 31 3e 0a 3c 2f 62 6f 64 79 3e 0a .0</h1> </body> 00000180: 3c 2f 68 74 6d 6c 3e 0a </html> NSE: TCP 192.168.1.106:59923 > 192.168.1.105:80 | CLOSE NSOCK INFO [0.2660s] nsi_delete(): nsi_delete (IOD #1) Nmap scan report for 192.168.1.105 Host is up (0.00053s latency). PORT STATE SERVICE 80/tcp open http |_http-vuln-check_openssl: Vulnerable 443/tcp closed https Nmap done: 1 IP address (1 host up) scanned in 0.27 seconds |
local shortport = require "shortport" local http = require "http" local stdnse = require "stdnse" local string = require "string" -- The Rule Section -- portrule = shortport.http -- The Action Section -- action = function(host, port) local uri = "/arcticfission.html" local options = {headers={}} options['headers']['User-Agent'] = "Mozilla/5.0 (compatible; ArcticFission)" local response = http.get(host, port, uri, options) if ( response.status == 200 ) then local title = string.match(response.body, "<[Tt][Ii][Tt][Ll][Ee][^>]*>ArcticFission ([^<]*)</[Tt][Ii][Tt][Ll][Ee]>") if ( title == "1.0" ) then return "Vulnerable" else return "Not Vulnerable" end end end |
漏洞管理 |
上述漏洞发现脚本有些问题。首先,它没有漏洞相关的描述信息,其次,完成扫描后,你需要编写脚本解析整个扫描结果。上面的这些,可以用Nmap的库'vulns'进行处理。 |
NSE漏洞库 |
-- The Head Section -- description = [[Sample script to detect a fictional vulnerability in a fictional ArcticFission 1.0 web server]] --- -- @usage -- nmap --script http-vuln-check <target> -- @output -- PORT STATE SERVICE -- 80/tcp open http -- |_http-vuln-check_packaging: Vulnerable -- | VULNERABLE -- | ArcticFission 1.0 Vulnerability -- | State: VULNERABLE -- | IDs: CVE:CVE-XXXX-XX -- | References: -- |_ http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-XXXX-XX author = "iphelix" license = "Same as Nmap -- See http://nmap.org/book/man-legal.html" categories = {"default", "safe"} local shortport = require "shortport" local http = require "http" local stdnse = require "stdnse" local string = require "string" local vulns = require "vulns" -- The Rule Section -- portrule = shortport.http -- The Action Section -- action = function(host, port) -- The Vuln Definition Section -- local vuln = { title = "ArcticFission 1.0 Vulnerability", state = vulns.STATE.NOT_VULN, IDS = { CVE = 'CVE-XXXX-XXX' } } local report = vulns.Report:new(SCRIPT_NAME, host, port) local uri = "/arcticfission.html" local options = {header={}} options['header']['User-Agent'] = "Mozilla/5.0 (compatible; ArcticFission)" local response = http.get(host, port, uri, options) if ( response.status == 200) then local title = string.match(response.body, "<[Tt][Ii][Tt][Ll][Ee]>ArcticFission ([^<]*)</[Tt][Ii][Tt][Ll][Ee]>") if ( title == "1.0" ) then vuln.state = vulns.STATE.VULN else vuln.state = vulns.STATE.NOT_VULN end end return report:make_output(vuln) end |
扫描结果如下: |
offensive@security:~/nmap_nse$ nmap -p 80,443 --script /home/offensive/nmap_nse/http-vuln-check_packaging.nse 192.168.1.105 Starting Nmap 6.47 ( http://nmap.org ) at 2014-09-30 10:22 EDT Nmap scan report for localhost (192.168.1.105) Host is up (0.00053s latency). PORT STATE SERVICE 80/tcp open http | http-vuln-check_packaging: | VULNERABLE: | ArcticFission 1.0 Vulnerability | State: VULNERABLE | IDs: CVE:CVE-XXXX-XXX | References: |_ http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-XXXX-XXX 443/tcp closed https Nmap done: 1 IP address (1 host up) scanned in 0.07 seconds |
从这里获取了什么 |
我希望你能够对上面我提到的Nmap脚本感到兴奋。最好的办法就是学习库相关的文档,并编写一些复杂的脚本,不局限于http。Nmap是一款强大的工具,强大的脚本库及开源的社区支持,会促使其变成一款强大的漏洞扫描器。感谢,Fyodor和所有的Nmap开发者。 |
参考链接 |