zoukankan      html  css  js  c++  java
  • 代码审计中的XSS

    0x00 背景

    XSS漏洞也叫跨站脚本攻击,是Web漏洞中最常见的漏洞,原理与SQL注入相似,通过来自外部的输入直接在浏览器端触发。XSS漏洞通常被入侵者用来窃取Cookie等,本文以代码审计的形式研究XSS攻击原理、挖掘形式、防御方案及缺陷。

    0x01 XSS攻击原理

    我们看下面一段代码:

    1 <?php
    2 
    3 // Is there any input?
    4 if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {
    5 // Feedback for end user
    6 echo '<pre>Hello ' . $_GET[ 'name' ] . '</pre>';
    7 }
    8 
    9 ?> 

    通过上面的代码我们可以轻松看出,用户输入的变量name没有经过任何处理直接输出到了页面上,如果我们在name变量的输入框中输入

    <script>alert(/xss/)</script>

    第六行代码就变成了

    echo '<pre>Hello ' . <script>alert(/xss/)</script> . '</pre>';

    这样我们的浏览器上就会弹出一个内容为/xss/的窗口。这就是XSS的基本原理。

    0x02 XSS漏洞的挖掘形式

    根据上文的原理介绍,在挖掘XSS漏洞的时候,我们需要找的是可以传输到输出函数的参数,我们常用的输出函数有print、printf、print_r、echo、sprintf、die、var_dump、var_export,所以我们只需要搜索这些函数,追踪其变量即可。

    XSS的挖掘也可以重点关注相关的业务,例如论坛、博客、图片引用、资料修改等,Web程序在保证业务正常运行的前提下很难面面俱到地进行防御,在挖掘的时候我们也可以通读这些业务的代码寻找XSS漏洞。

    反射型XSS

    反射型XSS如同0x01中所呈现的代码,用户发出一个带有XSS攻击的请求,服务器端接受请求后进行处理并把带有XSS的代码发送给了浏览器,浏览器解析带有XSS的代码,这就造成了XSS攻击,整个过程如同一次反射,因此命名反射型XSS。

    反射型XSS的挖掘利用扫描器进行黑盒测试基本可以直接发现,原理是向Web服务器提交尖括号等XSS常用符号,检查返回的HTML页面里是否还有特殊字符即可。在代码审计中我们需要找输出函数中的参数,然后回溯参数观察过滤情况。

    存储型XSS

    存储型XSS顾名思义,是将带有XSS攻击的代码存储起来,每次Web程序读取到这段代码的时候就会触发一次攻击。因此存储型XSS的利用难度更低、危害更大(很多SRC不收录反射型XSS)。一个最常见的带有存储型XSS漏洞的代码如下:

     1 <?php
     2 
     3 if( isset( $_POST[ 'btnSign' ] ) ) {
     4     // Get input
     5     $message = trim( $_POST[ 'mtxMessage' ] );
     6     $name    = trim( $_POST[ 'txtName' ] );
     7 
     8     // Sanitize message input
     9     $message = stripslashes( $message );
    10     $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)) ? "" : ""));
    11 
    12     // Sanitize name input
    13     $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)) ? "" : ""));
    14 
    15     // Update database
    16     $query  = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );";
    17     $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>' );
    18 
    19     //mysql_close();
    20 }

    根据这段代码我们可以看出,用户向页面提交变量mtxMessage和txtName,然后Web程序未经任何过滤就将这两个变量存储到数据库,每次用户访问这个页面的时候都会从数据库提取代码造成攻击。

    与挖掘反射型XSS漏洞一样,我们也是要寻找带有参数并且未经过滤的输出函数,并对这些参数进行全局追踪。

    0x03 防御方案及缺陷

    XSS漏洞的防御比较复杂,在不同的业务情境下需要考虑不同的情况,以下介绍几种常见的防御方式。

    黑白名单

    与SQL注入防御一样,黑名单是最低效的防御方案,一个典型的黑名单案例如下

     1 <?php
     2 
     3 // Is there any input?
     4 if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {
     5     // Get input
     6     $name = str_replace( '<script>', '', $_GET[ 'name' ] );
     7 
     8     // Feedback for end user
     9     echo "<pre>Hello ${name}</pre>";
    10 }
    11 
    12 ?> 

    这个案例中采用了str_replace函数将变量name中的<script>标签置换为空。在这里我们有两种绕过方式

    1.采用大小写绕过(<ScRiPt>)或者采用双写绕过(<scr<script>ipt>);

    2.采用除<script>标签外的其他标签,例如<img>标签等实现XSS攻击。

    而白名单就是一种相对可靠一些的过滤方式,我们可以采用正则进行事件匹配,如果匹配到规则内的事件直接进行拦截,而不采用替换为空的方式。

    特殊字符转码为HTML实体

    这种防御方案是目前最流行的XSS防御方案之一,这些特殊字符集包括:尖括号、单引号、双引号、反斜杠、&等。案例如下:

     1 <?php 
     2 // Is there any input? 
     3 if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) { 
     4     // Check Anti-CSRF token 
     5     checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' ); 
     6     // Get input 
     7     $name = htmlspecialchars( $_GET[ 'name' ] ); 
     8     // Feedback for end user 
     9     echo "<pre>Hello ${name}</pre>"; 
    10 } 
    11 // Generate Anti-CSRF token 
    12 generateSessionToken(); 
    13 ?>

    在这个案例中,采用了htmlspecialchars函数,把预定义的字符&<>转换为 HTML 实体,防止浏览器将其作为HTML元素。虽然看起来这样处理XSS就能万事大吉,但在htmlspecial函数中有个大坑需要格外注意!该函数的用法如下:

    htmlspecialchars(string,flags,character-set,double_encode)
    

     我们注意第二个参数flags。这个参数对引号的编码规则如下:

    #可用的引号类型:
    
    ENT_COMPAT #- 默认。仅编码双引号。
    ENT_QUOTES #- 编码双引号和单引号。
    ENT_NOQUOTES #- 不编码任何引号。

    注意!flags参数默认状态值编码双引号!这个默认参数在实际开发中非常容易被忽略,我们看下面这个案例:

    <?php  
        $name = $_GET["name"]; 
        $name = htmlspecialchars($name); 
    ?> 
       
    <input type='text' value='<?php echo $name?>'> 

    如果我们提交:/test.php?name=1' onmouseover='javascript:alter(1)

    单引号无法被转码成HTML实体,依然会造成反射型XSS漏洞。

  • 相关阅读:
    【转】php三种工具pecl pear composer的区别
    【转】Git使用详细教程
    【转】chrome Network 过滤和高级过滤
    Python3第三方组件最新版本追踪实现
    Python3版本号比较代码实现
    模糊测试工具设计思路浅谈
    Python3+WebSockets实现WebSocket通信
    Python3+PyCryptodome实现各种加密算法教程
    HTTP漫谈
    Python3+Robot Framework+RIDE安装使用教程
  • 原文地址:https://www.cnblogs.com/richardlee97/p/10506687.html
Copyright © 2011-2022 走看看