端口扫描漏洞检测实战从日常安全排查到攻击者常用手法一网打尽
端口扫描:安全世界的”透视眼”
说端口扫描,很多刚入行的朋友脑子里可能立马浮现出黑客入侵电影里那种炫酷的画面——满屏滚动的绿色代码,一个接一个地破解防火墙。说实话,真实情况比那朴素得多,但也绝对不枯燥。
端口扫描本质上就是在问你:”这台机器开了哪些’门’?”
想象一下,你有一栋大楼(服务器),里面有很多房间(服务),每个房间都有门牌号(端口)。端口扫描就是站在楼外,一个个敲门听动静——有回应的说明屋里有人(服务开放),没回应的要么是锁了门,要么根本不存在这个房间。
这个行为本身是中性的。网管用它做健康检查,安全人员用它做渗透测试,当然,坏人也会用它来找漏洞。今天咱们就掰开揉碎了,从日常排查到攻击手法,把端口扫描这事儿讲透。
日常安全排查:先把自己家看明白
做安全排查的第一步,永远是搞清楚自己有什么。很多安全事件的发生,不是因为攻击者有多厉害,而是负责人压根不知道自己暴露了什么。
本地端口查看
在Linux系统上,最基础的操作就是看看本机开了哪些端口:
# 查看当前监听的所有TCP端口
netstat -tlnp
# 更现代的替代方案(部分系统可能需要安装net-tools)
ss -tlnp
# 查看UDP端口
ss -ulnp
输出大概长这样:
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 0 128 0.0.0.0:22 0.0.0.0:* 1234/sshd
LISTEN 0 128 0.0.0.0:80 0.0.0.0:* 5678/nginx
LISTEN 0 128 0.0.0.0:443 0.0.0.0:* 5678/nginx
LISTEN 0 128 [::]:22 [::]:* 1234/sshd
LISTEN 0 128 [::]:80 [::]:* 5678/nginx
看到0.0.0.0:22意味着SSH服务在所有网络接口上都监听,这是正常的。但如果看到0.0.0.0:3389(Windows远程桌面)对外暴露,那就得警惕了。
用nmap做本地自检
nmap是最经典的端口扫描工具,先拿本地练手:
# 扫描本机所有端口
nmap -sS -p- 127.0.0.1
# 扫描局域网内自己的IP,看看外部视角看到什么
nmap -sS 192.168.1.100
# 详细扫描,包括服务版本和系统探测
nmap -sS -sV -O 192.168.1.100
注意看这里的-sS,这是TCP SYN扫描(半开扫描),只发送SYN包,收到SYN-ACK就断开,不会完成完整TCP三次握手。这种扫描方式比较安静,不容易被简单的日志记录到。-p-表示扫描全部65535个端口,而默认nmap只扫前1000个常用端口。
如果扫描结果显示:
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.4
80/tcp open http nginx 1.18.0
443/tcp open http nginx 1.18.0
3306/tcp open mysql MySQL 5.7.38
发现MySQL的3306端口对外开放?这就是典型的配置问题——MySQL应该只允许本地或内网访问,不应该直接暴露在公网。
攻击者的视角:他们怎么扫的
了解攻击者的手法,不是为了学坏,而是为了更好地防守。
全端口扫描与常用端口扫描的区别
普通用户扫端口,通常关注前1000个(占90%以上的常见服务)。但攻击者会做更彻底的扫描:
# 全端口扫描(会很慢,尤其是跨网段时)
nmap -p- 10.0.0.0/24
# 针对已知高危端口快速扫描
nmap -p 21,22,23,25,53,80,110,135,139,443,445,
1433,1521,3306,3389,5432,5900,6379,8080,
8443,27017 10.0.0.0/24
注意看这些端口背后的服务:
| 端口 | 服务 | 常见风险 |
|---|---|---|
| 21 | FTP | 明文传输,暴力破解常见 |
| 22 | SSH | 弱密码、未授权访问 |
| 23 | Telnet | 几乎明文,极度危险 |
| 445 | SMB | EternalBlue等高危漏洞 |
| 1433/3306/5432 | 数据库 | 弱口令、未授权访问 |
| 6379 | Redis | 默认无认证,常被利用写入Webshell |
| 27017 | MongoDB | 同理,无认证直接访问 |
隐蔽扫描手法
正规扫描太容易被防火墙和IDS发现了,攻击者会玩各种花活:
XMAS扫描 —— 给包打上所有标志位,像一棵装饰过度的圣诞树:
nmap -sX 10.0.0.1
按照TCP规范,收到XMAS包的机器应该返回RST。但如果对方是某些老旧系统或者配置了特殊规则的设备,可能直接响应,从而暴露端口。
FIN扫描 —— 发送一个只有FIN标志的包,正常系统应该忽略或返回RST,但某些配置不当的系统会错误响应:
nmap -sF 10.0.0.1
NULL扫描 —— 不给任何标志位:
nmap -sN 10.0.0.1
ACK扫描 —— 主要用于探测防火墙规则,而非直接发现端口:
nmap -sA 10.0.0.1
OS指纹识别 —— 确定目标系统类型,为后续攻击做准备:
nmap -O --osscan-guess 10.0.0.1
输出可能显示:
OS details: Linux 5.4 - 5.15 (Ubuntu 20.04 - 22.04)
Network Distance: 1 hop
知道对方跑的是Ubuntu什么版本,后面就可以针对性地找CVE了。
实战:从扫描到利用的完整链条
光会扫不够,还得理解整个攻击链。下面模拟一个完整的实战场景。
第一步:发现存活主机
# ICMP ping扫描,发现网段内存活主机
nmap -sn 192.168.1.0/24
第二步:对存活主机进行端口扫描
# 快速扫描常用100个端口
nmap -sS -T4 -F 192.168.1.10
# 详细扫描发现的端口
nmap -sS -sV -O -p 22,80,443,3306,8080 192.168.1.10
第三步:服务版本探测后的漏洞匹配
扫描发现某个8080端口运行的是Apache Tomcat 9.0.62:
PORT STATE SERVICE VERSION
8080/tcp open http Apache Tomcat 9.0.62
这版本号就是情报!直接去搜CVE:
# 用nmap的NSE脚本自动检测已知漏洞
nmap --script vuln -p 8080 192.168.1.10
NSE脚本会返回类似:
| vuln: CVE-2021-41077:
| IDs: CVE:CVE-2021-41077
| Risk factor: HIGH
| Description: ...
| References:
| https://nvd.nist.gov/vuln/detail/CVE-2021-41077
| https://www.docker.com/blog/...
|_ https://www.docker.com/blog/...
第四步:自动化批量扫描
如果面对的是一个大型网络,人工操作不现实。写个脚本批量处理:
#!/usr/bin/env python3
"""
端口扫描报告生成器
"""
import subprocess
import re
import json
from datetime import datetime
class PortScanner:
def __init__(self, target):
self.target = target
self.results = {}
def run_nmap(self, scan_type="-sS", ports="22,80,443,8080,3306,5432,6379,27017,3389,445"):
cmd = f"nmap {scan_type} -p {ports} --open -oX - {self.target}"
result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
return result.stdout
def parse_nmap_xml(self, xml_output):
"""解析nmap XML输出"""
import xml.etree.ElementTree as ET
root = ET.fromstring(xml_output)
scan_info = {
"target": self.target,
"scan_time": datetime.now().isoformat(),
"open_ports": []
}
for host in root.findall(".//host"):
for ports_elem in host.findall(".//ports/port"):
port_id = ports_elem.get("portid")
state = ports_elem.find("state").get("state")
if state == "open":
service = ports_elem.find("service")
port_info = {
"port": int(port_id),
"protocol": ports_elem.get("protocol"),
"service": service.get("name", "unknown") if service is not None else "unknown",
"version": service.get("product", "") if service is not None else ""
}
scan_info["open_ports"].append(port_info)
return scan_info
def generate_report(self):
xml_output = self.run_nmap()
report = self.parse_nmap_xml(xml_output)
# 输出JSON格式报告
print(json.dumps(report, indent=2, ensure_ascii=False))
return report
if __name__ == "__main__":
import sys
if len(sys.argv) < 2:
print("用法: python3 scanner.py <目标IP>")
sys.exit(1)
scanner = PortScanner(sys.argv[1])
report = scanner.generate_report()
# 高危端口告警
high_risk_ports = {21, 23, 135, 139, 445, 1433, 3306, 3389, 5432, 5900, 6379, 27017}
open_high_risk = [p for p in report["open_ports"] if p["port"] in high_risk_ports]
if open_high_risk:
print("\n⚠️ 高危端口开放告警:")
for port in open_high_risk:
print(f" 端口 {port['port']}/{port['protocol']} - {port['service']} ({port['version']})")
运行这个脚本:
python3 scanner.py 192.168.1.10
会输出结构化的JSON报告,自动识别高危端口并发出告警。这种自动化能力在批量排查时非常有用。
防御角度:怎么防端口扫描
1. 最小化暴露原则
最根本的防御是:不开不必要的端口。
# 查看哪些端口在监听
ss -tlnp
# 关闭不需要的服务
systemctl stop unwanted-service
systemctl disable unwanted-service
2. 防火墙规则配置
用iptables或firewalld做精细化控制:
# 仅允许特定IP访问SSH
iptables -A INPUT -p tcp --dport 22 -s 10.0.0.0/8 -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -j DROP
# 允许HTTP/HTTPS
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT
# 默认拒绝所有
iptables -A INPUT -j DROP
如果用firewalld:
# 只开放必要服务
firewall-cmd --permanent --add-service=ssh
firewall-cmd --permanent --add-service=http
firewall-cmd --permanent --add-service=https
# 限制SSH来源IP
firewall-cmd --permanent --add-rich-rule="rule family='ipv4' source address='10.0.0.0/8' service name='ssh' accept"
firewall-cmd --permanent --add-rich-rule="rule service name='ssh' reject"
firewall-cmd --reload
3. 使用 fail2ban 防御暴力破解
# 安装fail2ban
apt install fail2ban -y
# 配置SSH保护
cat > /etc/fail2ban/jail.local << 'EOF'
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 3600
findtime = 600
EOF
systemctl enable fail2ban
systemctl restart fail2ban
4. 端口扫描检测
在服务器上部署扫描检测,发现异常立即告警:
# 使用 fail2ban 检测端口扫描
cat > /etc/fail2ban/jail.local << 'EOF'
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 7200
[portscan]
enabled = true
filter = portscan
action = iptables[type=$protocol]
logpath = /var/log/kern.log
maxretry = 2
bantime = 86400
EOF
# 创建portscan过滤规则
cat > /etc/fail2ban/filter.d/portscan.conf << 'EOF'
[Definition]
failregex = .*UFW BLOCK.*SRC=(<HOST>)
ignoreregex =
EOF
5. 定期安全审计
# 每月一次全面扫描
nmap -sS -sV -O --script vuln -oA monthly-scan target-ip
# 对比历史基线
diff baseline-nmap.xml current-nmap.xml
建立基线很重要。第一次扫描结果要保存好,后续扫描结果与之对比,发现新增开放端口或服务版本变化,就是异常。
常见误区与注意事项
很多人觉得”扫描就是我的,我想扫就扫”,这个认知有待商榷。
先搞清楚法律边界。 未经授权对他人系统做端口扫描,在大多数国家和地区都是违法的。即使是安全测试,也要获得书面授权。白帽和黑帽的分界线,往往就在这纸授权上。
扫描速度要克制。 高速扫描不仅容易触发IDS告警,还可能对被扫系统造成类似DDoS的影响。-T参数控制扫描速率,-T1最慢最安静,-T5最快最激进。在渗透测试中,通常建议用-T2或-T3。
注意扫描的副作用。 全端口扫描(65535个端口)对某些老旧或配置不当的系统可能造成性能影响。生产环境扫描务必避开业务高峰期,并提前通知运维团队。
日志留痕。 自己的扫描行为也要记录,包括时间、目标、使用的命令和参数。这是职业安全的基本素养,也是在争议时的自我保护。
给新手的学习路径
如果你觉得这些内容信息量有点大,没关系,按这个顺序来:
第一阶段:在自己的虚拟机上练习。装一个Kali Linux,再装几个靶机(比如Metasploitable),用nmap各种扫描方式试一遍,观察不同扫描技术的输出差异。
第二阶段:学习识别扫描结果。拿到一个nmap输出,能准确判断出开放了哪些服务、大概什么版本、存在什么风险。
第三阶段:了解防御工具。自己部署防火墙规则,配置fail2ban,搭建简单的IDS(比如Suricata),观察扫描行为如何被记录。
第四阶段:实战演练。在合法的渗透测试平台(如TryHackMe、HackTheBox)上实践,把学到的东西串起来。
记住,端口扫描只是起点。真正的安全能力在于理解每个端口后面的服务,知道它的配置是否正确,版本是否存在已知漏洞,日志有没有异常。把单一技术放到完整的安全链条中去理解,才能真正用好它。
