news 2026/9/28 5:22:02

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
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 Jar(Cookie 仓库)。默认配置下,Burp 会记录响应里的 Set-Cookie,并在之后的请求里自动把对应 Cookie 加进请求头。这对测试是一把双刃剑——方便是方便,但会掩盖很多现象。

具体到 DVWA 这个场景:你第一次访问页面时,Burp 记录了Set-Cookie: dvwaSession=xxx,之后你再刷新,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: dvwaSession=xxx。

这里有一个必须提醒的坑:清掉 Cookie 等于把 DVWA 的登录态也清掉了,重新登录后安全级别会回到默认值。别以为刚才设了 High 就一直有效,你要重新到 DVWA Security 页把它切成 High,否则你会发现生成的 Cookie 变成了时间戳。

3.2 实验二:开着 Burp 的 HTTP History 观察

用 Burp 的标准做题姿势:浏览器走 Burp 拦截,先清干净浏览器 Cookie,然后访问 Weak Session IDs 页面。

HTTP History 里第一条请求的响应能看到Set-Cookie: dvwaSession=xxx。之后你再怎么刷新,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: dvwaSession=xxx删掉,注意保留登录需要的 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; dvwaSecurity=high" \ | 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 的作者想表达的东西,全都在三份代码的差异里——从时间戳到哈希链,再到伪随机数,每一级都在演示一个特定的失败模式。搞懂了这三份 diff,Weak Session IDs 这关才算真正通关。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/28 5:21:56

基于Java的MooseFS重构:分布式文件系统设计与实现

简介:基于Java与Moosefs的分布式文件系统设计实现资料,适合计算机相关专业学生或开发者用于课程设计、毕业设计以及分布式存储项目实践。资料以完整项目源码与配套文档为核心,涵盖Java后端核心逻辑、Moosefs分布式存储集成、文件上传下载与目…

作者头像 李华
网站建设 2026/9/28 5:21:52

Web4移动端实战:从技术选型到上线冲刺的完整记录

很多人在聊Web4的时候,聊的都是概念、愿景和大厂叙事,真正愿意把它落成一个具体产品的不多。SYNBO CLUB移动端,算是我们自己的一次实践尝试。作为聚焦Web4趋势的会员内容社区,我们准备把完整的Web4体验塞进手机里。对用户来说&…

作者头像 李华
网站建设 2026/9/28 5:20:56

Windows进程与服务排查实战:从概念到命令行工具详解

很多刚接触网安的朋友,上手第一课就会撞上一堵墙:Windows系统里那么多进程和服务,密密麻麻的,看着都头疼,更别说从中找出哪个有问题。但不管你是做应急响应、做入侵排查,还是单纯想把自己的电脑收拾利索&am…

作者头像 李华
网站建设 2026/9/28 5:19:46

J-Link RTT Viewer嵌入式调试实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/28 5:19:40

C#连接MySQL实战指南:从安装配置到连接池与批量写入排坑

直接开干。搞C#开发,免不了要跟数据库打交道。前阵子有个项目要从SQL Server迁到MySQL,我顺手把整个流程完整捋了一遍,从装库到C#里增删改查,再到连接池、批量写入这些坑,全部实测过一遍。这篇东西就是把这些经验沉淀下…

作者头像 李华
网站建设 2026/9/28 5:19:38

医疗OCR+语义检索:构建高精度临床文献检索系统

简介:本资源是一个面向医疗AI开发者与前端工程师的实战型项目——基于OCR技术的医疗文献检索系统,聚焦解决医生、医学研究人员在纸质/扫描文献中快速定位专业内容的效率瓶颈。项目完整实现从图像预处理、文字识别(CNNRNN模型)、结…

作者头像 李华