DVWA靶场系列(二)—— CSRF(跨站请求伪造)

#免责声明:
本文属于个人笔记,仅用于学习,禁止使用于任何违法行为,任何违法行为与本人无关。

漏洞原理

CSRF,全称Cross-site request forgery,翻译过来就是跨站请求伪造,是指利用受害者尚未失效的身份认证信息(cookie、会话等),诱骗其点击恶意链接或者访问包含攻击代码的页面,在受害人不知情的情况下以受害者的身份向(身份认证信息所对应的)服务器发送请求,从而完成非法操作(如转账、改密等)。
CSRF的攻击过程有以下两个重点:
1、目标用户已经登录了网站,能够执行网站的功能。
2、目标用户访问了攻击者构造的URL。

漏洞危害

以目标用户的名义发送邮件、发消息,盗取目标用户的账号,甚至购买商品、虚拟货币转账,这会泄露个人隐私并威胁到了目标用户的财产安全。

防御措施

1、验证请求的Referer值,如果Referer是以自己的网站开头的域名,则说明该请求来自网站自己,是合法的。如果Referer是其他网站域名或空白,就有可能是CSRF攻击,那么服务器应拒绝该请求,但是此方法存在被绕过的可能。
2、CSRF攻击之所以能够成功,是因为攻击者可以伪造用户的请求,由此可知,抵御CSRF攻击的关键在于:在请求中放入攻击者不能伪造的信息。例如可以在HTTP请求中以参数的形式加入一个随机产生的token,并在服务器端验证token,如果请求中没有token或者token的内容不正确,则认为该请求可能是CSRF攻击从而拒绝该请求。

靶场实战

Low难度

源码分析



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( '
' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '
'
); // Feedback for the user echo "
Password Changed.
"
; } else { // Issue with passwords matching echo "
Passwords did not match.
"
; } ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res); } ?>

DVWA靶场系列(二)—— CSRF(跨站请求伪造)_第1张图片

可以看到low难度的源码中,并没有隐藏的token验证,,这里的密码检测是自接将GET请求到的参数进行拼接,检验password_new与password_conf是否一致。

漏洞复现

我们可以随便输入一个密码,用BurpSuite抓包看一下如图所示:
DVWA靶场系列(二)—— CSRF(跨站请求伪造)_第2张图片
正如上述所说,这里可以直接按get方式构建一个链接:

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

当用户点击这个链接时,就会自动实现密码更改,如下图所示点击链接后出现密码更改成功的提示:
DVWA靶场系列(二)—— CSRF(跨站请求伪造)_第3张图片
这就是一个简单的CSRF(跨站请求伪造)漏洞,当然,为了更好的诱骗用户点击这个链接可以将链接修饰一下:
1、替换为一个短链接
DVWA靶场系列(二)—— CSRF(跨站请求伪造)_第4张图片
2、可以利用html构造一个攻击界面
DVWA靶场系列(二)—— CSRF(跨站请求伪造)_第5张图片
看似一个失效的404页面,其实已经请求了链接更改了密码。

Medium难度

源码分析



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( '
' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '
'
); // Feedback for the user echo "
Password Changed.
"
; } else { // Issue with passwords matching echo "
Passwords did not match.
"
; } } else { // Didn't come from a trusted source echo "
That request didn't look correct.
"
; } ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res); } ?>

DVWA靶场系列(二)—— CSRF(跨站请求伪造)_第6张图片
里我们可以看到相比于low难度多了一行,这一行代码的函数是为了判断Host字段是否出现在referer字段中(stripos(str1, str2)检查str2在str1中出现的位置(不区分大小写),如果有返//回True,反之False)也就是判断HTTP_REFERER中是否包含SERVER_NAME
HTTP_REFERER是Referer参数值,即来源地址
SERVER_NAME是host参数及主机ip名

漏洞复现

想要破解它,就要让Referer参数值包含主机名,先打开burpsuite对界面进行抓包,可以看到多了一个referer头:Referer: http://127.0.0.1/DVWA-master/vulnerabilities/csrf/DVWA靶场系列(二)—— CSRF(跨站请求伪造)_第7张图片
将其复制下来,再使用同low上面所构造的链接访问,对其抓包,会发现其中并没有referer字段:
DVWA靶场系列(二)—— CSRF(跨站请求伪造)_第8张图片
将刚才复制的referer头粘贴上去,重新发送请求可以看到响应回复如下:
DVWA靶场系列(二)—— CSRF(跨站请求伪造)_第9张图片

High难度

源码分析



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( '
' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '
'
); // Feedback for the user echo "
Password Changed.
"
; } else { // Issue with passwords matching echo "
Passwords did not match.
"
; } ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res); } // Generate Anti-CSRF token generateSessionToken(); ?>

DVWA靶场系列(二)—— CSRF(跨站请求伪造)_第10张图片
可以看到,High级别的代码加入了Anti-CSRF token机制,用户每次访问改密页面时,服务器会返回一个随机的token,向服务器发起请求时,需要提交token参数,而服务器在收到请求时,会优先检查token,只有token正确,才会处理客户端的请求。构建上述恶意链接就不可取了因为token是随机的无法伪造。

漏洞复现

这里我们需要先获取到修改密码界面的token,我们自接使用靶场的XSS环境,执行XSS代码来获取token,如图所示:
DVWA靶场系列(二)—— CSRF(跨站请求伪造)_第11张图片
将token复制下来,再用构造的链接进行抓包将token值修改,再重新发包即可更改密码成功:
DVWA靶场系列(二)—— CSRF(跨站请求伪造)_第12张图片

Impossible难度

源码分析



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 "
Password Changed.
"
; } else { // Issue with passwords matching echo "
Passwords did not match or current password incorrect.
"
; } } // Generate Anti-CSRF token generateSessionToken(); ?>

DVWA靶场系列(二)—— CSRF(跨站请求伪造)_第13张图片
这里不仅加了token验证,还要求输入原密码,当攻击者不知道原密码时,是无法进行CSRF攻击的。

又是朴实无华的一天!!!!!!!!!!!!

参考文章:https://blog.csdn.net/zy15667076526/article/details/109705286

你可能感兴趣的:(csrf,web安全,安全,学习)