flowise任意文件读取漏洞分析

Posted on 20 days ago  37 Views


很久之前看到了这个漏洞通告

【已复现】Flowise 任意文件读取漏洞(QVD-2025-35890)安全风险通告

但是一直没时间看

今天看了一下,第一眼看过去感觉平平无奇,但是仔细分析发现还是很有意思的,至少对我这种不熟悉nodejs的新手来说,还是有一些收获

先看漏洞通告内容,几乎把漏洞细节都告诉我们了

image

很简单,把源代码下载下来,搜一下接口就找能到漏洞位置,这里读文件是三个参数拼接的,开发者只做了两个参数的过滤,然后就被挖洞了

这里chatflowId必须要和数据库中的数据对应,Controller层会做校验

image

其实到这里我就打算下机了,没意思,平平无奇

不过来都来了,搭环境也花了点时间,如果就这么走了,感觉这折腾的半个小时活得没什么意思

于是我注意到漏洞通告里云淡风轻的说,通过报错获取chatflowId

image

什么报错?源码里面到处都是throw,也不知道是什么原因的报错,我找了两个小时,愣是没找到怎么报错的

没办法了,翻答案吧,漏洞通告末尾给了github漏洞情报的地址,点进去看看

Flowise has an Arbitrary File Read · GHSA-99pg-hqvx-r4gf · GitHub Advisory Database

image

这是什么,试一下?

image
image

而且把文件名换成其他的,就不爆chatflowId了

image

何意味?

按理说,这个接口不止文件名参数有奇怪的问题,路径上面应该还有一个chatflowId的参数,完整的请求路径应该是/api/v1/vector/upsert/xxx,这里我们没有传任何chatflowId,为什么没有报错参数不存在?

我直接翻代码,看看为什么会这样,导航到upsertVector

image

不对,为什么?

人开发明明检查了chatflowId是否存在,但是为什么没有用?我们打poc的时候,没有传递任何id参数,为什么直接就过掉检查了?

image

这里想破脑袋都想不出来,只能debug看看了

按照官方部署教程,使用docker-compose启动,但是不能老老实实启动,要开启debug模式

image

run起来之后,用chrome://inspect调试,直接下断点

image

虽然很震惊,但是也算情理之中?我估计这是TypeORM的一个 bug feature,当条件为undefined的时候,findOneBy方法直接返回第一个结果

不难理解,当条件值为undefined时,where子句直接没有条件了,我推测TypeORM在拼SQL的时候看到查询条件是undefined,就直接跳过where语句的生成,变成SELECT * FROM xxx LIMIT 1,很合理

这个地方的代码没有做到检查chatflowId是否传入的功能,那难道这个项目根本不检查传入参数吗?其实不是的,开发者在别的地方基本都做了检查,就这里忘了

那么这里就解决了第一个问题,第二个问题是,为什么文件名必须是“?”?

在打过poc之后,flowise会输出错误日志,看看

image

错误日志里面打印了这次poc的调用栈,可以看到文件报错是在storageUtils.js里面

嗷?原来跟文件读取的漏洞点在同一个文件,而且是文件写入的操作报错;估计挖洞那哥们本来想挖任意文件写入RCE,已经强烈关注了文件写入的那个点,但是发现写入有点难,就去挖文件读取,正好文件写入那个点会报错泄露文件路径,就被哥们拿去做exp的一环了

直接在storageUtils.js打断点

image

nb,因为“?”是非法字符,直接被过滤掉,过滤出来的文件名是空字符串,这样在拼接到路径上,这个路径就表示的是文件夹而不是文件了

image

向文件夹写入数据,当然会报错,报错就把文件路径显示出来了,而文件路径正好包含chatflowId,下面这两张图是拼路径的代码,可以看到报错的那两个uuid分别是orgId和chatflowId

image
image

太精彩了,看来敏感信息泄露真的是高危漏洞

基于这里泄露的chatflowId,最终成功复现任意文件读取漏洞

image

你好