一、NSE介紹

  雖然Nmap內(nèi)嵌的服務(wù)于版本探測(cè)已足夠強(qiáng)大,但是在某些情況下我們需要多倫次的交互才能夠探測(cè)到服務(wù)器的信息,這時(shí)候就需要自己編寫NSE插件實(shí)現(xiàn)這個(gè)功能。NSE插件能夠完成網(wǎng)絡(luò)發(fā)現(xiàn)、復(fù)雜版本探測(cè)、脆弱性探測(cè)、簡(jiǎn)單漏洞利用等功能。

  轉(zhuǎn)載請(qǐng)注明出處:http://www.cnblogs.com/liun1994/

  在文章   "Nmap腳本文件分析(AMQP協(xié)議為例)"   中會(huì)將版本探測(cè),NSE腳本原理聯(lián)系起來,具體分析Nmap探測(cè)的執(zhí)行過程。

  在文章  " 編寫自己的NSE腳本"  中將以一個(gè)簡(jiǎn)單的例子說明NSE的編寫。

萬碼學(xué)堂,電腦培訓(xùn),計(jì)算機(jī)培訓(xùn),Java培訓(xùn),JavaEE開發(fā)培訓(xùn),青島軟件培訓(xùn),軟件工程師培訓(xùn)

腳本掃描通過選項(xiàng)被激活 -sC: 使通用scripts生效 --script: 指定自己的腳本文件 --script-trace: 查看腳本執(zhí)行過程 -A: 同時(shí)進(jìn)行版本探測(cè)和腳本掃描 為了不進(jìn)行主機(jī)發(fā)現(xiàn)也不進(jìn)行端口掃描,直接使用自定義的腳本探測(cè)??梢允褂孟旅娴倪x項(xiàng): -Pn -sn --script --script-args和--script-args-file,指定腳本要讀入的參數(shù)
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

萬碼學(xué)堂,電腦培訓(xùn),計(jì)算機(jī)培訓(xùn),Java培訓(xùn),JavaEE開發(fā)培訓(xùn),青島軟件培訓(xùn),軟件工程師培訓(xùn)

  腳本文件分類:brute、default、dos、safe、exploit等,具體的可查看:https://nmap.org/book/nse-usage.html#nse-categories

  根據(jù)腳本的運(yùn)行階段不同分為四類:Prerule scripts、Host scripts、Service scripts、Postrule scripts。

  應(yīng)用最多的就是Service scripts,Post scripts對(duì)Nmap輸出進(jìn)行格式化輸出,Host scripts這個(gè)階段在Nmap運(yùn)行完主機(jī)發(fā)現(xiàn)、端口掃描、版本探測(cè)、OS偵測(cè)后執(zhí)行;Prerule scripts執(zhí)行一些資源操作,先于各探測(cè)執(zhí)行。

二、Nmap執(zhí)行原理圖

萬碼學(xué)堂,電腦培訓(xùn),計(jì)算機(jī)培訓(xùn),Java培訓(xùn),JavaEE開發(fā)培訓(xùn),青島軟件培訓(xùn),軟件工程師培訓(xùn)


  由上圖可以看到四類腳本的運(yùn)行階段,以及他們的功能。

  1)在nmap_main里面,調(diào)用init_main()進(jìn)行詳細(xì)的初始化過程,加載Lua標(biāo)準(zhǔn)庫與Nmap擴(kuò)展庫,準(zhǔn)備參數(shù)環(huán)境,加載并執(zhí)行nse_main.lua文件;這個(gè)文件加載用戶選擇的腳本文件,執(zhí)行完之后返回函數(shù)對(duì)象給init_main(),被保存到Lua注冊(cè)表中。

  2)在nse_main.lua中,定義兩個(gè)核心的類,Script和Thread,Script用于管理NSE腳本,當(dāng)新的腳本被加載時(shí),調(diào)用 Script.new創(chuàng)建腳本對(duì)象,該對(duì)象被保存下來在后續(xù)的掃描過程中使用;Thread用于管理腳本的執(zhí)行,該類中也包含對(duì)腳本健全性的檢查。在腳本執(zhí)行時(shí),如果腳本之間存在依賴關(guān)系,那么會(huì)將基礎(chǔ)的無依賴的腳本統(tǒng)一執(zhí)行完畢,再執(zhí)行依賴性的腳本。

  3)執(zhí)行腳本掃描時(shí),從nmap_main()中調(diào)用script_scan()函數(shù)。在進(jìn)入script_scan()后,會(huì)標(biāo)記掃描階段類型,然后進(jìn)入到初始化階段返回的main()函數(shù)(來自nse_main.lua腳本中的main)中,在函數(shù)中解析具體的掃描類型。

  4)main()函數(shù)負(fù)責(zé)處理三種類型的腳本掃描:預(yù)掃描(SCRIPT_PRE_SCAN)、腳本掃描(SCRIPT_SCAN)、后掃描 (SCRIPT_POST_SCAN)。預(yù)掃描即在Nmap調(diào)用的最前面(沒有進(jìn)行主機(jī)發(fā)現(xiàn)、端口掃描等操作)執(zhí)行的腳本掃描,通常該類掃描用于準(zhǔn)備基本的信息,例如到第三服務(wù)器查詢相關(guān)的DNS信息。而腳本掃描,是使用NSE腳本來掃描目標(biāo)主機(jī),這是最核心的掃描方式。后掃描,是整個(gè)掃描結(jié)束后,做一些善后處理的腳本,比如優(yōu)化整理某些掃描。

  5)在main()函數(shù)中核心操作由run函數(shù)負(fù)責(zé)。而run()函數(shù)的本身設(shè)計(jì)用于執(zhí)行所有同一級(jí)別的腳本(根據(jù)依賴關(guān)系劃分的級(jí)別),直到所有線程執(zhí)行完畢才退出。run()函數(shù)中實(shí)現(xiàn)三個(gè)隊(duì)列:執(zhí)行隊(duì)列(Running Queue)、等待隊(duì)列(Waiting Queue)、掛起隊(duì)列(Pending Queue),并管理三個(gè)隊(duì)列中線程的切換,直到全部隊(duì)列為空或出錯(cuò)而退出。

三、Nmap API

  數(shù)據(jù)傳遞

  nmap.luadoc是與nmap內(nèi)部函數(shù)交互和數(shù)據(jù)結(jié)構(gòu)化的API,API提供目標(biāo)主機(jī)的詳細(xì)信息例如端口狀態(tài)和版本探測(cè)結(jié)果;同時(shí)API也提供與Nsock交互的接口,這樣方便我們自己寫NSE腳本與服務(wù)器交互,目前文件中共48個(gè)函數(shù)。

  在腳本引擎中,用戶可以輕松訪問Nmap已經(jīng)了解的有關(guān)目標(biāo)主機(jī)的信息。該數(shù)據(jù)作為參數(shù)傳遞給NSE腳本的action方法,參數(shù)host和port是lua表,其中包含腳本執(zhí)行的目標(biāo)的信息。下面介紹每個(gè)表里面所含有的變量。

  nmap使用注冊(cè)表來共享信息,每個(gè)腳本之間共享nmap.registry,每個(gè)主機(jī)還有自己的注冊(cè)表名為host.registry;在整個(gè)掃描會(huì)話中,全局注冊(cè)表始終存在。腳本可以使用它,例如,存儲(chǔ)稍后將由postrule腳本顯示的值。機(jī)注冊(cè)表僅在主機(jī)被掃描時(shí)存在。它們可以用于將信息從一個(gè)腳本發(fā)送到另一個(gè)腳本。例如:1)ssh-hostkey腳本的portrule收集SSH密鑰指紋,并將其存儲(chǔ)在全局nmap.registry中,以便稍后可以由postrule打印。2)ssl-cert腳本收集SSL證書并將其存儲(chǔ)在每個(gè)主機(jī)注冊(cè)表中,以便ssl-google-cert-catalog腳本可以使用它們,而無需再次連接到服務(wù)器。nmap.registry是全局的,因此key選擇很重要;使用另一個(gè)腳本結(jié)果的腳本必須使用dependencies變量來聲明它,以確保先前的腳本首先運(yùn)行。

萬碼學(xué)堂,電腦培訓(xùn),計(jì)算機(jī)培訓(xùn),Java培訓(xùn),JavaEE開發(fā)培訓(xùn),青島軟件培訓(xùn),軟件工程師培訓(xùn)

host.ip host.name         通過dns反向查詢的主機(jī)名,如果沒查到則為空串 host.targetname host.reason:      給出host處于現(xiàn)在這個(gè)狀態(tài)的解釋 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:    字符串表示的運(yùn)行在端口號(hào)上的服務(wù),該服務(wù)由服務(wù)探測(cè)階段探測(cè)出,如果 port.version.service_dtype字段是table,那么Nmap基于端口號(hào)猜測(cè)服務(wù);如果不是table,那么版本探測(cè)階段能夠確定是什么服務(wù),這個(gè)字段的值被設(shè)定為port.version.name port.reason:      字符串解釋處于port.state狀態(tài)的原因。 port.reason_ttl port.version:    這個(gè)字段是一個(gè)表格,包含版本探測(cè)階段返回的全部信息,包括:name;name_confidence;等,具體可參考官方文檔版本探測(cè)章節(jié)。     port.state

參考:https://nmap.org/book/nse-api.htm

萬碼學(xué)堂,電腦培訓(xùn),計(jì)算機(jī)培訓(xùn),Java培訓(xùn),JavaEE開發(fā)培訓(xùn),青島軟件培訓(xùn),軟件工程師培訓(xùn)

  Network I/O API

萬碼學(xué)堂,電腦培訓(xùn),計(jì)算機(jī)培訓(xùn),Java培訓(xùn),JavaEE開發(fā)培訓(xùn),青島軟件培訓(xùn),軟件工程師培訓(xùn)

require("nmap") -- 簡(jiǎn)單的使用Nsock連接服務(wù)器的例子 local socket = nmap.new_socket() socket:set_timeout(1000) 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

萬碼學(xué)堂,電腦培訓(xùn),計(jì)算機(jī)培訓(xùn),Java培訓(xùn),JavaEE開發(fā)培訓(xùn),青島軟件培訓(xùn),軟件工程師培訓(xùn)

四、編寫自己的腳本的建議

  編寫NSE腳本,需要根據(jù)Nmap規(guī)范編寫description,author,license,categories,rule,action字段的內(nèi)容,其中主要是action字段的編寫;如果rule函數(shù)返回結(jié)果為真,那么執(zhí)行編寫的action函數(shù)。

  The Rule

  這部分決定是否執(zhí)行action函數(shù),A prerule or a postrule 類型的腳本總是執(zhí)行;在端口規(guī)則腳本里面,NSE僅給我們當(dāng)前掃描端口的信息,比如一個(gè)腳本要執(zhí)行,但是必須保證當(dāng)前端口開啟并且113端口開啟,為了檢測(cè)113端口是否開啟,我們使用nmap.get_port_state這個(gè)函數(shù),如果113端口沒有被掃描,函數(shù)將返回nil。

萬碼學(xué)堂,電腦培訓(xùn),計(jì)算機(jī)培訓(xùn),Java培訓(xùn),JavaEE開發(fā)培訓(xùn),青島軟件培訓(xùn),軟件工程師培訓(xùn)

portrule = function(host, port)     local auth_port = { number=113, 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

萬碼學(xué)堂,電腦培訓(xùn),計(jì)算機(jī)培訓(xùn),Java培訓(xùn),JavaEE開發(fā)培訓(xùn),青島軟件培訓(xùn),軟件工程師培訓(xùn)

  The Action

  腳本首先連接到我們探測(cè)的端口,通過調(diào)用nmap.new_socket創(chuàng)建兩個(gè)套接字選項(xiàng)。接下來,我們定義一個(gè)錯(cuò)誤處理捕獲功能,如果檢測(cè)到故障,則關(guān)閉這些套接字。此時(shí)我們可以安全地使用諸如打開,關(guān)閉,發(fā)送和接收的對(duì)象方法來在網(wǎng)絡(luò)套接字上操作。在這種情況下,我們調(diào)用connect來建立連接。 NSE的異常處理機(jī)制用于避免過多的錯(cuò)誤處理代碼。 try用來包圍可能出錯(cuò)的代碼,如果有任何問題,這將調(diào)用catch函數(shù)。如果兩個(gè)連接成功,我們構(gòu)造一個(gè)查詢字符串并解析響應(yīng),最后返回解析結(jié)果。

 

萬碼學(xué)堂,電腦培訓(xùn),計(jì)算機(jī)培訓(xùn),Java培訓(xùn),JavaEE開發(fā)培訓(xùn),青島軟件培訓(xùn),軟件工程師培訓(xùn)

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, 113))         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(1))         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

萬碼學(xué)堂,電腦培訓(xùn),計(jì)算機(jī)培訓(xùn),Java培訓(xùn),JavaEE開發(fā)培訓(xùn),青島軟件培訓(xùn),軟件工程師培訓(xùn)

五、參考文獻(xiàn)

  https://nmap.org/changelog.html#7.50       Nmap各版本更新內(nèi)容

   https://nmap.org/book/nse-tutorial.html      NSE編寫指南

   https://nmap.org/book/nse-api.html           Nmap API

   https://nmap.org/                                       Nmap官網(wǎng)

http://www.cnblogs.com/liun1994/p/7041373.html