购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

1.2 XSS

跨站脚本攻击(Cross Site Scripting)本来缩写为CSS,后来为了与层叠样式表(Cascading Style Sheet, CSS)的缩写进行区分,改为XSS。XSS的本质是攻击者在Web页面插入恶意的Script代码(这个代码可以是JavaScript脚本、CSS或者其他意料之外的代码),当用户浏览该页面时,嵌入其中的Script代码会被执行,从而达到恶意攻击的目的,比如读取cookie、session、token,或者网站其他的敏感信息,对用户进行钓鱼欺诈等。

根据维基百科给出的解释,XSS出自2000年微软安全工程师的安全报告,当时XSS用于描述一种从无关页面跳转到被攻击页面的攻击行为,随后攻击方式不断进化,而XSS这个名字被沿用下来,成了Web应用代码注入攻击的统称。

1.2.1 XSS类型

本节介绍XSS的3种类型。

1.反射型XSS

反射型XSS又称非持久型XSS,指的是让请求的响应结果中包含恶意代码,浏览器解析后触发XSS。恶意代码并没有保存在目标网站,而是通过引诱用户点击一个恶意链接来实施攻击,代码如下。

将URL中的GET参数Name的值直接输出在网页中,如图1-54所示。

图1-54 传递参数

设置Name参数的值为<script>alert(1);</script>,我们写入的代码会直接输出和解析,执行结果如图1-55所示,这就是一个典型的反射型XSS。

图1-55 反射型XSS弹窗

2.存储型XSS

存储型XSS与反射型XSS的不同之处在于恶意代码会被保存在目标网站中,只要受害者浏览包含此恶意代码的页面就会执行恶意代码。这意味着只要有访客访问了这个页面,就有可能执行这段恶意脚本,因此存储型XSS的危害更大。

存储型XSS一般出现在个人信息、网站留言、评论、博客日志等交互处。

3.DOM型XSS

出现在DOM(Document Object Model,文档对象模型)中而不是HTML中的XSS称为DOM型XSS。DOM是HTML和XML文档的编程接口,提供了对文档的结构化的表述,并定义了一种从程序中对该结构进行访问的方式,从而改变文档的结构、样式和内容。DOM将文档解析为一个由节点和对象(包含属性和方法的对象)组成的结构集合,代码如下。

访问www.test.com/dom-xss.xhtml#alert(1)时,alert(1)会被执行并触发弹窗,如图1-56所示。

图1-56 触发弹窗

在DOM型XSS中,受攻击页面的HTML源代码和响应页面将完全相同,响应页面是找不到Payload的。DOM型XSS不会被服务器端的过滤器阻止,因为在URL中,“#”之后的内容不会发送到服务器上。

1.2.2 XSS Bypass技巧

1.判断输出点及其上下文

尝试插入正常的字符串如“xsstest”“111111”,确定字符串输出的位置。

当输出位置在标签的属性里时,可以看到输出位置位于input标签的value属性处,输出内容被引号包围,如图1-57所示。

图1-57 输出内容被引号包围

闭合value属性,写入一个新的属性并构造XSS Payload,比如我们可以通过HTML的事件对象来构造。一般在<、>被过滤时使用这种方法。

利用事件对象onclick语法执行JavaScript语句,当用户点击对象时调用其事件句柄。在浏览器中输入Payload:?name="onclick="alert(xss);,执行结果如图1-58所示。

图1-58 onclick弹框

这里列出一些常用的事件对象,如表1-2所示。

表1-2 常用的事件对象

闭合input标签,直接在页面里构造XSS Payload。这时候构造Payload的方法就很多了,部分代码如下。

执行结果如图1-59所示。

图1-59 闭合标签

输出位置在<script>标签的情况还是比较常见的。举个例子,我们输入的name字段会被拼接到<script>标签内,并且被一个函数的"和{}包裹,代码如下。

输入?name=1";}alert('xss');{"1,可以闭合"和{},执行结果如图1-60所示。

图1-60 绕过<script>标签

因为输出位置已经被script标签包裹,所以我们的输入会被当成JavaScript代码执行,开发者在做XSS防护的时候很容易忽略这一点。

将用户输入的内容直接输出在页面上,这种没有上下文的情况也比较常见,因为没有上下文干扰,所以我们可以直接写Payload。

2.构造Payload

下面介绍XSS靶场Prompt(1) to win中3个简单的关卡。Prompt(1) to win的最终目标是在页面上执行Prompt(1)。输出点位于input标签的value属性中,两边被"符号包裹,如图1-61所示。

图1-61 定位输出点

将input标签闭合,再写入prompt标签。输入"><script>prompt(1);</script>,执行结果如图1-62所示。

图1-62 执行成功

再来看一个例子,输出点位于article标签内,并且用正则表达式过滤了<内容>的标签格式,如图1-63所示。

图1-63 正则过滤

正则规则分析如图1-64所示。

图1-64 正则规则分析

我们直接利用<img src=x onerror="prompt(1)",不输入最后一个">",浏览器会自动往后寻找">"帮我们闭合img标签,如图1-65所示。

图1-65 自动闭合标签

接着进行下一关,过滤了=(,输出位置没有任何干扰,直接输出在页面上,如图1-66所示。

图1-66 过滤特殊符号

JavaScript里某些函数是支持用``代替()的,除了prompt()函数不支持。SVG标签会将XML实体解析后加入标签,我们可以利用其会解析编码的特性绕过一些符号的过滤,代码如下。

或者利用eval函数。在JavaScript里,eval函数能够接受十六进制的字符串。

执行结果如图1-67所示。

图1-67 成功绕过特殊符号

1.2.3 XSS进阶

1.CSP

内容安全策略(Content Security Policy, CSP)是一种计算机安全标准,由Robert Hansen于2004年提出,首先在Firefox 4中实现,并很快被其他浏览器采用。CSP用于防止XSS、点击劫持和其他由于在受信任的网页上下文中执行恶意代码而导致的代码注入攻击。CSP为网站所有者提供了一种标准方法来声明允许浏览器在该网站上加载资源,如JavaScript、CSS、HTML网页等。

CSP可以通过两种方式进行设置,在HTTP的消息头中设置,或者在HTML的Meta标签中设置。正常的CSP配置由多组策略组成,每组策略包含一个策略指令和一个内容源列表,如表1-3、表1-4所示,每组策略之间由分号分隔。CSP主要是通过限制JavaScript的执行、限制跨域请求来防御XSS的。

表1-3 CSP指令

表1-4 CSP指令值表

具体配置参见https://developers.google.com/web/fundamentals/security/csp/。

举个例子来看看CSP的效果。未设置CSP时,代码如图1-68所示。

图1-68 未设置CSP的代码

成功加载图片后的效果如图1-69所示。

图1-69 成功加载图片

我们配置一个常见的CSP,代码如下。允许执行内联JavaScript代码,但不允许加载外部资源。

可以看到,配置完CSP之后,获取图片失败了,如图1-70所示。

图1-70 CSP策略生效

2.绕过CSP

下面介绍如何利用CSP的配置缺陷。

在真实的开发环境中,常常不得已需要执行内联,我们可以借此执行内联JavaScript,当然也可以利用location跳转带外数据,代码如下。

利用unsafe-eval错误配置的代码如下。

不允许加载外部资源,并且不允许加载内联JavaScript代码,但是配置了unsafe-eval指令值,使用了data配置,可通过Base64编码Payload,代码如下,结果如图1-71所示。

图1-71 成功绕过CSP

如果网站设置了script nonce,在无法猜测nonce值且base-uri没有被设置的情况下,可以使用base标签设置默认地址为我们构造的恶意服务器地址。如果页面中的合法script标签采用了相对路径,那么最终加载的JavaScript代码就是针对base标签中设置的默认地址的相对路径,如图1-72所示。

图1-72 成功绕过

这样就会默认加载我们构造的恶意服务器上的main.js。

我们也可以通过link标签进行预加载。如下代码是一个简单的CSP规则,不允许加载外部资源,我们用img标签引入baidu.com的图片时就会被阻止,如图1-73所示。

图1-73 不允许加载外部资源

可以通过link标签的预加载来绕过,代码如下。大部分浏览器都约束了该标签,如图1-74所示。

图1-74 通过link标签的预加载绕过

外带数据可以使用如下代码绕过。

在浏览器的机制上,跳转也算是一种跨域行为,并且不受CSP约束,可以通过跳转绕过CSP,带出我们要的数据。部分Payload可参考以下代码。

CSP中原本有sandbox和child-src限制iframe的行为,但是当一个同源站点存在A页面和B页面,且A页面有CSP保护,而B页面没有CSP保护时,我们可以通过B页面新建iframe嵌套A页面,这样就可以绕过A页面的CSP获取A页面的数据,如图1-75所示。

图1-75 通过iframe标签绕过

通过站点允许访问的资源来构造XSS,最经典的案例就是利用www.google.analytics.com中提供自定义JavaScript代码的功能(因为Google会封装自定义的JavaScript,所以还需要unsafe-eval字段),绕过CSP,代码如下,如图1-76所示。

图1-76 利用站点可控静态资源绕过

浏览器解析html标签的规则为遇到左尖括号标签开始解析,直到遇到右尖括号结束,两者之间的数据都会被当成标签名或者属性。

在某些场景下,利用这个规则我们可以劫持别的标签的属性,代码如下。

CSP为不允许请求外部资源,仅允许属性nonce为test的标签执行JavaScript代码。

我们构造Payload:?xss=%3Cscript+src=data:text/plain,alert(1),结果如图1-77所示。

图1-77 绕过不完整的script标签

如图1-77所示,Payload拼接到页面上就是成功劫持了nonce='test'属性,并且执行了我们构造的alert函数。

JSONP其实就是一个跨域解决方案,JavaScript是不可以跨域请求JSON数据的,但是可以跨域请求JavaScript脚本。我们可以把数据封装成一个JavaScript语句,做一个方法的调用,跨域请求JavaScript脚本可以得到此脚本。因为程序得到JavaScript脚本之后会立即执行,所以把数据作为参数传递到方法中就可以获得数据,从而解决跨域问题。为了便于客户端使用数据,我们发明了一种非正式传输协议,JSONP。该协议的一个要点就是允许用户传递一个callback参数给服务端,服务端返回数据时会将这个callback参数作为函数名来包裹JSON数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了。

JSONP是用来解决跨域问题的,能够绕过CSP,构造如下Payload。如果返回的数据为JSON格式,此方法就无法利用了。

3.XSS升级为RCE

浏览器一般对JavaScript调用系统命令设置限制,但是在一些客户端上往往会忽略这个细节。当XSS在浏览器以外的客户端被触发时,攻击者可以利用XSS构造JavaScript去调用系统命令,这样一个简单的XSS漏洞可能就会升级为一个RCE漏洞。

举个例子,Electron是GitHub发布的跨平台桌面应用开发工具,支持Web技术开发桌面应用,其本身是基于C++开发的,图形用户界面核心来自Chrome。Electron相当于精简版的Chromium浏览器。Xmind、Slack、Atom、Visual Studio Code、Wordpress Desktop、GitHub Desktop、蚁剑和Mattermost等应用程序都是采用Electron框架构建的。

简单来说,Electron可以将一个Web应用转为桌面应用,在Web应用中可能会出现的XSS漏洞,在Electron开发的桌面应用中也会出现,并且这种XSS漏洞很容易升级成为一个RCE漏洞。Xmind、GitHub Desktop等都曾被爆出过XSS漏洞导致的任意命令执行。

我们先来看看JavaScript如何调用系统命令。

exec()是child_process模块里面最简单的函数,作用是执行一个固定的系统命令。

例如执行命令whoami。

构造执行命令的XSS Payload调用计算器,代码如下。

execSync()的作用同exec(),不同之处在于该函数在子进程完全关闭之前不会返回,代码如下。当遇到超时并发送killSignal时,该函数在进程完全退出之前不会返回。

execFile()函数的作用是运行可执行文件,函数参数信息如下。

execFile()函数用法如下。

execFileSync()的作用与execFile()相同,不同之处在于该函数在子进程完全关闭之前不会返回。当遇到超时并发送killSignal时,该方法在进程完全退出之前不会返回,代码如下。

1.2.4 XSS CTF例题

我们以CISCN2019-华东北赛区-Web2题目为例,本题的考点为XSS和SQL注入,我们重点来看XSS的部分,题目如图1-78所示。

图1-78 题目首页

打开题目环境是一个博客,我们能够注册普通账户并投稿,投稿需要通过管理员的审核。一个很经典的XSS漏洞场景是,我们在文章中构造XSS Payload,获取管理员的cookie,然后通过cookie获取管理员权限。我们随意提交数据并测试,结果如图1-79所示。

图1-79 随意提交数据

在文章页面还设置了CSP,如图1-80所示。

图1-80 CSP策略

CSP策略代码如下。

策略允许执行内联JavaScript代码,例如内联script元素,但不允许加载外部资源,可以使用eval()函数。要获得cookie,就必须绕过CSP不允许加载外部资源这个限制。在CSP策略允许unsafe-inline的情况下,我们可以通过跳转来绕过限制,代码如下。

这样管理员访问时就会把cookie回带到我们用于接收数据的服务器http://dataserver上。

这题还将(、)、'等符号替换为中文符号,我们可以通过svg标签加HTML Markup去编码绕过,最终Payload如下。 ZTR9z+2faTxOL/Y6iBlKifc4k2lts9U8BO+MTuVFlLhnOCaSkIH4RiAsMcAGcDJm

点击中间区域
呼出菜单
上一章
目录
下一章
×

打开