register_globals导致的变量覆盖问题
默认在5.4中废弃
register_globals的意思就是注册为全局变量,所以当On的时候,传递过来的值会被直接的注册为全局变量直接使用,而Off的时候,我们需要到特定的数组里去得到它。 C O O K I E , _COOKIE, COOKIE,_POST,$_GET全部会注册为全局变量.
漏洞原理
变量覆盖是指可以用自己的传参值代替程序原有的变量值。
漏洞寻找
例如下面的函数或者语法使用不当时就会出现漏洞。
$$
extract()
parse_str()
import_request_variables()
mb_parse_str
register_globals
$$
原理
$$产生的漏洞主要是因为foreach遍历数组的值,然后将获取的数组键名作为变量,数组中的值作为变量的值。
在这先简单介绍一下foreach和$$。
foreach循环只适用于数组,并用于遍历数组中的每个键/值对。
<
?php
$colors = array("red","green","blue","yellow");
foreach ($colors as $value) {
echo "$value n";
}
?>
输出:red
green
blue
yellow
$$这里举个例子
在PHP中, v a r 表 示 一 个 名 为 v a r 的 普 通 变 量 , 它 存 储 字 符 串 、 整 数 、 浮 点 等 任 何 值 。 而 var表示一个名为var的普通变量,它存储字符串、整数、浮点等任何值。而 var表示一个名为var的普通变量,它存储字符串、整数、浮点等任何值。而 v a r 是 一 个 引 用 变 量 , 用 于 存 储 var是一个引用变量,用于存储 var是一个引用变量,用于存储var的值。
在我看来就是套娃。 先来个简单的
$a = "b";
$$a = "123"
echo $b;
结果 : 123
<?php
$var = "ee";
$$var = "eeknight";
echo $var ;
echo "n";
echo $$var;
echo "n";
echo "$ee";
?>
输出:ee
eeknight
eeknight
php中的数组
通过数组可以一次性定义一组变量.
数组有多个元素组成,每个元素相当于一个变量
每一个元素是一个"键值对" (key => value) , 键是变量的名字, 值是变量中的数据.
<?php
$a[1] = "bihuo";
$a[2] = "lisi";
$a[3] = 123;
print_r($a);
echo"<br/>";
var_dump($a);
foreach函数遍历数组
.foreach函数有两种语法格式:
·foreach(array as v a l u e ) , 循 环 读 取 数 组 中 元 素 的 值 并 赋 值 给 变 量 value),循环读取数组中元素的值并赋值给变量 value),循环读取数组中元素的值并赋值给变量value。。
·foreach(array as k e y = > key=> key=>value),循环读取数组中元素的键赋值给变量 k e y , 元 素 的 值 赋 值 给 变 量 key,元素的值赋 值给变量 key,元素的值赋值给变量value。
$users=array("01"=>"zhangsan","02"=>"1isi","03"=>123);
$colors = array("red","green","blue");
foreach($users as $value) {
echo $value . "<br/>";
}
foreach($colors as $key=>$value) {
echo "$key=>$value" . "<br/>";
}
来看一个例题
foreach 配合$$
<?php
//可变变量
//$a = 'b';
//$$a = 'hello';
//echo $b;
foreach (array('_GET', '_POST', '_COOKIE') as $item) {
foreach ($$item as $k => $v) {
//$$item = $_GET as $k=>$v 这里可变变量 $_GET
$$k = $v; //$$k = $XDEBUG_SESSION_START = PHPSTORM
} //数值定义变量 $a = " bihuo.cn"
}
if (!isset($a)) {
$a = 100; // bihuo.cn
}
if ($a == 'bihuo.cn') {
echo 'ok';
}
举个例子
php
<?php
include'flag.php';
$yds = "dog";
$is = "cat";
$handsome = 'yds';
foreach($_GET as $x => $y){
//get传值
$$x = $$y; //漏洞在这里 比如输入 yds=flag 相当于 $yds=$flag
}
foreach($_GET as $x => $y){
if($_GET['flag'] === $x && $x !== 'flag'){
//判断get传进来的值等不等于flag 如果等于flag则跳过
exit($handsome);
}
}
//检测get是否为flag 或者post是否为flag 必须两方都为假 否则输出$yds
//通过这里我们就可以结合前面的来构造 既然要输出$yds所以我们想办法让$flag的值赋值给$yds
//构造yds=flag GET传输 在经过第一个foreach的时候进行了赋值 等于进行了这样的一个操作$yds=$flag
//所以这个条件为真就可以输出flag了。
if(!isset($_GET['flag']) && !isset($_POST['flag'])){
exit($yds);
}
//
//检测POST flag是否为flag 或者get 是否为flag //至少有一个为真则为真
if($_POST['flag'] === 'flag' || $_GET['flag'] === 'flag'){
exit($is);
}
echo "the flag is: ".$flag;
?>
parse_str() 解析字符串 目前用的很多
将字符串中的值注册为全局变量表中的变量
默认的话 就是将str中的值注册为全局变量
例如
<?php
$str = $_GET['str'];
parse_str($str);
if ($name === 'bihuo.cn'){
echo 'success';
}
else{
echo 'fail';
}
<?php
$str = $_GET['str'];
parse_str($str);
if ($name === 'bihuo.cn' && $age === '18'){
echo 'success';
}
else{
echo 'fail';
}
parse_str能够解析多个变量
需要%26编码
在看这一个例题
<?php error_reporting(0);
$a = "www.bihuo.cn";
$id = $_GET['id'];
@parse_str($id);
var_dump($a);
if ($a[0] != "QNKCDZO" && md5($a[0]) == md5("QNKCDZO")) {
echo "success";
} else {
exit("failure");
}
传一个数组 md5弱类型
注意点 将变量导入到指定的数组中
extract() 转换独立的变量
这里先分析函数,再分析漏洞。
extract()
原理
extract()
函数可以将数组中的元素转换切多个独立的变量
他使用数组键名作为变量名,使用数组值作为变量值
例如 这是本来的使用
<?php
$a ="roda";
$my_array = array("a" => "123","b" => "456", "c" => "567");
extract($my_array);
echo "\$a = $a; \$b = $b; \$c = $c";
echo "<br>";
echo "$a";
extract变量覆盖
这个变量的名字正好跟这个数组里边的这个元素的键重名
<?php
$a = "eeknight";
$my_array = array("a" => "C","b" => "T", "c" => "F");
extract($my_array);
echo "\$a = $a; \$b = $b; \$c = $c";
?>
输出:
$a = C; $b = T; $c = F
如果要避免覆盖原有的变量,可以在extract()函数中加上EXTR_PREFIX SAME参数。
·这样如果有冲突,就在变量名前加上前缀,当然前缀也需要由我们来指定。
这里先举个例子
<?php
$a="echo 'eeknight';";
echo $a;
echo "n";
eval($a);
?>
输出:
echo 'eeknight';
eeknight
在上面双引号包裹了单引号,然后通过eval去利用他,就可以直接输出单引号里的东西了。
为什么要说这个东西,因为当你单引号里的东西可以被利用,是不是就可以写什么执行什么了。
怎么利用呢,这时候刚才介绍的extract就发挥作用了。
把上面的例子简单改一下
<?php
$a="echo 'eeknight';";
extract($_GET);
eval($a);
?>
例题
<?php $flag = 'flag.php';
extract($_GET);
if (isset($ceshi)) {
$content = trim(file_get_contents($flag));
if ($ceshi == $content) {
echo 'flag{bihuo.cn}';
} else {
echo 'Oh.no';
}
} ?>
<?php
include 'flag.php';
if ($_SERVER['REQUEST_METHOD'] == 'POST'){
extract($_POST);
if ($pass == $bihuo){
echo 'now this is the flag:{bihuo.cn}';
}
}
<?php
include 'flag.php';
$status_403 = 'denied';
$status_200 = 'ok';
if ($_SERVER['REQUEST_METHOD'] == 'POST'){
if (!isset($_POST['flag'])){
exit($status_403);
}
foreach ($_GET as $k=>$v){
$$k = $$v;
}
foreach ($_POST as $k=>$v){
$$k = $v;
}
if ($_POST['flag'] !== $flag){
exit($status_403);
}
echo 'now the flag is '.$flag;
}
import_request_variables变量覆盖
参考 https://www.secpulse.com/archives/155955.html