• DVWA-CSRF


    一、CSRF简介
    CSRF(Cross-site request forgery)跨站请求伪造,也被称为“One Click Attack”或者Session Riding,通常缩写为CSRF或者XSRF。它是利用受害者尚未失效的身份认证信息(cookie、会话等),诱骗其点击恶意链接或者访问包含攻击代码的页面,在受害者不知情的情况下以受害者的身份向(身份认证信息所对应的)服务器发送请求,从而完成非法操作(如转账、改密等)。
    二、原理示意图

    CSRF攻击成功的前提条件:
    
       1、 用户必须登录
       2、Hacker必须懂得一些发包的请求
       3、 服务器端不会有二次认证
       4、 被害方是不知情的
    


    现在我们在kali,dvwa进行试验操作。
    安全级别: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);
    

    }

    ?> `
    源码分析

    从源码中可以看到,密码中不能包含SQL中的特殊字符;
    服务器收到修改密码的请求后,会检查参数pass_new
    与pass_conf是否相同,如果相同,则会更新数据库,
    修改密码。这个过程没有任何的防CSRF机制(用户已经登录服务器)。
    比如我们修改对应的URL
    让参数pass_new与pass_conf相同。
    127.0.0.1/dvwa/vulnerabilities/csrf/?password_new=password&password_conf=password&Change=Change#
    我们可以把对应的URL发给用户,如果用户点击

    我们可以看见这样我们就可以成功修改用户的密码,
    但是要注意需要服务器验证Cookie,所以必须让该URL和DVWA系统打开的浏览器一致,这样才可以验证成功
    这个很明显,用户不容易上当。
    修改密码的链接过于明显,可以使用一些缩短链接的方法,这样用户更容易上当。
    当然我们也可以写一个修改密码的脚本文件,尝试访问该页面就可以修改密码

    404

    file not found.

    这个脚本文件很简单
    就是用一个标签插入http://127.0.0.1/dvwa/vulnerabilities/csrf/?password_new=password&password_conf=password&Change=Change#
    这样当用户点击访问这个页面时,会以为访问的页面丢失了,但是当他打开这个页面时,用户的密码已经被修改了!
    Medium级别
    先看源码
    `<?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);
    

    }

    ?>
    if( stripos( $_SERVER[ 'HTTP_REFERER' ] ,$_SERVER[ 'SERVER_NAME' ]) !== false )`
    这里通过STRIPOS函数对比HTTP_REFERER,SERVER_NAME是否一致
    后台的服务器会去检查HTTP_REFERER函数是否包含SERVER_NAME(host参数、主机名等),用此方法来抵御CSRF攻击
    方法:
    通过验证,就必须保证在Http请求中Referer字段中必须包含Host,所以攻击者只需要将文件名改成受害者的Host以及name就可以完美通过验证!
    使用burp suite来抓包,发送到Repeater模块

    然后修改一致

    点击GO
    回到游览器刷新页面

    我们可以看到密码修改成功。
    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();

    ?>
    `
    checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
    通过源代码分析可以看到该模块中加入了Anti-CSRF token来防范CSRF攻击,同时每次随机生成了一个Token,当
    用户提交的时候,在服务器端比对一下Token值是否正确,不正确就丢弃掉,正确就验证通过。
    将数据包发送到Repeater模块:

    我们可以把Cookie里面的security的值修改为low。

    Impossible等级
    看源代码
    `<?php

    if( isset( $_GET[ 'Change' ] ) ) {

    // Check Anti-CSRF token
    
    checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
    
    // Get input
    
    $pass_curr = $_GET[ 'password_current' ];
    
    $pass_new  = $_GET[ 'password_new' ];
    
    $pass_conf = $_GET[ 'password_conf' ];
    
    // Sanitise current password input
    
    $pass_curr = stripslashes( $pass_curr );
    
    $pass_curr = mysql_real_escape_string( $pass_curr );
    
    $pass_curr = md5( $pass_curr );
    
    // Check that the current password is correct
    
    $data = $db->prepare( 'SELECT password FROM users WHERE user = (:user) AND password = (:password) LIMIT 1;' );
    
    $data->bindParam( ':user', dvwaCurrentUser(), PDO::PARAM_STR );
    
    $data->bindParam( ':password', $pass_curr, PDO::PARAM_STR );
    
    $data->execute();
    
    // Do both new passwords match and does the current password match the user?
    
    if( ( $pass_new == $pass_conf ) && ( $data->rowCount() == 1 ) ) {
    
        // It does!
    
        $pass_new = stripslashes( $pass_new );
    
        $pass_new = mysql_real_escape_string( $pass_new );
    
        $pass_new = md5( $pass_new );
    
        // Update database with new password
    
        $data = $db->prepare( 'UPDATE users SET password = (:password) WHERE user = (:user);' );
    
        $data->bindParam( ':password', $pass_new, PDO::PARAM_STR );
    
        $data->bindParam( ':user', dvwaCurrentUser(), PDO::PARAM_STR );
    
        $data->execute();
    
        // Feedback for the user
    
        echo "<pre>Password Changed.</pre>";
    
    }
    
    else {
    
        // Issue with passwords matching
    
        echo "<pre>Passwords did not match or current password incorrect.</pre>";
    
    }
    

    }

    // Generate Anti-CSRF token

    generateSessionToken();

    ?>
    `

    Impossible级别的代码利用PDO技术防御SQL注入
    对于防护CSRF,则要求用户输入原始密码,攻击者在不知道原始密码的情况下,无法进行CSRF攻击。

  • 相关阅读:
    Git基本操作(Windows下)
    Git for Windows安装和基本设置
    OpenCV 2.4.3在VS2010上的应用
    VS2010安装Visual Assist
    django中表单处理
    django自定义错误响应
    django的url配置
    django模板语言
    zabbix利用api批量添加item,并且批量配置添加graph
    高性能集群软件Keepalived(1)
  • 原文地址:https://www.cnblogs.com/renletao/p/13514493.html
Copyright © 2020-2023  润新知