Vite开发服务器任意文件读取漏洞分析复现(CVE-2025-31125)
MeteorKai 漏洞分析 1876浏览 · 2025-04-03 17:39


Affected versions

6.2.0 <= Vite <= 6.2.3

6.1.0 <= Vite <= 6.1.2

6.0.0 <= Vite <= 6.0.12

5.0.0 <= Vite <= 5.4.15

Vite <= 4.5.10


前言

这个漏洞其实是CVE-2025-30208的升级版

这里直接先给出公开的POC:/@fs/etc/passwd?import&?inline=1.wasm?init

我们看看6.2.2,6.2.3,6.2.4,6.2.5版本的packages/vite/src/node/server/middlewares/transform.ts文件的commit先吧。

先看看修补6.2.2的commit:此处是修补了CVE-2025-30208,但是CVE-2025-31125仍然是存在的。

https://github.com/vitejs/vite/commit/f234b5744d8b74c95535a7b82cc88ed2144263c1#diff-6d94d6934079a4f09596acc9d3f3d38ea426c6f8e98cd766567335d42679ca7cL43-R188

image.png


此处的修补其实主要在于去除末尾多的?&

然后我们再看看修补6.2.3的commit

https://github.com/vitejs/vite/commit/59673137c45ac2bcfad1170d954347c1a17ab949

image.png


此处的修补主要是对于inlineRE的修补。也就是对上面那个公开POC的修补!但是未公开的POC还是可以使用的!!!!

再看看修补6.2.4的commit(下面分析的时候再说),修补了未公开的POC。。。

https://github.com/vitejs/vite/commit/62d7e81ee189d65899bb65f3263ddbd85247b647#diff-6d94d6934079a4f09596acc9d3f3d38ea426c6f8e98cd766567335d42679ca7c

漏洞分析

公开POC

/@fs/etc/passwd?import&?inline=1.wasm?init

看看vite6.2.4

先看看最末尾的文件读取处:

image.png


查看函数调用

继续查看函数调用,全局搜发现load函数,其实这里也可以通过6.2.5的commit来发现6.2.4删除了!id.endsWith('.wasm?init'),换成了!wasmInitRE.test(id)

上述其实是满足id的末尾是.wasm?init的话,就进入fileToUrl。也就是结尾需要满足.wasm?init。

进入fileToUrl后会默认进入fileToDevUrl,就是在这里读取了file。

对id进行cleanUrl,也就是一次清洗(匹配从 ?# 开始直到字符串末尾的所有字符),如/etc/passwd?&raw??会被替换为/etc/passwd。cleanUrl后读取文件!

我们用poc走一遍代码(vite6.2.4)。/@fs/etc/passwd?import&?inline=1.wasm?init

image.png


这里经过了removeTimestampQuery函数,但是我们最后不是问号所以没事

接下来是:

url还是/@fs/etc/passwd?import&?inline=1.wasm?init

然后我们要进入一个if语句:

我们要让前三个test都为false才行!

但是此处inlineRE.test会匹配到!因此vite6.2.4 修补了这个漏洞(CVE-2025-31125)!

接下来我们跟一遍vite6.2.3:

我们从if语句处开始分析,此时url为/@fs/etc/passwd?import&?inline=1.wasm?init

这里就匹配不到了,我们就可以往下走了。

进入下一个if语句:

匹配到了,进入if语句。进行一次removeImportQuery(url)。

经过removeImportQuery后url就变成了/@fs/etc/passwd??inline=1.wasm?init

接下来进入transformRequest

没有对url进行什么操作,直接跟进doTransform

首先对url进行一次removeTimestampQuery,但是没什么效果。

跟进loadAndTransform后,继续跟进

直接进入fileToUrl!然后进入fileToDevUrl。

进入if语句:/@fs/etc/passwd??inline=1.wasm?init

进入if语句后进行一次Url的清洗

file也就等于/@fs/etc/passwd了!然后readFile后赋值为content。最后进行回显!

未公开POC

看一下最新的commit,发现多了对于svg的判断。这个poc是可以打6.2.4的。

我们先看看fileToDevUrl

发现其中不知有inlineRE,还有一个svgExtRE,我们可以通过svg来进行文件读取。

那么就有这样的poc:

我们跟一遍vite6.2.4先。

由于最末尾没有?之类的,我们直接进入下面的if语句:

要求rawRE,urlRE,inlineRE均为false才行,自然是可以的。

那么接下来进入下面的if语句:

isImportRequest为true,直接进入if语句。

经过removeImportQuery后url变成了/@fs/etc/passwd??meteorkai.svg?.wasm?init

然后进入transformRequest

接着跟进doTransform

跟进loadAndTransform

然后进入load函数

进入fileToUrl。再跟进fileToDevUrl。

这里inlineRE.test(id)是false的。

但是svgExtRE.test(id)为true。

然后就是清洗Url,file为/@fs/etc/passwd,可以读取任意文件。

接下来我们看看vite6.2.5是如何进行防御的:

/@fs/etc/passwd?import&?meteorkai.svg?.wasm?init

svgRE.test(url))为true了。。。直接防下!

0 条评论
某人
表情
可输入 255

没有评论