HackThisSite - Extended Basic Mission 06
Challenge
This site is run by a new sysadmin who does not know much about web configuration. The script is located at http://moo.com/moo.php Attempt to make the script think you are authed by entering the correct URI. 进入正确的 URI,让脚本以为你已经通过认证。
关卡页给出脚本 me.php 的源码:
1 |
|
页面底部还有一行全局提醒:All missions are case sensitive. I tried to keep them lowercase however.。答案大小写敏感。
Solution
isAuthed($a,$b) 的返回值写死为
FALSE,所以走正常表单提交
user/pass,if (isAuthed($user,$pass))
永远不成立,$passed = TRUE
这一行根本不会执行。想从凭据这条路进去是没有出口的。
脚本只从 $_GET 里取了 user 和
pass,$passed
在整个文件里没有任何赋值默认值的语句:
1 | $user = $_GET['user']; |
如果 $passed 只是一个普通的未定义局部变量,第二个
if
恒为假,这题无从下手。题面第一句正是钥匙:new sysadmin who does not know much about web configuration,一个不懂
Web 配置的管理员,对应的就是这个时代最典型的一项 PHP
配置错误:register_globals = On。
当 register_globals 打开时,PHP
会在脚本运行前把查询字符串里的每个键自动导入成同名全局变量。于是
URL 里的 passed 会直接落到脚本的 $passed
上,完全绕过 isAuthed() 这条分支。
要让 $passed == TRUE 成立,只需在 URL 上挂一个
passed 参数:
1 | http://moo.com/moo.php?passed=TRUE |
PHP 的松散比较 ==
在两侧类型不同时会做类型转换:字符串和布尔值比较时,字符串被转成布尔值,任何非空且非
"0" 的字符串都为真。因此
"TRUE" == TRUE 求值为 true,脚本进入
if 分支并输出 you win。
值按源码里惯用的写法给 TRUE。
formkey
每次加载关卡页都会变,取页面和提交必须在同一次运行里完成;cookie
只从环境变量读入,不落盘。
1 | import os |
关卡以 You have already done this mission. 与个人资料的
Extbasic: 徽章 (6) 两处同时作为完成判据。
Key points
register_globals会把查询字符串的键自动提升为全局变量,攻击者可以覆盖脚本本应自己掌控的标志位(如$passed)- 判断是否登录/是否通过的标志必须由服务端在可信逻辑里赋值,不能依赖任何用户可控的名字
- 认证分支不可达时,漏洞往往在缺失的初始化和宽松比较上,而不是在比较内容上
==的类型转换让"TRUE" == TRUE为真;权限判断应使用===并显式校验类型register_globals早已在 PHP 5.4 中被移除,现代 PHP 不再存在这条路径