加一个参数就是一个洞。在挖洞的时候,我注意到一些特殊的请求参数,好比说 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)