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_new与password_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