加一個參數就是一個洞。在挖洞的時候,我注意到一些特殊的請求參數,好比說 output
、retype
、callback
、fun
、width
、height
等等,更改其中一些數值,返回包中會出現明顯變化。看了大師傅們的文章,才逐漸瞭解到這些參數以及一些特殊的 http 頭的妙用。此文做爲一個筆記梳理,並本身嘗試寫了一個簡單腳本(經測試,BUG 巨多😵),以避免去使用 BURP 測試那麼複雜。php
衆所周知,更改 HTTP 的 Origin
頭即可以測試 CORS 漏洞。因此在碰到包含敏感信息的頁面的時候,即可以從新發包,加一個 Origin
頭。
可是怎麼可能這麼容易就挖到呢?不少網站在 Origin
頭處作了限制,沒有匹配其後臺規則便不會返回 Access-Control-Allow-Origin
等字段。
常見限制以下:html
Origin: https://test.com # 白名單,只容許固定的域名 Origin: http://whatever.com # 未作限制 Origin: http://test.com.evil.vom # 域名前綴或必須包含特定域名字符串 Origin: http://sub.test.com # 容許子域名
若是沒有匹配上述中的某些規則,網站便不會返回 Access-Control-Allow-Origin
字段,也就沒法判斷是否存在 CORS
當只測試了一種規則但其沒有匹配網站規則,看到沒有返回該字段是否就應該放棄?
其實否則,咱們能夠一個個添加/修改,每個可能的規則都試一遍。python
不知道師傅們碰到過可修改返回數據類型的參數沒有,常見的有 retype
、output
、format
、datatype
等。
好比說 output=html、output=json、output=script
或者 retype=一、retype=二、retype=3
,1234分別表明不一樣數據類型
看到下面一個接口的請求包:git
GET /api.php?kw=<img/src/onerror=alert(!)> HTTP/1.1 Host: test.cn ···
返回包爲:github
HTTP/1.1 200 OK Content-Type: application/json ··· {"wd":"<img/src/onerror=alert(!)>"}
因爲嚴格限定了 Content-Type
頭,因此瀏覽器只會將其做爲 json 格式解析。
這個時候是否是沒辦法了,其實能夠嘗試添加一些參數
好比說加一個 ?retype=html
參數,返回包可能就會變成 Content-Type: text/html;charset=utf-8
,
此時瀏覽器便會將其解析爲 html 格式,因而一個反射型 xss 便有了。
固然得認可這個狀況很難利用(參數跟值都沒法肯定),而且也十分少見,可是在 jsonp 劫持的時候就不見得了。json
在請求 json 格式的數據時,請求中常見 callback=test
、call=test
、cb=test
、func=test
、jsoncallback=test
等參數
且此時返回包數據爲 test({"paramer":"value"})
,
例如:
api
能夠看到,burp 識別其爲 script 格式,當一個個在 burp 中尋找可能的 jsonp 劫持漏洞時,單找 script 格式的數據就會讓人瘋。由於不少 script 數據內容都是 js 函數
咱們再次看到上圖,有沒有發如今 script 那一欄有兩個 JSON 格式的數據?其實不少網站返回信息都爲 json 格式。當其中的數據爲敏感數據時,因爲沒有看到回調函數,如 callback 時,是否是這個點就沒法利用?
其實此時能夠測試能不能利用這些 json 格式的數據造一個 jsonp 劫持呢?此時重點來了:瀏覽器
當請求爲:安全
GET /getUser.php HTTP/1.1 Host: test.cn Cookie: xxxxx ···
網站返回一個這樣的 json 數據包cookie
HTTP/1.1 200 OK Content-Type: application/json ··· {"name":"R0oKi3","phone":"13888888888","addr":"湖南省長沙市···"}
是否是就不能繼續測試下一步呢?其實否則:
此時能夠修改請求包爲:
GET /getUser.php?callback=test HTTP/1.1 Host: test.cn Cookie: xxxxx ···
網站即可能會返回:
HTTP/1.1 200 OK Content-Type: application/json ··· test({"name":"R0oKi3","phone":"13888888888","addr":"湖南省長沙市···"});
當其餘限制(referer、token)不嚴格時,一個 jsonp 劫持漏洞便有了。
固然,大多 json 格式的數據內容是不包含敏感信息的,那麼是否是就沒用了?其實也否則。
當用戶可控 Content-Type
(也就是上一個點)時,而且也能構成不含敏感信息的 jsonp 劫持時,此時即可以考慮構成反射型 xss
如 http://test.cn/getUser.php?callback=<img/src/onerror=alerrt(1)>&retype=html
即可以造成反射型 xss,由於其返回的數據包中含:Content-Type: text/html;charset=utf-8
,瀏覽器將該數據包解析成了 html 格式
右鍵打開驗證碼/二維碼等圖片的連接,若是看到參數中存在某些鍵值對,如 width=20&heigth=15
等,而且改變其數值大小時,驗證碼圖片大小也跟着改變時,即可能形成驗證碼 Dos
當沒有這些參數時,即可以考慮本身添加,如 https://test.com/captcha.php?width=2000&height=20000
,fuzz 出這些參數,來形成 Dos
而且,當 fuzz 出一個能夠控制驗證碼位數的參數時,如 n=4
,也能夠將其改成 0 等數字,嘗試是否能使驗證碼失效,或者改成很大的數值,若是圖片大小跟驗證碼位數相關的話,也能形成 Dos
在 cookie 中添加一些字段,可能會致使未受權訪問
admin=true access=1 debug=true
具體可見:個人Web應用安全模糊測試之路
EasyFuzz.py
""" python3 EasyFuzz.py -u https://test.com -m jsonp -u 或者 -url 指定 url -m 或者 -method 指定要探測的可能漏洞,暫時有的選項有 cors jsonp img 三種漏洞的探測 注意,在傳輸 url 參數時,url中有 & 符號與要用雙引號包裹起來,不然會報錯 因爲沒有采用多線程,因此會丶慢 """ import requests import argparse import re from tld import get_fld jsonps = ["callback", "_callback", "func", "cb", "_cb", "jsonp", "jsonpcallback", "jsonpcb", "json", "jsoncallback", "jbc", "jsonp_cb", "call", "callBack", "jsonCallback", "jsonpCb", "ca", "jsonp_Cb"] headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36" } def send(url): rep = requests.get(url, headers=headers) return rep def CorsFuzz(url): # 獲取本域名 subdomin = re.findall(r'(http.*://[^/]*)', url, re.DOTALL)[0] protocol = re.findall(r'(http.*://)', url, re.DOTALL)[0] # 獲取主域名 domain = get_fld(subdomin) # print(subdomin,domain) # 建立 cors 字典 自己 主域名 任意域名 以其開頭 其餘子域名 cors = [subdomin, protocol + domain, protocol + "test.com", protocol + domain + ".test.com", protocol + "test." + domain] # print(cors) flag = 0 for cor in cors: headers["Origin"] = cor print("------Origin: " + cor) try: # 獲取響應頭 # print(url) reph = send(url).headers # print(reph) if "Access-Control-Allow-Origin" in str(reph): print(url + "存在 CORS,其 Origin 頭爲" + cor + "\n返回值爲 Access-Control-Allow-Origin:" + reph["Access-Control-Allow-Origin"]) flag = 1 except: print(url + " 請求錯誤") if flag == 0: print(url+" 不存在 CORS 漏洞") def JsonpFuzz(url): flag = 0 for jsonp in jsonps: jsonp = jsonp + "=myJsonpFunc" try: if "?" in url: newurl = url + "&" + jsonp print("------" + newurl) rep = send(newurl).content.decode("utf-8") else: newurl = url + "?" + jsonp print("------" + newurl) rep = send(newurl).content.decode("utf-8") if "myJsonpFunc" in rep: flag = 1 print(url + "可能存在 jsonp 劫持,回調函數爲:" + jsonp) break except: print(url + " 請求錯誤") if flag == 0: print(url+" 不存在 jsonp 回調函數") def ImgFuzz(url): # 獲取原數據大體大小 repl = len(send(url).content) par = "height=250&width=250&w=250&h=250&size=250&margin=250&font_size&=250length=250" try: if "?" in url: print(url + "&" + par) newl = len(send(url + "&" + par).content) else: print(url + "&" + par) newl = len(send(url + "?" + par).content) except: print(url + " 請求錯誤") if abs(newl - repl) >= 1000: # 當數據大小相差 1000 時 print(url + "可能存在驗證碼 Dos\n測試參數爲:" + par) def main(url, method): if method=="cors": CorsFuzz(url) elif method=="jsonp": JsonpFuzz(url) else: ImgFuzz(url) if __name__ == '__main__': parser = argparse.ArgumentParser(description='Easy Fuzz') parser.add_argument("-u", "--url", help="指定URL", default="img") parser.add_argument("-m", "--method", help="指定操做") args = parser.parse_args() url = args.url method = args.method # url = "https://baidu.com" # method = "cors" main(url, method)