CSRF(Cross-site request forgery),翻译过来就是跨站请求伪造,是指利用受害者尚未失效的身份认证信息(cookie、会话等),诱骗其点击恶意链接或者访问包含攻击代码的页面,在受害人不知情的情况下以受害者的身份向(身份认证信息所对应的)服务器发送请求,从而完成非法操作(如转账、改密等)。
CSRF与XSS最大的区别就在于,CSRF并没有盗取cookie而是直接利用。而最常见的就是QQ空间的登陆。
CSRF属于业务逻辑漏洞,服务器信任经过身份认证的用户。
XSS属于技术漏洞,客户信任服务器。
漏洞利用前提::用户必须登录、黑客懂得一些发包的请求,服务器端是不会有二次认证的,被害者是不知情的
CSRF Source
vulnerabilities/csrf/source/low.php
' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '
' );
// Feedback for the user
echo "Password Changed."; } else { // Issue with passwords matching echo "
Passwords did not match."; } ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res); } ?>
代码解析:
查看源代码,首先获取输入的两个密码然后判断两个值是否相等,如果相等则对$pass_new变量进行调用mql_real_escape_string函数来进行字符串的过滤(防御SQL注入),再调用md5函数对输入的密码进行MD5加密,最后再将新密码更新到数据库中。分析源码只看到只对SQL注入进行了防御,并没有防御CSRF。
分析策略:
服务器收到修改密码的请求后,会检查参数password_new与password_conf是否相同,如果相同,就会修改密码,并没有任何的防CSRF机制,所以我们只需要用户在cookie还有效的时间内在相同的浏览器访问我们给定的url(该操作是服务器对请求的发送者进行了身份验证,检查cookie),就可以实现CSRF攻击,修改用户密码。
测试用DVWA的默认密码登录,发现登录不进去,然后用修改过的密码登录,发现登录成功,说明存在CSRF漏洞。
按照提示框输入密码和确认密码之后得到链接为:http://192.168.40.1/DVWA-master/vulnerabilities/csrf/?password_current=password&password_new=123456&password_conf=123456&Change=Change&user_token=c0c8394b2f0bb672adc073e1f5c62d5f#
当用户点击这个链接,密码就会自动被修改成123456,因此会有其他的工具用于将长链接缩短为短链接,如网站:百度短网址
新建一个html文件,通过img标签中的src属性来加载CSRF攻击利用的URL,并进行布局隐藏,实现了受害者点击链接则会将密码进行修改,再把该html文件放在攻击者自己准备的网站上。
404
file not found
当受害者点击该html之后,页面返回的404,会让受害者误以为自己点击的是一个失效的url,但实际上已经遭受了CSRF攻击,密码修改为123456。
解析源代码:
' . mysql_error() . '
' );
// Feedback for the user
echo "Password Changed."; } else { // Issue with passwords matching echo "
Passwords did not match."; } } else { // Didn't come from a trusted source echo "
That request didn't look correct."; } mysql_close(); } ?>
stripos(string,find,start):函数查找字符串在另一字符串中第一次出现的位置,不区分大小写。
eregi(string pattern, string string):检查string中是否含有pattern(不区分大小写),如果有返回True,反之False。
PHP超全局变量$_SERVER中的两个值:
$_SERVER['HTTP_REFERER']:PHP中获取链接到当前页面的前一页面的url链接地址,即HTTP数据包中的Referer参数的值。
$_SERVER['SERVER_NAME']:PHP中获取服务器主机的名称,即HTTP数据包中的Host参数的值。
referer是HTTP请求header的一部分,当浏览器(或模拟浏览器行为)向web服务器发送请求的时候,头信息里有referer。
Medium级别的代码检查了保留变量 HTTP_REFERER(http包头的Referer参数的值,表示来源地址)中是否包含SERVER_NAME(http包头的Host参数,及要访问的主机名,这里是127.0.0.1),希望通过这种机制抵御CSRF攻击。一开始就调用eregi()函数来判断HTTP头的referer字段里是不是包含“127.0.0.1”字符串,即发送请求的是不是本机,如果是则继续后面代码的执行。
因为过滤规则是http包头的referer参数的值中必须包含主机名(这里是127.0.0.1)
我们可以将攻击页面命名为127.0.0.1.html.则可以绕过过滤。
' . mysql_error() . '
' );
// Feedback for the user
echo "Password Changed."; } else { // Issue with passwords matching echo "
Passwords did not match."; } mysql_close(); } // Generate Anti-CSRF token generateSessionToken(); ?>
在这里,添加了一个generateSessionToken()函数,加入了Anti-CSFR token机制,用户每次访问修改密码页面时,服务器会返回一个随机的token,向服务器发起请求时,需要提交token参数,而服务器在收到请求时,会优先检查token,只有token正确,才会处理客户端的请求。
解决方法:
DVWA-CSRF(跨站请求伪造) - 简书
DVWA之CSRF(跨站请求伪造) - Res0lve - 博客园