關(guān)于libnmap 的一些應(yīng)用

隨筆描述

nmap 可以進(jìn)行端口的掃描,在安全或運(yùn)維中可以說是一款不錯(cuò)的神奇吧,在大部分LINUX 里面都自帶了nmap 這款工具,他不僅僅是端口掃描,自身還提供許多插件可以使用。

官方文檔

nmap 官方文檔
github文檔

說說libnmap

libnmap是一個(gè)python庫,使python開發(fā)人員能夠操縱nmap進(jìn)程和數(shù)據(jù)。

如果您需要實(shí)現(xiàn)以下操作,則libnmap是您要查找的內(nèi)容:

  1. 定期自動(dòng)或安排nmap掃描
  2. 操縱nmap掃描結(jié)果進(jìn)行報(bào)告
  3. 比較和差異nmap掃描生成圖
  4. 批處理掃描報(bào)告
    ...
    上述用例將在libnmap模塊的幫助下輕松實(shí)現(xiàn)。

nmap 的模塊

github
lib目前提供以下模塊:

  • 過程:使您能夠啟動(dòng)nmap掃描
  • 解析:使您能夠從文件,字符串...中解析nmap報(bào)告或掃描結(jié)果(到目前為止只有XML)
  • 報(bào)告:使您能夠操作解析的掃描結(jié)果,并以json格式對(duì)掃描結(jié)果進(jìn)行序列化
  • diff:使您能夠看到兩次掃描之間發(fā)生了什么變化
  • common:包含基本的nmap對(duì)象,如NmapHost和NmapService。要注意的是,每個(gè)對(duì)象都可以與另一個(gè)類似的對(duì)象“diff()ed”。
  • 插件:使您能夠直接在“NmapReport”對(duì)象中支持掃描結(jié)果的數(shù)據(jù)存儲(chǔ)。從報(bào)告模塊:

開始應(yīng)用

簡(jiǎn)單的例子

rom libnmap.process import NmapProcess
from libnmap.parser import NmapParser

nm = NmapProcess("127.0.0.1",options="-sV  -p 22")
nm.run()

nmap_report = NmapParser.parse(nm.stdout)

for scanned_hosts in nmap_report.hosts:
    print scanned_hosts
x=[ [a, [ b.address for b in nmap_report.hosts for c in b.get_open_ports() if a==c[0] ] ] for a in sorted(set([ b[0] for a in nmap_report.hosts for b in a.get_open_ports()]),key=int) ]
print  x
y=sorted(set([ b[0] for a in nmap_report.hosts for b in a.get_open_ports()]), key=int)
#print y

運(yùn)行的結(jié)果:

結(jié)果

主要參數(shù)的介紹

  • NmapProcess 開始一個(gè)掃描任務(wù)
  • NmapParser 對(duì)掃描的結(jié)果進(jìn)行處理,實(shí)例化

端口信息

開放指定端口號(hào)的主機(jī)

  • 顯示所有開放指定端口號(hào)的主機(jī)。生成一個(gè)包含主機(jī)地址(string)的列表。下面以 443 端口為例,你可以修改成你自己需要的值。

[ a.address for a in nmap_report.hosts if (a.get_open_ports()) and 443 in [b[0] for b in a.get_open_ports()] ]
開放端口數(shù)量


- 顯示一系列主機(jī)開放端口的數(shù)量。生成一個(gè)包含端口數(shù)量(int)的列表,并進(jìn)行排序。

sorted(set([ b[0] for a in nmap_report.hosts for b in a.get_open_ports()]), key=int)

### 主機(jī)開放端口對(duì)應(yīng)的服務(wù),按端口號(hào)進(jìn)行分組

- 顯示所有主機(jī)開放的端口號(hào),按端口號(hào)進(jìn)行分組和排序。生成一個(gè)包含多個(gè)列表的列表(即列表的每個(gè)元素也為列表),其中每個(gè)成員列表第一個(gè)元素為端口號(hào)(int),第二個(gè)元素為一個(gè)包含開放對(duì)應(yīng)端口主機(jī) IP 地址(string)的列表。

[ [a, [ b.address for b in nmap_report.hosts for c in b.get_open_ports() if a==c[0] ] ] for a in sorted(set([ b[0] for a in nmap_report.hosts for b in a.get_open_ports()]),key=int) ]

###SSL/TLS 和 HTTP/HTTPS

- 使用 SSL 的主機(jī)和端口
顯示所有使用 SSL 的主機(jī)和端口。這是通過查找是否有服務(wù)使用了 “SSL” 通道或者相關(guān)腳本檢測(cè)的結(jié)果中包含 pem 證書。生成一個(gè)包含一系列列表的列表,每個(gè)成員列表中包含主機(jī)地址(string)和端口號(hào)(int)。

[ [a.address, b.port] for a in nmap_report.hosts for b in a.services if b.tunnel=='ssl' or "'pem'" in str(b.scripts_results) ]


- 下面的內(nèi)容包含上述相同的信息,但不在是一個(gè)包含列表的列表,而是使用 join 函數(shù)創(chuàng)建了一個(gè)包含 “主機(jī):端口號(hào)”(string) 的列表。

[ ':'.join([a.address, str(b.port)]) for a in nmap_report.hosts for b in a.services if b.tunnel=='ssl' or "'pem'" in str(b.scripts_results) ]
包含 web 服務(wù)的主機(jī)和端口


- 顯示所有的 web 服務(wù)及其對(duì)對(duì)應(yīng)的端口號(hào)和協(xié)議(http 或 https)。這會(huì)生成一個(gè)包含多個(gè)列表的列表,其中每個(gè)成員列表包含協(xié)議(string)、地址(string)和端口號(hào)(int)。但這里會(huì)有些問題,nmap 在報(bào)告使用 https 的網(wǎng)站時(shí),有些時(shí)候會(huì)顯示服務(wù)是 “https”,而有時(shí)則會(huì)顯示為使用 “ssl” 通道的 “http”,所以我調(diào)整了下數(shù)據(jù)格式以便統(tǒng)一輸出。

[ [(b.service + b.tunnel).replace('sl',''), a.address, b.port] for a in nmap_report.hosts for b in a.services if b.open() and b.service.startswith('http') ]

- 這里還是相同的信息,只不過是在原先包含協(xié)議、主機(jī)和端口號(hào)的列表中增加了url(string)。

[ (b.service + b.tunnel).replace('sl','') + '://' + a.address + ':' + str(b.port) + '/' for a in nmap_report.hosts for b in a.services if b.open() and b.service.startswith('http') ]

### 其他服務(wù)信息

未知服務(wù)

- 顯示所有 nmap 無法識(shí)別的服務(wù)。生成一個(gè)包含多個(gè)列表的列表,其中每個(gè)成員列表包含地址(string)、端口號(hào)(int)和 nmap 掃描的端口指紋(string)。生成這些信息,主要是為了方便后續(xù)人工審查那些特定的服務(wù),而不會(huì)參與到任何自動(dòng)化的過程中。

[ [ a.address, b.port, b.servicefp ] for a in nmap_report.hosts for b in a.services if (b.service =='unknown' or b.servicefp) and b.port in [c[0] for c in a.get_open_ports()] ]

### nmap 識(shí)別出的軟件

- 顯示 nmap 掃描中識(shí)別出的所有軟件。生成按產(chǎn)品字母排序的列表。

sorted(set([ b.banner for a in nmap_report.hosts for b in a.services if 'product' in b.banner]))

### 軟件對(duì)應(yīng)的主機(jī)和端口號(hào),按產(chǎn)品分組

- 顯示掃描出軟件對(duì)應(yīng)的主機(jī)和端口,按產(chǎn)品分組。生成一個(gè)包含多個(gè)列表的列表,其中每個(gè)成員列表的第一個(gè)元素為軟件的名稱(string),隨后是另一個(gè)列表包含地址(string)和端口號(hào)(int)。

[ [ a, [ [b.address, c.port] for b in nmap_report.hosts for c in b.services if c.banner==a] ] for a in sorted(set([ b.banner for a in nmap_report.hosts for b in a.services if 'product' in b.banner])) ]

- 同上相同的信息,只是輸出略有不同。同樣還是生成一個(gè)包含多個(gè)列表的列表,成員列表的第一個(gè)元素還是軟件的名稱(string),但第二個(gè)是一個(gè)包含 “主機(jī):端口號(hào)” 的列表。

[ [ a, [ ':'.join([b.address, str(c.port)]) for b in nmap_report.hosts for c in b.services if c.banner==a] ] for a in sorted(set([ b.banner for a in nmap_report.hosts for b in a.services if 'product' in b.banner])) ]


### 搜索指定關(guān)鍵詞相關(guān)的主機(jī)和端口
- 顯示所有與給定關(guān)鍵詞相關(guān)聯(lián)的主機(jī)和端口,從 nmap 掃描結(jié)果的原始文本中查找包含產(chǎn)品名稱、服務(wù)名稱等等。下面以 “Oracle” 為例。生成一個(gè)包含多個(gè)列表的列表,其中每個(gè)成員列表包含主機(jī)地址(string)和端口號(hào)(int)。

[ [a.address, b.port] for a in nmap_report.hosts for b in a.services if b.open() and 'Oracle' in str(b.get_dict()) + str(b.scripts_results) ]

## 掃描結(jié)果生產(chǎn)JSON 對(duì)象

from libnmap.parser import NmapParser
from libnmap.reportjson import ReportDecoder, ReportEncoder
import json
nmap_report_obj = NmapParser.parse_fromfile('/root/ip.xml')

create a json object from an NmapReport instance

nmap_report_json = json.dumps(nmap_report_obj, cls=ReportEncoder)
print(nmap_report_json)

create a NmapReport instance from a json object

nmap_report_obj = json.loads(nmap_report_json, cls=ReportDecoder)
print(nmap_report_obj)


![結(jié)果](http://upload-images.jianshu.io/upload_images/3941016-7e499ab039f3d1e4.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

## 函數(shù)化例子

!/usr/bin/env python

-- coding: utf-8 --

from libnmap.process import NmapProcess
from libnmap.parser import NmapParser, NmapParserException

start a new nmap scan on localhost with some specific options

def do_scan(targets, options):
parsed = None
nmproc = NmapProcess(targets, options)
rc = nmproc.run()
if rc != 0:
print("nmap scan failed: {0}".format(nmproc.stderr))
print(type(nmproc.stdout))

try:
    parsed = NmapParser.parse(nmproc.stdout)
except NmapParserException as e:
    print("Exception raised while parsing scan: {0}".format(e.msg))

return parsed

print scan results from a nmap report

def print_scan(nmap_report):
print("Starting Nmap {0} ( http://nmap.org ) at {1}".format(
nmap_report.version,
nmap_report.started))

for host in nmap_report.hosts:
    if len(host.hostnames):
        tmp_host = host.hostnames.pop()
    else:
        tmp_host = host.address

    print("Nmap scan report for {0} ({1})".format(
        tmp_host,
        host.address))
    print("Host is {0}.".format(host.status))
    print("  PORT     STATE         SERVICE")

    for serv in host.services:
        pserv = "{0:>5s}/{1:3s}  {2:12s}  {3}".format(
                str(serv.port),
                serv.protocol,
                serv.state,
                serv.service)
        if len(serv.banner):
            pserv += " ({0})".format(serv.banner)
        print(pserv)
print(nmap_report.summary)

if name == "main":
report = do_scan("127.0.0.1", "-sV")
if report:
print_scan(report)
else:
print("No results returned")

## 把nmap掃描結(jié)果存儲(chǔ)到數(shù)據(jù)庫
- 主的運(yùn)行的腳本

import xml.etree.ElementTree as ET
import MySQLdb
import datetime
nmapdb = MySQLdb.connect(host="134.96.111.202", user="root", passwd="admin2017", db="nmap")
cursor = nmapdb.cursor()
hostsql = "INSERT INTO hosts (timeofscan,ipaddress,hostname,osname,accuracy) values(%s,%s,%s,%s,%s);"
portsql = "INSERT INTO ports (timeofscan,ipaddress,protocol,portid,state,reason,reason_ttl,servicename) values(%s,%s,%s,%s,%s,%s,%s,%s);"
tree = ET.parse('/root/ip.xml')
root = tree.getroot()
for host in root.iter('host'):
hosts=[]
timescan = int(host.get('starttime'))
timeof = (datetime.datetime.fromtimestamp(timescan).strftime('%Y-%m-%d %H:%M:%S'))
for address in host.iter('address'):
addr = address.get('addr')
for hostnames in host.iter('hostnames'):
if len(hostnames.findall('hostname')) > 0:
for hostname in host.iter('hostname'):
hostn = hostname.get('name')
else:
hostn = "none"
for os in host.iter('osmatch'):
osname = os.get('name')
accuracy = os.get('accuracy')
hosts.append(timeof)
hosts.append(addr)
hosts.append(hostn)
hosts.append(osname)
hosts.append(accuracy)
cursor.execute(hostsql,hosts)
for port in host.iter('port'):
ports=[]
ports.append(timeof)
ports.append(addr)
ports.append(port.get('protocol'))
ports.append(port.get('portid'))
for state in port.iter('state'):
ports.append(state.get('state'))
ports.append(state.get('reason'))
ports.append(state.get('reason_ttl'))
for service in port.iter('service'):
ports.append(service.get('name'))
cursor.execute(portsql,ports)
nmapdb.commit()
cursor.close()
nmapdb.close()


-  數(shù)據(jù)庫sql 文件

CREATE DATABASE IF NOT EXISTS nmap;

USE nmap;

CREATE TABLE IF NOT EXISTS hosts (
id int(11) NOT NULL AUTO_INCREMENT,
timeofscan datetime NOT NULL,
ipaddress varchar(15) NULL,
hostname varchar(40) NULL,
osname varchar(200) NULL,
accuracy int(4) NULL,
PRIMARY KEY (id)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

CREATE TABLE IF NOT EXISTS `ports` (
    `id` int(11) NOT NULL AUTO_INCREMENT,
    `timeofscan` datetime NOT NULL,
    `ipaddress` varchar(15) NULL,
    `protocol` varchar(20) NULL,
    `portid` int(10) NULL,
    `state` varchar(20) NULL,
    `reason` varchar(20) NULL,
    `reason_ttl` int(10) NULL,
    `servicename` varchar(20) NULL,
    PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

TRUNCATE hosts;
TRUNCATE ports;


### 后話可以配合數(shù)據(jù)庫web 做圖表展示



![圖表展示](http://upload-images.jianshu.io/upload_images/3941016-c96442d3c8518567.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)


![數(shù)據(jù)庫信息](http://upload-images.jianshu.io/upload_images/3941016-112525984c212336.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)



![nmap web開發(fā)](http://upload-images.jianshu.io/upload_images/3941016-d784216cc2c7d489.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

























最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • nmap使用指南(終極版) 原創(chuàng)2017-09-09hl0rey信安之路 一、目標(biāo)指定 1.CIDR標(biāo)志位 192...
    用電熱毯烤豬閱讀 12,150評(píng)論 1 49
  • Nmap掃描原理與用法 1Nmap介紹 Nmap掃描原理與用法PDF:下載地址 Nmap是一款開源免費(fèi)的網(wǎng)絡(luò)發(fā)現(xiàn)(...
    y0ungta1a閱讀 5,532評(píng)論 0 50
  • Nmap輸出的是掃描目標(biāo)的列表,以及每個(gè)目標(biāo)的補(bǔ)充信息,至于是哪些信息則依賴于所使用的選項(xiàng)。“所感興趣的端口表格...
    令狐沖233閱讀 2,100評(píng)論 0 4
  • 入冬之后有過三場(chǎng)雪,每一次都把整個(gè)世界包裹在白色的禮盒里,炫的讓人睜不開眼睛。 每次天氣昏昏沉沉的...
    朕是正閱讀 254評(píng)論 1 0
  • 拉大片的老頭 在端村有一個(gè)去世的老藝人,說起他,八十年代出生的小孩都認(rèn)識(shí)。他經(jīng)常拉著一個(gè)大片車出現(xiàn)在大街上,集...
    淺一點(diǎn)不驚濃艷閱讀 512評(píng)論 0 3

友情鏈接更多精彩內(nèi)容