No.7

XSS 详解

XSS 一般分为 反射型XSS、存储型XSS、DOM型XSS 三类,下面我将逐个为大家讲解

反射型XSS

什么是反射型XSS,最简单的理解就是注入点URL里的,你只能通过这个URL去利用XSS。

官方一点的说法是,网站在接收了含有用户可修改的数据的 http 请求后,没有做任何安全处理,就直接在响应包中又返回给了客户端,从而造成了XSS语句被执行。

利用方法

攻击者构造一个含有恶意代码的 url

他将这个 url 通过各种途径进行传播

一个倒霉蛋看到了这个链接,然后就点了,这个 就在他的浏览器上执行了,最终实现了攻击者的目的

靶场演示

任务简报

要求很简单,执行 alert 就行。

点击进入靶场

任务过程

首先我们来看看这个页面,一个简单的搜索框,输入要搜索的内容点击搜索之后会在页面上显示你搜索内容的命中条数,同时在 url 上也有一个参数,它的值就是你的搜索的内容(多标准的一个反射型 XSS 啊)

下面就让我们看看这个输出在哪里吧,F12打开开发者工具,点击 123 所在的位置

可见它是在一个 h1 标签里面,那我们就直接给一个完整的

就可以了,不用考虑闭合语句之类的问题

这就通关了,是不是很简单

存储型XSS

存储型XSS,从字面上就可以看出来他是存储在一个地方的,这个地方就是对方的服务器。

它和反射型XSS最大的不同就是,你不用费尽心思的去传播你的 ,你在完成注入之后就可以想干啥干啥了,坐等受害者的 自动跑到你的服务器里,所以它的危害远比反射型XSS大的多。

利用方法

攻击者在一个保存数据的地方(可以是评论、新建、修改 等等可以自定义内容并保存的功能点),发现了一个 XSS 漏洞,然后提交了一个包含恶意代码的

受害者在浏览网站的时候打开了含有攻击者提交的恶意信息的页面,然后浏览器上就弹出了一个警告框

靶场演示

任务简报

一样的要求,触发 alert() 函数

点击进入靶场

任务过程

进入靶场之后我们到详情页面,可以看到有一个提交评论的功能

在这里我们先提交一个测试数据摸摸底

可以看到我们在提交的时候,它要求我们输入一个 Email,说明这里是有格式校验的,但是我们可以查看 burp 可以发现它并没有发送请求,说明是前端校验,众所周知,前端校验约等于不校验,这里我们先按它的要求改一下数据,等到注入的时候,再看看它服务端有没有相应的校验,下面的同理

这里我们通过开发者工具可以看到,前端一共接收了我们提交三个数据 name 所以我们的注入也是围绕这三个参数展开的,其中 需要前端绕过,name 和 直接写 即可

需要注意的是, 和 name 并不一样, 的位置是在标签中(就是 里),而name 则是在标签外,所以 的需要闭合原有的语句,所以最终的如下

可以注意到,上面的 alert() 中的提示词都不一样,这可以在一起弹出多个框的时候帮助我们更直观的确定哪些参数有注入点,下面直接提交

这里我们发现只弹了 的窗,其他两个并没有弹窗,name 甚至直接显示了 ,那凭啥呢,大家都是一样的,凭啥就你俩特殊呢,这里我们打开开发者工具看看

这里似乎也看不出什么东西来(其实从颜色上也能看出来"双引号并没有闭合掉原语句),那我们就把它粘贴出来,我这里用的是 编辑器,大家需要的话直接去官网下载正版即可,激活码淘宝几块钱一个

这里就可以看出差距了,name 的 被编码了, 的 " 被编码了,所以它们没有被执行,而 的数据未做任何处理,所以被执行了,就是这么简单

收工下班!

DOM型XSS

DOM型 XSS 通常是由于前端代码没有对用户的输入进行适当的处理和转义造成的,虽然反射型和存储型也有前端的锅,但它们还需要服务器的参与,而 DOM 型则不需要服务器参与就可以了。

DOM型XSS和其他两种XSS最大的不同就是它不需要和服务器进行交互,对于反射型和存储型来说,你都可以在服务器响应中找到你的 ,但 DOM 型 XSS 主要围绕的是 (数据源) 和 sinks (数据触发点) 这两个进行的,这意味着它不需要服务器的响应来植入 ,即使响应中不包含 也可以执行 XSS 语句。

你可以将 对应到 反射型XSS的注入点, sinks 对应到服务器响应后 在前端显示的位置,这样可能对你理解这两个概念有一定的帮助。

靶场演示-URL注入点

任务简报

在这个实验室里有一个DOM型XSS,它使用 .write 函数调用来自 .. 的数据,并将它写入到 html页面中。发起一次 XSS 攻击,并调用 alert 即可通关。

点击进入靶场

【函数解释】

.write: 用于向 html 写入内容。当文档正在加载时调用,在当前位置写入内容;在文档加载完成后调用,将会重写整个文档。

..:用于返回当前 URL 的查询字符串部分,即在URL中 ? 符号后面的部分,如本例中的 ?=

任务过程

可以看到,这个页面和我们之前的那个 反射型XSS 的页面看上去是一模一样

既然如此反射型xss,那我们直接使用之前的那个语句试试,

欸?奇了怪了,好像没有反应啊,打开 开发者工具 看看

看上去和反射型XSS的出现位置也是一样的啊,为什么这里没有成功呢,它被编码了吗?我们用存储型XSS提到的那个方法看看,复制出去看看怎么样

果然被编码了,那该怎么办呢,明明说了这里有XSS的啊,不要急,让我们看看有没有其他地方也有这个 参数的值,在检查器搜索 123 看看

这里我们可以发现, 还被插入到了一个 img 标签里,虽然我们在页面中并没有看到有图片,但这并不妨碍我们对它做点什么,现在我们试试闭合它看看会是什么结果,">

成了,收工下班(不是)

DOM 型XSS详解

我在初学 DOM 型XSS的时候也看过很多文章,大部分都是到这里就结束了,但是看完之后我依然不知道这个 DOM 型XSS和反射型XSS的区别在哪里,不就是闭合了一下吗。下面我们来看看这个弹窗背后的过程。

还记得在简介中我提到了 DOM型XSS不需要服务器的响应来植入 ,即使响应中不包含 也可以执行 XSS 语句 这句话吗,从表面上看,这是和反射型XSS最大的不同,那下面我们看看把DOM型XSS响应包中的删掉会怎么样

还是输入

">

点击搜索,不同的是这次我们使用 把响应包拦截下来

我们把响应包中的删掉,这里其实删不删都可以,因为我们可以看到在响应中只有一个 alert,但是这里服务器在响应的时候对进行了HTML实体编码,所以这个理论上是不会被执行的,但是保修起见我们还是删了它看看

这里我们可以发现即使删除了 这个XSS语句还是被执行了,如果这里是反射型XSS那么这里肯定不会执行成功的

那么问题来了,被执行的这个XSS语句是哪里来的呢,我们 F12 看一下

这里我们可以看到, 只剩下了 img 标签中的那个,并且它现在已经被闭合了,导致了这个弹窗

那这里的这个语句是哪来的呢,大家还记得任务简报里提到的 .write 和 .. 这两个函数和属性吗,我们可以看到在这个 img 标签的上面有一段 代码,这里我对它进行格式化写在下面


function trackSearch(query) { # 调用 document.write 将 query 的值拼接到原有的 标签的 ? 的位置 document.write('+query+'">'); }# 将 URL 中 search 的值赋值给 query 变量var query = (new URLSearchParams(window.location.search)).get('search');# 判断 query 是否为空if(query) { # 如果 query 不为空就执行 trackSearch函数,并将 query 传入该函数 trackSearch(query); }

看了上面的注释大家应该可以明白 XSS 是哪里来的了吧,它就是浏览器从 URL 上提取后写入 HTML 页面的,全程没有服务器的事。对应到我们提到的 和 sinks,本例中 .. 就是 ,.write 是就是 sinks,这也能更好的帮助大家理解这两个新概念。

所以这就是反射型XSS和DOM型XSS的区别,当然在测试上两者并没有什么区别,都是给所有的参数输入 随机字符串 看它们最后出现在了哪里。

那可能有的同学要说了,实际测试中的网站怎么可能就这几行代码,我怎么找哪些没有在URL上出现的注入点呢,那就只能通过扫描器或者翻代码了,下面通过一个靶场给大家演示一下如何翻代码

靶场演示-隐藏URL参数

任务简报

在这个实验室里有一个DOM型XSS,它使用 .write 函数调用来自 .. 的数据反射型xss,并将它写入到 html页面中。发起一次 XSS 攻击,并调用 alert 即可通关。

点击进入靶场

任务过程

由于任务简报已经给了我们 和 sink 所以我们就不瞎试了,直接 F12 搜 .write 和 .. 即可

在首页中我们发现了3个 .write 其中前两个明显不是函数调用,第三个不知道为什么会在图中标识的位置搜索到 .write (懵),那就点到下面的页面看看有没有

在这里我们发现了一段JS代码,其中就有 .write 函数被调用,下面看看这个代码是什么意思

# 定义一个列表var = ["","Paris","Milan"];# 获取URL中的 的指,并赋值给 store = (new (..)).get('');# 写入一个 标签.write('');

看了上面的代码我们应该注意到,它会获取 URL 的 这个参数的值,但是我们在上面的页面中只看到一个 参数,那改怎么办呢,给它写上一个不就行了,&=123

可以看到选项中多了一个 123 的选项,但是这里有个问题, 的值是被植入到

完事收工,在实际测试中,如果你想手工找这些参数其实是相当麻烦的,这里更推荐使用扫描器完成就行了,如果你非要用手工测试的话,下面我整理了一份常见的 和 sinks,大家可以参考一下

DOM型XSS常见 及 sinks

No.8

多种场景下的XSS利用

看完前面的内容相信大家已经对XSS有了一个基本的认识,下面就通过大量的示例来带大家看看各种场景下的 XSS 应该如何挖掘,由于反射型和存储型的难度不高,这里使用DOM型作为举例,大家根据 在页面上的输出位置举一反三即可。

href 标签里的XSS - 伪协议利用

任务简报

在这个实验室的提交反馈页面,存在一个XSS漏洞,它使用了 库的 $() 选择器来查找一个锚点元素,并使用 . 来更新这个元素的 href 属性。

弹出当前 即可通关

【函数解释】

库的 $() 选择器在这里的作用主要是选中符合条件的元素,如:

$('#backLink').attr("href", (new URLSearchParams(window.location.search)).get('returnPath'));

本例中用到的这这段代码的作用是,选定所有 id = 的元素,并修改其 href 属性为 URL 中 的值

任务过程

首先来到注入点所在的页面

首先我们可以看都有一个 的参数,这里我们随便修改一下它看看是什么结果 123

修改之后我们可以发现它出现在了一个 a 标签的 href 属性中,那我们就试着闭合它看看 ">

看来不太行,他把我们的引号给编码了,那也就意味着我们不能通过闭合语句的方法来使 生效了。

让我们回到这个 a 标签本身上做点文章,这里 Back 的作用是,在你点击 Back 的时候,前往网站的根目录

但是 herf 这个属性是可以执行 伪协议的,也就是说,我们可以给 herf 里面添加一个 js 代码,当用户点击 back 的时候就执行这个代码,那就来试试

payload javascript:alert(document.cookie)

这里由于唯一的一个 被设置了 所以这里的弹窗只返回了 值,但是我们的目的也达到了,收工下班

反射DOM型XSS

我们前面说过,DOM型XSS于反射型XSS的区别在于,DOM型XSS不需要服务器传回的数据,但是这并不意味着不需要服务器传回的数据的XSS才是DOM型XSS,下面我们来看一种需要服务器响应数据的DOM型XSS

任务简报

此实验室演示了一个反射DOM漏洞。当服务器端应用程序处理请求中的数据并在响应中回显数据时,会出现反射DOM漏洞。页面上的脚本然后以不安全的方式处理反射的数据,最终将其写入危险的接收器。

调用 alert() 即可通关

任务过程

虽然这个任务简报没有告诉我们注入点,但是它就搜索一个功能,所以就略过找注入点的步骤了

这里我们可以看到,前端对我们搜索的内容是进行了 html 编码后才进行的输出,对于一个反射型xss来说,这就差不多是判了死刑,但这里肯定有XSS漏洞的,我们继续向下分析

这里我们可以看到调用了一个 js 文件,所以我们可以合理的怀疑这个 h1 标签的内容是通过这个 js 文件写入的,我们按住 'ctrl + 左键' 进去看看

这里我们直接搜索 h1 ,看看 js 在哪里对它做了修改

可以看到这里通过 设置 h1 标签,但是这个并不会造成 XSS,它会确保内容以文本的形式显示出来,而不是当成一个 HTML 代码,所以应该不是这里,我们看到它是由 '.' 和 '' 拼接起来组成的,前面的 '.' 明显不是用户可控的,所以我们看看这个 是哪来的

我们跟着代码一步一步找过去发现,它获取的是 get 请求中的响应包的内容,但是这里我们有一个需要重点关注的地方,就是 eval 这个函数。

我们先来介绍一下 eval 的作用是什么,它的作用是把传递给它的字符串当做代码进行解析并运行,比如下面的例子:当你定义了一个字符串 '2+2',直接打印它你可以得到原本的 '2+2' 这串字符,但是把这个变量放在 eval 中的话它就会把他当成js代码进行运算,最后得出了 '4' 这个答案

那我们能不能在这里让他执行 alert() 呢,当然是可以的,让我们先看看这个 是从哪里得到的吧,看看抓包的结果

看来前端就是从这个JSON数据中提取的 这个键值对,那我们就试试让他来携带上 alert 看看会是什么结果,当然,我们还需要调试一下 ,大家可以直接在浏览器的 中进行调试

我们把响应中的JSON数据以字符串的形式替换掉原来的 this.,然后给后面执行一个 -1 可以看到 123 变成了 122,那我们就试着让它弹个窗看看

可以看到顺利弹窗,那么下面我们就应该像办法闭合原来的语句,让 == 123"-alert(1)}, 123"-alert(1)}// 这里 // 的作用是注释掉原本语句中的 }), } 的作用是闭合 JSON 数据

这里我们发现并没有弹窗,让我们看看响应包有没有什么变化

原来是服务器返回的时候给 " 转义了,这个好办,我们再加上一个转义符让它转义转义符就好了, 123"-alert(1)}//

收工下班

存储DOM型XSS - 关键字替换绕过

这个案例和上面的反射DOM型XSS的区别只是在存储型上面,这个没有什么讲的,主要是通过这里的字符处理给大家讲一下绕过的思路。

任务简报

存在一个存储DOM型XSS,调用 alert() 即可通关

点击进入靶场

任务过程

进入实验室,还是熟悉的页面,我们直奔评论提交的地方提交一个看看效果

可见他们都被替换成了 HTML 实体编码,老样子 我们看看上面的js里是怎么处理的, Ctrl + 左键 点进去看看

从上面的代码我们可以看出,重点在于框选出来的两行代码,下面的三元运算说明,有一个 img 标签的 src 属性的值,在响应包的 为空的时候是默认的 '///.svg',如果不为空那么就调用 函数,让 src 等于 服务器相应中的 当前循环下的 值,所以我们要做的就是让服务器响应中的 不为空,且要绕过 中的尖括号替换,这个到简单,只要写一个多余的 就可以了,这个函数只会替换遇到的第一个字符,下面我们看看提交评论时的请求包和获取评论时的响应包

这里可以发现提交的时候没有 这个参数,获取评论的时候 也为空,那我们试试给它添加一个看看,

刷新页面

发现响应包中的 字段并没有被修改,说明这个方法不太行,没关系我们继续往下看

在这里我们发现了这么多的 属性,这个和我们上个案例中提到的 最大的区别就是, 会把里面的值当成 HTML 标签去解析,所以他是一个可能造成 XSS 的重点部位,我们看看哪些元素的值是可控的

上面我们可以发现一共有两个地方是用户可控的,分别是响应包中的 body 和 这两个字段的值,也就是提交评论那里的 和 name 的内容,那我们就写上去试试

收工下班,这里虽然替换的 但是大家也可以在 / 之类的关键字检测中通过双写、大小写、加注释等方法进行绕过,不要拘泥于案例,重点在于思路。

No.9

结语

上面对于三种类型的XSS介绍,我不敢说是全网最详细的,起码前几名应该还是可以算的上的。虽然上面查代码之类的可能比较复杂,但对于身为脚本小子的我们来说,看到有提交的地方就插几句 看看是最简单的测试方法,只要测试的目标足够多就不怕没有货。不到万不得已实在没 kpi 了,大家就不用去干扒代码这种吃力不讨好的事情了,毕竟前端的代码也扒不出什么高危漏洞,除非他把账号密码硬编码进去了或者有什么未授权接口,但这个咱们完全可以使用其他的一些工具来快速定位,后面有机会的话再单开一章详细讲解。

好了 就这样了,如果文中有什么错误的地方还请各位大佬指正。

No.10

网安沟通交流群

扫码加客服小姐姐拉群

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注