标题 | 简介 | 类型 | 公开时间 | ||||||||||
|
|||||||||||||
|
|||||||||||||
详情 | |||||||||||||
[SAFE-ID: JIWO-2024-3333] 作者: Candy 发表于: [2023-09-05] [2023-09-05]被用户:Candy 修改过
本文共 [273] 位读者顶过
漏洞信息漏洞编号:CVE-2023-2317 漏洞范围:Typora,≤1.67 漏洞说明:低于1.67版本的Typora存在代码执行漏洞,通过在标签中加载typora://app/typemark/updater/update.html实现在Typora主窗口的上下文中运行任意JavaScript代码。 问题代码段整段代码如下,我们可以逐段进行分析:
[出自:jiwo.org]
首先看获取输入部分:
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]));
通过正则表达式匹配的方式,获取传入的5个GET参数:curVersion、newVersion、releaseNoteLink、hideAutoUpdates和labels。接收参数releaseNoteLink时会对输入做一次URI解码,接收labels参数时会先做一次URI解码,再做一次json解析。 获取输入后,会使用dom.innerText和din.innerHTML替换原页面中的代码,且没经过任何清洗,也就是这个地方会导致DOM型XSS。
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]; });
代码里有两处替换,第一处将参数labels[4]和labels[5].replace("$1", newVersion).replace("$2", curVersion)做拼接,然后直接替换掉页面中的元素
因此,我们分析出传入的参数labels是一个长度至少为5的数组,数组的前3个元素都会未经清洗的替换掉页面中的元素导致DOM型XSS(第4、5个参数使用的时innerText替换,无法利用),我们只需要在labels前4个元素中填入Payload,就可以实现命令执行。 漏洞利用我们只需要,让Typora界面加载带有我们的payload访问的updater.html文件,就能实现命令执行。
Typora内部实现了typora://协议,可以用于Typora访问特定文件。我们在Typora中按下Shift+F12,可以看到Typora页面中使用了这种协议: 以这个访问为例,lib.asar位于Typora安装目录的resources文件夹下,而updater.html位于Typora安装目录的updater文件下,所以使用typora://协议访问updater.html应该这样写:
typora://app/typemark/updater/updater.html?a=xxx&b=xxx&c=xxx 根据前文分析的结果,我们需要传入curVersion、newVersion、releaseNoteLink、hideAutoUpdates和labels五个参数。对参数releaseNoteLink做一次URI解码,参数labels是一个长度至少为5的数组,也需要做一次URI编码,在labels的前3个元素中任选一个填入payload。 构建payload根据常规思路,我们应该require库child_process然后调用exec参数,但是typora内没有定义require函数,而是使用reqnode函数代替:
因此,Windows环境下的payload可以这样写: reqnode('child_process').exec("calc") 包在svg标签里实现页面加载: 编码前的Poc: 最后对releaseNoteLink、lables两个参数做URI编码,最终Poc为: 为了同时在Windows环境和Linux环境生效,我们可以这么写payload: 漏洞复现
保存后使用Typore打开,成功弹出calc:
漏洞修复安装最新的1.6.7版本查看其updater.html文件,可以看到已经把innerHTML改成了innerText:
|