$_session无法存储变量怎么回事_代码审计去理解变量覆盖漏洞

前言:

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

变量覆盖是有啥用处?

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

正文

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

  1. extract()

  2. parse_str()

  3. Import_request_variables()

  4. $$(双美元符)

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

0x01. extract() 函数

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

4dfb1b52f1ad1f2fbcf4ef71f1aabb15.png

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

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

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

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

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

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

 array(‘user’ => ‘admin’)

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

716180c6ffe2002c774e50757ba575e6.png

0x02.parse_str()函数

老规矩,看下是怎么解释的,这里说,如果没有设置array参数那么函数设置的变量将会覆盖已经存在的 同名变量

fa67a1aa64c604662d82b5d345d42da4.png

然后我们看下面这个 array这个参数规定存储变量的数组的名称。该参数指示变量将被存储到数组中所以也就是说,我们只要没有array这个参数,就会导致变量覆盖这个漏洞

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

0ac45195b8ca46f91157b405744c7a11.png

0x03. import_request_variables()函数

5588407f48218711e1d095d620e00cde.png

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

8180f8301491fcb63c9fbb277010e7dc.png

差不多就是这个意思了

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

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

ba77955c794f4d5e618f6207c7b61204.png

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

0x05.实战讲解

0c125d48d9ab1514bc041b63dd830796.png

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

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

d707d00cb81e2de26d12d18d71f6061c.png

我们直接进入我们的$$符查找

4f4276157505dd73db91d010d3e5a89f.png

0de5a0b89939432d3f1a70b8dd123ef4.png

这在我的博客上面也有提到过,键值分离 点击跳转博客

849c4e885557bd80818b6ea496a400c3.png

先把其他的注释掉,然后我们看下 $request 是个什么鬼

48721892419725134fbb98f107157dc6.png

其实就是把array('GET','POST','COOKIE')中的值遍历出来,其实就可以等价于

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

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

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

那我们就看第二层foreach是个什么梗

$request 其实就等于  _GET,POST,_COOKIE

而$$request 就等于 $_GET,$_POST,$_COOKIE

但是这里的第二层foreach() 其实就是键值分离,而我们可以看下

24bb2cfd5658a88ae528c52710379533.png

其实简单来说这3个地方可以被我们控制

d7152261d7ca451516520f3117f22983.png

注意看,因为我们这边是 只使用一个函数,所以我们函数也给复制过来,然后我们在输出一下,发现就跟我们前面写的一模一样但是我们可以看到的执行顺序是  GET > POST > COOKIE

eb660c3fb329d1b49f8bb99f422756c8.png

这时候我们可以进行覆盖,我们再去看一下如何才能进入这一步

5b4d65a165cf180150f35b750303ef95.png

我们发现上面没有exit(),die()就忽略了

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

phpforeach($_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就是键,我们必须要满足,我们看下面那个图,如果我们没有键的话,根本无法控制利用

7bf13dad18c999502569bf4d56d34ee5.png

第二个条件:这其实就是一个正则(这是用户自定义的,就不纠结了),然后正则里面能不能有cfg和 GLOBALS

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

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

然后变量覆盖只能覆盖上面的代码

b29b5c137e667aaee4bff21e54de8cd6.png

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

7c66c34683f110c23c9cb61f5f15b8c7.png

然后这时候我们发现login.php 包含了 common.php这时候我们有看到了下面又调用了一个 check.admin.php了英语会点的就知道,意思就是检查 是否为admin的意思这时候我们发现找不到这个文件,duomi_INC 在哪里

24907131e8b6ebb90a8024d775e0ba8b.png

这时候我们可以去打开login.php

f86d587a3ec94c04ab6f2134be40bc81.png

然后进行简单的修改一下Exit(duomi_INC);这时候就爆出路径

9a190208220eb6f191818d87989579d8.png

然后再去寻找一下路径

5910debd5ee66fbf475b62a57b15736f.png

成功的在duomiphp下面找到了check.admin.php因为这边用了session_start 才能对其进行覆盖登陆后台

d171221a09ff33408dd32b8a107ff4e1.png

然后我们全局搜索找到这个session_start(),在这个 /interface/comment.php 路径下

这时候我们再去寻找那个check.admin.php进行构造session,进入后台

Userlogin 顾名思义,就是用户登陆,而session需要有

duomi_admin_id

duomi_group_id

duomi_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;
}
}
}
?>

首先是获取用户权限

3bcde61dbf638e629c1c983dd605f7a6.png

这时候我们发现当 groupid=1的时候是系统管理员,我们这就开始构造payload

覆盖session首先得strat,也就是要开启session_strat一下

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

24d5130d059b0cd2098ec906d2033253.png

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

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

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

(其实这里只要权限写对,其他随便写,因为这边只对权限进行判断,没有对用户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

就成功构建好了,把我脑瓜子都整的嗡嗡叫了,我语文是真的不好啊

bb8464a7e9d6e7f5c5b99aa4c198d112.png

这里提示我们要登录,这时候我们传参进去

87acd73c9e825ed24cbe0f153d0c444d.png

这时候去访问admin页面发现成功访问了,因为session是存储在服务端,然后会持续会话,我们传参进去报错,但是session已经存储到了服务端,这时候访问admin,就可以进去了

bf575c223dbad2baceefaafda8071245.png

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值