14 - 端口与服务映射及安全扫描
前提条件
- 已完成 SSH 端口 2222 配置、fail2ban、AppArmor、nftables/ufw 防火墙
- 系统只暴露必要端口(当前仅
2222/tcp允许入站) - 以 root 身份登录,或 ops 用户执行
sudo -i切换至 root 环境 - 虚拟机环境:VMware Workstation Pro(建议桥接网络,便于从宿主机扫描)
全局参数
主机名 linuxdc,IP 192.168.1.100/24,SSH 端口 2222,运维用户 ops
详细步骤
1. 本地端口与服务自查
查看当前监听端口和服务映射:
ss -tulnjp # 监听端口 + 进程 PID / 名称(推荐)
ss -tunap # 所有连接状态 + 进程信息
lsof -i -P -n | grep LISTEN # 进程视角查看监听端口
预期输出示例(最小化安全系统):
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
tcp LISTEN 0 128 0.0.0.0:2222 0.0.0.0:* users:(("sshd",pid=1234,fd=3))
tcp LISTEN 0 128 [::]:2222 [::]:* users:(("sshd",pid=1234,fd=4))
检查点
ss -tulnjp 输出中除 2222 端口外,不应出现任何其他对外监听的端口(127.0.0.1 上的本地监听可以有,如 systemd-resolved 的 53)。
2. 安装扫描工具
apt update
apt install -y nmap
3. 本地扫描自身(快速自检)
# TCP 连接扫描(不需要 root)
nmap -sT localhost
# SYN 半连接扫描全端口(需要 root,更快、更隐蔽)
nmap -sS -p- localhost
# 服务版本探测
nmap -sV -p 1-65535 localhost
# 运行安全脚本(无破坏性,适合自检)
nmap --script safe localhost
sS 与 sT 的区别
-sT(TCP connect scan)完成完整的三次握手,日志清晰但速度慢,会在目标日志留下连接记录。-sS(SYN scan)只发送 SYN 包,收到 SYN-ACK 后立即发 RST 终止,速度更快,日志较少。-sS 需要 root 权限(原始套接字)。
4. 从宿主机扫描虚拟机(外部视角验证)
在宿主机(Windows/Mac/Linux)安装 nmap 后执行:
# 快速扫描常用端口
nmap -sS -p 1-10000 192.168.1.100
# 服务版本 + 操作系统指纹
nmap -sV -O 192.168.1.100
# 全面扫描(OS、服务、默认脚本,速度较慢)
nmap -A 192.168.1.100
预期结果(安全配置正确时):
PORT STATE SERVICE
2222/tcp open ssh
# 其他端口显示 filtered 或 closed
检查点
宿主机扫描结果中,2222/tcp 显示 open,其他端口均为 filtered 或 closed。若出现其他 open 端口,需立即排查是否为未授权服务。
5. 自动化定期端口扫描脚本
创建巡检脚本:
mkdir -p /opt/security
vim /opt/security/port-scan.sh
脚本内容:
#!/bin/bash
# 端口巡检脚本 - 定期扫描本机开放端口并记录日志
LOGFILE="/var/log/port-scan.log"
ALERT_MAIL="root"
EXPECTED_PORTS="2222" # 预期开放的端口列表(逗号分隔)
TARGET="192.168.1.100"
DATE=$(date '+%Y-%m-%d %H:%M:%S')
echo "[$DATE] 开始端口扫描 - 目标: ${TARGET}" >> "${LOGFILE}"
# 扫描并记录开放端口
OPEN_PORTS=$(nmap -sT -p- --open "${TARGET}" 2>/dev/null | grep "^[0-9]" | awk -F'/' '{print $1}' | tr '\n' ',')
echo "[$DATE] 开放端口: ${OPEN_PORTS:-无}" >> "${LOGFILE}"
# 检查是否有意外开放端口
UNEXPECTED=$(echo "${OPEN_PORTS}" | tr ',' '\n' | grep -vE "^(${EXPECTED_PORTS})$" | grep -v '^$')
if [ -n "${UNEXPECTED}" ]; then
echo "[$DATE] 警告:发现意外开放端口: ${UNEXPECTED}" >> "${LOGFILE}"
echo "主机 ${TARGET} 发现意外开放端口: ${UNEXPECTED}" | mail -s "端口巡检告警" "${ALERT_MAIL}" 2>/dev/null
fi
echo "[$DATE] 扫描完成" >> "${LOGFILE}"
echo "------------------------------" >> "${LOGFILE}"
赋予权限并测试:
chmod +x /opt/security/port-scan.sh
/opt/security/port-scan.sh
tail /var/log/port-scan.log
检查点
/var/log/port-scan.log 中显示只有 2222 为开放端口,无"意外开放端口"告警。
添加到 systemd timer(推荐,比 cron 更现代):
vim /etc/systemd/system/port-scan.service
[Unit]
Description=Daily Port Scan
[Service]
Type=oneshot
ExecStart=/opt/security/port-scan.sh
vim /etc/systemd/system/port-scan.timer
[Unit]
Description=Daily Port Scan Timer
[Timer]
OnCalendar=*-*-* 03:00:00
Persistent=true
[Install]
WantedBy=timers.target
systemctl daemon-reload
systemctl enable --now port-scan.timer
systemctl list-timers | grep port-scan
6. 系统安全审计工具(可选)
# 综合安全审计(覆盖账号、文件权限、SSH 配置、内核参数等)
apt install -y lynis
lynis audit system
# 查看审计评分和建议
cat /var/log/lynis.log | grep "Suggestion\|Warning" | head -30
实践任务
- 用
ss -tulnjp确认当前系统只监听2222/tcp(及本地回环上的其他端口) - 在虚拟机内运行
nmap -sV localhost,记录输出 - 从宿主机用 nmap 扫描虚拟机 IP,确认只有
2222端口开放 - 创建
port-scan.sh脚本并手动运行一次,查看日志是否显示预期结果
自测问题
1. ss -tuln 和 nmap localhost 的输出区别是什么?
ss -tuln 是系统内部视图:直接读取内核套接字表,显示所有监听端口(包括只绑定在 127.0.0.1 的本地端口),无需网络通信,速度极快,结果绝对准确,但只能在本机执行。nmap localhost 是网络探测视图:模拟外部客户端发起 TCP/UDP 探测,只能看到网络层可达的端口,受防火墙规则影响(本地回环通常不受 nftables 过滤),速度较慢。生产审计时两者配合使用:ss 查本机完整监听,nmap 从宿主机确认外部可见的暴露面。
2. 为什么生产环境中推荐使用 -sS(SYN scan)而非 -sT(TCP connect)?
-sT 完成完整的三次握手,每次扫描都在目标的连接日志中留下完整记录,速度慢,且会消耗目标的连接资源(可能触发 fail2ban)。-sS 发送 SYN 后收到 SYN-ACK 就立即发 RST 终止,不完成握手,对目标系统的影响最小,扫描速度更快(不需要等待连接超时),日志噪音更少。在对自身系统做安全巡检时,-sS 是更专业的选择;但要注意 -sS 需要 root 权限,-sT 普通用户也可运行。
3. 如果 nmap 显示某个端口 "filtered" 而非 "closed",代表什么情况?
closed:端口可达,目标主机发回了 TCP RST 包,表示该端口没有服务监听,但防火墙放行了探测包。filtered:nmap 发出的探测包被丢弃(没有任何响应),通常意味着防火墙在该端口上配置了 DROP 而非 REJECT 规则。生产环境推荐将非授权端口设为 filtered(防火墙 drop),而非 closed(防火墙 reject),前者不向扫描者透露系统存在,后者会返回 RST/ICMP unreachable,泄露系统信息。
4. 如何快速判断系统是否意外暴露了不该开的端口?
三步闭环检查:
# 步骤一:本机内部视图(无防火墙影响)
ss -tulnjp | grep LISTEN
# 步骤二:防火墙外部视图(模拟攻击者视角)
nmap -sS -p- 192.168.1.100 # 从宿主机执行
# 步骤三:对比预期端口列表
# 预期:只有 2222/tcp
# 如有其他 open 端口立即排查:systemctl status <对应服务>
若两者结果不一致(内部有监听但外部看不到),说明防火墙正确过滤;若外部能看到内部未预期的端口,说明有新服务启动且防火墙未拦截,需立即处理。
总结
定期端口扫描是发现配置漂移、未授权服务暴露的第一道警戒线。结合防火墙"默认拒绝 + 只开必要端口"原则,通过 nmap 自检 + 外部验证 + 自动化巡检脚本,形成闭环安全监控。后续每新增一个业务服务并开放端口后,都应立即执行本章的扫描流程验证暴露情况。