CTFshow Web 应用安全与防护 | Base64编码隐藏、HTTP头注入、Base64多层嵌套解码 Base64编码隐藏是一个登录框页面根据题目名能够知道是一个 base 编码隐藏了查看源码在最下面找到了一串 base64 编码Q1RGe2Vhc3lfYmFzZTY0fQ解码CTF{easy_base64}本题考点信息收集、base64 编码HTTP头注入目录扫描到了 check.php index.php两个都访问了下并没有什么用使用adminCTF{easy_base64}进行登录返回必须使用特定的浏览器才能够登录成功User-Agent: ctf-show-brower返回 flagCTF{user_agent_inject_success}本题考点HTTP 注入、抓包Base64多层嵌套解码查看页面源代码发现了 base64 编码对代码审计知道了他对这个 base64 编码进行了多层嵌套加密document.getElementById(loginForm).addEventListener(submit, function(e) { const correctPassword SXpVRlF4TTFVelJtdFNSazB3VTJ4U1UwNXFSWGRVVlZrOWNWYzU; function validatePassword(input) { let encoded btoa(input); encoded btoa(encoded xH7jK).slice(3); encoded btoa(encoded.split().reverse().join()); encoded btoa(aB3 encoded qW9).substr(2); return btoa(encoded) correctPassword; } const enteredPassword document.getElementById(password).value; const messageElement document.getElementById(message); if (!validatePassword(enteredPassword)) { e.preventDefault(); messageElement.textContent Login failed! Incorrect password.; messageElement.className message error; } });在控制台运行脚本得到密码使用任意一个密码都能够登录成功// 定义一个常量 correctPassword用来保存题目中给出的最终目标字符串也就是最后要比对的“正确结果” const correctPassword SXpVRlF4TTFVelJtdFNSazB3VTJ4U1UwNXFSWGRVVlZrOWNWYzU; // 定义一个函数 validatePassword用来验证输入的密码 input 是否能够通过题目的校验 function validatePassword(input) { // 第一步把输入的密码 input 进行 Base64 编码并把结果保存到变量 encoded 中 let encoded btoa(input); // 第二步 // 1. 先把上一步的 encoded 和固定字符串 xH7jK 拼接起来 // 2. 再对拼接后的结果做一次 Base64 编码 // 3. 最后使用 slice(3) 从下标 3 开始截取到末尾相当于删掉前 3 个字符 encoded btoa(encoded xH7jK).slice(3); // 第三步 // 1. 先用 split() 把字符串 encoded 拆成字符数组 // 2. 再用 reverse() 把字符顺序反转 // 3. 再用 join() 把反转后的数组重新拼接成字符串 // 4. 最后对这个倒序后的字符串再做一次 Base64 编码 encoded btoa(encoded.split().reverse().join()); // 第四步 // 1. 在当前 encoded 前面拼接固定字符串 aB3 // 2. 在当前 encoded 后面拼接固定字符串 qW9 // 3. 对拼接后的整体再做一次 Base64 编码 // 4. 再用 substr(2) 从下标 2 开始截取到最后相当于删掉前 2 个字符 encoded btoa(aB3 encoded qW9).substr(2); // 第五步 // 把当前的 encoded 再进行一次 Base64 编码 // 然后使用 与最开始定义的 correctPassword 进行严格比较 // 如果完全相等返回 true否则返回 false return btoa(encoded) correctPassword; } // 使用 for 循环来枚举 ASCII 码从 32 到 126 的所有常见可打印字符 for (let i 32; i 126; i) { // 把当前 ASCII 码 i 转成对应字符再和字符串 17316 拼接组成一个待测试的密码 let test String.fromCharCode(i) 17316; // 调用 validatePassword(test) 检查这个测试密码是否能通过校验 if (validatePassword(test)) { // 如果能通过校验就把这个可用密码输出到浏览器控制台中 console.log(test); } }使用脚本跑出来的密码进行登录登录之后和上一题一样也需要更改 User-Agent返回 flagCTF{base64_brute_force_success}本题考点代码审计