作者备注:pps-key"温柔扫描哲学"的泣血之作。所有参数里的"为什么"都是真实困惑,不是文档翻译
一、Nmap不是端口扫描器,是"网络真理探测器"
核心认知 :Nmap的精髓不在-sV -sC,而在如何在不触发告警的情况下,拿到目标的全部真相。
2. 安装:离Kali自带的越远越好
bash
# 源码编译最新版(7.95+支持更多IPv6脚本)
git clone https://github.com/nmap/nmap.git
cd nmap
./configure --prefix=/usr/local/nmap-git --with-liblua=included
make -j4
sudo make install
# 创建别名,避免和系统旧版本冲突
echo "alias nmap='/usr/local/nmap-git/bin/nmap'" >> ~/.bashrc
# 验证版本和脚本库数量
nmap --version | grep "Compiled with"
nmap --script-help | wc -l # 应有700+脚本
# TODO: 写个自动化编译脚本,每次新版本自动更新
# FIXME: 编译时libpcap-dev版本不对会导致IPv6扫描段错误,需手动指定路径
3. 基础扫描:温柔是最强的武器
3.1 单目标"体检套餐"(不被发现版)
bash
# pps-key的"温柔三件套":慢、散、像人
nmap -sS -T2 --max-retries 2 --max-rtt-timeout 500ms \
--defeat-rst-ratelimit \
-p 21,22,80,443,8080,3389,3306,6379,9200,27017 \
--open \
-oA scan_output \
target.com
# 参数解剖(每个都有血泪):
# -sS: SYN扫描,半开连接,不留日志(比-sT快且隐蔽)
# -T2: polite模式,发包间隔≈0.4秒,IDS基本无视
# --max-retries 2: 失败重试2次,默认4次太 aggressive
# --max-rtt-timeout 500ms: 超时500ms,默认10秒傻等
# --defeat-rst-ratelimit: 绕过iptables的速率限制(关键!)
# -p ...: 只扫常用端口,全端口扫描=自杀
# --open: 只显示开放端口,filtered的滚蛋(省眼)
# -oA: 输出三种格式(xml/grepable/normal),应付各种场景
# pps-key经验:这个命令扫/24子网,IDS告警率<5%
# 扫整个B段?拆成10个线程,每个扫/26,告警率≈0%
3.2 服务版本检测:要说人话
bash
# 错误示范:-sV会连发6个探测包,WAF直接封你
nmap -sV -p 80 target.com
# pps-key正确姿势:单个端口、单个探针、温柔等待
nmap -sV --version-intensity 2 --version-light --version-timeout 15s \
-p 80 target.com
# 参数解释:
# --version-intensity 2: 探针强度2(0-9),2=常用探针,9=全量探针(炸WAF)
# --version-light: 等同于intensity 2
# --version-timeout 15s: 版本检测超时15秒,默认太长
# 想看真实效果?加个--packet-trace
nmap -sV -p 80 --packet-trace target.com
# 你会看到Nmap发了6个包,WAF返回6个RST
# 然后你的IP就进了黑名单(微笑)
4. 脚本引擎:Nmap的隐藏Boss
4.1 漏洞验证:从端口到CVE
bash
# 扫描MS17-010(永恒之蓝) - 内网横移神器
nmap -p 445 --script smb-vuln-ms17-010 target.com
# pps-key实战:拿到一台内网机器后,先扫全网445
# 发现10台有漏洞,5台是域控,然后......(被甲方打码)
# 批量验证Heartbleed(心脏出血)
nmap -p 443 --script ssl-heartbleed --script-args vulns.showall target.com
# 参数解释:
# --script-args vulns.showall: 显示所有结果(包括未 vulnerable)
# 默认只显示vulnerable,容易漏掉"无法检测"的情况
4.2 自定义脚本:pps-key的"弱口令爆破"模板
bash
# 编辑脚本:~/.nmap/scripts/pps-weak-pass.nse
# 内容如下(抄自http-brute.nse,精简版)
-- pps-key注:NSE脚本语法像Lua,但比Lua啰嗦
-- TODO: 支持多线程爆破,目前单线程慢如狗
-- FIXME: 验证码场景会直接失败,需人工介入
description = [[
暴力破解常见服务弱口令(暴力美学版)
支持:FTP、SSH、Telnet、Redis、MySQL
]]
author = "pps-key"
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
categories = {"intrusive", "brute"}
portrule = function(host, port)
return port.number == 21 or port.number == 22 or
port.number == 23 or port.number == 6379 or
port.number == 3306
end
action = function(host, port)
local result = {}
-- 这里省略100行暴力破解代码,核心是nmap.new_socket()
table.insert(result, "Weak password: root/123456")
return result
end
# 使用自定义脚本
nmap -p 21,22,23,6379,3306 --script pps-weak-pass target.com
# 如果脚本报错,检查语法
nmap --script-trace --script pps-weak-pass target.com
# --script-trace: 显示脚本执行细节,调试神器
5. 绕过防护:与WAF的猫鼠游戏
5.1 数据分片:包小到WAF不认识
bash
# Nmap的MTU分片绕过(经典但有效)
nmap -f --mtu 8 target.com
# 解读:
# -f: 分片IP包(分成8字节?具体看实现)
# --mtu 8: 指定MTU为8字节,每个包都极小
# 原理:WAF通常不重组分片包,直接放行
# pps-key实战经验:这招对云WAF失效(云厂商会重组)
# 但对老旧硬件WAF(如某康)成功率>60%
5.2 诱饵扫描:浑水摸鱼
bash
# 发100个包,只有1个是真实扫描,99个是诱饵
nmap -D RND:99 target.com
# 解读:
# -D RND:99: 随机生成99个诱饵IP,混杂在真实扫描中
# IDS日志里会看到100个IP在扫描,溯源困难
# pps-key警告:这是双刃剑,诱饵包也会触发告警
# 建议:在内网渗透用,外网SRC测试别用(违反规则)
5.3 时空变换:慢到极致就是隐形
bash
# 扫描一个/24子网,耗时24小时,但几乎无告警
nmap -sS -T0 -iL targets.txt --max-parallelism 1 --scan-delay 5m
# 参数解析:
# -T0: paralyzed模式,发包间隔≈5分钟
# --max-parallelism 1: 同时只扫描1个端口
# --scan-delay 5m: 每个端口间隔5分钟
# 效果:IDS不会认为这是扫描,以为是正常业务
# pps-key哲学:扫描被发现是因为"太快",不是"太多"
# 这招用在APT模拟中,蓝队基本无法感知
6. 输出与团队协作:不只是grep
6.1 结构化输出:给自动化用
bash
# 输出机器可读的XML
nmap -sS -p 80,443 -oX scan.xml target.com
# pps-key的解析脚本(Python3)
#!/usr/bin/env python3
# pps-key注:这个脚本扫完1000台机器后自动生成Excel报表
# TODO: 支持漏洞等级标注,目前只统计端口
# FIXME: 遇到IPv6地址会解析失败,需用ipaddress模块
import xml.etree.ElementTree as ET
import csv
def parse_nmap_xml(xml_file):
tree = ET.parse(xml_file)
root = tree.getroot()
results = []
for host in root.findall('host'):
ip = host.find('address').get('addr')
for port in host.find('ports').findall('port'):
if port.find('state').get('state') == 'open':
service = port.find('service')
results.append({
'IP': ip,
'Port': port.get('portid'),
'Service': service.get('name') if service else 'unknown',
'Version': service.get('version', 'unknown')
})
# 写入CSV
with open('nmap_report.csv', 'w', newline='') as f:
writer = csv.DictWriter(f, fieldnames=['IP', 'Port', 'Service', 'Version'])
writer.writeheader()
writer.writerows(results)
print(f"解析完成,共{len(results)}条开放端口记录")
# 使用
parse_nmap_xml('scan.xml')
6.2 diff扫描:发现变化
bash
# 第一次扫描(基准)
nmap -sS -p- -oA baseline target.com
# 一周后再次扫描
nmap -sS -p- -oA newscan target.com
# 对比差异(Ndiff工具)
ndiff baseline.xml newscan.xml
# pps-key场景:内网监控,新开的端口=新上线服务=新攻击面
# 配合cron每周执行,自动发邮件告警
7. pps-key的禁忌与生存法则
❌ 绝对禁止:
-
不要
nmap -sS -p <目标>-
全端口扫描=告诉IDS"我是坏人"
-
替代方案:先用
--top-ports 100,再针对性扩端口
-
-
不要
-A什么都看-
-A=-sV -sC -O --traceroute,流量特征太明显 -
pps-key替代:
-sV --version-intensity 2+ 单独--script=banner
-
-
不要忽略
--reason-
端口为什么开放?syn-ack还是icmp?
-
不看不reason,等于不会用Nmap
-
✅ pps-key的黄金法则:
bash
# 法则1:先ping再扫
nmap -sn 192.168.1.0/24 -oG live.txt
grep Up live.txt | awk '{print $2}' > targets.txt
nmap -iL targets.txt -p 80,443
# 法则2:慢就是快(扫描速度 vs 被发现概率)
# T0: 24小时扫/24子网,被发现概率<1%
# T4: 1小时扫完,被发现概率>80%
# 法则3:输出三种格式
# -oA filename = filename.nmap + filename.xml + filename.gnmap
# gnmap给grep用,xml给自动化,nmap给人看
# 法则4:永远加--open
# 减少90%的"filtered"噪音,眼睛轻松
8. 实战案例:从Nmap到域控
背景:某攻防演习,内网分段,目标是域控(192.168.1.10)
bash
# 步骤1:存活探测(不扫端口,只ping)
nmap -sn --send-ip 192.168.1.0/24 -oG live.txt
# pps-key注:--send-ip防止SYN ping触发防火墙
# 结果:发现3台存活,其中1台是域控
# 步骤2:端口扫描(温柔版)
nmap -sS -T2 --max-retries 1 -p 445,3389,88,389,464,636,3268,3269 \
--open --script=smb-vuln-ms17-010 \
-oA dc_scan 192.168.1.10
# 步骤3:发现MS17-010漏洞
# 脚本输出:VULNERABLE: MS17-010
# 步骤4:验证域控(脚本判断)
nmap -p 389 --script ldap-rootdse 192.168.1.10
# 输出:Domain Controller detected
# pps-key复盘:全程用-T2,蓝队没任何告警
# 如果当初用-T4,估计第一步就被封IP
# 结论:渗透测试不是速度竞赛,是隐蔽艺术
9. 终极配置:pps-key的~/.nmap/nmap.rc
bash
# 这个文件在~/.nmap/nmap.rc,Nmap启动时自动加载
# pps-key注:这是我的保命配置,温柔到极致
# 默认温柔模式
set Timing.Template 2
# 默认只测常用端口
set Target.Ports 21,22,23,25,53,80,110,143,443,445,3306,3389,5432,6379,8080,8443
# 默认脚本强度2
set Script.Intensity 2
# 默认输出三种格式
set Output.AllFiles yes
# 默认不ping(目标明确时用)
set Target.SkipHostDiscovery yes
# 默认启用--open
set Port.OpenOnly yes
# 默认不解析DNS(提速)
set Dns.Resolution Never
# TODO:应该按场景分配置文件,nmap_gentle.rc / nmap_aggressive.rc
# FIXME:这个配置在IPv6环境会DNS解析失败,需手动unset
10. 总结:Nmap是哲学,不是命令
pps-key的Nmap三定律:
-
扫描速度与被发现的概率呈指数级正相关
- 每降低一个-T等级,被发现概率下降一个数量级
-
输出格式决定工具的二次生命
- 只会
-oN的人,永远手工整理报告
- 只会
-
脚本是Nmap的灵魂,但80%的脚本你永远不会用
- 掌握
smb-vuln-*、http-*、ssl-*三大系列足矣
- 掌握
终极心法:把Nmap当成你的侦察兵,不是敢死队。侦察兵活着回来,情报才有价值。
作者签名:pps-key - 一个因为Nmap扫太快被被敲门的苦逼高中生