变量覆盖漏洞
本文最后更新于40 天前,其中的信息可能已经过时,如有错误请发送邮件到1416359402@qq.com

什么是变量覆盖?

变量覆盖指的是可以用我们的传参值替换程序原有的变量值

比如

<?php
$ a=1;
$ a=2;
echo $a;
?>

像这个输出是2因为a=2覆盖了a=1

基本概念

  • 程序未正确验证用户输入
  • 用户输入被直接赋值给变量
  • 缺乏适当的过滤和验证机制

怎么去寻找变量覆盖?

经常导致变量覆盖漏洞场景有:$$使用不当,extract()函数使用不当,parse_str()函数使用不当import_request_variables()使用不当,开启了全局变量注册等,还是要多多代码审计

手动测试

  1. 识别接收用户输入的入口点
  2. 尝试覆盖已知变量
  3. 观察程序行为变化

自动化工具

  • 使用Burp Suite等工具进行参数模糊测试
  • 自定义扫描规则检测危险函数

变量覆盖漏洞有的时候可以直接让我们获取Webshell,拿到服务器的权限

什么是变量覆盖漏洞

变量覆盖指的是用我们自定义的参数值替换程序原有的变量值,一般变量覆盖漏洞需要结合程序的其它功能来实现完整的攻击。变量覆盖漏洞大多数由函数使用不当导致,$$使用不当,extract()函数使用不当,parse_str()函数使用不当,import_request_variables()使用不当,开启了全局变量注册等。

危害

变量覆盖漏洞的危害非常广泛,因为攻击者能够改变程序的行为,绕过安全机制,甚至获取系统权限。以下是一些主要的危害:

1.认证绕过:攻击者可以覆盖用于认证的变量,例如将`$is_admin`覆盖为`true`,从而获得管理员权限。
2.权限提升:通过覆盖角色或权限变量,攻击者可以提升自己的权限,执行未授权的操作。
3.业务逻辑绕过:例如在电子商务网站中,覆盖价格变量,从而以低价购买商品。
4.信息泄露:通过覆盖配置变量,开启调试模式,从而泄露敏感信息,如数据库连接字符串、系统路径等。
5.任意文件读取:覆盖文件路径变量,读取任意文件,包括系统文件、配置文件等。
6.任意代码执行:通过覆盖变量,导致包含恶意文件或执行任意命令。
7.数据库操作:覆盖数据库连接变量,导致连接攻击者控制的数据库,或者覆盖SQL查询条件,导致数据泄露或篡改。
8.会话劫持:覆盖会话变量,冒充其他用户。

函数解析

经常引发变量覆盖漏洞的函数有:extract() parse_str() import_request_variables()

extract()函数(作用:将数组中将变量导入到当前的符号表)

PHP中的extract()函数

extract() 函数从数组中将变量导入到当前的符号表。
该函数使用数组键名作为变量名,使用数组键值作为变量值。针对数组中的每个元素,将在当前符号表中创建对应的一个变量。
该函数返回成功设置的变量数目。

实例:

<?php
$a = "1";
$my_array = array("a" => "Cat","b" => "Dog", "c" => "Horse");
extract($my_array);
echo "$a = $a; $b = $b; $c = $c";
?>
运行结果:$a = Cat; $b = Dog; $c = Horse
// 漏洞代码
extract($_GET);
if ($is_admin) {
    // 执行管理员操作
}

// 攻击:?is_admin=1

extract()函数(作用:从数组中将变量导入到当前的符号表) 一道CTF题目

分析源码我们可以知道,

1、文件将get方法传输进来的值通过extrace()函数处理。

2、通过两个if语句分别判断是否存在gift变量,和变量gift的值和变量content的值是否相等。变量content的值是通过读取变量test的值获取到的。如果两个变量相等输出flag。如果不相等,输出错误。

似乎逻辑上没啥问题,但是如果我们传参了test呢?

第一开始test在php中已经定义了,但是因为extrace()函数,我传参test时相当于重新给test赋值对不对?因为php执行语句是自上而下,那我传的参数完全可以覆盖掉之前所定义的

那么当我传参gift=a&test=a,相当于$gift=a;$test=a
那么这里是不是就直接输出flag了呢 (因为$content是由$test决定,$gift和$test都是我可以决定的)

parse_str()函数

parse_str函数的作用就是解析字符串并注册成变量,在注册变量之前不会验证当前变量是否存在,所以直接覆盖掉已有变量

注意:如果未设置 array 参数,由该函数设置的变量将覆盖已存在的同名变量。

parse_str() 将查询字符串解析到变量中:

<?php
    parse_str("name=zkaq&&age=60");   // test=123&gift=123
    echo $name."<br>";
    echo $age;
    ?>
输出了zkaq和60 
那么parse_str("name=Bill&age=60") 相当于完成了$name ='zkaq'和$age ='60'

那么如果在parse_str中可以直接传参的话,那么是不是也可以覆盖变量呢。
// 漏洞代码
parse_str($_SERVER['QUERY_STRING']);
if ($authenticated) {
    // 访问敏感功能
}

// 攻击:?authenticated=1

什么是$$

$$这种写法称为可变变量,一个可变变量获取了一个普通变量的值作为这个可变变量的变量名。

不仅仅是函数会导致变量覆盖,有些特殊符号的特殊搭配也会引起变量覆盖漏洞,比如$$

$$ 导致的变量覆盖问题在CTF代码审计题目中经常在foreach中出现,如以下的示例代码,使用foreach来遍历数组中的值,然后再将获取到的数组键名作为变量,数组中的值作为变量的值。因此就产生了变量覆盖漏洞。请求?name=test 会将$name的值覆盖,变为test。

上一个例题:

<?php
$a = 1;
foreach(array('_COOKIE','_POST','_GET') as $_request) {
foreach($_request as $_key=>$_value) 
{$_key=addslashes($_value);}}
echo $a;
?>
这个代码会接受我们的GET提交、POST提交、COOKIE参数,将这个接受来的参数依次放入$_request
    $_key=>$_value 这是个数组解析,实际上就是键值分离
正常而言$a = 1是一个定值,但是因为$_key的缘故,当我传参a=2;那么$_key=addslashes($_value);就变为了$a = 2 .
// 基本动态变量
$var_name = "username";
$var_name = "John Doe"; // 创建变量 $username = "John Doe"

// 在循环中使用
foreach ($_REQUEST as $key => $value) {
    $key = $value; // 极度危险!
}

import_request_variables()

import_request_variables—将 GET/POST/Cookie 变量导入到全局作用域中
import_request_variables()函数就是把GET、POST、COOKIE的参数注册成变量,用在register_globals被禁止的时候

// 漏洞代码(PHP < 5.4)
import_request_variables('G');
if ($admin_flag) {
    // 管理员权限
}

此函数在 PHP 5.4.0 中已被移除

漏洞分类

直接变量覆盖

// 示例代码
$is_admin = false;
extract($_POST);

if ($is_admin) {
    // 执行管理员操作
}

攻击者可通过提交 is_admin=1 来提升权限。

全局变量覆盖

// 旧版PHP中register_globals开启时
// 用户提交 ?admin=1 会自动创建 $admin 变量
if ($admin) {
    // 管理员功能
}

数组键名覆盖

$config = array(
    'debug' => false,
    'security_level' => 'high'
);

foreach($_GET as $key => $value) {
    $config[$key] = $value;
}

漏洞利用技术

基础利用

GET /vulnerable.php?is_admin=1&username=attacker HTTP/1.1

条件竞争利用

// 存在条件竞争的场景
if (isset($_POST['token']) && $_POST['token'] === $secret_token) {
    $authorized = true;
}

// 稍后检查
if ($authorized) {
    // 执行敏感操作
}

对象属性覆盖

class User {
    public $is_admin = false;
    public $username = 'guest';
}

$user = new User();
extract($_POST); // 可能覆盖$user对象的属性

案例分析

WordPress插件漏洞 (CVE-2018-12895)

// 漏洞代码片段
extract(shortcode_atts(array(
    'count' => 10,
    'type' => 'post'
), $atts));

// 攻击者可以通过shortcode属性覆盖任意变量
// [shortcode count=10 type=post _wpnonce=invalid]

知名CMS配置覆盖漏洞

// 安装脚本中的漏洞
$db_host = 'localhost';
$db_user = 'root';
$db_pass = '';

// 从配置文件读取
if (file_exists('config.php')) {
    include 'config.php';
}

// 攻击者可以在包含前覆盖变量
// 请求:?db_host=attacker-server.com&db_user=hacker

漏洞演示环境

<?php
// vulnerable_demo.php
error_reporting(0);

$is_authenticated = false;
$user_role = 'guest';

// 危险代码 - 存在变量覆盖漏洞
if (isset($_GET['action']) && $_GET['action'] == 'login') {
    extract($_POST);

    if ($is_authenticated && $user_role == 'admin') {
        echo "Welcome Admin! Flag: FLAG{sanjiu6666flag}";
    } else {
        echo "Access Denied!";
    }
}
?>

<form method="post" action="?action=login">
    <input type="text" name="username" placeholder="Username">
    <input type="password" name="password" placeholder="Password">
    <input type="submit" value="Login">
</form>

代码审计

代码逻辑

初始化两个变量:$is_authenticated 设置为 false$user_role 设置为 'guest'

检查GET参数 action 是否为 login,如果是,则执行登录逻辑。

在登录逻辑中,使用 extract($_POST) 将POST数组中的键值对转换为变量。例如,如果POST数据中有 username=test,那么就会创建一个变量 $username 并赋值为 'test'

然后检查 $is_authenticated 是否为真,并且 $user_role 是否为 'admin'。如果两个条件都满足,就输出管理员欢迎信息和flag;否则,输出“Access Denied!”。

漏洞产生原因

漏洞在于使用了 extract($_POST) 函数。这个函数会将POST请求中的每个参数都转换为变量,并且如果已经存在同名的变量,则会覆盖原有的变量。

在代码中,原本已经定义了 $is_authenticated$user_role 两个变量。但是,通过 extract($_POST),攻击者可以通过POST请求提交同名的参数来覆盖这两个变量的值。

利用原理

攻击者可以构造一个POST请求,其中包含两个参数:is_authenticateduser_role,并分别设置值为 1(或任何非零值,在条件判断中为真)和 'admin'。这样,当执行 extract($_POST) 时,原本的 $is_authenticated$user_role 就会被覆盖为攻击者指定的值。

因此,在后续的条件判断中:

if ($is_authenticated && $user_role == 'admin')

条件就会成立,因为现在 $is_authenticated 为真(被覆盖为1),并且 $user_role'admin'(被覆盖为'admin')。

流程详解

1:GET参数触发条件

GET参数: ?action=login

满足条件 isset($_GET['action']) && $_GET['action'] == 'login'

进入if语句块,执行 extract($_POST)

2:extract()函数执行

extract($_POST); // 将POST数组转换为变量

POST数据解析为:

$_POST = array(
    'is_authenticated' => '1',
    'user_role' => 'admin',
    'username' => 'test',
    'password' => 'test'
);

extract()执行后相当于:

$is_authenticated = '1';    // 覆盖了原来的false
$user_role = 'admin';       // 覆盖了原来的'guest'
$username = 'test';
$password = 'test';

3:条件检查

if ($is_authenticated && $user_role == 'admin') {

现在变量的值:

  • $is_authenticated = '1' (布尔值为true)
  • $user_role = 'admin' (等于’admin’)

条件判断:

  • $is_authenticated → true
  • $user_role == 'admin' → true
  • 整体条件:true && true → true

Payload

POST /vulnerable_demo.php?action=login HTTP/1.1
Content-Type: application/x-www-form-urlencoded

is_authenticated=1&user_role=admin&username=test&password=test

总结

变量覆盖漏洞是一个严重的安全威胁,主要源于:

  1. 危险函数的不当使用 – extract(), parse_str()等
  2. 缺乏输入验证 – 直接使用用户输入赋值变量
  3. 动态变量滥用 – $$var形式的变量操作
  4. 配置不当 – register_globals等危险配置

防护核心原则

  • 避免使用危险函数 – 如extract()、parse_str()等
  • 实施输入验证 – 使用白名单机制
  • 明确变量初始化 – 避免使用未初始化的变量
  • 代码安全审查 – 定期检查代码中的安全隐患

文末附加内容
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇