摘要:这是 bWAPP 系列第三十四篇,聚焦于 Broken Auth. – Insecure Login Forms(不安全的登录表单)。这一关的特殊之处在于——三个安全级别显示的是完全不同的登录页面,每个级别的漏洞类型也不同:Low 级别把账号密码直接显示在 HTML 源码里;Medium 级别把密码藏在 JavaScript 混淆代码中;High 级别才是正常的登录验证。文章会逐级分析漏洞原理,演示如何从源码和 JS 中提取凭证。附真实案例。
一、找目标
| 攻击面 | 登录表单 |
| Low 级别漏洞 | 硬编码凭证泄露(HTML 源码可见) |
| Medium 级别漏洞 | 密码隐藏在 JavaScript 混淆代码中 |
| High 级别漏洞 | 正常数据库验证(需要正确凭证) |
| 最终目标 | 获取三个级别的登录凭证 |
二、前言:三个级别三个不同的页面
这一关非常特殊——三个安全级别对应的是三个完全不同的 PHP 文件。
| Low | ba_insecure_login_1.php | 硬编码账号密码(源码可见) |
| Medium | ba_insecure_login_2.php | JavaScript 混淆密码 |
| High | ba_insecure_login_3.php | 数据库验证 |
切换安全级别时,ba_insecure_login.php 会根据 cookie 值跳转到不同的文件:
switch($_COOKIE["security_level"])
{
case "0" : header("Location: ba_insecure_login_1.php"); break;
case "1" : header("Location: ba_insecure_login_2.php"); break;
case "2" : header("Location: ba_insecure_login_3.php"); break;
}
所以这一关不是同一个页面不同防护,而是三个独立的小关卡,每个都演示了一种典型的“不安全登录”实现方式。
三、Low 安全级别:源码直接暴露凭证
3.1 关卡介绍
Low 级别的页面是一个普通登录框,但仔细看源码,会发现账号密码就写在 HTML 里:
<p><label for="login">Login:</label><font color="white">tonystark</font><br />
<input type="text" id="login" name="login" size="20" /></p>
<p><label for="password">Password:</label><font color="white">I am Iron Man</font><br />
<input type="password" id="password" name="password" size="20" /></p>
页面上用白色字体显示了 tonystark 和 I am Iron Man,虽然肉眼看不到(因为背景也是白色),但查看页面源码就能直接看到。



3.2 源码分析
if(isset($_POST["form"]))
{
if($_POST["login"] == "tonystark" && $_POST["password"] == "I am Iron Man")
{
$message = "<font color=\\"green\\">Successful login! You really are Iron Man :)</font>";
}
else
{
$message = "<font color=\\"red\\">Invalid credentials!</font>";
}
}
认证逻辑很简单:直接硬编码比较用户名和密码。
3.3 通关方法
方法一:直接查看页面源码(Ctrl+U),找到白色字体显示的账号密码。
方法二:在浏览器中选中输入框附近的空白区域,复制粘贴到文本编辑器。
输入:
Login: tonystark
Password: I am Iron Man
登录成功。

四、Medium 安全级别:JavaScript 混淆密码
4.1 关卡介绍
Medium 级别的页面和 Low 级别完全不同——它是一个“解锁秘密”的页面,要求输入正确的“passphrase”。
页面上有个 Name 字段(显示 brucebanner,不可修改),一个 Passphrase 输入框,一个 Unlock 按钮。
点击 Unlock 按钮会调用 JavaScript 函数 unlock_secret()。

4.2 源码分析
页面中有一段 JavaScript:
function unlock_secret()
{
var bWAPP = "bash update killed my shells!"
var a = bWAPP.charAt(0); var d = bWAPP.charAt(3); var r = bWAPP.charAt(16);
var b = bWAPP.charAt(1); var e = bWAPP.charAt(4); var j = bWAPP.charAt(9);
var c = bWAPP.charAt(2); var f = bWAPP.charAt(5); var g = bWAPP.charAt(4);
var j = bWAPP.charAt(9); var h = bWAPP.charAt(6); var l = bWAPP.charAt(11);
var g = bWAPP.charAt(4); var i = bWAPP.charAt(7); var x = bWAPP.charAt(4);
var l = bWAPP.charAt(11); var p = bWAPP.charAt(23); var m = bWAPP.charAt(4);
var s = bWAPP.charAt(17); var k = bWAPP.charAt(10); var d = bWAPP.charAt(23);
var t = bWAPP.charAt(2); var n = bWAPP.charAt(12); var e = bWAPP.charAt(4);
var a = bWAPP.charAt(1); var o = bWAPP.charAt(13); var f = bWAPP.charAt(5);
var b = bWAPP.charAt(1); var q = bWAPP.charAt(15); var h = bWAPP.charAt(9);
var c = bWAPP.charAt(2); var h = bWAPP.charAt(2); var i = bWAPP.charAt(7);
var j = bWAPP.charAt(5); var i = bWAPP.charAt(7); var y = bWAPP.charAt(22);
var g = bWAPP.charAt(1); var p = bWAPP.charAt(4); var p = bWAPP.charAt(28);
var l = bWAPP.charAt(11); var k = bWAPP.charAt(14);
var q = bWAPP.charAt(12); var n = bWAPP.charAt(12);
var m = bWAPP.charAt(4); var o = bWAPP.charAt(19);
var secret = (d + "" + j + "" + k + "" + q + "" + x + "" + t + "" + o + "" + g + "" + h + "" + d + "" + p);
if(document.forms[0].passphrase.value == secret)
{
location.href = "…" + "?secret=" + secret;
}
else
{
location.href = "…" + "?secret=";
}
}
4.3 提取密码
这段 JS 从字符串 "bash update killed my shells!" 中按指定位置提取字符,拼成密码。
我们只需要拿到最终 secret 的值。在浏览器中按 F12 打开开发者工具,在 Console 中执行这段代码的简化版:
var bWAPP = "bash update killed my shells!"
var d = bWAPP.charAt(3);
var j = bWAPP.charAt(9);
var k = bWAPP.charAt(10);
var q = bWAPP.charAt(12);
var x = bWAPP.charAt(4);
var t = bWAPP.charAt(2);
var o = bWAPP.charAt(13);
var g = bWAPP.charAt(1);
var h = bWAPP.charAt(2);
var p = bWAPP.charAt(23);
var secret = (d + "" + j + "" + k + "" + q + "" + x + "" + t + "" + o + "" + g + "" + h + "" + d + "" + p);
console.log(secret);
或者更简单,直接在 Console 中执行:
var bWAPP = "bash update killed my shells!"
var secret = bWAPP.charAt(3) + bWAPP.charAt(9) + bWAPP.charAt(10) + bWAPP.charAt(12) + bWAPP.charAt(4) + bWAPP.charAt(2) + bWAPP.charAt(13) + bWAPP.charAt(1) + bWAPP.charAt(2) + bWAPP.charAt(3) + bWAPP.charAt(23);
console.log(secret);
输出:hulk smash!

4.4 通关方法
输入:
Passphrase: hulk smash!
点击 Unlock,页面显示解锁成功。

五、High 安全级别:数据库验证
5.1 关卡介绍
High 级别回到了正常的登录页面,提示信息是 “Remember: a bee is a bug…”。
这个页面的验证逻辑是从数据库读取账号密码:
if($_POST["login"] == $login && $_POST["password"] == $password)
{
$message = "<font color=\\"green\\">Successful login!</font>";
}
$login 和 $password 来自 admin/settings.php,默认是 bee 和 bug。
5.2 通关方法
输入:
Login: bee
Password: bug
登录成功。

六、三种级别对比
| Low | ba_insecure_login_1.php | HTML 源码(硬编码,白色字体隐藏) | 硬编码凭证泄露 |
| Medium | ba_insecure_login_2.php | JavaScript 混淆代码 | 客户端密码可提取 |
| High | ba_insecure_login_3.php | 数据库 | 正常验证(需知道凭证) |
七、真实世界:硬编码凭证泄露案例
硬编码凭证泄露是开发中非常常见的安全问题:
CVE-2024-1181:某开源项目管理工具的前端源码中硬编码了 AWS 访问密钥,导致大量云资源被非法访问,CVSS 评分 9.1(严重)。
CVE-2024-4910:某智能家居 App 的 JavaScript 文件中硬编码了 API 密钥,攻击者可提取密钥控制用户设备。
CVE-2025-22143:某在线教育平台的登录页面源码中硬编码了管理员测试账号,攻击者可利用该账号访问后台管理系统。
CVE-2025-41428:某医疗系统的前端代码中包含硬编码的数据库连接字符串,导致患者数据泄露。
CVE-2026-10967:某金融系统的移动端 App 中硬编码了支付接口密钥,攻击者可利用该密钥伪造支付请求。
八、总结
这一关演示了三种“不安全登录”的典型错误:
-
Low 级别——硬编码凭证:账号密码直接写在 HTML 里,用白色字体隐藏。安全靠“看不见”是幼稚的想法——查看源码就能发现。
-
Medium 级别——客户端混淆密码:密码藏在 JavaScript 混淆代码中。混淆 ≠ 加密,任何人都可以在浏览器开发者工具中提取。前端的一切代码都不安全。
-
High 级别——数据库验证:这才是正确的做法——凭证存放在服务端数据库,通过验证逻辑比对。但前提是要有正确的账号密码。
这三个级别呈现了一个从“最不安全”到“相对安全”的演进过程。记住一句话:永远不要在前端存放敏感信息,永远不要在客户端做安全判断。
重要声明:本教程及文中所有操作仅限于合法授权的安全学习与研究。作者及发布平台不承担因不当使用本教程所引发的任何直接或间接法律责任。请务必遵守中华人民共和国网络安全相关法律法规。
如果这篇文章帮你解决了实操上的困惑,别忘记点击点赞、分享,也可以留言告诉我你遇到的其它问题,我会尽快回复。你的关注是我坚持原创和细节共享的力量来源,谢谢大家。

