漏洞简述
CVE-2025-61686 是一个影响 React Router 和 Remix Run 框架的严重路径遍历漏洞。该漏洞存在于文件会话存储功能中,当应用程序使用
createFileSessionStorage()函数且未对会话 cookie 进行签名时,攻击者可以通过操纵会话标识符来访问或修改服务器文件系统上预期会话目录之外的文件。
当然你签名了如果可以伪造也是一样的
React Router 和 Remix Run 提供了多种会话存储选项,包括:
- Cookie 会话存储
- 内存会话存储
- 文件会话存储
- 自定义会话存储
createFileSessionStorage()函数允许开发者将会话数据持久化到文件系统,适用于需要在服务器重启后保持会话状态的场景。
漏洞利用
这里的环境我是基于Hiflower那个靶机(源码Hiflower那里有)进行分析利用

这里定义了session文件的储存文件夹和加密签名用的secrets,因此这里其实我们就是可以去写一个伪造session的js脚本了
1 | const crypto = require("crypto"); |
session的格式是:前半部分是sessionid的base64编码,后部分是基于前半部分和secret的签名,特别注意的一点是前半部分的sessionid是要带双引号去进行base64编码的

那么这里我们就可以通过脚本去伪造了一个恶意的session,接下来就是要找写入文件的函数

这个commitSession,然后我们改好session访问这个路由,成功写入了,但是这里我们并没有控制我们想写入的内容

但是这个可用用来覆盖文件!
于是我们去找能控制写入的路由

登录这个页面配合注册,可以通过对username的控制写入东西,然后对于这个靶机这里是有一个定时shell脚本的,我们配合变量替换:${}或者命令替换:反引号,去弹个shell

填入恶意session去登录就可以写入文件啦!接下来就从代码层面来浅析一下
漏洞分析
来浅析一下,毕竟深了我也弄不来
首先我们跟进createFileSessionStorage

发现调用了createSessionStorage,继续跟进

这里就可以看到commitSession的实现了,这里我们主要关注creatData和cookie.serialize
先来看前者

1 | let randomBytes = crypto.getRandomValues(new Uint8Array(8)); |
这里生成一个16位的sessionid
1 | let file = getFile(dir, id); |
file这里是先定义一个完整的路径
1 | function getFile(dir, id) { |
可以看到它把sessionid前4位拿出来作为了一个目录,path.join() 未拦截 ../ 等。导致带有目录穿越字符的输入能绕过存储目录约束。这里就可以知道为何可以目录穿越了吧
关于漏洞的总结:
- 只要是具有写的权限的目录下就可以任意文件写入
- 第一个是未使用签名,或者使用了签名但密钥泄露可以伪造,第二个就是构建路径的时候底层用的是
path.join(),这个本身是不会拦截../之类的东西。