PHP-fpm 遠端程式碼執行漏洞(CVE-2019-11043)分析
作者:LoRexxar'@知道創宇404實驗室
時間:2019年10月25日
原文連結:
國外安全研究員 Andrew Danau在解決一道 CTF 題目時發現,向目標伺服器 URL 傳送 %0a 符號時,服務返回異常,疑似存在漏洞。
2019年10月23日,github公開漏洞相關的詳情以及exp。當nginx配置不當時,會導致php-fpm遠端任意程式碼執行。
下面我們就來一點點看看漏洞的詳細分析,文章中漏洞分析部分感謝團隊小夥伴@Hcamael#知道創宇404實驗室
漏洞復現
為了能更方便的復現漏洞,這裡我們採用vulhub來構建漏洞環境。
git pull
並
docker-compose up -d
訪問
http://{your_ip}:8080/
下載github上公開的exp(需要go環境)。
go get github.com/neex/phuip-fpizdam
然後編譯
go install github.com/neex/phuip-fpizdam
使用exp攻擊demo網站
phuip-fpizdam http://{your_ip}:8080/
攻擊成功
漏洞分析
在分析漏洞原理之前,我們這裡可以直接跟入看修復的commit
-
從commit中我們可以很清晰的看出來漏洞成因應該是
path_info
的地址可控導致的,再結合漏洞發現者公開的漏洞資訊中提到
The regexp in `fastcgi_split_path_info` directive can be broken using the newline character (in encoded form, %0a). Broken regexp leads to empty PATH_INFO, which triggers the bug.
也就是說,當
path_info
被%0a截斷時,
path_info
將被置為空,回到程式碼中我就不難發現問題所在了。
其中
env_path_info
就是變數
path_info
的地址,
path_info
為0則
plien
為0.
slen
變數來自於請求後url的長度
int ptlen = strlen(pt); int slen = len - ptlen;
其中
int len = script_path_translated_len; len為url路徑長度 當請求url為%0atest.php script_path_translated來自於nginx的配置,為/var/www/html/index.php/123\ntest.php ptlen則為url路徑第一個斜槓之前的內容長度 當請求url為%0atest.php pt為/var/www/html/index.php
這兩個變數的差就是後面的路徑長度,由於路徑可控,則
path_info
可控。
由於
path_info
可控,在1222行我們就可以將指定地址的值置零,根據漏洞發現者的描述,透過將指定的地址的值置零,可以控制使
_fcgi_data_seg
結構體的
char* pos
置零。
其中
script_name
同樣來自於請求的配置
而為什麼我們使
_fcgi_data_seg
結構體的
char* pos
置零,就會影響到
FCGI_PUTENV
的結果呢?
這裡我們深入去看
FCGI_PUTENV
的定義.
char* fcgi_quick_putenv(fcgi_request *req, char* var, int var_len, unsigned int hash_value, char* val);
跟入函式
fcgi_quick_putenv
函式直接操作request的env,而這個引數在前面被預定義。
繼續跟進初始化函式
fcgi_hash_init
.
也就是說
request->env
就是前面提到的
fcgi_data_seg
結構體,而這裡的
request->env
是nginx在和fastcgi通訊時儲存的全域性變數。
部分全域性變數會在nginx的配置中定義
其中變數會在堆上相應的位置儲存
回到利用過程中,這裡我們透過控制
path_info
指向
request->env
來使
request->env->pos
置零。
繼續回到賦值函式
fcgi_hash_set
函式
緊接著進入
fcgi_hash_strndup
這裡
h->data-》pos
的最低位被置為0,且str可控,就相當於我們可以在前面寫入資料。
而問題就在於,我們怎麼能向我們想要的位置寫資料呢?又怎麼向我們指定的配置寫檔案呢?
這裡我們拿exp傳送的利用資料包做例子
GET /index.php/PHP_VALUE%0Asession.auto_start=1;;;?QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ HTTP/1.1 Host: ubuntu.local:8080 User-Agent: Mozilla/5.0 D-Gisos: 8=====================================D Ebut: mamku tvoyu
在資料包中,header中的最後兩部分就是為了完成這部分功能,其中
D-Gisos
負責位移,向指定的位置寫入資料。
而
Ebut
會轉化為
HTTP_EBUT
這個
fastcgi_param
中的其中一個全域性變數,然後我們需要了解一下
fastcgi
中全域性變數的獲取資料的方法。
可以看到當fastcgi想要獲取全域性變數時,會讀取指定位置的長度字元做對比,然後讀取一個字串作為value.
也就是說, 只要位置合理,var值相同,且長度相同,fastcgi就會讀取相對應的資料。
而
HTTP_EBUT
和
PHP_VALUE
恰好長度相同,我們可以從堆上資料的變化來印證這一點。
在覆蓋之前,該地址對應資料為
然後執行
fcgi_quick_putenv
該地址對應資料變為
我們成功寫入了
PHP_VALUE
並控制其內容,這也就意味著我們可以控制PHP的任意全域性變數。
當我們可以控制PHP的任意全域性變數就有很多種攻擊方式,這裡直接以EXP中使用到的攻擊方式來舉例子。
exp作者透過開啟自動包含,並設定包含目錄為
/tmp
,之後設定log地址為
/tmp/a
並將payload寫入log檔案,透過
auto_prepend_file
自動包含
/tmp/a
檔案構造後門檔案。
漏洞修復
在經過對漏洞的深入研究後,我們推薦兩種方案修復這個漏洞。
- 臨時修復:
修改nginx相應的配置,並在php相關的配置中加入
try_files $uri =404
在這種情況下,會有nginx去檢查檔案是否存在,當檔案不存在時,請求都不會被傳遞到php-fpm。
-
正式修復:
- 將PHP 7.1.X更新至7.1.33
- 將PHP 7.2.X更新至7.2.24
- 將PHP 7.3.X更新至7.3.11
漏洞影響
結合EXP github中提到的利用條件,我們可以儘可能的總結利用條件以及漏洞影響範圍。
1、Nginx + php_fpm,且配置
location ~ [^/]\.php(/|$)
會將請求轉發到php-fpm。
2、Nginx配置
fastcgi_split_path_info
並且以
^
開始以
$
,只有在這種條件下才可以透過換行符來打斷正規表示式判斷。 ps: 則允許
index.php/321 -> index.php
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
3、
fastcgi_param
中
PATH_INFO
會被定義透過
fastcgi_param PATH_INFO $fastcgi_path_info;
,當然這個變數會在
fastcgi_params
預設定義。
4、在nginx層面沒有定義對檔案的檢查比如
try_files $uri =404
,如果nginx層面做了檔案檢查,則請求不會被轉發給php-fmp。
這個漏洞在實際研究過程中對真實世界危害有限,其主要原因都在於大部分的nginx配置中都攜帶了對檔案的檢查,且預設的nginx配置不包含這個問題。
但也正是由於這個原因,在許多網上的範例程式碼或者部分沒有考慮到這個問題的環境,例如Nginx官方文件中的範例配置、NextCloud預設環境,都出現了這個問題,該漏洞也正真實的威脅著許多伺服器的安全。
在這種情況下,這個漏洞也切切實實的陷入了黑暗森林法則,一旦有某個帶有問題的配置被傳播,其導致的可能就是大批次的服務受到牽連,確保及時的更新永遠是對保護最好的手段:>
參考連結
如需轉載請註明來源。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69912109/viewspace-2661650/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- PHP 近期被爆存在遠端程式碼執行漏洞 CVE-2019-11043PHP
- Joomla遠端程式碼執行漏洞分析OOM
- 乾貨|CVE-2019-11043: PHP-FPM在Nginx特定配置下任意程式碼執行漏洞分析PHPNginx
- Discuz! X系列遠端程式碼執行漏洞分析
- ThinkPHP遠端程式碼執行漏洞PHP
- phpunit 遠端程式碼執行漏洞PHP
- ThinkPHP 5.0.23 遠端程式碼執行漏洞PHP
- OpenWRT 曝遠端程式碼執行漏洞
- 最新漏洞:Spring Framework遠端程式碼執行漏洞SpringFramework
- RCE(遠端程式碼執行漏洞)原理及漏洞利用
- WindowsJScript元件曝遠端程式碼執行漏洞WindowsJS元件
- .NET Remoting 遠端程式碼執行漏洞探究REM
- 什麼是遠端程式碼執行漏洞?
- ElasticSearch Groovy指令碼遠端程式碼執行漏洞分析(CVE-2015-1427)Elasticsearch指令碼
- PHP CGI Windows下遠端程式碼執行漏洞PHPWindows
- log4j遠端程式碼執行漏洞
- crash_for_windows_pkg遠端程式碼執行漏洞Windows
- Apache Struts 再曝高危遠端程式碼執行漏洞Apache
- [漏洞預警]Laravel <= 8.4.2 Debug模式 _ignition 遠端程式碼執行漏洞Laravel模式
- ElasticSearch 遠端程式碼執行漏洞分析(CVE-2015-1427)&高階利用方法Elasticsearch
- Spring WebFlow 遠端程式碼執行漏洞(CVE-2017-4971)SpringWeb
- Apache OFBiz遠端程式碼執行漏洞(CVE-2024-38856)Apache
- Log4j遠端程式碼執行漏洞漫談
- CVE-2020-17530——Apache Struts遠端程式碼執行漏洞Apache
- 網站漏洞檢測 squid反向代理存在遠端程式碼執行漏洞網站UI
- Firefox 31~34遠端命令執行漏洞的分析Firefox
- PHP-CGI遠端程式碼執行漏洞(CVE-2012-1823)PHP
- SMB遠端程式碼執行漏洞CVE-2020-0796安全通告
- Spring Cloud Gateway 遠端程式碼執行漏洞(CVE-2022-22947)SpringCloudGateway
- Struts2方法呼叫遠端程式碼執行漏洞(CVE-2016-3081)分析
- Steam客戶端發現遠端程式碼執行漏洞:已放補丁客戶端
- PHP-CGI遠端1程式碼執行漏洞(CVE-2012-1823)PHP
- Apache Kylin遠端程式碼執行漏洞復現(CVE-2020-1956)Apache
- Weblogic遠端程式碼執行漏洞(CVE-2020-14750)修復方案Web
- Apache log4j2 遠端程式碼執行漏洞復現?Apache
- Apache Solr應用伺服器存在遠端程式碼執行漏洞?ApacheSolr伺服器
- Apache SSI 遠端命令執行漏洞Apache
- 高危漏洞!Apache Log4j 遠端程式碼執行漏洞(附修復建議)Apache