来源: WDCP add_user.php任意数据库添加任意用户导致任意命令执行漏洞分析 – JoyChou’s Blog
0x1. 什么是WDCP
wdcp (WDlinux Control Panel) 是一套用PHP开发的Linux服务器管理系统,旨在易于使用和管理Linux服务器,通过web后台就可以管理服务器和虚拟主机。和国外的cPanel类似。虚拟主机的小能手。
2014年9月26,wdcp官网公布该漏洞,http://www.wdlinux.cn/bbs/thread-37476-1-1.html 而且可以看到最新版本是wdcp_v2.5.11(20140926
)
该漏洞影响版本:wdcp_v2.5.11版本以下。
0x2. 漏洞分析
简单分析下wdcp这个漏洞。由于wdcp是经过编码加密的,所以得解密后分析代码。我简单写了一个解密wdcp整个文件的代码,用的时候只需修改下wdcp的目录。
wdcp_decode.php
<?php
/*
Authou: JoyChou
Date: 2014年12月7日14:50
*/
error_reporting(0);
function wdcp_decode($filename) {
if (!file_exists($filename)) {
return false; //文件名不存在
}
$data = unpack('C*', substr(file_get_contents($filename), 9));
$key = array(0xB8, 0x35, 0x6, 0x2, 0x88, 0x1, 0x5B, 0x7, 0x44, 0x0);
$j = count($data);
foreach($data as $k => &$v) {
$v = $key [ 2 * ($j % 5) ] ^ ~$v;
// $v = sprintf('%u', $v);
$v &= 0xFF;
$v = pack('C*', $v);
-- $j;
}
return gzuncompress(join('', $data));
}
function Traversal_Files($path = '.'){
if (!is_dir($path)) {
echo '参数不是目录';
return false;
}
// //opendir()返回一个目录句柄,失败返回false
if ($current_dir = opendir($path)) {
while (false !== ($file = readdir($current_dir))) { // readdir获取当前目录的文件名喝目录名以及. ..
$sub_dir = $path . DIRECTORY_SEPARATOR . $file; // DIRECTORY_SEPARATOR \或者/
if ($file == '.' || $file == '..') {
continue;
}
else if (is_dir($sub_dir)) {
echo "<h3> Directory Name $file </h3>";
Traversal_Files($sub_dir); //如果是目录,进行递归判断。
}
else{
$file_ext = substr($file, strrpos($file,".")+1);
if ($file_ext == 'php' || $file_ext == 'PHP') {
//echo $sub_dir . '<br>';
file_put_contents($sub_dir . '_decode', wdcp_decode($sub_dir));
unlink($sub_dir);
rename($sub_dir . '_decode', $sub_dir);
}
}
}
}
closedir($current_dir);
}
// 在这修改wdcp目录即可
Traversal_Files("D:\web\cms\wdcp\wdcp_v2.5.11\www\wdlinux\wdcp");
?>
在网上下了一个wdcp_v2.5.7版本,解码后分析add_user.php
require_once "../inc/common.inc.php";
if (isset($_POST['Submit_add'])) {
$user=chop($_POST['user']);
$password=chop($_POST['password']);
$dbname=chop($_POST['dbname']);
check_user($user);
check_string($password);
check_string($dbname);
create_db_user($user,$password,$host);
grant_db_user($user,$host,$dbname);
mysql_add_user($user,$password,$host,$dbname,$rtime);
optlog($wdcdn_uid,"增加mysql数据库 $user",0,0);
str_go_url("数据库用户增加成功!",0);
}
毫无违和感,很粗暴的直接在数据库里增加用户,require的../inc/common.inc.php也没有做任何的登录限制。如果$_POST[‘dbname’]为空,默认的数据库是information_schema,当然要利用就得指定我们想要的数据库,一般是mySQL数据库。而且在mySQL目录下还有一个user_add.php,代码如下,和add_user.php最大的区别是它包含了login.php进行了登录验证。你肯定会猜不透为什么有了user_add.php还需要add_user.php。恩,我也猜不透。
user_add.php 关键代码
require_once "../inc/common.inc.php";
require_once "../login.php";
//require_once "../inc/admlogin.php";
//if ($wdcp_gid!=1) exit;
if (isset($_POST['Submit_add'])) {
$user=chop($_POST['user']);
$sid=intval($_POST['sid']);
$password=chop($_POST['password']);
$dbname=chop($_POST['dbname']);
$host=chop($_POST['host']);
if ($dbname=="0") go_back("选择的数据库有错!");
check_user($user);
//system_name_check($user,0);
//check_string($password);
check_passwd($password);
check_string($dbname);
system_name_check($user,0);
//check_exists_dbname($dbname);
//system_name_check($dbname,1);
create_db_user($user,$password,$host);
grant_db_user($user,$host,$dbname);
mysql_add_user($user,$password,$host,$dbname,$rtime);
optlog($wdcp_uid,"增加mysql数据库用户 $user",0,0);
str_go_url("数据库用户增加成功!",0);
0x3. 漏洞利用
该漏洞好无脑,跳广场舞的大妈都会搞站了。
测试环境:
- 版本: wdcp_v2.5.10,最新 wdcp_v2.5.11(20140926)
漏洞url:http://www.hackme.com:8080/mysql/add_user.php,可以看到用户名拿有一个6-15个字符
,其实对长度的限制是大于3小于30. 由于要指定mysql数据库,所以用hackbar提交POST数据,提交的数据是Submit_add=xxoo&user=xxoo&password=xxoo&dbname=mysql
而且lanmp一键安装的站在wdcp同级目录会有phpmyadmin,所以用phpmyadmin登录,可以看到用刚新增的xxoo用户登录成功。
登录成功后,就可以看到mysql数据库user表里面的root密码,wdcp密码(都是mysql5加密)。
如果wdcp密码丢cmd5没解出来,root密码解出来,那用phpmyadmin登录root,拥有wdcp数据库的权限后,再解wdcp密码的md5。再拥有wdcp后台密码和mysql数据库root密码后,权限也是掉掉的。
一般拿到wdcp密码后,登录wdcp,在后台的“系统管理”==>“运行命令”,可以随意执行非useradd|userdel|usermod|passwd|rc\.d|init\.d
和rm|dd|sudo
以及/dev/|mkfs
命令的命令。一般执行wget命令,下载远程恶意文件或者后门,chmod修改权限,运行自己的后门。这个命令修改的代码在/syc/cmd.php中。而且此时是root权限,有了root权限,在linux下面就可以任意操作了,达到任意命令执行。
0x4. 漏洞修复
- 删除add_user.php(这个文件确实也没用),或者升级最新版v2.5.11
在最新的wdcp_v2.5.11版本中,add_user.php内容解码只有9个字节,16进制是0A 20 20 20 20 20 20 20 20
T_T 想想也醉了,还不如删掉。 - 或者添加include login.php,然后再编码回去。
相关链接
- http://tkxxd.net/thread-1843-1-1.html
- http://www.wdlinux.cn/bbs/thread-37476-1-1.html