如下這段話摘自p神php
Fastcgi實際上是一個通訊協議,和HTTP協議同樣,都是進行數據交換的一個通道。 HTTP協議是瀏覽器和服務器中間件進行數據交換的協議,瀏覽器將HTTP頭和HTTP體用某個規則組裝成數據包,以TCP的方式發送到服務器中間件,服務器中間件按照規則將數據包解碼,並按要求拿到用戶須要的數據,再以HTTP協議的規則打包返回給服務器。 類比HTTP協議來講,fastcgi協議則是服務器中間件和某個語言後端進行數據交換的協議。Fastcgi協議由多個record組成,record也有header和body一說,服務器中間件將這兩者按照fastcgi的規則封裝好發送給語言後端,語言後端解碼之後拿到具體數據,進行指定操做,並將結果再按照該協議封裝好後返回給服務器中間件
http數據其實是由客戶端瀏覽器到達服務器中間件,中間件再將數據再次封裝打包給後端語言進行處理,處理結束再返回給服務器中間件。html
php-fpm(fastcgi進程管理器):前端
FPM實際上是一個fastcgi協議解析器,Nginx等服務器中間件將用戶請求按照fastcgi的規則打包好經過TCP傳給FPM。FPM按照fastcgi的協議將TCP流解析成真正的數據。java
用戶訪問http://127.0.0.1/index.php?a=1&b=2
,若是web目錄是/var/www/html
,那麼Nginx會將這個請求變成以下key-value對:nginx
PHP-FPM拿到fastcgi的數據包後,進行解析,獲得上述這些環境變量。而後,執行SCRIPT_FILENAME
的值指向的PHP文件,也就是/var/www/html/index.php
。git
好比解析漏洞就和PHP-FPM的處理配置有關係,主要在於其對script_filename的處理方式,好比/ppp.png/.php,從右向左解析,不存在/.php,則去除/.php繼續向左,存在ppp.png,拿來看成php解析,這種爲客戶考慮的想法卻致使了漏洞的存在github
正確的解決方法有兩種:
一是在Nginx端使用fastcgi_split_path_info將path info信息去除後,用tryfiles判斷文件是否存在;
二是藉助PHP-FPM的security.limit_extensions配置項,避免其餘後綴文件被解析。
PHP-FPM未受權訪問漏洞主要利用security.limit_extensions配置,PHP-FPM默認監聽9000端口,若是這個端口暴露在公網,則咱們能夠本身構造fastcgi協議,和fpm進行通訊。固然若是在內網中開放的此端口,若是存在SSRF,就能經過SSRF去打fastcgi。web
php-fpm根據script_filename的值來執行php文件,若是該文件不存在,則返回404mongodb
其限定了只有某些後綴的文件容許被fpm執行,默認是.php,因爲這個配置項的限制,若是想利用PHP-FPM的未受權訪問漏洞,首先就得找到一個已存在的PHP文件。
docker
一般使用源安裝php的時候,服務器上都會附帶一些php後綴的文件,可使用find / -name "*.php"
來全局搜索一下默認環境就能找到一些。接下來已經知道服務器能夠來執行咱們要指定的php,但只是執行服務器上的文件,不能執行咱們的惡意payload,那麼接下來就要想辦法構造代碼執行:
PHP.INI中有兩個重要配置項: auto_prepend_file: auto_prepend_file是告訴PHP,在執行目標文件以前,先包含auto_prepend_file中指定的文件; auto_append_file: auto_append_file是告訴PHP,在執行完成目標文件後,包含auto_append_file指向的文件。 假設咱們設置auto_prepend_file爲php://input,那麼就等於在執行任何php文件前都要包含一遍POST的內容。因此,咱們只須要把待執行的代碼放在Body中,他們就能被執行了。
(須要開啓遠程文件包含選項allow_url_include) 可是上面兩個值是在服務器端,咱們能夠經過PHP-FPM來設置auto_prepend_file的值,這又涉及到PHP-FPM的兩個環境變量,PHP_VALUE和PHP_ADMIN_VALUE。
這兩個環境變量就是用來設置PHP配置項的,PHP_VALUE能夠設置模式爲PHP_INI_USER和PHP_INI_ALL的選項,PHP_ADMIN_VALUE能夠設置全部選項。
(disable_functions除外,這個選項是PHP加載的時候就肯定了,在範圍內的函數直接不會被加載到PHP上下文中)
好比給php-fpm傳遞以下變量:
{ 'GATEWAY_INTERFACE': 'FastCGI/1.0', 'REQUEST_METHOD': 'GET', 'SCRIPT_FILENAME': '/var/www/html/index.php', 'SCRIPT_NAME': '/index.php', 'QUERY_STRING': '?a=1&b=2', 'REQUEST_URI': '/index.php?a=1&b=2', 'DOCUMENT_ROOT': '/var/www/html', 'SERVER_SOFTWARE': 'php/fcgiclient', 'REMOTE_ADDR': '127.0.0.1', 'REMOTE_PORT': '12345', 'SERVER_ADDR': '127.0.0.1', 'SERVER_PORT': '80', 'SERVER_NAME': "localhost", 'SERVER_PROTOCOL': 'HTTP/1.1' 'PHP_VALUE': 'auto_prepend_file = php://input', 'PHP_ADMIN_VALUE': 'allow_url_include = On' }
設置auto_prepend_file = php://input
且allow_url_include = On
,而後將咱們須要執行的代碼放在Body中,便可執行任意代碼。
用gopherus就能夠直接生成payload,須要指定一個script_filename,即一個服務器上已經存在的文件,若是沒有指定將使用默認的一個php,/usr/share/php/PERL.php,實際滲透過程當中可能須要經過網站報錯,phpinfo信息泄露等去找其存在的php文件,還要輸入咱們要執行的系統命令,這個payload實際上利用的正是p牛說的,auto_prepend_file一個php://input,從而在http body中去傳遞咱們的payload,如前文所說動態地修改了php.ini裏的配置:
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"
環境:
https://github.com/vulhub/vulhub/tree/master/fpm
路徑改成p牛環境中配的路徑,直接用gopherus生成gopher的payload打,ubuntu16.04的curl的liburl爲7.47,不存在%00截斷,所以直接經過gopher發送payload到本機的9000端口
也能夠直接用p牛的腳本直接打,直接向127.0.0.1的9000端口發送payload,這裏假設是公網的fastcgi端口未受權訪問:
腳本連接地址:
https://gist.github.com/phith0n/9615e2420f31048f7e30f3937356cf75
curl/libcurl 7.43
上 gopher 協議存在 bug(%00 截斷),經測試 7.49 可用
並不限於 PHP 的 SSRF。當存在 XXE、ffmepg SSRF 等漏洞的時候,也能夠進行利用
通常來講,apache服務器經常使用module方式起php,nginx服務器經常使用fastcgi模式起php,php-fpm下還能夠繼續分,若是使用fastcgi模式,nginx與php-fpm通訊能夠經過兩種模式,一種是TCP模式,一種是unix 套接字(socket)模式
TCP模式便是php-fpm進程會監聽本機上的一個端口(默認9000),而後nginx會把客戶端數據經過fastcgi協議傳給9000端口,php-fpm拿到數據後會調用cgi進程解析
unix socket其實嚴格意義上應該叫unix domain
socket,它是unix系統進程間通訊(IPC)的一種被普遍採用方式,以文件(通常是.sock)做爲socket的惟一標識(描述符),須要通訊的兩個進程引用同一個socket描述符文件就能夠創建通道進行通訊了。
$fp = stream_socket_client("/var/run/php/U_wi11_nev3r_kn0w.sock", $errno, $errstr,30);$out = urldecode("這裏填寫payload"); stream_socket_sendto($fp,$out); while (!feof($fp)) {echo htmlspecialchars(fgets($fp, 10)); }fclose($fp);//'
利用以上代碼就能夠與unix套接字進行通訊,來進行rce
PHP_ADMIN_VALUE['extension'] = /tmp/tr1ple.so 讓php加載擴展
memcached是一套分佈式的高速緩存系統。它以Key-Value(鍵值對)形式將數據存儲在內存中,這些數據一般是應用讀取頻繁的。正由於內存中數據的讀取遠遠大於硬盤,所以能夠用來加速應用的訪問。
漏洞成因:
因爲memcached安全設計缺陷,客戶端鏈接memcached服務器後無需認證就可讀取、修改服務器緩存內容。
漏洞影響:
除memcached中數據可被直接讀取泄漏和惡意修改外,因爲memcached中的數據像正常網站用戶訪問提交變量同樣會被後端代碼處理,當處理代碼存在缺陷時會再次致使不一樣類型的安全問題。 不一樣的是,在處理前端用戶直接輸入的數據時通常會接受更多的安全校驗,而從memcached中讀取的數據則更容易被開發者認爲是可信的,或者是已經經過安全校驗的,所以更容易致使安全問題。
具體案例分析見:
DiscuzX 兩處 SSRF 挖掘及利用
https://zhuanlan.zhihu.com/p/51907363
默認狀況下 Jenkins 面板中用戶能夠選擇執行腳本界面來操做一些系統層命令,攻擊者可經過未受權訪問漏洞或者暴力破解用戶密碼等進腳本執行界面從而獲取服務器權限。
詳情見:https://paper.seebug.org/409/#0x03-jenkins
開啓 MongoDB 服務時不添加任何參數時,默認是沒有權限驗證的,並且能夠遠程訪問數據庫,登陸的用戶能夠經過默認端口無需密碼對數據庫進行增、刪、改、查等任意高危操做。
詳情見:https://paper.seebug.org/409/#0x04-mongodb
Zookeeper 的默認開放端口是2181。Zookeeper 安裝部署以後默認狀況下不須要任何身份驗證,形成攻擊者能夠遠程利用 Zookeeper,經過服務器收集敏感信息或者在 Zookeeper 集羣內進行破壞(好比:kill命令)。攻擊者可以執行全部只容許由管理員運行的命令。
詳情見:https://paper.seebug.org/409/#0x05-zookeeper
Elasticsearch 是一款 java 編寫的企業級搜索服務。愈來愈多的公司使用 ELK 做爲日誌分析,啓動此服務默認會開放9200端口,可被非法操做數據。
詳情見:https://paper.seebug.org/409/#0x06-elasticsearch
CouchDB 默認在 5984 端口開放 Restful 的 API 接口,用於數據庫的管理功能。其 HTTP Server 默認開啓時沒有進行驗證,並且綁定在0.0.0.0,全部用戶都可經過 API 訪問致使未受權訪問。任何鏈接到服務器端口上的人,均可以調用相關 API 對服務器上的數據進行任意的增刪改查,其中經過 API 修改 local.ini 配置文件,可進一步致使執行任意系統命令,獲取服務器權限
詳情見:https://paper.seebug.org/409/#0x09-couchdb
Docker Remote API 是一個取代遠程命令行界面(rcli)的REST API。經過 docker client 或者 http 直接請求就能夠訪問這個 API,經過這個接口,咱們能夠新建 container,刪除已有 container,甚至是獲取宿主機的 shell
詳情見:https://paper.seebug.org/409/#0x010-docker
參考:
https://www.leavesongs.com/PENETRATION/fastcgi-and-php-fpm.html
https://paper.seebug.org/409/