PHP代码审计之变量覆盖

漏洞简介


什么是变量覆盖?

变量覆盖指的是用我们自定义的参数值替换程序原有的变量值,

通常来说,单独的变量覆盖漏洞很难有利用价值,需要和其他漏洞结合起来才能完成攻击

但在某些情况下,可可通过变量覆盖漏洞直接获取getshell

变量覆盖漏洞,很难通过黑盒测试发现,需要掌握白盒审计

漏洞原理


漏洞产生

  • 经常导致变量覆盖漏洞场景有:$$使用不当,extract()函数使用不当,parse_str()函数使用不当,import_request_variables()使用不当,开启了全局变量注册等。
  • 全局变量注册,register_globals的意思就是注册为全局变量,所以当On的时候,传递过来的值会被直接的注册为全局变量直接使用,而Off的时候,我们需要到特定的数组里去得到它。
  • 从 PHP » 4.2.0 版开始配置文件中 PHP 指令 register_globals 的默认值从 on 改为 off 了,自 PHP 5.3.0 起废弃并将自 PHP 5.4.0 起移除,所以这个应该是比较少了

漏洞复现


全局变量覆盖漏洞

当register_global=ON时,变量来源可能是各个不同的地方,比如页面的表单,Cookie等。

";

if ($a){
   echo "success!";
}
?>

尝试代码,开始全局变量,如下

PHP代码审计之变量覆盖_第1张图片

PHP代码审计之变量覆盖_第2张图片

如果上面的代码中,已经对变量$a赋了初始值,比如$a=0,那么即使在URL中有/test.php?a=1,也不会将变量覆盖,a值为0

PHP代码审计之变量覆盖_第3张图片

通过$GLOBALS获取的变量,也可能导致变量覆盖

"; 
if (ini_get('register_globals')) foreach($_REQUEST as $k=>$v) unset(${$k});  
print $a."
"; print $_GET[b]; ?>

变量$a未初始化,在register_globals=ON时,再尝试控制“$a”的值(http://xxx.xxx.x.x/test.php?a=1&b=2),会因为这段代码而出错

PHP代码审计之变量覆盖_第4张图片

而当尝试注入“GLOBALS[a]”以覆盖全局变量时(http://xxx.xxx.x.x/test.php?GLOBALS[a]=1&b=2),则可以成功控制变量“$a”的值。这是因为unset()默认只会销毁局部变量,要销毁全局变量必须使用$GLOBALS,unset用于释放给定的变量

PHP代码审计之变量覆盖_第5张图片

$$使用不当

$$ 导致的变量覆盖问题在CTF代码审计题目中经常在foreach中出现,

如以下的示例代码,使用foreach来遍历数组中的值,然后再将获取到的数组键名作为变量,数组中的值作为变量的值。

因此就产生了变量覆盖漏洞。请求?name=test 会将$name的值覆盖,变为test

$_value) 
{$$_key=addslashes($_value);}}
echo $a;
?>

PHP代码审计之变量覆盖_第6张图片

extract()变量覆盖

函数定义

extract()函数能将变量从数组导入当前的符号表,其函数定义如下:

extract(array,extract_rules,prefix)
  • array 必需。规定要使用的数组
  • extract_rules 可选。extract() 函数将检查每个键名是否为合法的变量名,同时也检查和符号表中已存在的变量名是否冲突。对不合法和冲突的键名的处理将根据此参数决定
  • 前缀和数组键名之间会自动加上一个下划线

函数作用

该函数使用数组键名作为变量名,使用数组键值作为变量值。针对数组中的每个元素,将在当前符号表中创建对应的一个变量。

第二个参数 type 用于指定当某个变量已经存在,而数组中又有同名元素时,extract() 函数如何对待这样的冲突。

该函数返回成功导入到符号表中的变量数目

  • EXTR_OVERWRITE - 默认。如果有冲突,则覆盖已有的变量。
  • EXTR_SKIP - 如果有冲突,不覆盖已有的变量。
 "Cat","b" => "Dog", "c" => "Horse");
extract($my_array);
echo "\$a = $a; \$b = $b; \$c = $c";
?>

PHP代码审计之变量覆盖_第7张图片

PHP代码审计之变量覆盖_第8张图片

下面给出一个靶场,挺不错的:http://chinalover.sinaapp.com/web18/

parse_str()变量覆盖

函数定义

函数定义如下:

parse_str(string,array)
  • string 必需。规定要解析的字符串
  • array 可选。规定存储变量的数组的名称。该参数指示变量将被存储到数组中

函数作用

parse_str()中如果未设置 array 参数,则由该函数设置的变量将覆盖已存在的同名变量

该函数在注册变量之前不会验证当前变量是否已存在,如果存在会直接覆盖

PHP代码审计之变量覆盖_第9张图片

题目分析 

**$a[0] != ‘QNKCDZO’ && md5($a[0]) == md5(‘QNKCDZO’)**
**PHP Hash比较存在缺陷**
**md5(‘QNKCDZO’)**的结果是**0e830400451993494058024219903391**

PHP在处理哈希字符串时,会利用”!=”或”==”来对哈希值进行比较,它把每一个以”0E”开头的哈希值都解释为0,所以如果两个不同的密码经过哈希以后,其哈希值都是以”0E”开头的,那么PHP将会认为他们相同,都是0。详细参照 http://www.freebuf.com/news/67007.html
 

解题思路

md5(s878926199a)=0e545993274517709034328855841020 php解析为0

php处理哈希字符串 http://www.cnblogs.com/Primzahl/p/6018158.html

使用get请求?id=a[0]=s878926199a 得到flag

PHP代码审计之变量覆盖_第10张图片

与parse_str()类似的函数还有mb_parse_str()

import_request_variables()变量覆盖

函数定义

(PHP 4 >= 4.1.0, PHP 5 < 5.4.0)

函数定义如下:

bool import_request_variables ( string $types [, string $prefix ] )

$type代表要注册的变量,G代表GET,P代表POST,C代表COOKIE,第二个参数为要注册变量的前缀

函数作用

import_request_variables—将 GET/POST/Cookie 变量导入到全局作用域中

import_request_variables()函数就是把GET、POST、COOKIE的参数注册成变量,用在register_globals被禁止的时候

PHP代码审计之变量覆盖_第11张图片

推荐审计


多米cms2.0,会在后续文章单独写

PHP代码审计之变量覆盖_第12张图片

你可能感兴趣的:(web渗透学习笔记)