【技术好文】使用Nmap模块进行扫描脚本的开发

335 阅读4分钟

使用Nmap模块进行网络端口扫描

1、Nmap模块简介

python-nmap是一个帮助使用nmap端口扫描器的python库。它允许轻松操纵nmap进行扫描,并且在扫描后生成对应的结果报告。

Nmap模块安装

pip install python-namp

常见的类与方法

在Nmap模块中,最常使用的就是PortScanner扫描类,这个类实现了Nmap工具功能上的封装。

PortScanner类常用方法

all_hosts():返回扫描后所有主机的列表

analyse_nmap_xml_scan(nmap_xml_output=None, nmap_err='', nmap_err_keep_trace='', nmap_warn_keep_trace=''):分析NMAP xml扫描输出,其中param nmap_xml_output参数是要分析的xml字符串

command_line():返回用于扫描的命令行,命令行返回后可以通过使用nmap工具的方式进行扫描

csv():将CSV输出作为文本返回

get_nmap_last_output():以原始文本返回nmap的最后文本输出

has_host(host):如果主机有结果则返回True,否则返回False

listscan(hosts='127.0.0.1'):不进行扫描,但解释目标主机并返回一个主机列表

nmap_version():如果检测到返回nmap版本

scaninfo():返回扫描过程中的扫描参数{'tcp': {'services': '22', 'method': 'connect'}}

scanstats():返回扫描过程中的历时参数{'uphosts': '3', 'timestr': 'Thu Jun 3 21:45:07 2010', 'downhosts': '253', 'totalhosts': '256', 'elapsed': '5.79'}

scan(hosts='127.0.0.1', ports=None, arguments='-sV', sudo=False):扫描指定的主机,如果nmap输出不是xml,可能会引发PortScannerError异常。

scan方法参数详解

hosts:需要扫描的IP或IP段

ports:扫描的端口

sudo:是否使用sudo启动nmap

arguments`-O`	系统扫描
    `-V,-v,-D,-d,-p`	debug信息
    `–fuzzy`	推测操作系统检测结果
    `-sT`	TCP端口扫描(完整三次握手)
    `-sU`	UDP端口扫描(不回应可能打开,回应则关闭)
    `-sL`	DNS反向解析
    `-sS`	隐藏扫描(半开SYN`-sP`	发现存活主机(直连arp,非直连TCP80ICMP`-sO`	确定主机协议扫描
    `-sW`	对滑动窗口的扫描
    `-sA`	TCP ACK扫描
    `-sN`	关闭主机扫描(不管是否存活直接扫描)
    `-sF`	fin扫描
    `-sX`	Xmas扫描(fin psh urg为置位)
    `-sI`	完全隐藏(以一个跳板为主机(无流量)扫描另一台主机)
    `-sV`	服务器版本
    `-sC`	跟安全有关的脚本
    `-PN`	扫描自己

来自Nmap官方公布的示例代码

>>> import nmap
>>> nm = nmap.PortScanner()
>>> nm.scan('127.0.0.1', '22-443')
>>> nm.command_line()
'nmap -oX - -p 22-443 -sV 127.0.0.1'
>>> nm.scaninfo()
{'tcp': {'services': '22-443', 'method': 'connect'}}
>>> nm.all_hosts()
['127.0.0.1']
>>> nm['127.0.0.1'].hostname()
'localhost'
>>> nm['127.0.0.1'].state()
'up'
>>> nm['127.0.0.1'].all_protocols()
['tcp']
>>> nm['127.0.0.1']['tcp'].keys()
[80, 25, 443, 22, 111]
>>> nm['127.0.0.1'].has_tcp(22)
True
>>> nm['127.0.0.1'].has_tcp(23)
False
>>> nm['127.0.0.1']['tcp'][22]
{'state': 'open', 'reason': 'syn-ack', 'name': 'ssh'}
>>> nm['127.0.0.1'].tcp(22)
{'state': 'open', 'reason': 'syn-ack', 'name': 'ssh'}
>>> nm['127.0.0.1']['tcp'][22]['state']
'open'

>>> for host in nm.all_hosts():
>>>     print('----------------------------------------------------')
>>>     print('Host : %s (%s)' % (host, nm[host].hostname()))
>>>     print('State : %s' % nm[host].state())
>>>     for proto in nm[host].all_protocols():
>>>         print('----------')
>>>         print('Protocol : %s' % proto)
>>>
>>>         lport = nm[host][proto].keys()
>>>         lport.sort()
>>>         for port in lport:
>>>             print ('port : %s\tstate : %s' % (port, nm[host][proto][port]['state']))
----------------------------------------------------
Host : 127.0.0.1 (localhost)
State : up
----------
Protocol : tcp
port : 22   state : open
port : 25   state : open
port : 80   state : open
port : 111  state : open
port : 443  state : open

导出扫描结果信息

>>> print(nm.csv())
host;protocol;port;name;state;product;extrainfo;reason;version;conf
127.0.0.1;tcp;22;ssh;open;OpenSSH;protocol 2.0;syn-ack;5.9p1 Debian 5ubuntu1;10
127.0.0.1;tcp;25;smtp;open;Exim smtpd;;syn-ack;4.76;10
127.0.0.1;tcp;53;domain;open;dnsmasq;;syn-ack;2.59;10
127.0.0.1;tcp;80;http;open;Apache httpd;(Ubuntu);syn-ack;2.2.22;10
127.0.0.1;tcp;111;rpcbind;open;;;syn-ack;;10
127.0.0.1;tcp;139;netbios-ssn;open;Samba smbd;workgroup: WORKGROUP;syn-ack;3.X;10
127.0.0.1;tcp;443;;open;;;syn-ack;;

检测网络状态

>>> nm.scan(hosts='192.168.1.0/24', arguments='-n -sP -PE -PA21,23,80,3389')
>>> hosts_list = [(x, nm[x]['status']['state']) for x in nm.all_hosts()]
>>> for host, status in hosts_list:
>>>     print('{0}:{1}'.host)
192.168.1.0:down
192.168.1.1:up
192.168.1.10:down
192.168.1.100:down
192.168.1.101:down
192.168.1.102:down
192.168.1.103:down
192.168.1.104:down
192.168.1.105:down
[...]

2、使用Nmap开发简型的端口扫描脚本

### 导入Nmap模块
import nmap

### 设计IPV4的正则格式模块和端口的正则格式模块,用于在后续中提取IP地址和端口号
ip_add_pattern = re.compile("^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$")
port_range_pattern = re.compile("([0-9]+)-([0-9]+)")

### 初始化的端口扫描范围
port_min = 0
port_max = 65535

### 维护一个端口列表,用于存放存活的端口号
open_ports = []

while True:
    ### 要求输入一个ip地址
    ip_add_entered = input("\nPlease enter the ip address that you want to scan: ")
    ### 判断Ip地址是否符合要求
    if ip_add_pattern.search(ip_add_entered):
        print(f"{ip_add_entered} is a valid ip address")
        break

while True:
    ### 输入端口号范围
    print("Please enter the range of ports you want to scan in format: <int>-<int> (ex would be 60-120)")
    port_range = input("Enter port range: ")
    port_range_valid = port_range_pattern.search(port_range.replace(" ",""))
    ### 验证端口号是否有效,并且分别提取最低范围端口号和最高范围端口号
    if port_range_valid:
        port_min = int(port_range_valid.group(1))
        port_max = int(port_range_valid.group(2))
        break

### 创建PortScanner扫描类
nm = nmap.PortScanner()
for port in range(port_min, port_max + 1):
    try:
        ### 进行目标ip和端口的扫描
        result = nm.scan(ip_add_entered, str(port))
        ### 端口状态
        port_status = (result['scan'][ip_add_entered]['tcp'][port]['state'])
        ### 打印存活的端口和端口的状态
        print(f"Port {port} is {port_status}")
        ### 将端口号加入到维护的存活列表中
        open_ports.append(port)
    ### 若无法扫描,则会抛出异常
    except:
        print(f"Cannot scan port {port}.")

加入社群

康创护网研习社