ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

DVWA High级别会话ID不刷新?根因在isset与mt_rand

DVWA High级别会话ID不刷新?根因在isset与mt_rand 做 DVWA 靶场的时候很多人会在 Weak Session IDs弱会话标识这一关卡上卡很久。现象非常统一安全级别切到 High打开页面看到 Cookie Value 显示了一串数字然后你刷新也好、点页面上的 Generate 也好这串数字纹丝不动抓包工具里也搜不到新的 Set-Cookie。更诡异的是之前切到 Medium 的时候明明每次刷新都有新值怎么一到 High 就哑火了。于是不少人开始怀疑是 Burp 配置问题、浏览器缓存问题甚至想重装 DVWA。这篇就把High 的 dvwaSession 为什么刷新不出来从头到尾拆一遍告诉你根因在哪、怎么复现、以及这一关真正要你掌握的东西。1. 先把关卡目标说清楚这关不是靠刷新练出来的1.1 认清对象dvwaSession 不是 PHP 的 Session新手最容易把 Weak Session IDs 和菜单里的 Brute Force 弄混。Brute Force 那关是爆破密码Weak Session IDs 这关跟密码没关系它的核心对象就是那个叫 dvwaSession 的 Cookie。这里有必要先把概念捋一下DVWA 登录后浏览器里一般会有两个 Cookie——一个是 PHP 自己维持会话用的 PHPSESSID另一个才是应用逻辑里手动创建的 dvwaSession。PHPSESSID 是 PHP 框架自动生成和维护的而 dvwaSession 完全是源码里用setcookie()函数塞进去的业务 Cookie。它走不走 PHP 的 session 机制它安不安全、可不可预测、能不能被伪造完全取决于 DVWA 源码里那几行代码怎么写。所以做这一关前我强烈建议先打开 DVWA 目录下的vulnerabilities/weak_session_ids/source/把low.php、medium.php、high.php三个文件通读一遍。代码短得可怜但信息量极大。1.2 三个级别的生成逻辑差异下面是 DVWA 1.9 / 2.x 常见版本的源码逻辑归纳不同小版本可能有细节差异核心分支结构基本一致Low 级别的逻辑是如果$_COOKIE[dvwaSession]已存在就只把当前值显示出来如果不存在就用当前时间戳time()生成一个 Cookie。这意味着 Low 生成的值就是时间戳肉眼可读直接就能还原出生成时间。Medium 级别稍微绕了一点Cookie 已存在时它取上一条 Cookie 值的md5()作为新值重新写入不存在时才用时间戳初始化。所以你切到 Medium 会发现每次刷新都有新的 Set-Cookie因为每个新值都是对旧值做一次 md5 运算形成一条哈希链。High 级别则回到和 Low 一样的存在就显示、不存在才生成的模式只是生成函数换成了 PHP 的伪随机数mt_rand()。部分 DVWA 版本用rand()本质是一样的。三个级别的差异可以看下表安全级别首次生成方式后续刷新弱点Low时间戳 time()只显示不重新生成值直接可读等于知道时间Medium时间戳 time()每次重算 md5(旧值) 并写入哈希链知道起点就能推Highmt_rand() / rand()只显示不重新生成伪随机种子可预测1.3 High 级别真正想考的东西很多人以为切到 High 之后页面上的 Cookie Value 应该像 Medium 那样每次刷新都变这才叫难度高。其实正好相反。High 级别的考点是这个看起来随机的大整数比如1081417437它真的随机吗mt_rand()是 PHP 的梅森旋转伪随机数生成器它需要一个种子默认配置下种子往往跟时间相关。只要你能连续拿到多个 Cookie 值再结合大致的生成时间窗口是可以推算种子的。知道种子就能预测下一个值等于可以伪造别人的会话令牌。这就是弱会话 ID的含义——不是没做随机而是随机得不够安全。所以当你在 High 卡在刷新不出来这个问题上时先别急着找工具换个角度想DVWA 是故意让 Cookie 只在不存在时才生成的。它想让你亲眼看到会话令牌生成后不更换和会话令牌由弱随机源产生这两个问题叠加起来是什么效果。2. 为什么刷新不出新 Cookie根因在源码的 isset 判断2.1 结论先给出来刷新不出新 Cookie十有八九不是 Burp 的问题而是这一行判断if (isset($_COOKIE[dvwaSession])) { // Cookie 已存在直接显示当前值 } else { // Cookie 不存在才生成并调用 setcookie() }只要请求头里带着 dvwaSession服务端就认定你已经有会话标识了直接走显示分支既不生成新值也不调用setcookie()。因此响应里不会有 Set-Cookie页面上的 Cookie Value 自然也不变。这个设计对 Low 和 High 是同一个套路Medium 反而每次刷新都有新值。所以你从 Medium 切到 High 会觉得怎么一下子没反应了这正是最容易产生是不是我环境坏了错觉的原因。2.2 浏览器会自动带上旧 Cookie第二个容易忽略的细节是 Cookie 的自动携带机制。Cookie 一旦由服务端种下浏览器之后对同域名的每次请求都会自动带上它。你手动刷新也好在 Burp 里重放也好只要请求头里带着 dvwaSession服务端的isset分支就成立永远不会再生成。也就是说刷新这个动作在服务端看来不是请给我一个新令牌而是我拿着旧令牌来了。2.3 Burp 的 Cookie Jar 会在中间添乱如果你开着 Burp 测试还会遇到第二层坑Burp 自带 Cookie JarCookie 仓库。默认配置下Burp 会记录响应里的 Set-Cookie并在之后的请求里自动把对应 Cookie 加进请求头。这对测试是一把双刃剑——方便是方便但会掩盖很多现象。具体到 DVWA 这个场景你第一次访问页面时Burp 记录了Set-Cookie: dvwaSessionxxx之后你再刷新Burp 自动替你把这个 Cookie 补进请求头。服务端一看 Cookie 存在就不再生成。于是 HTTP History 里只有第一条响应有 Set-Cookie后面的请求统统没有。所以Burp 里刷新不出来本质上还是根因一在起作用Burp 只是忠实地把服务端没有生成新值这件事展示给了你。我见过不少同学以为把 Burp 的自动 Cookie 功能关掉就能解决实际上关不关服务端都不会生成真正的开关在请求里是否携带旧 Cookie。2.4 缓存和 304 是更小概率的干扰还有一个小概率原因浏览器缓存。DVWA 这类 PHP 页面默认不太容易被缓存但如果你的浏览器插件、Burp 的拦截规则或者本地反向代理配置介入刷新时可能命中 304 Not Modified直接用本地缓存渲染页面请求可能都没真正发出去。排障时第一步永远是打开开发者工具的 Network 面板确认这一下到底有没有发出请求、有没有拿到 200 响应再谈其他的。3. 三组对照实验把问题链路彻底看穿3.1 实验一纯浏览器 开发者工具打开 DVWA 的 Weak Session IDs 页面按 F12 进入开发者工具在 Application 面板的 Cookies 里找到dvwaSession记下当前值然后按 F5 刷新。正常情况下你会看到请求发出了响应 200但 Set-Cookie 一栏为空Cookie 的 dvwaSession 值不变。这证明服务端走的是isset成立的分支压根没有重新生成。接下来做一个对照组在 Application 面板里选中站点域名把 Cookie 全部删除或者干脆开一个无痕窗口重新登录。登录后把安全级别切回 High再访问 Weak Session IDs这时的 Network 面板里第一趟请求的响应头就出现了Set-Cookie: dvwaSessionxxx。这里有一个必须提醒的坑清掉 Cookie 等于把 DVWA 的登录态也清掉了重新登录后安全级别会回到默认值。别以为刚才设了 High 就一直有效你要重新到 DVWA Security 页把它切成 High否则你会发现生成的 Cookie 变成了时间戳。3.2 实验二开着 Burp 的 HTTP History 观察用 Burp 的标准做题姿势浏览器走 Burp 拦截先清干净浏览器 Cookie然后访问 Weak Session IDs 页面。HTTP History 里第一条请求的响应能看到Set-Cookie: dvwaSessionxxx。之后你再怎么刷新History 里新增的请求响应都没有 Set-Cookie 了。此时去 Burp 的 Project options → Sessions → Cookie Jar 里看dvwaSession 已经被自动记录进去。这正是自动 Cookie 管理在替你做带旧 Cookie 重放这件事。3.3 实验三Repeater 手动剥离 Cookie把 Weak Session IDs 首页的请求 Send to Repeater。第一次直接 Send响应没有 Set-Cookie因为请求头里的 Cookie 带着 dvwaSession。第二次手动把请求头里的Cookie: dvwaSessionxxx删掉注意保留登录需要的 PHPSESSID以及 DVWA 安全级别相关的 dvwaSecurity 等再 Send。这时响应头里出现了 Set-Cookie响应正文里的 Cookie Value 也变成了新值。连续删连续发每次都能拿到一个新值——这才是收集 High 样本的正确姿势。三组实验的结论对比如下方式请求是否携带旧 dvwaSession能否看到 Set-Cookie结论浏览器直接刷新带否服务端不生成Burp History 刷新带Cookie Jar 自动补否同上但 Cookie Jar 有记录Repeater 删掉 dvwaSession不带是服务端才重新生成4. 四招逼出新 Cookie按场景选着用4.1 无痕窗口 / 清站点 Cookie新手最推荐的方式开一个无痕窗口重新登录 DVWA安全级别切到 High再打开 Weak Session IDs。每次关闭并重开无痕窗口都是一次全新的干净状态服务端必然重新生成 dvwaSession。把想要的目标访问路径完整走一遍首页 → 登录 → DVWA Security 切 High → Weak Session IDs就能拿到一个新 Cookie。缺点是手动重复太繁琐如果只是验证现象没问题但你要攒几十个样本做分析这个办法效率太低。4.2 Burp Repeater 删掉 Cookie 头最推荐用于采样。按照实验三的流程在 Repeater 里把请求头整理干净只保留 Host、User-Agent、Cookie里面只放 PHPSESSID 和 dvwaSecurity把 dvwaSession 去掉然后每次 Send 都会收到一个新 Set-Cookie。如果你需要大批量采集可以更进一步把请求发到 Intruder给请求配置一条删除 dvwaSession 请求头的宏或正则替换规则用空 payload 跑几十次一次拿到几十个新值。这里的关键始终是同一个让服务端认为你没有 dvwaSession。4.3 curl 脚本采集不想开 GUI 的时候curl 也能干。思路一样每次请求都不携带 dvwaSession。最省事的方式是从浏览器里复制一个有效的 PHPSESSID直接放在 Cookie 头里手动指定for i in $(seq 1 20); do curl -s http://127.0.0.1/dvwa/vulnerabilities/weak_session_ids/ \ -H Cookie: PHPSESSID你的会话ID; dvwaSecurityhigh \ | grep -oE Cookie Value: [0-9] done注意三点第一DVWA 的实际路径按你的安装位置调整可能是/DVWA/而不是/dvwa/第二PHPSESSID 每次登录都会变要用当前有效值第三如果你的 DVWA 版本较新登录页可能有user_token之类的 CSRF 防护从浏览器会话复制 PHPSESSID 可以绕开登录接口的 token 问题。4.4 本地靶场改源码强制生成如果你就是想在页面上反复观察生成过程可以在自己搭的 DVWA 里改代码比如把 High 源码改成只要有 POST 请求就重新生成或者加一个专门触发setcookie()的调试接口。这样每点一次按钮都能看到 Set-Cookie 出现。这套操作只适合本地自建靶场目的是直观理解服务端何时生成、何时不生成的分支逻辑。改完记得改回去否则后续做题逻辑就不对了。5. 刷新出来以后把 High 这关真正做完5.1 先采集足够样本拿到新 Cookie 只是开始。High 考查的是可预测性一两个值没有分析价值。用第 4.2 或 4.3 的方法连续采集 30~50 个 Cookie 值并且把每个值对应的触发时间记录下来——Burp 响应里的 Time 字段或者脚本里的时间戳都行。样本量太少时很多统计特征出不来样本量超过 50 个你会看到 mt_rand() 输出在数值范围上的分布特征。5.2 用直觉扫一遍数据特征拿到样本先别急着上工具用肉眼做三件事。第一看位数mt_rand()默认输出范围是 0 到 231-1通常表现为 9~10 位整数如果你拿到的是 32 位十六进制说明这版 DVWA 可能用了别的生成方式。第二看相邻值的变化Low 的时间戳是线性递增一眼能看出来mt_rand() 看起来毫无规律但如果你把几十个值按时间排列结合大致的生成时间窗口用 php_mt_seed 这类工具去爆破种子时间窗猜得够近的话往往能跑出来。第三看有没有固定前缀或固定高位如果某些 bit 位总是相近说明熵源不足或者种子变化范围小而引起的周期性。5.3 验证思路从源码反推最直接的验证还是读源码。High 里用的是mt_rand()没有调用random_bytes()、openssl_random_pseudo_bytes()这类加密安全随机函数所以在理论上就站不住。你可以在本地写一个 PHP 脚本做对照实验设定一个种子调用mt_rand()生成一串值跟抓到的 dvwaSession 对比。实验环境里完全允许这样玩目的就是建立弱随机数 会话令牌可预测这个直觉。5.4 一份会话令牌的检查清单做完这一关你脑子里应该形成一份可复用的检查清单以后再看别的系统时直接套用熵要够会话 ID 至少应该有 128 位熵通常用 CSPRNG 生成。来源要对time()、md5(time())、mt_rand()这类组合都是一眼不过的雷区。生命周期要短登录成功、权限提升、修改密码后必须调用会话 ID 更换机制比如 PHP 的session_regenerate_id()。属性要全HttpOnly、SameSite、Secure 这些 Cookie 属性要按需设置。服务端要判不能无条件信任浏览器传来的 Cookie超时、异地、异常指纹要能触发重新认证。这些对应到真实漏洞就是会话固定、会话预测和会话侧信道问题OWASP 的 Session Management Cheat Sheet 里都有值得拉出来对照。6. 回到真实 Web 安全这个坑对应什么问题6.1 会话固定攻击的现实版本Cookie 只在不存在时才生成这个逻辑在真实系统里对应的就是会话固定攻击。攻击者先自己拿到一个合法会话 ID然后想方设法让受害者用这个 ID 访问系统只要服务端不在登录成功后更换会话 ID攻击者就能用同一个 ID 冒充受害者的身份。DVWA 这里因为你手动清掉 Cookie 才会生成新值而真实系统里用户根本不会主动清 Cookie所以登录后不更换会话 ID是实打实的漏洞。6.2 可预测会话导致越权High 级别的mt_rand()对应的是会话预测。攻击者如果能算出下一个会话值就能直接伪装成任意在线用户。历史上不少 CMS 和框架都出过这类问题某个版本里用可预测随机数生成重置令牌导致任意账号密码重置的漏洞原理和这个一模一样——随机数不可预测性不足。6.3 我给自己留的排障习惯最后分享几个我实际做事时的习惯你可以直接抄第一凡是遇到Cookie 不更新这类问题第一步不是折腾 Burp而是去服务端源码里找setcookie()的调用条件一个isset判断往往就是全部答案。第二在 Burp 里观察会话相关行为时把 Cookie Jar 的自动更新规则看清楚。需要看原始流量时临时关掉自动携带 Cookie 的功能避免 Burp 替你补请求头掩盖真相。第三在 Repeater 里重放请求时请求头要自己审一遍。该删的 Cookie 删干净否则你看到的只是浏览器旧行为的重演而不是服务端对新请求的响应。第四记录样本时把时间和请求流水号一起记录后面做随机性分析时时间轴就是最重要的线索。最后补一个小技巧做完这一关建议把 Low / Medium / High 三份源码放在一起做 diff。你会发现 DVWA 的作者想表达的东西全都在三份代码的差异里——从时间戳到哈希链再到伪随机数每一级都在演示一个特定的失败模式。搞懂了这三份 diffWeak Session IDs 这关才算真正通关。
返回列表