PHP代码审计学习(8)——CSRF漏洞

CSRF

  跨站请求伪造(英语:Cross-site request forgery),也被称为 one-click attack 或者 session riding,通常缩写为 CSRF 或者 XSRF, 是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法。跟(XSS)相比,XSS 利用的是用户对指定网站的信任,CSRF 利用的是网站对用户网页浏览器的信任。与XSS攻击相比,CSRF攻击往往不大流行(因此对其进行防范的资源也相当稀少)和难以防范,所以被认为比XSS更具危险性

攻击思路

  CSRF(Cross-site request forgery)跨站请求伪造:攻击者诱导受害者进入第三方网站,在第三方网站中,向被攻击网站发送跨站请求。利用受害者在被攻击网站已经获取的注册凭证,绕过后台的用户验证,达到冒充用户对被攻击的网站执行某项操作的目的。

  一个典型的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执行了自己定义的操作。

挖掘思路

  CSRF主要是越权操作,出现的位置自然就是要有权限控制的地方,所以在黑盒审计的时候,多注意管理后台、交易管理,用户操作等地方,找交互页面抓包查看token头,若没有删referer再提交是否返回一致,若一致则有可能有CSRF。

  在白盒的时候,就看核心代码有没有验证referer和token,若核心文件没有则去功能点找

案例

  直接上DVWA的源码(我太菜了不会写这个场景)

<?php

if( isset( $_GET[ 'Change' ] ) ) {
    // 获取用户的输入
    $pass_new  = $_GET[ 'password_new' ];
    $pass_conf = $_GET[ 'password_conf' ];

    // 确认两次输入的密码是否相同,相同就更新数据库内的信息
    if( $pass_new == $pass_conf ) {
        // 以下两段代码都是防止SQL注入的
        $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 );

        // 更新数据库内的信息,具体函数作用以及对代码的理解,在暴力破解那里我写过的,这里就不写了
        $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>' );

        // 修改成功,返回信息给用户
        echo "<pre>Password Changed.</pre>";
    }
    else {
        // 两次输入的密码不同,所以返回信息给用户
        echo "<pre>Passwords did not match.</pre>";
    }

    ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}

?>

  可以看到,服务器收到修改密码的请求后,会检查参数password_newpassword_conf是否相同,如果相同,就会修改密码,并没有任何的防CSRF机制

  抓一下包

 

 

 

   构造http://192.168.43.167/DVWA/vulnerabilities/csrf/?password_new=123456&password_conf=123456&Change=Change#

  当受害者点击了这个链接,他的密码就会被改成password,这样就完成了一次CSRF攻击,当然这种很明显,可以使用BP自带的POC攻击

 

 

   诱导受害者使用浏览器访问生成的html文件,点击submit,会发现密码修改成功。用户密码变成了123456

防御

  1、将cookie设置为HttpOnly 

  CRSF攻击很大程度上是利用了浏览器的cookie,为了防止站内的XSS漏洞盗取cookie,需要在cookie中设置"HttpOnly"属性,这样通过程序(js、applet等)无法读取到cookie信息。避免了攻击者伪造cookie的情况出现。服务端的CSRF方式方法很多样,但总的思想都是一致的,就是在客户端页面增加伪随机数。  

  2、Cookie Hashing(所有表单都包含同一个伪随机值)

    这可能是最简单的解决方案了,因为攻击者不能获得第三方的Cookie(理论上),所以表单中的数据也就构造失败了

  3、验证码

  这个方案的思路是:每次的用户提交都需要用户在表单中填写一个图片上的随机字符串,厄....这个方案可以完全解决CSRF,但个人觉得在易用性方面似乎不是太好,还有听闻是验证码图片的使用涉及了一个被称为MHTML的Bug,可能在某些版本的微软IE中受影响。

  在业界目前防御 CSRF 攻击主要有三种策略:验证 HTTP Referer 字段;在请求地址中添加 token 并验证;在 HTTP 头中自定义属性并验证。

参考

  https://www.freebuf.com/articles/web/118352.html

posted @ 2020-06-29 20:20  Lee-404  阅读(340)  评论(0编辑  收藏  举报
Live2D