XSS初探及实验
一、前置了解
1、什么是跨站点脚本 (XSS)?
跨站点脚本(也称为 XSS)是一种 Web 安全漏洞,它允许攻击者破坏用户与易受攻击应用程序的交互。它允许攻击者规避同源策略,该策略旨在将不同的网站彼此隔离。跨站脚本漏洞通常允许攻击者伪装成受害者用户,执行用户能够执行的任何操作,并访问用户的任何数据。如果受害用户在应用程序中具有特权访问权限,则攻击者可能能够完全控制应用程序的所有功能和数据。
2、XSS 是如何工作的?
跨站点脚本的工作原理是操纵易受攻击的网站,以便将恶意 JavaScript 返回给用户。当恶意代码在受害者的浏览器中执行时,攻击者可以完全破坏他们与应用程序的交互。
3、XSS 概念验证
您可以通过注入有效负载alert()
来确认大多数类型的 XSS 漏洞,该负载会导致您自己的浏览器执行一些任意 JavaScript。长期以来,将该函数alert()
用于此目的一直是常见的做法,因为它简短、无害,并且在成功调用时很难错过。事实上,您通过调用模拟受害者的浏览器来解决我们的大多数 XSS 实验室。
不幸的是,如果您使用 Chrome,则会遇到一些小问题。从版本 92 开始(2021 年 7 月 20 日),跨域 iframe 无法调用 。由于这些攻击用于构建一些更高级的 XSS 攻击,因此有时需要使用替代的 PoC 有效负载。在此方案中,我们建议使用该函数。如果您有兴趣了解有关此更改的更多信息以及我们喜欢的原因,请查看我们关于该主题的博客文章。alert()
print()
print()
由于我们实验室中的模拟受害者使用 Chrome,因此我们修改了受影响的实验室,以便也可以使用 print()
.我们在相关说明中指出了这一点。
4、XSS 攻击有哪些类型?
XSS 攻击主要有三种类型。这些是:
- 反射的 XSS其中恶意脚本来自当前 HTTP 请求。
- 存储的 XSS其中恶意脚本来自网站的数据库。
- 基于 DOM 的 XSS漏洞存在于客户端代码中,而不是服务器端代码中。
二、XSS类型原理及实验
1、 反射型XSS
① 什么是反映的跨站点脚本?
当应用程序在 HTTP 请求中接收数据并以不安全的方式将该数据包含在即时响应中时,就会出现反射式跨站点脚本(或 XSS)。
假设一个网站有一个搜索功能,该功能在 URL 参数中接收用户提供的搜索词:
https://insecure-website.com/search?term=gift
应用程序在对此 URL 的响应中回显提供的搜索词:
You searched for: gift
假设应用程序不对数据执行任何其他处理,攻击者可以构建如下攻击:
https://insecure-website.com/search?term=<script>/*+Bad+stuff+here...+*/</script>
此 URL 将生成以下响应:
You searched for:
如果应用程序的其他用户请求攻击者的 URL,则攻击者提供的脚本将在受害者用户的浏览器中执行,在他们与应用程序的会话上下文中。
实验室1:将 XSS 反射到 HTML 上下文中,无需任何编码
本实验在搜索功能中包含一个简单的反射式跨站点脚本漏洞。
若要解决实验室问题,请执行调用函数alert
的跨站点脚本攻击。
打开实验室,发现有一个搜索框,随便输入一个字符,观察反应
发现返回,多次输入搜索值,发现这里的1,是我们输入的值
那么猜测,我们输入什么,服务器就返回什么到浏览器,这里打开浏览器的开发者工具,查看这里的返回
可以看到是返回到HTML中的<h1>
标签中,那么输入代码,会怎么处理呢,进行测试
直接输入<script>alert(1);</script>
,发现竟然执行了这个,查看前端的代码,发现,确实是作为脚本代码执行了
<script>
标签表示,在标签内的数据会被作为JavaScript代码执行
② 反射 XSS 攻击的影响
如果攻击者可以控制在受害者浏览器中执行的脚本,那么他们通常可以完全破坏该用户。除其他事项外,攻击者可以:
- 在应用程序中执行用户可以执行的任何操作。
- 查看用户能够查看的任何信息。
- 修改用户能够修改的任何信息。
- 发起与其他应用程序用户的交互,包括恶意攻击,这些攻击似乎来自初始受害者用户。
攻击者可以通过多种方式诱使受害用户发出他们控制的请求,以提供反射的 XSS 攻击。这些措施包括在攻击者控制的网站上放置链接,或在允许生成内容的其他网站上放置链接,或者通过电子邮件、推文或其他消息发送链接。该攻击可能直接针对已知用户,也可能是针对应用程序的任何用户的不分青红皂白的攻击。
对攻击的外部交付机制的需求意味着反射 XSS 的影响通常不如存储的 XSS 严重,后者可以在易受攻击的应用程序本身内传递独立攻击。
③ 不同上下文中的反射 XSS
有许多不同的反射式跨站点脚本。反映的数据在应用程序响应中的位置决定了利用它所需的有效负载类型,并且还可能影响漏洞的影响。
此外,如果应用程序在反映之前对提交的数据执行任何验证或其他处理,这通常会影响所需的 XSS 有效负载类型。
④ 如何查找和测试反射的 XSS 漏洞
使用 Burp Suite 的 Web 漏洞扫描程序可以快速可靠地找到绝大多数反映的跨站点脚本漏洞。
手动测试反射的 XSS 漏洞涉及以下步骤:
- 测试每个入口点。单独测试应用程序 HTTP 请求中数据的每个入口点。这包括 URL 查询字符串和邮件正文以及 URL 文件路径中的参数或其他数据。它还包括 HTTP 标头,尽管只能通过某些 HTTP 标头触发的类似 XSS 的行为在实践中可能无法利用。
- 提交随机字母数字值。对于每个输入点,提交唯一的随机值,并确定该值是否反映在响应中。该值应设计为能够经受住大多数输入验证,因此需要相当短且仅包含字母数字字符。但是它需要足够长的时间,以使响应中的意外匹配极不可能。大约 8 个字符的随机字母数字值通常是理想的。您可以使用 Burp Intruder 的数字有效负载和随机生成的十六进制值来生成合适的随机值。您可以使用 Burp Intruder 的 grep 有效负载设置来自动标记包含已提交值的响应。
- 确定反射上下文。对于响应中反映随机值的每个位置,确定其上下文。这可能是在 HTML 标签之间的文本中、可能被引用的标签属性中、JavaScript 字符串中等。
- 测试候选有效负载。根据反射的上下文,测试初始候选 XSS 有效负载,如果该负载在响应中未修改地反映,则将触发 JavaScript 执行。测试有效负载的最简单方法是将请求发送到 Burp Repeater,修改请求以插入候选有效负载,发出请求,然后查看响应以查看有效负载是否有效。一种有效的工作方法是将原始随机值保留在请求中,并将候选 XSS 有效负载放在它之前或之后。然后将随机值设置为 Burp Repeater 响应视图中的搜索词。打嗝将突出显示搜索词出现的每个位置,让您快速找到倒影。
- 测试替代有效负载。如果候选 XSS 有效负载被应用程序修改或完全阻止,则需要测试替代有效负载和技术,这些有效负载和技术可能会根据反射的上下文和正在执行的输入验证类型提供有效的 XSS 攻击。
- 在浏览器中测试攻击。最后,如果您成功找到似乎可以在 Burp Repeater 中工作的有效负载,请将攻击转移到真正的浏览器(通过将 URL 粘贴到地址栏中,或通过修改 Burp Proxy 拦截视图中的请求,并查看注入的 JavaScript 是否确实被执行。通常,最好执行一些简单的 JavaScript,例如如果攻击成功,它将在浏览器中触发一个可见的弹出窗口。
alert(document.domain)
⑤ 有关反射式跨站点脚本的常见问题
反射的 XSS 和存储的 XSS 有什么区别?
当应用程序从 HTTP 请求中获取一些输入并以不安全的方式将该输入嵌入到即时响应中时,就会出现反射 XSS。使用存储的 XSS,应用程序会存储输入,并以不安全的方式将其嵌入到以后的响应中。
反射 XSS 和自我 XSS 有什么区别?
Self-XSS 涉及与常规反射 XSS 类似的应用程序行为,但它无法通过构建的 URL 或跨域请求以正常方式触发。相反,只有当受害者自己从其浏览器提交 XSS 有效负载时,才会触发该漏洞。提供自我 XSS 攻击通常涉及对受害者进行社会工程,以将攻击者提供的一些输入粘贴到他们的浏览器中。因此,它通常被认为是一个蹩脚的、影响较小的问题。
2、存储型XSS
① 什么是存储的跨站点脚本?
当应用程序从不受信任的源接收数据并以不安全的方式将该数据包含在其以后的 HTTP 响应中时,就会出现存储的跨站点脚本(也称为二阶或持久性 XSS)。
假设一个网站允许用户提交对博客文章的评论,这些评论会显示给其他用户。用户使用 HTTP 请求提交评论,如下所示:
POST /post/comment HTTP/1.1
Host: vulnerable-website.com Content-Length: 100
postId=3&comment=This+post+was+extremely+helpful.&name=Carlos+Montoya&email=carlos%40normal-user.net
提交此评论后,任何访问博客文章的用户都将在应用程序的回复中收到以下内容:
<p>This post was extremely helpful.</p>
假设应用程序不对数据执行任何其他处理,攻击者可以提交如下恶意评论:
<script>/* Bad stuff here... */</script>
在攻击者的请求中,此注释的 URL 编码为:
comment=%3Cscript%3E%2F*%2BBad%2Bstuff%2Bhere...%2B*%2F%3C%2Fscript%3E
现在,访问博客文章的任何用户都将在应用程序的响应中收到以下内容:
<p><script>/* Bad stuff here... */</script></p>
然后,攻击者提供的脚本将在受害者用户的浏览器中执行,在他们与应用程序的会话上下文中。
实验室2:将 XSS 存储到 HTML 上下文中,不进行任何编码
本实验在留言功能中包含一个存储的跨站脚本漏洞。
若要解决此实验,请提交在查看博客文章时调用alert
函数
打开实验室,发现是一个博客页面,随便打开一个文章,发现在文章的下面,含有评论功能,并且评论的内容,就在文章的下面,首先,先在评论功能出随便发一些内容进行观察。
这里可以看到,发送什么评论,评论的地方就会显示什么,那么如果在评论处发送一个代码呢<script>alert(1);</script>
可以看到,作为JS代码执行了,以至于浏览器弹窗出现,并且,因为这个评论一直在这个文章的下面,不管是谁访问这个文章,并且下翻到含有这个评论的位置,就会导致浏览器解析并执行,导致弹窗出现,而且,如果服务器没有把这个评论删除的话,会一直存在,刷新也会导致触发。
② 存储的 XSS 攻击的影响
如果攻击者可以控制在受害者浏览器中执行的脚本,那么他们通常可以完全破坏该用户。攻击者可以执行适用于反射的 XSS 漏洞影响的任何操作。
在可利用性方面,反射和存储的 XSS 之间的主要区别在于,存储的 XSS 漏洞支持应用程序本身中自包含的攻击。攻击者不需要找到一种外部方法来诱导其他用户发出包含其漏洞的特定请求。相反,攻击者将他们的漏洞利用放入应用程序本身,并等待用户遇到它。
在 XSS 漏洞仅影响当前登录到应用程序的用户的情况下,存储的跨站点脚本攻击的独立性质尤其重要。如果 XSS 被反射,那么攻击必须是偶然的时机:被诱导在未登录时发出攻击者请求的用户不会受到损害。相反,如果存储了 XSS,则可以保证用户在遇到漏洞时登录。
③ 在不同上下文中存储的 XSS
存储的跨站点脚本有许多不同的种类。存储数据在应用程序响应中的位置决定了利用它所需的有效负载类型,并且还可能影响漏洞的影响。
此外,如果应用程序在存储数据之前或在将存储的数据合并到响应中时对数据执行任何验证或其他处理,这通常会影响所需的 XSS 有效负载类型。
④ 如何查找和测试存储的 XSS 漏洞
许多存储的 XSS 漏洞都可以使用 Burp Suite 的 Web 漏洞扫描程序找到。
手动测试存储的 XSS 漏洞可能具有挑战性。您需要测试所有相关的“入口点”,攻击者可控制的数据可以通过这些入口点进入应用程序的处理,以及该数据可能出现在应用程序响应中的所有“出口点”。
应用程序处理的入口点包括:
- URL 查询字符串和消息正文中的参数或其他数据。
- URL 文件路径。
- 与反射的 XSS 相关的可能无法利用的 HTTP 请求标头。
- 攻击者可以通过这些路由将数据传送到应用程序的任何带外路由。存在的路由完全取决于应用程序实现的功能:网络邮件应用程序将处理电子邮件中收到的数据;显示 Twitter 提要的应用程序可能会处理第三方推文中包含的数据;新闻聚合器将包括来自其他网站的数据。
存储的 XSS 攻击的出口点是所有可能的 HTTP 响应,在任何情况下都返回给任何类型的应用程序用户。
测试存储的 XSS 漏洞的第一步是找到入口点和出口点之间的链接,从而从出口点发出提交到入口点的数据。这可能具有挑战性的原因是:
- 原则上,提交到任何入口点的数据都可以从任何出口点发出。例如,用户提供的显示名称可能显示在仅对某些应用程序用户可见的模糊审核日志中。
- 由于在应用程序中执行的其他操作,应用程序当前存储的数据通常容易被覆盖。例如,搜索功能可能会显示最近搜索的列表,当用户执行其他搜索时,这些列表会快速替换。
要全面识别入口点和出口点之间的联系,需要分别测试每个排列,将特定值提交到入口点,直接导航到出口点,并确定该值是否出现在那里。但是,此方法在具有多个页面的应用程序中并不实用。
相反,更现实的方法是系统地处理数据输入点,向每个输入点提交特定值,并监视应用程序的响应以检测出现提交值的情况。可以特别注意相关的应用程序功能,例如对博客文章的评论。在响应中观察到提交的值时,您需要确定数据是否确实存储在不同的请求中,而不是简单地反映在即时响应中。
在应用程序处理中识别出入口点和出口点之间的链接后,需要对每个链接进行专门测试,以检测是否存在存储的 XSS 漏洞。这涉及确定响应中存储数据出现的上下文,并测试适用于该上下文的合适候选 XSS 有效负载。在这一点上,测试方法与查找反映的 XSS 漏洞大致相同。
3、DOM型XSS
① 什么是基于 DOM 的跨站点脚本?
当 JavaScript 从攻击者可控制的源(如 URL)获取数据并将其传递给支持动态代码执行的接收器(如 eval()
或innerHTML
)时,通常会出现基于 DOM 的 XSS 漏洞。这使攻击者能够执行恶意 JavaScript,这通常允许他们劫持其他用户的帐户。
若要提供基于 DOM 的 XSS 攻击,需要将数据放入源中,以便将其传播到接收器并导致执行任意 JavaScript。
DOM XSS 最常见的来源是 URL,它通常与对象一起访问。攻击者可以构造一个链接,将受害者发送到一个易受攻击的页面,该页面的有效负载位于查询字符串中,并对 URL 的部分进行片段化。在某些情况下,例如当定位到 404 页面或运行 PHP 的网站时,有效负载window.location
也可以放置在路径中。
DOM Invader 是一种基于浏览器的工具,可帮助您使用各种源和接收器(包括 Web 消息和原型污染向量)测试 DOM XSS 漏洞。它只能通过 Burp 的内置浏览器获得,它预装为扩展程序。
② 如何测试基于 DOM 的跨站点脚本
使用 Burp Suite 的 Web 漏洞扫描程序可以快速可靠地发现大多数 DOM XSS 漏洞。若要手动测试基于 DOM 的跨站点脚本,通常需要使用带有开发人员工具(如 Chrome)的浏览器。您需要依次处理每个可用源,并单独测试每个源。
1. 测试 HTML 接收器
若要在 HTML 接收器中测试 DOM XSS,请将随机字母数字字符串放入源代码(例如 location.search
),然后使用开发人员工具检查 HTML 并查找字符串的显示位置。请注意,浏览器的“查看源代码”选项不适用于 DOM XSS 测试,因为它不考虑 JavaScript 在 HTML 中执行的更改。在 Chrome 的开发者工具中,您可以使用Control+F
(或Command+F
在 MacOS 上)在 DOM 中搜索字符串。
对于字符串在 DOM 中出现的每个位置,您需要标识上下文。基于此上下文,您需要优化输入以查看其处理方式。例如,如果字符串出现在双引号属性中,则尝试在字符串中注入双引号,以查看是否可以跳出该属性。
请注意,浏览器在 URL 编码方面的行为不同,Chrome、Firefox 和 Safari 将进行 URL 编码 ,而 IE11 和 Microsoft Edge(Chromium 之前)不会对这些源进行 URL 编码。如果数据在处理之前经过 URL 编码,则 XSS 攻击不太可能奏效。location.search
location.hash
2. 测试 JavaScript 执行接收器
测试基于 DOM 的 XSS 的 JavaScript 执行接收器有点困难。使用这些接收器时,您的输入不一定出现在 DOM 中的任何位置,因此您无法搜索它。相反,需要使用 JavaScript 调试器来确定是否以及如何将输入发送到接收器。
对于每个潜在的源location
,例如 ,您首先需要在页面的 JavaScript 代码中查找引用源的案例。在 Chrome 的开发者工具中,您可以使用Control+Shift+F
(或Command+Alt+F
在 MacOS 上)搜索页面的所有 JavaScript 代码以查找源代码。
找到读取源的位置后,可以使用 JavaScript 调试器添加断点,并遵循源值的使用方式。您可能会发现源被分配给其他变量。如果是这种情况,则需要再次使用搜索函数来跟踪这些变量,并查看它们是否传递到接收器。当您找到正在为源分配数据的接收器时,可以使用调试器检查该值,方法是将鼠标悬停在变量上以显示其值,然后再将其发送到接收器。然后,与 HTML 接收器一样,您需要优化输入,看看是否可以成功进行 XSS 攻击。
3. 使用 DOM Invader 测试 DOM XSS
在野外识别和利用 DOM XSS 可能是一个繁琐的过程,通常需要您手动浏览复杂的、缩小的 JavaScript。但是,如果您使用 Burp 的浏览器,您可以利用其内置的 DOM Invader 扩展程序,它为您做了很多艰苦的工作。
③ 利用具有不同源和接收器的 DOM XSS
原则上,如果存在数据可以从源传播到接收器的可执行路径,则网站容易受到基于 DOM 的跨站点脚本的影响。在实践中,不同的源和接收器具有不同的属性和行为,这些属性和行为可能会影响可利用性,并确定哪些技术是必要的。此外,网站的脚本可能会对尝试利用漏洞时必须适应的数据执行验证或其他处理。有多种接收器与基于 DOM 的漏洞相关。
接收器适用于元素,因此您可以使用简单的有效负载,如下所示:document.write
script
document.write('... <script>alert(document.domain)</script> ...');
④ 哪些接收器会导致 DOM-XSS 漏洞?
以下是一些可能导致 DOM-XSS 漏洞的主要接收器:
document.write()
document.writeln()
document.domain
element.innerHTML
element.outerHTML
element.insertAdjacentHTML
element.onevent
以下 jQuery 函数也是可能导致 DOM-XSS 漏洞的接收器:
add()
after()
append()
animate()
insertAfter()
insertBefore()
before()
html()
prepend()
replaceAll()
replaceWith()
wrap()
wrapInner()
wrapAll()
has()
constructor()
init()
index()
jQuery.parseHTML()
$.parseHTML()
实验室3:使用源代码document.write
在接收器location.search
中使用 DOM XSS
本实验在搜索查询跟踪功能中包含一个基于 DOM 的跨站点脚本漏洞。它使用 JavaScript 函数document.write
,该函数将数据写出到页面。该函数document.write
是使用location.search
的数据调用的,您可以使用网站 URL 进行控制。
若要解决此实验,请执行调用该函数的跨站点脚本攻击。alert
打开页面,发现含有搜索与评论功能,先对搜索进行测试,随便输入一个字符,然后进行观察,发现,结果在h1
标签,并且有'
号加在了输入的字符中。
那么,有回显,尝试代码<script>alert(1);</script>
,但是发现代码并没有被执行,而是以字符串的形式展示
那么,可以分析,不管输入什么,都会被当成字符串,那么可以猜测这个字符串使用什么闭合
但是发现,闭合'
和<h1>
标签,都不行,使用开发者工具继续查看,看其他代码处,发现有一个值得测试
可以从这里下手了,通过与HTML中的响应事件进行联合,值得注意的是,这里需要对"
进行闭合,使得输入的不作为字符串。
但请注意,在某些情况下,写入的内容包括一些在利用漏洞时需要考虑的周围上下文。例如,在使用 JavaScript 有效负载之前,您可能需要关闭一些现有元素。document.write
实验室4:在接收器document.write
中使用 select 元素内的源代码location.search
的 DOM XSS
本实验在库存检查器功能中包含一个基于 DOM 的跨站点脚本漏洞。它使用 JavaScript 函数document.write
,该函数将数据写出到页面。该函数document.write
使用数据location.search
调用,您可以使用网站 URL 从中进行控制。数据包含在 select 元素中。
若要解决此实验,请执行跨站点脚本攻击,该攻击会中断 select 元素并调用该函数。alert
打开实验室,发现只有查看商品的功能,首先可以看到的是产品号,尝试对这个进行测试,发现并不可以,接着就抓取数据包分析,然后在一个进行检查商品库存的地方,发现点击后,会有响应的回显
通过开发者功能查看,发现这是一个form
表单中的,并且其中有一段JS脚本代码
var stores = ["London","Paris","Milan"]; //定义的选项
var store = (newURLSearchParams(window.location.search)).get('storeId');
//定位当前的URL链接中的参数,也就是URL中?以及后面的值。从URL中获取storeId的值
document.write('<select name="storeId">');
//显示该标签
if(store) { //如果不为空
document.write('<option selected>'+store+'</option>');
} //显示store,前提是有的情况下,也就是URL中有storeId这个参数
for(var i=0;i<stores.length;i++) {
if(stores[i] === store) {
continue; //遍历stores数组,如果前面store获取的库存号能够对应的上,继续
}
document.write('<option>'+stores[i]+'</option>');
//把遍历的stores结合HTML标签,组合在一起
}
document.write('</select>'); //进行HTML中的标签闭合
根据上面的代码,写出了一段HTML代码,这段HTML代码,完全根据上面的JS代码才创造的
在上面的JS代码中,有一段怀疑,这个是从URL中获取storeId
,然后拿获取到的这个值去与数组中的进行对比,但是还是会作为HTML代码打印出来
var store = (newURLSearchParams(window.location.search)).get('storeId');
因为测试过window.location.search
是定位URL中的参数,那么,后面的这个get
,应该也是URL中的一个参数,尝试在URL中添加这个参数,并随便复制,观察响应
这就说明上面的JS代码确实是不论如何也会打印,而且确实在URL中有一个参数storeId,再看代码来确定
可以看到从URL中添加的参数storeId与前面的JS代码中的对应上了,确实写入了
if(store) { //如果不为空
document.write('<option selected>'+store+'</option>');
} //显示store,前提是有的情况下,也就是URL中有storeId这个参数
那么这里的storeId是可控参数,并且还会显示在页面,说明会被触发,尝试构造XSS语句,进行攻击
&storeId=121</select><img src=1 onerror=alert(1);>
可以看到已经标签闭合成功了,如果这里的语句闭合失败的话,可以配合开发者工具查看,或者直接盲闭合,一般的闭合字符都是' " < >
接收器innerHTML
不接受任何现代浏览器上的元素 script
,也不会触发事件。这意味着您需要使用替代元素,例如svg onload
或 img
iframe
。事件处理程序(如 onload
和onerror
)可以与这些元素结合使用。例如:
element.innerHTML='... <img src=1 onerror=alert(document.domain)> ...'
实验室5:使用源代码location.search
在接收器innerHTML
中使用 DOM XSS
本实验在搜索博客功能中包含一个基于 DOM 的跨站点脚本漏洞。它使用innerHTML
赋值,该赋值使用来自 div
的数据更改元素的 HTML 内容。location.search
若要解决此实验,请执行调用该函数的跨站点脚本攻击。alert
打开实验室,发现有搜索和评论功能,在搜索功能进行测试,输入1 的时候,发现返回被截断成两部分
在下面发现一段JS代码
function doSearchQuery(query) {
document.getElementById('searchMessage').innerHTML = query;
//通过定位到该id的值,然后使用innerHTML进行处理
}
var query = (new URLSearchParams(window.location.search)).get('search');
//和前面一样,获取URL中的参数,以及search参数
if(query) {
doSearchQuery(query); //如果不为空,调用上面的函数
}
这段代码也就导致,输入的代码不会被执行,可以进行测试
可以看到,即使对<span>
标签进行闭合,但是<script>
依旧无法以JS代码执行
innerHTML介绍
有两个功能, 一个是可以获取指定DOM的HTML元素, 另一个就是替换指定DOM的HTML元素
innerHTML插入js会发生什么
什么也不会发生, 因为用 innerHTML 插入文本到网页中有可能成为网站攻击的媒介,从而产生潜在的安全风险问题。所以HTML 5 中指定不执行由 innerHTML 插入的 <script>标签。
所以,如果使用默认的innerHTML的话,也就是不是自定义或者加了过滤。可以通过其他标签搭配事件处理来绕过,如使用<img>
标签搭配事件处理onerror
来绕过
⑤ 第三方依赖项中的源和接收器
现代 Web 应用程序通常使用许多第三方库和框架构建,这些库和框架通常为开发人员提供额外的功能和能力。重要的是要记住,其中一些也是 DOM XSS 的潜在源和接收器。
jQuery 中的 DOM XSS
如果正在使用 JavaScript 库(如 jQuery),请留意可以更改页面上的 DOM 元素的接收器。例如,jQuery 的函数attr()
可以更改 DOM 元素的属性。如果从用户控制的源(如 URL)读取数据,然后传递给函数attr()
,则可以操纵发送到 XSS 的值。例如,这里有一些 JavaScript,它使用 URL 中的数据来更改锚元素的属性href
:
$(function() {
$('#backLink').attr("href",(new URLSearchParams(window.location.search)).get('returnUrl'));
});
您可以通过修改 URL 来利用此漏洞,使源包含恶意 JavaScript URL。在页面的 JavaScript 将此恶意 URL 应用于反向链接后,单击反向链接将执行它:location.search``href
?returnUrl=javascript:alert(document.domain)
实验室6:使用源的 jQuery 锚href
属性接收器中的 DOM XSS
此实验室在提交反馈页面中包含一个基于 DOM 的跨站点脚本漏洞。它使用 jQuery 库的选择器函数$
来查找锚href
元素,并使用location.search
中的数据更改其属性。
要解决此实验,请使“返回”链接发出警报。document.cookie
打开实验室,使用burp进行抓包分析,把能点的功能界面都点击进行测试。
发现有留言功能,但是不管评论什么都不会作为元素执行,无法触发xss,点击一个界面时,发现也有提交的功能,但是提交后的界面,不管输入的什么,都会在原有界面产生一句提交成功
关注一下这个界面,发现网址的请求,对应着一个链接
尝试在URL中修改参数returnPath的值,观察back的链接是否会改变
可以看到已经改变,那么尝试进行xss注入,首先想到的是闭合,但是发现这里不可以,无论如何都是作为字符出现在href中,但是正是因为href的原因,所以考虑JavaScript
,构造语句 javascript:alert(document.cookie);
那么这个意思是,作为JS处理,配合超链接标签使用,导致点击的时候,是作为JS触发的
点击后,即可触发构造的语句
另一个需要注意的潜在接收器是 jQuery 的选择器函数,它可以用来将恶意对象注入 DOM 中。$()
jQuery曾经非常流行,一个经典的DOM XSS漏洞是由网站将此选择器与动画源结合使用或自动滚动到页面上的特定元素引起的。此行为通常是使用易受攻击的事件处理程序实现的,类似于以下内容:location.hash``hashchange
$(window).on('hashchange', function() {
var element = $(location.hash);
element[0].scrollIntoView();
});
由于 the 是用户可控的,攻击者可利用此漏洞将 XSS 向量注入选择器接收器。最新版本的jQuery通过阻止您在输入以哈希字符()开头时将HTML注入选择器来修补此特定漏洞。但是,您可能仍然会在野外找到易受攻击的代码。hash``$()``#
要实际利用这个经典漏洞,您需要找到一种方法来触发事件,而无需用户交互。执行此操作的最简单方法之一是通过以下方式提供您的漏洞利用:hashchange
iframe
<iframe src="https://vulnerable-website.com#" onload="this.src+='<img src=1 onerror=alert(1)>'">
在此示例中,该属性指向具有空哈希值的易受攻击的页面。加载 时,XSS 向量将追加到哈希中,从而导致事件触发。src``iframe``hashchange
注意
即使是较新版本的jQuery仍然可以通过选择器接收器受到攻击,前提是您可以完全控制来自不需要前缀的源的输入。$()
#
实验室7:使用 hashchange 事件的 jQuery 选择器接收器中的 DOM XSS
此实验室在主页上包含一个基于 DOM 的跨站脚本漏洞。它使用 jQuery 的选择器函数自动滚动到给定的帖子,其标题通过属性传递。$()
location.hash
为了解决实验室问题,向受害者提供一个漏洞利用,该漏洞在其浏览器中调用该函数。print()
打开实验室,发现在主界面有js代码
$(window).on('hashchange', function(){
var post = $('section.blog-list h2:contains(' + decodeURIComponent(window.location.hash.slice(1)) + ')');
if (post) post.get(0).scrollIntoView();
});
与上面所说一样,可以通过<iframe>
来触发,前提是需要一台公网服务器,
构造语句,写入公网服务器的文件中
<iframe src="https://0a3a00420334e6a28052bc9300030008.web-security-academy.net/#" onload="this.src+='<img src=1 onerror=print()>'"></iframe>
这里是在公网服务器上写入的目标服务器的地址,这里还需要确认目标有调用print()
,也就是浏览器的打印。
看到可以,那么返回到公网服务器,点击发送给受害者,实验就完成了,这个也就是需要进行社工的发送
AngularJS 中的 DOM XSS
如果使用像 AngularJS (后面会细说)这样的框架,则可以在没有尖括号或事件的情况下执行 JavaScript。当一个网站在HTML元素上使用该属性时,它将由AngularJS处理。在这种情况下,AngularJS 将在双大括号内执行 JavaScript,这些大括号可以直接出现在 HTML 中或属性内部。ng-app
示例:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="https://cdn.staticfile.net/angular.js/1.4.6/angular.min.js"></script>
</head>
<body>
<div ng-app="">
<p>名字 : <input type="text" ng-model="name"></p>
<h1>Hello {{name}}</h1>
</div>
</body>
</html>
常用的参数 | 参数意义 |
---|---|
ng-app=" " | 定义angularJS的使用范围; |
ng-init="变量=值;变量='值'" | 初始化变量的值,有多个变量时,中间用分号隔开; |
ng-model="变量" | 定义变量名; |
ng-bind="变量" | 绑定变量名,获取该变量的数据。这里的变量就是第3条的变量名。但是一般都用双重花括号来获取变量的值,比如:{{变量}}。 |
实验室8:AngularJS 表达式中的 DOM XSS,带有尖括号和双引号 HTML 编码
此实验室在搜索功能的 AngularJS 表达式中包含一个基于 DOM 的跨站点脚本漏洞。
AngularJS 是一个流行的 JavaScript 库,它扫描包含属性(也称为 AngularJS 指令)的 HTML 节点的内容。将指令添加到 HTML 代码中时,可以在双大括号内执行 JavaScript 表达式。在对尖括号进行编码时,此方法非常有用。ng-app
要解决此实验,请执行跨站点脚本攻击,该攻击执行 AngularJS 表达式并调用该函数。alert
打开实验室,发现含有搜索功能和评论功能,查看主界面的代码,发现还有AngularJS指令
并且在其中的input标签中,有定义name,但是并没有通过AngularJS中的ng-model定义变量,在搜索中随便输入字符,查看代码,可以看到是在ng-app下的
即使这里没有定义变量,但是这个字符串是在ng-app下的,那么使用{{}}包含的话,其中的内容不就可以作为js代码执行了
构造语句,在搜索框输入即可弹窗
{{$on.constructor('alert(1)')()}}
constructor
是一种用于创建和初始化 class
对象实例的特殊方法。
通过构造函数,你可以在调用实例化对象的其他方法之前,提供必须完成的自定义初始化。
如果不指定构造函数,则使用默认的构造函数。如果你的类是基类,默认构造函数会是空的
⑥ DOM XSS 与反射和存储数据相结合
一些纯基于 DOM 的漏洞是自包含在单个页面中的。如果脚本从 URL 读取一些数据并将其写入危险的接收器,则该漏洞完全是客户端的漏洞。
但是,来源不仅限于浏览器直接公开的数据 - 它们也可以来自网站。例如,网站通常会在服务器的 HTML 响应中反映 URL 参数。这通常与普通的 XSS 相关联,但它也可能导致反射的 DOM XSS 漏洞。
在反射的 DOM XSS 漏洞中,服务器处理来自请求的数据,并将数据回显到响应中。反射的数据可能会被放入 JavaScript 字符串文本中,或者放入 DOM 中的数据项中,例如表单字段。然后,页面上的脚本以不安全的方式处理反射的数据,最终将其写入危险的接收器。
eval('var data = "reflected string"');
实验室9:反射式 DOM XSS
此实验室演示了一个反射型 DOM 漏洞。当服务器端应用程序处理来自请求的数据并在响应中回显数据时,就会发生反射型 DOM 漏洞。然后,页面上的脚本以不安全的方式处理反射的数据,最终将其写入危险的接收器。
若要解决此实验,请创建调用函数的注入。alert()
打开实验室,发现有搜索界面,尝试随便输入字符,抓取数据包,打开开发者工具,发现其中含有一个js文件,打开这个文件,可以看到其中的代码,发现其中包括了eval()
函数
function search(path) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
eval('var searchResultsObj = ' + this.responseText); //这里重点
displaySearchResults(searchResultsObj);
}
};
xhr.open("GET", path + window.location.search);
xhr.send();
测试可以发现,搜索的会返回一个json信息
尝试不同的字符,测试有无转义,发现"
被转义,但是\
转义符号并没有,所以可以在"
即将被转义处,加上转义符号,凑成把转义符号转义,但是没有转义到"
,如:\"da
就会使得"
没有被转义
\"-alert(1)}//
或者
da\"}+alert(1);//
抓取数据包,观察到:
解释:
注入了反斜杠,但站点没有转义它们,因此当 JSON 响应尝试转义左双引号字符时,它会添加第二个反斜杠。由此产生的双反斜杠会导致转义被有效地抵消。这意味着双引号将在不转义的情况下进行处理,这将关闭应包含搜索词的字符串。
然后,在调用函数之前,使用算术运算符(在本例中为减法运算符)分隔表达式。最后,一个右大括号和两个正斜杠可以提前关闭 JSON 对象,并注释掉对象的其余部分。因此,响应将按如下方式生成:alert()
网站也可能在服务器上存储数据,并将其反映在其他地方。在存储的 DOM XSS 漏洞中,服务器从一个请求接收数据,存储它,然后在以后的响应中包含数据。后面响应中的脚本包含一个接收器,然后以不安全的方式处理数据。
element.innerHTML = comment.author
实验室10:存储的 DOM XSS
此实验演示了博客评论功能中存储的 DOM 漏洞。要解决此实验,请利用此漏洞调用函数。alert()
打开实验室发现只有一个评论功能,抓取数据包,其中有一个文件,其中包含JS代码文件,打开查看,发现其中是对评论内容进行处理的,其中有一个函数,是进行替换的,并且多次被调用,所以尝试输入<>
测试
function escapeHTML(html) {
return html.replace('<', '<').replace('>', '>');
}
而且js代码中调用的是这样调用
if (comment.body) {
let commentBodyPElement = document.createElement("p");
commentBodyPElement.innerHTML = escapeHTML(comment.body); //调用一次
网站使用 JavaScript 函数对尖括号进行编码。但是,当第一个参数是字符串时,该函数仅替换第一个匹配项。我们通过简单地在注释的开头包含一组额外的尖括号来利用此漏洞。这些尖括号将被编码,但任何后续的尖括号都不会受到影响,这使我们能够有效地绕过过滤器并注入 HTML。replace()
所以构造<><img src=1 onerror=alert(1);>
4、跨站点脚本上下文
在测试反射和存储的 XSS 时,一个关键任务是识别 XSS 上下文:
- 响应中显示攻击者可控数据的位置。
- 应用程序对该数据执行的任何输入验证或其他处理。
根据这些详细信息,您可以选择一个或多个候选 XSS 有效负载,并测试它们是否有效。
注意
我们构建了一个全面的 XSS 作弊表来帮助测试 Web 应用程序和过滤器。您可以按事件和标签进行筛选,并查看哪些向量需要用户交互。作弊表还包含 AngularJS 沙箱转义和许多其他部分,以帮助进行 XSS 研究。
① HTML 标记之间的 XSS
当 XSS 上下文是 HTML 标签之间的文本时,您需要引入一些新的 HTML 标签,这些标签旨在触发 JavaScript 的执行。
执行 JavaScript 的一些有用方法包括:
<script>alert(document.domain)</script>
<img src=1 onerror=alert(1)>
实验室11:将 XSS 反射到 HTML 上下文中,大多数标签和属性都被阻止了
此实验室在搜索功能中包含一个反射型 XSS 漏洞,但使用 Web 应用程序防火墙 (WAF) 来防止常见的 XSS 向量。
为了解决实验室问题,请执行跨站点脚本攻击,绕过 WAF 并调用函数。print()
注意
您的解决方案不得要求任何用户交互。手动导致在您自己的浏览器中被调用并不能解决实验室问题。print()
打开实验室,发现有搜索框和评论功能,尝试在搜索框中随便输入,输入字符的时候发现会在页面中显示的,那么尝试输入其他的进行测试
构造</h1><img src=1 onerror=print()>
发现提示错误,这类似于实际中的WAF拦截时提示检测到攻击是一样的,所以,假设这里对标签进行了限制,且没有对符号< >
进行过滤,那么是否所有的标签都拦截了,使用burp进行爆破测试
在可能含有XSS的地方构造,在<>
中添加爆破点,把标签都走一遍
爆破后发现有两个标签可以,能够返回正常的页面
那么在其中的body
标签进行与事件处理程序进行测试,构造</h1><body onload=print()>
,出现错误
这个提示明确,属性不被允许,那么假设这里也是过滤,是否有没有被过滤的呢,进行爆破测试
设置payload为各种事件处理程序,进行爆破,发现有很多可以
测试,其中一个onbeforinput
,发现在input
标签中输入之前会触发事件
构造</h1><body onbeforeinput=print()>
,然后页面加载成功,并且在input
标签输入前,触发
根据实验要求,需要使用到漏洞利用的公网服务器,并且,要在知道含有XSS漏洞所在位置,然后在公网服务器中构造一个文件,可以把这个文件放到网站上或者发送给指定的某个人
这里选择onresize
事件处理程序,然后与<iframe>
联合使用,这么说吧,在含有XSS注入的地方,因为标签只有两个可以使用,如使用<body>
然后事件处理选择onresize
,这个是在含有XSS注入的地方构造的。因为要构造链接,那么在公网服务器上使用<iframe>
标签,然后改变size
,使得触发事件,导致可直接触发。
<iframe src="目标网站有xss漏洞处/?s=<body%20onresize=print()> " onload=this.style.width='100px'>
发送给受害者,即可实验完成
实验室12:将 XSS 反射到 HTML 上下文中,除自定义标签外的所有标签都被阻止
此实验室会阻止除自定义标记之外的所有 HTML 标记。
要解决该实验室问题,请执行跨站点脚本攻击,该攻击会注入自定义标签并自动发出警报。document.cookie
打开实验室,发现搜索框,随便输入字符,发现有回显,那么尝试标签,发现提示标签不被允许,那么和之前一样,如果有标签没有被过滤呢,尝试爆破
实验室提示,只能使用自定义标签,爆破的发现,基本上也都是自定义标签
浏览器必须将自定义元素保留在 DOM 之中,但不会任何语义。除此之外,自定义元素与标准元素都一致。
事实上,浏览器提供了一个HTMLUnknownElement
对象,所有自定义元素都是该对象的实例。
payload:
<xss id=x onfocus=alert(document.cookie) tabindex=1>
此注入创建一个ID为x的自定义标记,其中包含一个触发alert函数的onfocus事件处理程序。页面加载后,URL末尾的散列将立即关注此元素,从而导致调用alert负载。
url编码:
%3Cxss+id%3Dx+onfocus%3Dalert%28document.cookie%29%20tabindex=1%3E
- tabindex=负值 (通常是 tabindex=“-1”),表示元素是可聚焦的,但是不能通过键盘导航来访问到该元素,用 JS 做页面小组件内部键盘导航的时候非常有用。
tabindex="0"
,表示元素是可聚焦的,并且可以通过键盘导航来聚焦到该元素,它的相对顺序是当前处于的 DOM 结构来决定的。- tabindex=正值,表示元素是可聚焦的,并且可以通过键盘导航来访问到该元素;它的相对顺序按照tabindex 的数值递增而滞后获焦。如果多个元素拥有相同的 tabindex,它们的相对顺序按照他们在当前 DOM 中的先后顺序决定。
注入后,发现可行,并且确实鼠标聚焦在'
时会触发
这就可以在公网服务器上构造了,尝试<iframe>
测试,发现会直接拒绝连接,那么只能换,因为是在自己的公网服务器上,那么构造一个直接跳转到含有xss漏洞的网站,并且链接也是给定的,导致跳转就会触发,那么就用到JS的location
<script>
location='https://0a9a003f03d43a23827ece0e0020000f.web-security-academy.net/?search=%3Cxss+id%3Dx+onfocus%3Dalert%28document.cookie%29+tabindex%3D1%3E#x';</script>
保存到公网服务器后,测试发现跳转页面并且直接触发,那么就可以发送给目标即可
实验室13:事件处理程序和属性被阻止的反射型 XSShref
此实验室包含一个反射型 XSS 漏洞,其中包含一些列入白名单的标签,但所有事件和锚属性都被阻止。href
为了解决该实验问题,请执行跨站点脚本攻击,该攻击会注入一个向量,当单击该向量时,该向量将调用该函数。alert
请注意,您需要用“Click”一词标记您的载体,以便诱导模拟实验室用户点击您的载体。例如:
<a href="">Click me</a>
打开实验室,发现有搜索框,首先测试搜索框,随便输入,发现有回显,那么测试可以有哪些标签可用
发现有a
标签可用,就可以考虑a
标签中的href
属性,这也是常用的,但是测试,发现一旦href
与=一起使用,就会报错,提示属性不被允许,那么还有其他标签,测试svg
,发现常用的事件处理是被拒绝的。使用 SVG 中自带的 animate
元素添加动画。使用 SVG 中自定的 animate
主要还是 SVG 自己的东西
示例:
<svg viewBox="0 0 10 10" xmlns="http://www.w3.org/2000/svg">
<rect width="10" height="10">
<animate
attributeName="rx"
values="0;5;0"
dur="10s"
repeatCount="indefinite" />
</rect>
</svg>
那么构造语句,并经过浏览器测试,发现确实可以弹窗
<svg>
<a>
<animate
attributeName=href
values=javascript:alert(1);
/>
<text x=20 y=20>
click me
</text>
</a>
</svg>
参考文章:animate(动画)标签的xss利用 - 先知社区 (aliyun.com)
实验室14:允许使用一些 SVG 标记的反射型 XSS
此实验室有一个简单的反射型 XSS 漏洞。该网站阻止了常见标签,但遗漏了一些 SVG 标签和事件。
若要解决该实验室问题,请执行调用该函数的跨站点脚本攻击。alert()
打开实验室,发现搜索框,随便输入字符进行测试,发现有回显,尝试输入标签,发现报错,那么测试有哪些标签,进行爆破
发现一个常用的svg
标签,对这个进行测试,发现onerror
被拒绝,animateTransform
元素变动了目标元素上的一个变形属性,从而允许动画控制转换、缩放、旋转或斜切。
那么再爆破测试有哪些事件处理
发现只有一个onbegin
可用,那么百度看看是干什么的
每次元素开始活动持续时间时(即,当它重新启动时,但当它重复时)时,它都会引发。
在正常(即计划或交互式)时间线播放过程中,以及在元素以 DOM 方法启动的情况下,都可能引发它。
那么就可以通过上面的实验室进行修改
<svg>
<animatetransform onbegin=alert(1)>
</animatetransform>
</svg>
代码保存为html文件,放在浏览器进行测试,发现可以弹窗
那么就可以在目标网站上测试了
② HTML 标记属性中的 XSS
当 XSS 上下文位于 HTML 标记属性值中时,您有时可能能够终止属性值、关闭标记并引入新的标记。例如:
"><script>alert(document.domain)</script>
在这种情况下,更常见的是,尖括号被阻止或编码,因此您的输入无法脱离它所在的标记。如果可以终止属性值,则通常可以引入创建可编写脚本的上下文的新属性,例如事件处理程序。例如:
" autofocus onfocus=alert(document.domain) x="
上述有效负载创建一个事件,该事件将在元素接收到焦点时执行 JavaScript,并且还添加了属性以尝试在没有任何用户交互的情况下自动触发事件。最后,它添加了优雅地修复以下标记。onfocus
autofocus
onfocus
x="
实验室15:将 XSS 反射到带有尖括号 HTML 编码的属性中
此实验室包含搜索博客功能中一个反射的跨站点脚本漏洞,其中尖括号是 HTML 编码的。要解决此实验,请执行跨站点脚本攻击,该攻击会注入属性并调用函数。alert
打开实验室,发现搜索框,那么直接测试,随机输入字符,发现回显有两处
两处都进行测试,看能否绕过,首先构造</h1><script>alert(1);</script>
,发现在上面的结果回显或者搜索框中,都对<>
进行编码处理
那么尝试在另一处进行尝试,也就是value
中的值,能否闭合然后触发事件,构造
" onclick="alert(1);"
" onmouseover="alert(1);"
" onfocus="alert(1);"
"
与前面的value
的值闭合了 ,就可以使得后面的属性可以触发
有时,XSS 上下文属于一种 HTML 标记属性,该属性本身可以创建可编写脚本的上下文。在这里,您可以执行 JavaScript,而无需终止属性值。例如,如果 XSS 上下文位于锚标记的属性中,则可以使用伪协议来执行脚本。例如:href
javascript
<a href="javascript:alert(document.domain)">
实验室16:将 XSS 存储到带有双引号 HTML 编码的锚属性中href
此实验室在评论功能中包含一个存储的跨站脚本漏洞。若要解决此实验,请提交一条注释,该注释在单击注释作者姓名时调用该函数。alert
打开实验室,发现只有一个评论功能的界面,尝试直接输入字符等测试
在进行评论的时候,发现有一个填写的website
处,会作为超链接在用户评论处留下,那么可测试点就可以从这里下手,尝试使用伪协议javascript
在website处构造 javascript:alert(1)
,那么就会导致href
链接指向这个代码,作为JS执行。
您可能会遇到对尖括号进行编码的网站,但仍允许您注入属性。有时,即使在通常不会自动触发事件的标签(例如规范标签)中,也可以进行这些注入。您可以在 Chrome 上使用访问密钥accesskey
和用户交互来利用此行为。访问键允许您提供引用特定元素的键盘快捷键。该属性允许您定义一个字母,当与其他键(这些键在不同平台上有所不同)结合使用时,将导致触发事件。在下一个实验中,您可以试验访问密钥并利用规范标记。您可以使用 PortSwigger Research 发明的技术在隐藏的输入字段中利用 XSS。
实验室17:规范链接标签中的反射 XSS
此实验在规范链接标记中反映用户输入,并对尖括号进行转义。
要解决该实验,请在主页上执行跨站点脚本攻击,该攻击会注入调用函数的属性。alert
为了帮助您利用漏洞,您可以假设模拟用户将按以下组合键:
ALT+SHIFT+X
CTRL+ALT+X
Alt+X
请注意,此实验室的预期解决方案仅在 Chrome 中可用。
打开实验室,发现只有评论功能,尝试输入' " < >
关键字符进行测试,在源代码中发现,进行了编码
定义和用法
accesskey
属性规定快捷键,用于激活/聚焦元素。
accesskey
属性的值必须是单字符(一个字母或一个数字)。
实例
带有指定快捷键的两个超链接:
<a href="https://www.w3school.com.cn/html/" accesskey="h">HTML</a><br>
<a href="https://www.w3school.com.cn/css/" accesskey="c">CSS</a>
根据上面的理解,只要找到注入点,就可以把快捷键注入进去
这里看到该链接包含主页面链接,那么通过修改URL,是否可以把快捷键注入呢,进行测试
/?'accesskey='x'onclick='alert(1)
accesskey定义一个快捷键为x,当在允许该快捷键允许的浏览器使用快捷键,就会导致后面的事件触发。
如ALT+x x就是这里定义的值
③ XSS 转换为 JavaScript
当 XSS 上下文是响应中的一些现有 JavaScript 时,可能会出现各种各样的情况,需要使用不同的技术来执行成功的利用。
a、终止现有脚本
在最简单的情况下,可以简单地关闭包含现有 JavaScript 的 script 标签,并引入一些新的 HTML 标签来触发 JavaScript 的执行。例如,如果 XSS 上下文如下所示:
<script>
...
var input = 'controllable data here';
...
</script>
然后,您可以使用以下有效负载来脱离现有的 JavaScript 并执行您自己的 JavaScript:
</script><img src=1 onerror=alert(document.domain)>
这样做的原因是浏览器首先执行 HTML 解析以识别包括脚本块在内的页面元素,然后才执行 JavaScript 解析以理解和执行嵌入的脚本。上述有效负载使原始脚本损坏,并带有未终止的字符串文本。但这并不能阻止后续脚本以正常方式解析和执行。
实验室18:将 XSS 反射到带有单引号和反斜杠转义的 JavaScript 字符串中
此实验室包含搜索查询跟踪功能中反映的跨站点脚本漏洞。反射发生在 JavaScript 字符串中,其中单引号和反斜杠被转义。
要解决此实验,请执行跨站点脚本攻击,该攻击会脱离 JavaScript 字符串并调用函数。alert
打开实验室,发现搜索框,随便输入字符jk
进行测试,发现有回显,并且,其中有JS代码可以看到
那么尝试在JS代码中提前闭合<script>
,然后添加HTML标签元素,使得HTML标签元素先执行
</script><img src=1 onerror=alert(1)>
b、脱离 JavaScript 字符串
如果 XSS 上下文位于带引号的字符串文本内,则通常可以脱离字符串并直接执行 JavaScript。按照 XSS 上下文修复脚本至关重要,因为其中的任何语法错误都会阻止整个脚本执行。
打破字符串文字的一些有用方法是:
'-alert(document.domain)-'
';alert(document.domain)//
实验室19:将 XSS 反射到带有尖括号 HTML 编码的 JavaScript 字符串中
此实验包含对尖括号进行编码的搜索查询跟踪功能中一个反射型跨站点脚本漏洞。反射发生在 JavaScript 字符串内部。要解决此实验,请执行跨站点脚本攻击,该攻击会脱离 JavaScript 字符串并调用函数。alert
打开实验室,发现有搜索框,随便输入字符进行测试,发现有回显,并且有JS代码
尝试在JS代码中,提前闭合标签,并且插入HTML标签,以使其先执行HTML标签
</script><img src=1 onerror=alert(1)>
发现被闭合< >
,那么尝试截断,但是还是会产生警告
'-alert(1)-' 闭合字符',然后执行其中的alert
';alert(1)// 闭合字符',然后使用;分割语句,最后注释后面的东西,也就导致会执行
某些应用程序试图通过反斜杠转义任何单引号字符来防止输入脱离 JavaScript 字符串。字符前的反斜杠告诉 JavaScript 解析器该字符应按字面意思解释,而不是作为特殊字符(如字符串终止符)进行解释。在这种情况下,应用程序经常会犯一个错误,即无法对反斜杠字符本身进行转义。这意味着攻击者可以使用自己的反斜杠字符来中和应用程序添加的反斜杠。
例如,假设输入:
';alert(document.domain)//
转换为:
\';alert(document.domain)//
现在,您可以使用备用有效负载:
\';alert(document.domain)//
这将转换为:
\\';alert(document.domain)//
在这里,第一个反斜杠意味着第二个反斜杠是按字面意思解释的,而不是作为特殊字符解释的。这意味着引号现在被解释为字符串终止符,因此攻击成功。
实验室20:将 XSS 反射到带有尖括号和双引号的 JavaScript 字符串中,HTML 编码和单引号进行了转义
此实验包含搜索查询跟踪功能中一个反射型跨站脚本漏洞,其中尖括号和双引号是 HTML 编码的,单引号是转义的。
要解决此实验,请执行跨站点脚本攻击,该攻击会脱离 JavaScript 字符串并调用函数。alert
打开实验室,发现搜索框,随便输入字符进行测试,发现有回显,并且有JS代码
那么尝试输入几个特殊字符,看有无编码或者转义等' " < > \
可以看到单引号'
是被转义," < >
被编码,但是转义符号\
并没有任何操作,那么就可以使用这个来尝试绕过,比如这里是单引号有闭合作用,并且没有编码,是进行的转义,那么在单引号前,加上转义符号,使得服务器在进行处理的时候,会在我们插入的转义符号前进行转义操作,单引号就不会被转义。
\'alert(1)//
一些网站通过限制您可以使用的字符来使 XSS 变得更加困难。这可以在网站级别进行,也可以通过部署 WAF 来阻止您的请求到达网站。在这些情况下,您需要尝试使用其他方式来调用绕过这些安全措施的函数。一种方法是将该语句alert()
与异常处理程序throw
一起使用。这使您能够在不使用括号的情况下将参数传递给函数throw
。以下代码将函数分配给全局异常处理程序,语句将 alert
传递给异常处理程序(在本例中)。最终结果是将函数alert()
作为参数1
调用。
onerror=alert;throw 1
有多种方法可以使用此技术来调用不带括号的函数。
下一个实验演示了一个筛选特定字符的网站。为了解决它,您必须使用与上述技术类似的技术。
实验室21:在 JavaScript URL 中反射 XSS,阻止了某些字符
此实验反映了您在 JavaScript URL 中的输入,但一切并非看起来那样。这最初似乎是一个微不足道的挑战;但是,该应用程序正在阻止某些字符,以试图阻止 XSS 攻击。
为了解决该实验,请执行跨站点脚本攻击alert
,该攻击使用消息中包含的字符串1337
调用函数alert
。
打开页面,发现只有评论功能,进行测试,发现并无注入点,查看源代码,发现在"返回博客"的功能处,代码很有意思,这里的body
就是URL链接中的后面目录及请求,那么从这里进行下手
构造链接:
post?postId=5&%27},x=x=%3E{throw/**/onerror=alert,1337},toString=x,window%2b%27%27,{x:%27
?postId=5&'},x=x=>{throw/**/onerror=alert,1337},toString=x,window+'',{x:'
在您单击页面底部的“返回博客”时才会调用警报。
该漏洞利用异常处理来调用带有alert
参数的函数。该语句使用throw
,并用空白注释分隔,以绕过无空格限制。该函数将alert
分配给异常处理程序。onerror
由于是语句,因此不能用作表达式。相反,我们需要使用箭头函数来创建一个块,以便可以使用该语句throw
。然后我们需要调用这个函数throw
,所以我们把它分配给 toString
的属性,并通过强制字符串window
转换来触发这个函数。window
c、使用 HTML 编码
当 XSS 上下文是带引号的标记属性中的一些现有 JavaScript(例如事件处理程序)时,可以使用 HTML 编码来解决某些输入过滤器。
当浏览器在响应中解析出 HTML 标签和属性时,它将在进一步处理标签属性值之前执行 HTML 解码。如果服务器端应用程序阻止或清理了成功利用 XSS 所需的某些字符,则通常可以通过对这些字符进行 HTML 编码来绕过输入验证。
例如,如果 XSS 上下文如下所示:
<a href="#" onclick="... var input='controllable data here'; ...">
并且应用程序会阻止或转义单引号字符,您可以使用以下有效负载来脱离 JavaScript 字符串并执行您自己的脚本:
'-alert(document.domain)-'
序列'
是一个 HTML 实体,表示撇号或单引号。由于浏览器 HTML 在解释 JavaScript 之前对属性的值进行解码,因此实体被解码为引号,引号成为字符串分隔符,因此攻击成功。 onclick
实验室22:将 XSS 存储到事件中,带有尖括号和双引号、HTML 编码和单引号以及反斜杠转义onclick
此实验室在评论功能中包含一个存储的跨站脚本漏洞。
若要解决此实验,请提交一条注释,该注释在单击注释作者姓名时调用该函数。alert
打开实验室,发现只有评论功能,所有项目填写一下,然后查看进行分析,发现在填写的website
中有一个类似于JS调用的,点击后就会触发onclick
事件,而该事件是通过JS代码执行链接的,所以代表这个链接是在JS代码中执行,那么就可以尝试进行截断。
http://dijia?'-alert(1)-'
尝试直接注入,发现对单引号进行了转义处理,并且经过测试,发现转义符号\
,也被转义处理
尝试进行编码,看能否绕过,对特殊符号'
进行HTML编码
http://dijia?'-alert(1)-'
编码后测试,发现确实可以,这里也可以注意,我在实验中并没有加?
也可以执行成功的
d、JavaScript 中的 XSS 模板文字
JavaScript 模板文字是允许嵌入 JavaScript 表达式的字符串文字。对嵌入的表达式进行评估,并通常将其连接到周围的文本中。模板文本封装在反引号中,而不是普通引号中,嵌入的表达式使用语法进行标识。${...}
例如,以下脚本将打印包含用户显示名称的欢迎消息:
document.getElementById('message').innerText = `Welcome, ${user.displayName}.`;
当 XSS 上下文位于 JavaScript 模板文本中时,无需终止文本。相反,您只需要使用语法嵌入一个 JavaScript 表达式,该表达式将在处理文本时执行。例如,如果 XSS 上下文如下所示:${...}
<script>
...
var input = `controllable data here`;
...
</script>
然后,您可以使用以下有效负载来执行 JavaScript,而无需终止模板文本:
${alert(document.domain)}
实验室23:将 XSS 反射到带有尖括号、单引号、双引号、反斜杠和反引号的模板文本中,经过 Unicode 转义
此实验室包含搜索博客功能中反映的跨站点脚本漏洞。反射发生在一个模板字符串内,该字符串带有尖括号、单引号和双引号 HTML 编码,反引号已转义。要解决此实验,请执行跨站点脚本攻击,该攻击会调用模板字符串内的函数。alert
打开实验室,发现只有搜索框,随便输入字符进行测试,发现有回显,查看回显,发现有JS代码
可以看到回显到页面中的字符串,是通过JS代码处理后返回的,那么可以看到输入的字符是在JS代码中处理,并且是通过反引号包裹的,尝试构造,看能否闭合包裹字符反引号
`</script><img src=1 onerror=alert(1)>
发现并不行,进行了unicode编码处理
无法闭合的话,尝试进行内嵌处理,也就相当于python中的输出语句时,使用{}
,里面的变量可以被执行,那么这里效果也一样,使用${}
,大括号中可以包括JS的一些处理语句,如
${alert(1)}
实验就可以了
④ 客户端模板注入
在本节中,我们将了解客户端模板注入漏洞以及如何利用它们进行 XSS 攻击。这种攻击技术是由我们的研究团队开创的 - 在不含 HTML 的 XSS 中阅读更多内容:客户端模板 使用 AngularJS 注入。尽管客户端模板注入是一个通用问题,但我们将重点关注 AngularJS 框架中的示例,因为这是最常见的。我们将介绍如何制作从 AngularJS 沙箱中逃脱的漏洞,以及如何使用 AngularJS 功能来绕过内容安全策略 (CSP)。
a、什么是客户端模板注入?
当使用客户端模板框架的应用程序动态地将用户输入嵌入网页中时,就会出现客户端模板注入漏洞。在呈现页面时,框架会扫描其中的模板表达式,并执行它遇到的任何表达式。攻击者可以通过提供恶意模板表达式来利用此漏洞,从而启动跨站点脚本 (XSS) 攻击。
b、什么是 AngularJS 沙箱?
AngularJS 沙箱是一种机制,可防止访问 AngularJS 模板表达式中的潜在危险对象,例如 window
或document
。它还可以防止访问具有潜在危险的属性,例如__proto__
。尽管 AngularJS 团队不认为它是安全边界,但更广泛的开发者社区通常不这么认为。尽管绕过沙盒最初具有挑战性,但安全研究人员已经发现了许多方法。因此,它最终在 1.6 版中从 AngularJS 中删除。但是,许多遗留应用程序仍然使用旧版本的 AngularJS,因此可能容易受到攻击。
c、AngularJS 沙箱是如何工作的?
沙箱的工作原理是解析表达式,重写 JavaScript,然后使用各种函数来测试重写的代码是否包含任何危险对象。例如ensureSafeMemberName()
,该函数检查给定对象是否引用自身。例如ensureSafeObject()
,这是检测物体的一种方法。通过检查构造函数属性是否引用自身,以大致相同的方式检测构造函数。window
Function
该函数ensureSafeFunction()
检查对象的每个属性访问,如果它包含危险属性(如 __proto__
或__lookupGetter__
),则对象将被阻止。该函数可防止调用 constructor()
、call()
、apply()
或 bind()
。
您可以通过访问此小提琴并在文件的第 13275 行设置断点来亲自查看沙箱的运行情况。该变量包含您重写的代码,因此您可以查看 AngularJS 如何转换它。angular.js``fnString
d、AngularJS 沙箱逃生如何工作?
沙盒逃脱涉及欺骗沙盒,使其认为恶意表达是良性的。最著名的转义在表达式中全局使用修改后的函数:charAt()
'a'.constructor.prototype.charAt=[].join
当它最初被发现时,AngularJS 并没有阻止这种修改。该攻击通过使用该方法覆盖函数来工作,这会导致函数返回发送给它的所有字符,而不是特定的单个字符。由于 AngularJS 中函数的逻辑,它会将它认为是单个字符的内容与多个字符进行比较。由于单个字符始终小于多个字符,因此该函数始终返回 true,如以下示例所示:[].join``charAt()``isIdent()``isIdent()
isIdent = function(ch) { return ('a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || '_' === ch || ch === '$'); } isIdent('x9=9a9l9e9r9t9(919)')
一旦函数被愚弄,你就可以注入恶意的JavaScript。例如,允许使用 such as 表达式,因为 AngularJS 将每个字符视为标识符。请注意,我们需要使用 AngularJS 的函数,因为只有在执行沙箱代码后,覆盖函数才会生效。然后,此技术将绕过沙箱并允许任意 JavaScript 执行。 PortSwigger Research 多次全面破解 AngularJS 沙箱。isIdent()``$eval('x=alert(1)')``$eval()``charAt()
e、构建高级 AngularJS 沙箱逃生
因此,您已经了解了基本的沙盒逃生的工作原理,但您可能会遇到对允许的字符限制更严格的网站。例如,某个网站可能会阻止您使用双引号或单引号。在这种情况下,您需要使用诸如生成字符之类的函数。尽管 AngularJS 会阻止在表达式中访问构造函数,但您可以通过使用字符串的构造函数属性来解决这个问题。这显然需要一个字符串,所以要构造这样的攻击,你需要找到一种不使用单引号或双引号来创建字符串的方法。String.fromCharCode()``String
在标准沙盒逃生中,您将用于执行 JavaScript 有效负载,但在下面的实验中,该函数未定义。幸运的是,我们可以改用过滤器。筛选器的典型语法如下:$eval()``$eval()``orderBy``orderBy
[123]|orderBy:'Some string'
请注意,运算符的含义与 JavaScript 中的含义不同。通常,这是一个按位操作,但在 AngularJS 中,它表示过滤器操作。在上面的代码中,我们将左侧的数组发送到右侧的过滤器。冒号表示要发送到过滤器的参数,在本例中为字符串。过滤器通常用于对对象进行排序,但它也接受一个表达式,这意味着我们可以使用它来传递有效负载。|``OR``[123]``orderBy``orderBy
现在,您应该拥有处理下一个实验室所需的所有工具。
本文来自博客园,作者:whitehe,转载请注明原文链接:https://www.cnblogs.com/whitehe/p/18578428
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?