Nmap 是一款网络扫描和主机侦测的非常有用的工具。合理使用,不仅可以用来信息收集和枚举,同时也可以用来作为一个漏洞探测器或安全扫描器。另外 Nmap 还跨平台,适用于 Windows、Linux 和 Macintosh 等主流操作系统,功能强大,乃居家旅行之必备良品。
总的来说,Nmap 具有四大功能。
这四大应用乃 Nmap 之精髓,同时它们之间具有逻辑上的顺序关系。首先进行主机判断,发现在指定信道上存活的主机,然后对这些存活的主机进行端口扫描,接着记录这些运行服务的版本号,最后针对不同操作系统我们还可以有不同的具体应对方案,顺手便把对方的操作系统给侦测了。
在这四大基本应用之上,Nmap 还有一些用来规避、绕过防火墙的组合技巧。最后本文将介绍 Nmap 的一个强大的应用模块,名曰 Nmap 脚本引擎(Nmap Script Engine),简称 NSE。在本文中,我们将学习使用 NSE 来干一些本来看起来繁琐的事情,也就是说实现了自动化。
本文实验系统环境为Ubuntu16.04,默认没有安装nmap工具
apt install nmap -y
临时关闭ping(别人无法ping),但使用nmap同样可进行探测,因为nmap不会像ping命令一样发送echo包
echo 1 >/proc/sys/net/ipv4/icmp_echo_ignore_all
nmap 172.17.2.82
分情况:如果是超级用户,无参数扫描等价于 sS 参数扫描(SYN,半连接);否则,无参数扫描等价于 sT 参数扫描(TCP,完整连接)。
nmap -vv 172.17.2.82
按照基本法,v 参数通常表示冗余。我们使用两个 v 参数表示将侦测过程原原本本的打印输出出来。
nmap -p22 172.17.2.222
这里 p 参数表示端口,标准写法后面跟的端口号之间没有空格。但是如果写一个空格也并无妨。
nmap -O 172.17.2.222
nmap -A 172.17.2.222
操作系统侦测有两个参数选项,其一是参数 O,其二是参数 A,后者乃前者的冗余版本。更多的使用 A 参数,以得到更多的信息。
root@docker:~# nmap -sn 172.17.2.222
Starting Nmap 7.01 ( https://nmap.org ) at 2020-03-30 16:02 CST
Nmap scan report for 172.17.2.222
Host is up (0.00057s latency).
MAC Address: 00:0C:29:07:1B:8D (VMware)
主机发现的手段不下几十种,但是最常用的却是 sn 参数,它表示 “使用 ping 扫描来侦测存活的主机,而不进行端口扫描”。
nmap -Pn 172.17.2.222
有时候对方主机开启了防火墙(这是很自然的事情),可能过滤掉了你发送的 ICMP 协议数据包,这样如果想要使用 sn 参数来进行主机发现就不管用了,产生的结果也不可靠。于是你不得不使用 Pn 参数,它假设所有的目标 IP 均为存活,并一个一个主机的进行端口扫描,你懂的这样会牺牲一些时间作为代价。
nmap -sV 172.17.2.222
该选项通过侦测开放的端口来判断开放的服务,并试图检测它的版本。虽然 A 选项也能做到,但是要检测开放的服务版本,sV 一定是最合适的。
nmap -sU 172.17.2.222
之前我们的扫描都是针对 TCP 的,而有些服务却是建立在 UDP 协议上的。比如 NTP(123端口)、SNMP(161端口)等服务,就必须使用 UDP 协议进行扫描。
前面讲的 Pn 选项就可以看成是 sn 选项的逃脱策略。所谓逃脱,就是不让别人发现自己,否则要干的侦测工作还没搞完,就被迫中止岂不让人笑话。
nmap -D 172.17.2.111,172.17.2.222 172.17.2.82
你可以使用 D 选项(英文 decoy)跟一些 IP 地址,IP 和 IP 之间用逗号隔开。这样看起来用来侦测而发送的数据包不仅来自于你的 IP 地址,还来自于这些掩体 IP。这就叫做 “混入其中”。如上面的172.17.2.111,172.17.2.222为掩体IP, 后面的172.17.2.82为扫描的对象
nmap -P0 172.17.2.222
在 2010 年之后,该选项和 PN 选项被一起合并到 Pn 选项之中。但是如果你愿意,你仍然可以使用 P0 选项(P 后面跟的是零)。
sudo proxychains nmap ...
伪装 IP 地址的方法也有很多,比如你可以使用 prxychains 这款工具来实现匿名代理。
nmap -sI 僵尸IP地址[:开放的僵尸端口] IP地址
和 D 选项不同的是,sI 根本不使用你自己的 IP 地址,而是使用空闲的网络资源。这样隐蔽性就更强了。开放的僵尸端口为选填,默认等于 80 端口。具体原理请参考 Nmap 文档。根据这个理论,你不能使用空闲扫描来扫描你自己的主机 IP。在 msfconsole 中,你可以使用 auxiliary/scanner/ip/ipidseq 来完成这个工作。
nmap -e 网卡 IP地址
当你拥有不止一个网卡的时候,这很有用。
nmap --host-timeout 时间 IP地址
限制每个 IP 地址的扫描时间(单位为秒),当要扫描大量的主机 IP 时这很有用。
nmap -S 源IP地址 IP地址
使用冒充的 IP 地址进行扫描以增强隐蔽性。这里伪装成的 IP 也可以来自于下线状态的主机地址。
nmap -g 53 IP地址
使用 g 参数,或者 source-port 参数,来手动设定用来扫描的端口。常用的,如 20、53、67 端口。
nmap -f IP地址
nmap --mtu mtu单元大小 IP地址
上面两种方法都可以利用数据包分片技术,某些防火墙为了加快处理速度而不会进行重组处理,这样从而逃脱防火墙或闯入检测系统的检测。注意,mtu 的值必须是 8 的倍数(如 8、16、24、32 等)。
nmap --data-length 垃圾数据长度 IP地址
一些常见的扫描之数据包是有特定的数据长度的,通过在发送的数据包末尾添加随机的垃圾数据,以达到混淆视听的作效果。
nmap --randomize-hosts IP地址
如果你要扫描大量的,比如成百上千的主机 IP,这很有效。它会打乱扫描顺序,以规避检测系统的检测。
nmap --spoof-mac 伪造MAC IP地址
你可以通过指定供应商的名字来伪装 MAC 地址。可选的名字有 Dell、Apple、3Com。当然也可以手动指定 MAC 地址的值。或者为了简单起见,可以在上面 “伪造IP” 的地方填写数字 0,这将生成一个随机的 MAC 地址。
nmap --badsum IP地址
这将使用伪造的 TCP / UDP / SCTP 校验和发送数据。
nmap -T0 IP地址
T后面跟的数字代表扫描速度,数字越大则速度越快。0~5分别表示:妄想症、鬼鬼祟祟、彬彬有礼、正常、好斗、精神病。
python-nmap模块基于nmap命令,如果是在windows系统上运行该模块,需要先安装nmap工具,linux系统使用以下命令安装:
pip install python-nmap
1:判断主机是否存活
import nmap
nm = nmap.PortScanner()
nm.scan(hosts = '172.17.2.0/24', arguments='-n -sP -PE')
up_hosts = nm.all_hosts() # 获取存活主机列表
print(up_hosts)
2:单个IP扫描
import nmap # 导入 nmap.py 模块
nm = nmap.PortScanner() # 获取 PortScanner 对象
nm.scan('127.0.0.1', '22-443') # 扫描主机 127.0.0.1 端口号 22-443
nm.command_line() # 获取用于扫描的命令行:nmap -oX - -p 22-443 127.0.0.1
nm.scaninfo() # 获取本次扫描的信息 {'tcp': {'services': '22-443', 'method': 'connect'}}
nm.all_hosts() # 获取所有扫描到的主机
nm['127.0.0.1'].hostname() # 获取 127.0.0.1 的主机名
nm['127.0.0.1'].hostnames() # 获取list格式的主机名dict 127.0.0.1 # 如 [{'name':'hostname1', 'type':'PTR'}, {'name':'hostname2', 'type':'user'}]
nm['127.0.0.1'].state() # 获取主机 127.0.0.1 的状态 (up|down|unknown|skipped)
nm['127.0.0.1']['tcp'].keys() # 获取所有tcp端口
nm['127.0.0.1'].all_tcp() # 获取所有tcp端口 (已排序)
nm['127.0.0.1'].all_udp() # 同上
nm['127.0.0.1'].all_ip() # 同上
nm['127.0.0.1'].all_sctp() # 同上
nm['127.0.0.1'].has_tcp(22) # 是否含有主机 127.0.0.1 的 22 端口的信息
nm['127.0.0.1']['tcp'][22] # 获取主机 127.0.0.1 22 端口(tcp)的所有信息
nm['127.0.0.1'].tcp(22) # 获取主机 127.0.0.1 22 端口的所有信息