什么是XSS?

XSS全称(Cross Site Scripting)跨站脚本攻击,是最常见的Web应用程序安全漏洞之一,位于OWASP top 10 2013/2017年度分别为第三名和第七名,在最新的owasp top 10 2021中XSS被归入注入漏洞,排第三名。XSS是指攻击者在网页中嵌入客户端脚本,通常是JavaScript编写的危险代码,当用户使用浏览器浏览网页时,脚本就会在用户的浏览器上执行,从而达到攻击者的目的。

从上面中的一段话,可以得知,XSS属于客户端攻击,受害者最终是用户,但特别要注意的是网站管理人员也属于用户之一。这就意味着XSS可以进行“服务端”攻击,因为管理员要比普通用户的权限大得多,一般管理员都可以对网站进行文件管理,数据管理等操作,而攻击者一般也是靠管理员身份作为“跳板”进行实施攻击。

XSS攻击最终目的是在网页中嵌入客户端恶意脚本代码,最常用的攻击代码是javascript语言,但也会使用其它的脚本语言,例如:ActionScript、VBscript。而如今的互联网客户端脚本基本是基于Javascript,所以如果想要深入研究XSS,必须要精通Javascript。

XSS换句话说,JavaScript能做到什么效果,XSS的胃口就有多大。这完全不是危言耸听。javascript可以用来获取用户的cookie,弹出窗口,那么存在XSS漏洞的网站,XSS就可以用来盗取用户Cookie,废掉页面,导航到恶意网站!更高端的XSS代码完全可以进行监控你的键盘操作,模仿Windows注销界面,诱导你输入开机密码!而攻击者需要做的仅仅是向你的代码中注入Javascript代码!

XSS漏洞出现的原因

程序对输入和输出的控制不够严格,导致”精心构造“的脚本输入后,在输到前端时被浏览器当作有效代码解析执行从而产生危害。

XSS的危害

针对用户

  1. 窃取用户Cookies资料,从而获取用户隐私信息,或利用用户身份进一步对网站执行操作
  2. 劫持用户浏览器会话,将用户当前使用的SessionID信息发送至攻击者控制的网站或服务器中,从而执行任意操作。例如进行非法转账、强制发表日志、发送电子邮件等
  3. 网站钓鱼。在网页中通过JS脚本,生成虚假的页面,欺骗用户执行操作,而用户所有的输入内容都会被发送到攻击者的服务器上
  4. 网页挂马(水坑攻击)
  5. 有局限性的键盘记录
  6. 发广告刷流量

针对WEB服务

  1. 内网扫描
  2. 进行大量的客户端攻击,如DDoS攻击
  3. 结合其他漏洞,如CSRF漏洞,实施进一步作恶
  4. 传播跨站脚本蠕虫

XSS分类

反射型XSS

反射型跨站脚本也称非持久型跨站脚本、参数型跨站脚本。这种类型的跨站脚本是最常见,也是使用最广泛的一种,主要用于将恶意脚本附加到URL地址的参数中。

反射性XSS的利用一般是攻击者通过特定手法(比如利用电子邮件),诱使用户去访问一个含有恶意代码的URL,当受害者点击这些专门设计的链接的时候,恶意JavaScript代码会直接在受害者主机的浏览器执行。它的特点是只在用户点击时触发,而且只执行一次,非持久化,所以称为反射型跨站脚本。

反射型XSS的攻击流程图:

image-20211104232043853

此类XSS通常出现在网站的搜索栏、用户登录入口等地方,常用来窃取Cookie或进行钓鱼欺骗。

反射型XSS的危害往往不如存储型XSS,因为恶意代码暴力在URL参数中,并且时刻要求用户单击方可触发,稍微有点安全意识的用户可以轻易看穿链接是不可信任的。如此一来反射型XSS的攻击成本要比存储型XSS高得多。

反射型XSS的URL可能被用户怀疑,但是可以通过短网址服务将之缩短,从而隐藏自己。

反射型XSS测试代码:

1
2
3
4
<?php
$name = $_GET['name'];
echo "Welcome $name<br>";
?>

http://hackrock.com/mylabs/xss/xss1.php?name=<script>alert(1)</script>

image-20211104225743847

可以看到执行了JavaScript中的代码

存储型XSS

存储型跨站脚本也称持久型跨站脚本,比反射型跨站脚本更具威胁性,并且可能影响到Web服务器自身的安全。

此类XSS不需要用户单击特定URL就能执行跨站脚本,攻击者事先将恶意的JavaScript代码上传或存储到漏洞服务器中,只要受害者浏览包含此恶意JavaScript代码的页面就会执行恶意代码。

存储型XSS的攻击流程图:

image-20211104233238841

存储型XSS一般出现在网站的留言、评论、博客日志等交互处,恶意脚本常常被存储到客户端或者服务器的数据库中,当其他用户浏览该网页时,站点即从数据库中读取恶意用户存入的非法数据,然后显示在页面中,即在受害者主机上的浏览器执行恶意代码。

存储型XSS不需要用户去单击URL进行触发,所以它的危害比反射型XSS大,黑客可以利用它渗透网站、挂马、钓鱼……

更严重的是,利用此类XSS能够轻易写危害性更大的XSS蠕虫,跨站蠕虫是使用Ajax/JavaScript脚本语言编写的蠕虫病毒,能够在网站中实现病毒的几何数级传播,其感染速度和攻击效果都非常可怕。XSS蠕虫会直接影响到网站中的所有用户,也就是一个地方出现XSS漏洞,同站点下的所有用户都可能被攻击。可想而知XSS蠕虫对网站的打击是十分巨大的。

另外,存储型XSS的恶意代码并不止是存储在服务器的数据库中,凡是能够进行持久化XSS都可以称之为存储型XSS,例如存储在浏览器的Cookie文件、LocalStorage、IndexedDB等本地存储中。随着HTML5的广泛普及,这种存储方式也越来越流行。

存储型XSS测试代码:

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
<?php
header("content-type:text/html;charset=utf-8");
$result = mysql_connect('localhost','root','Admin12345');
$select_db = mysql_select_db("test_db");

$txtMessage = "";

if(!empty($_POST)){
$txtMessage = $_POST['txtMessage'];
$sql = "insert into guestbook(txtMessage) values('$txtMessage')";
$result = mysql_query($sql);
if($result){
echo "<script>location.href='xss2.php';</script>";
}
}
?>

<html>
<head>
<meta charset="utf-8"/>
<title>留言板</title>
</head>
<body>
<?php
$sql = "select txtMessage from guestbook";
$result = mysql_query($sql);
while($row = mysql_fetch_array($result)){
?>
<table width="80%" align="center" border="1" style="margin-bottom:10px;" rules="all">
<tr>
<td><?php echo $row['txtMessage'];?></td>
</tr>
</table>
<?php
}
?>
<br>
<form method="POST">
<table width="80%" align="center" border="1" style="margin-bottom:10px;" rules="all">
<tr>
<td>留言内容</td>
<td><textarea id="txtMessage" name="txtMessage" cols="100" rows="6"><?php echo $txtMessage; ?></textarea></td>
</tr>
<tr>
<td></td>
<td><input type="submit" name="submit" value="提交" /></td>
</tr>
</table>
</form>
</body>
</html>

这是一个非常简单的留言板程序

image-20211105204949911

但是当我们再留言板中插入了一段XSS的payload

image-20211105205321198

弹出提示框,成功执行了JavaScript代码

image-20211105205409909

DOM型XSS

实际上,这种类型的XSS并非按照“数据是否保存在服务器端”来划分,DOM Based XSS从效果上来说也是反射型XSS。单独划分出来,是因为DOM Based XSS的形成原因比较特别,发现它的安全专家专门提出了这种类型的XSS。出于历史原因,也就把它单独作为一个分类了。

DOM-XSS不经过后端,而是通过DOM节点形成的XSS。

DOM型XSS在攻击中的优势:

  • 避开waf

    因为有些情况DOM-XSS的Payload,可以通过location.hash,即设置为锚部分从#之后的部分,既能让JS读取到该参数,又不让该参数传入到服务器,从而避免waf检测。location.search也类似,它可以把部分参数放在?之后的部分。

  • 长度不限

    这个很重要,关键时候,长度不够,可不是什么小药丸就解决的。

  • 隐蔽性强

    攻击代码可以具有隐蔽性,持久性。例如使用Cookie和localStorage作为攻击点的DOM-XSS,非常难以察觉,且持续的时间长。

DOM型XSS测试代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>DOM型XSS</title>
<script type="text/javascript">
function test() {
var str = document.getElementById("text").value;
document.getElementById("t").innerHTML = "<a href='"+str+"' >testLink</a>";
}
</script>
</head>
<body>
<div id="t"></div>
<input type="text" id="text" value="">
<input type="button" id="s" value="write" onclick="test()">
</body>
</html>

点击write按钮后,会在当前页面插入一个超链接,其地址为文本框的内容:

image-20211105214151523

在这里,write按钮的onclick事件调用了test()函数。而在test()函数中,修改了页面中的DOM节点,通过innerHTML把一段用户数据当做HTML写入到了页面中,这就造成了DOM-XSS。

构造如下数据:

1
' onclick=alert(1) //

输入后,页面代码就变成了:

1
<a href='' onclick=alert(1) //' >testLink</a>

首先用一个单引号闭合掉href的第一个单引号,然后插入一个onclick事件,最后再用注释符“//”注释掉第二个单引号。

点击这个新生成的链接,脚本被执行:

image-20211105214817378

实际上,这里还有另一种利用方式——除了构造一个新事件外,还可以选择闭合掉<a>标签,并插入一个新的HTML标签。尝试如下输入:

1
'><img src=# onerror=alert(1) /><'

页面代码变成了:

1
<a href=''><img src=# onerror=alert(1) /><'' >testLink</a>

XSS漏洞挖掘场景

黑盒测试

尽可能找到一切用户可控并且能够输出在页面代码中的地方,比如下面这些:

  • URL的每一个参数
  • URL本身
  • 表单
  • 搜索框

常见业务场景

  • 重灾区:评论区、留言区、个人信息、订单信息等
  • 针对型:站内信、网页即时通讯、私信、意见反馈
  • 存在风险:搜索框、当前目录、图片属性等

白盒测试(代码审计)

关于XSS的代码审计主要就是从接收参数的地方和一些关键词入手。

PHP中常见的接收参数的方式有 $_GET$_POST$_REQUEST 等等,可以搜索所有接收参数的地方。然后对接收到的数据进行跟踪,看看有没有输出到页面中,然后看输出到页面中的数据是否进行了过滤和html编码等处理。

也可以搜索类似echo这样的输出语句,跟踪输出的变量是从哪里来的,我们是否能控制,如果从数据库中取的,是否能控制存到数据库中的数据,存到数据库之前有没有进行过滤等等。

大多数程序会对接收参数封装在公共文件的函数中统一调用,我们就需要审计这些公共函数看有没有过滤,能否绕过等等。

同理审计DOM型注入可以搜索一些js操作DOM元素的关键词进行审计。

参考资料