freeBuf
主站

分类

云安全 AI安全 开发安全 终端安全 数据安全 Web安全 基础安全 企业安全 关基安全 移动安全 系统安全 其他安全

特色

热点 工具 漏洞 人物志 活动 安全招聘 攻防演练 政策法规

点我创作

试试在FreeBuf发布您的第一篇文章 让安全圈留下您的足迹
我知道了

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

99+
通过代码审计去学习变量覆盖
0x7e 2020-07-02 21:44:11 261985

前言

这篇文章是我在 前几个月写的,然后如今才打算发布的,咳咳,也没啥可以写的,就写一下变量覆盖的形成,如何代码审计查找白盒专属的变量覆盖漏洞。

变量覆盖是有啥用处?

变量覆盖可以使用我们自定义的变量去覆盖 源代码中的变量,去修改代码运行的逻辑。变量覆盖与其他漏洞结合后 伤害是比较大的,比如商品购买的支付系统如果存在变量覆盖的话可能出现0元支付下单的情况,或者说 登录管理员后台的时候,通过变量覆盖,进行登录后台(这篇文章讲解的就是duomicms的变量覆盖进入后台,小白也很容易懂)。

正文

变量覆盖产生原因引发变量覆盖漏洞函数:

  1. extract()

  2. parse_str()

  3. Import_request_variables()

  4. $$(双美元符)

  5. Register_globals=On (PHP 5.4之后移除)

0x01. extract() 函数

这时候看一下菜鸟教程是怎么使用的

file

看下语法是 extract(array,value1,value2)我们发现第一个参数是必选值,然后就不必说了

这时候我们发现,其实关键的是第二个参数值

EXTR_OVERWRITE - 默认。如果有冲突,则覆盖已有的变量。

并且发现这里是默认的,这时候就稳妥了,这就导致可以变量覆盖了

<?php
$user = 'user';
echo "欢迎用户 $user !<br>";
$admin = array('user' => 'admin');
extract($admin);
echo "欢迎管理员 $user ";?>

看下这个代码逻辑,变量user 等于 字符串user然后输出这个变量 user之后我们再定义一个变量admin然后就是定义数组,键为 字符串 user,值为admin然后通过extract() 这个函数,里面就是数组

 array(‘user’ => ‘admin’)

然后是默认 EXTR_OVERWRITE 这个参数,这时候发现键名和上面的变量名重复于是就会覆盖掉原本那个 userfile

0x02.parse_str()函数

老规矩,看下是怎么解释的,这里说,如果没有设置array参数那么函数设置的变量将会覆盖已经存在的 同名变量file然后我们看下面这个 array这个参数规定存储变量的数组的名称。该参数指示变量将被存储到数组中所以也就是说,我们只要没有array这个参数,就会导致变量覆盖这个漏洞

<?php
$username = 'user';
print_r('执行函数覆盖之前:$username ='.$username."<br>");

// 执行函数 parse_str() ,然后里面没有数组成功覆盖
parse_str("username=admin");
print_r('执行函数覆盖之后:$username ='.$username);
?>

file

0x03. import_request_variables()函数

file这里我们简单的看下type参数就行,其实这里就是说P = post g = get c = cookie然后就可以理解了,从左到右的顺序这些顺序就是优先级,也就是说 gpc,意思就是说,get传参会覆盖 post传参,而post传参,则覆盖cookie传参,同理可得: get传参也可以覆盖cookie

file差不多就是这个意思了

0x04. $$双美元符导致的变量覆盖

<?php
$a = 'b';
$b= 'admin';
echo $$a;
?>

这里源码我写的比较粗糙,哥哥们看的懂就行file输出的结果为 admin,而接下来讲的就是$$导致的变量覆盖

0x05.实战讲解

file先安装好这个cms,然后再审计

漏洞地址在 upload/duomiphp/common.phpfile

我们直接进入我们的$$符查找,奈何技术太菜,没法全文通读filefile这在我的博客上面也有提到过,键值分离file先把其他的注释掉,然后我们看下 $request 是个什么鬼file其实就是把array('GET','POST','COOKIE')中的值遍历出来,其实就可以等价于

<?php
$arr = array('_GET','_POST','_COOKIE');
foreach($arr as $_request)
{
   echo $_request."<br>";
}?>

这时候我们知道第一层的 foreach是 输出 GET,POST,_COOKIE

<?php 
$arr = array('_GET','_POST','_COOKIE');
foreach($arr as $_request)
{
   foreach($$_request as $_k => $_v){
       echo $_k.'=>'.$_v."<br>";
  }
}
?>

那我们就看第二层foreach是个什么梗$request 其实就等于 _GET,POST,_COOKIE

而$$request 就等于$GET$POST$COOKIE但是这里的第二层foreach() 其实就是键值分离,而我们可以看下

file其实简单来说这3个地方可以被我们控制(代码功底不行的话可以自己写下运行一下,像本菜鸡一样,没上过大学,代码全自学,如果我写的demo有什么问题可以说一下,我会纠正,奥利给)file注意看,因为我们这边是 只使用一个函数,所以我们函数也给复制过来,然后我们在输出一下,发现就跟我们前面写的一模一样file但是我们可以看到的执行顺序是 GET > POST > COOKIE

这时候我们可以进行覆盖,我们再去看一下如何才能进入这一步file我们发现上面没有exit(),die()就忽略了

然后我们看到了那个注释下面那边有个 exit() 这时候我们不能让它进入,不然就无法执行上面讲述的代码了

<?php
foreach($_REQUEST as $_k=>$_v)
{
   if( strlen($_k)>0 && m_eregi('^(cfg_|GLOBALS)',$_k) && !isset($_COOKIE[$_k]) )
  {
       exit('Request var not allow!');
  }
}?>

我们不能让这个if条件成立 && 其实就是跟 and一样,当着 3个条件满足,才会exit我们就让其中一个不满足

第一个条件:$k就是键,我们必须要满足,我们看下面那个图,如果我们没有键的话,根本无法控制利用file第二个条件:这其实就是一个正则(这是用户自定义的,就不纠结了),然后正则里面能不能有cfg和 GLOBALS

第三个条件:isset判断是否存在,如果是,则为 true,但是前面有个 感叹号这时候意思相反 如果是则为 flase,如果否,则为 true不能有cookie某个值传参

然后我们只需要满足其中一个条件,就不会进入exit了

然后变量覆盖只能覆盖上面的代码file如果下面的代码再次定义的话,我们覆盖也没什么用的然后注意,这是在 common.php这个文件其实就是通用文件,里面定义的东西全局可能 也会调用等等这时候就去查找一下哪个文件包含了这个common.php其实我们只要找到有危害的地方就行了,像其他地方,有危害即使调用了也没有卵用

然后这时候我们发现login.php 包含了 common.phpfile这时候我们有看到了下面又调用了一个 check.admin.php了英语会点的就知道,意思就是检查 是否为admin的意思这时候我们发现找不到这个文件,duomi_INC 在哪里file这时候我们可以去打开login.phpfile然后进行简单的修改一下Exit(duomi_INC);这时候就爆出路径 file然后再去寻找一下路径file成功的在duomiphp下面找到了check.admin.php因为这边用了session_start 才能对其进行覆盖登陆后台file

然后我们全局搜索找到这个session_start()在这个/interface/comment.php 路径下这时候我们再去寻找那个check.admin.php进行构造session,进入后台fileUserlogin 顾名思义,就是用户登陆,而session需要有duomi_admin_idduomi_group_idduomi_admin_name

<?php
//获得用户的权限值
   function getgroupid()
  {
       if($this->groupid!='')
      {
           return $this->groupid;
      }
       else
      {
           return -1;
      }
  }

   function getUserRank()
  {
       return $this->getgroupid();
  }
//获得用户的ID
    function getUserID()
    {
        if($this->userID!='')
        {
            return $this->userID;
        }
        else
        {
            return -1;
        }
    }
 //获得用户名
    function getUserName()
    {
        if($this->userName!='')
        {
            return $this->userName;
        }
        else
        {
            return -1;
        }
    }
}
?>

首先是获取用户权限file这时候我们发现当 groupid=1的时候是系统管理员,我们这就开始构造payload覆盖session首先得strat一下,我们看上面写了

interface/comment.php然后我们可以在get传参里面传入session

file注意看,键值这边的话是$$符,所以我们不用再加$然后需要有3个session,第一个是用户权限

interface/comment.php?_SESSION[duomi_group_id]=1

看上面源码,获取的顺序,第二个,userid我们不知道,这也没固定,那就乱写个 1

(N[duo其实这里只要权限写对,其他随便写,因为这边只对权限进行判断,没有对用户id和用户名进行判断)

interface/comment.php?_SESSIOmi_group_id]=1&_SESSION['duomi_admin_id']=1

还剩一个用户名

interface/comment.php?_SESSION[duomi_group_id]=1&_SESSION[duomi_admin_id]=1&_SESSION[duomi_admin_name]=admin

就成功构建好了,把我脑瓜子都整的嗡嗡叫了,我语文是真的不好啊,我丢file这里提示我们要登录,这时候我们传参进去filefile这时候去访问admin页面发现成功访问了,因为session是存储在服务端,然后会持续会话,我们传参进去报错,但是session已经存储到了服务端,这时候访问admin,就可以进去了。

# web安全 # 代码审计 # 变量覆盖
免责声明
1.一般免责声明:本文所提供的技术信息仅供参考,不构成任何专业建议。读者应根据自身情况谨慎使用且应遵守《中华人民共和国网络安全法》,作者及发布平台不对因使用本文信息而导致的任何直接或间接责任或损失负责。
2. 适用性声明:文中技术内容可能不适用于所有情况或系统,在实际应用前请充分测试和评估。若因使用不当造成的任何问题,相关方不承担责任。
3. 更新声明:技术发展迅速,文章内容可能存在滞后性。读者需自行判断信息的时效性,因依据过时内容产生的后果,作者及发布平台不承担责任。
本文为 0x7e 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
0x7e LV.2
....
  • 2 文章数
  • 8 关注者
一篇文章带你了解反序列化漏洞
2020-07-02
文章目录