FlawOpen

flawopen.com/Teardowns/cve-2024-33066-qualcomm-wlan-log-redirection

● CVE-2024-33066 · CVSS 9.8 · Критический
Исследования · FlawOpen

CVE-2024-33066: уязвимость перенаправления WLAN-логов

CVE-2024-33066 повреждает память, если WLAN Resource Manager Qualcomm перенаправляет журнал по выбранному пути. Исправлена в октябре 2024 года.

💡 Простыми словами (ELI5)

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

Ключевые понятия и термины

WLAN Resource Manager
Компонент Wi-Fi, названный в бюллетене Qualcomm о CVE-2024-33066. Он работает на сетевых платформах Qualcomm, которые используются в маршрутизаторах, mesh-системах и точках доступа.
Чипсеты IPQ / QCN
Семейства сетевых Wi-Fi-систем на кристалле от Qualcomm. В список затронутых входят IPQ5332, IPQ8074A, IPQ9574, QCN9000 и платформы Immersive Home, а не чипы для телефонов.
CWE-20
Некорректная проверка входных данных: программа доверяет вводу, не проверяя, обладает ли он свойствами, на которые опирается код, например максимальной длиной или допустимым каталогом.
Открытие относительно каталога
Открытие файла через openat() относительно дескриптора каталога и по простому имени без '/', чтобы результат не мог оказаться за пределами этого каталога.
Вектор CVSS 3.1
AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H: доступна по сети, низкая сложность, не нужны привилегии и действия пользователя, высокое влияние на все три свойства (оценка 9.8).

Связи со стандартами

  • Ссылка CWE для слабого места, описанного в этом руководстве: CWE-20

Анализ первопричины

В бюллетене Qualcomm сказано лишь, что в WLAN Resource Manager происходило повреждение памяти "while redirecting log file to any file location with any file name" (CWE-20). Место назначения из запроса на перенаправление журнала использовалось без проверки его длины и того, куда оно указывает. Код ниже моделирует этот пробел в проверке ввода; он иллюстративный и не является исходным кодом Qualcomm.

Пошаговый сценарий атаки

Шаг 1

1. Приходит запрос на перенаправление журнала

WLAN Resource Manager принимает запрос отправлять вывод журнала в другое место. Вектор CVSS (AV:N/PR:N/UI:N) оценивает уязвимость как доступную по сети без привилегий и без участия пользователя.

Шаг 2

2. Принимается любое место и любое имя

Согласно описанию Qualcomm, перенаправление работало в любое место и с любым именем файла: запрошенное место назначения не проверялось ни по длине, ни по тому, куда оно указывает.

Шаг 3

3. Непроверенный ввод повреждает память

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

Шаг 4

4. Последствия и статус

CVSS 3.1 оценивает влияние на конфиденциальность, целостность и доступность как высокое (9.8). Qualcomm передала исправление производителям в бюллетене за октябрь 2024 года; по оценке CISA, известных случаев эксплуатации нет.

Исходный код: Уязвимый vs Защищённый вариант

Иллюстративная модель класса уязвимостей, а не код Qualcomm. Защищённый обработчик ограничивает ввод через strnlen до его использования, принимает только короткое имя из фиксированного набора символов (без '/' и без ведущей '.') и открывает его через openat() относительно каталога журналов, выбранного при запуске, с флагом O_NOFOLLOW, чтобы подложенная символическая ссылка не перенаправила запись. Вызывающая сторона может выбрать имя файла, но не его место, а слишком длинный ввод отклоняется, а не копируется.

УЯЗВИМАЯ РЕАЛИЗАЦИЯ
#include <fcntl.h>
#include <string.h>

#define LOG_PATH_MAX 64

struct rm_log_cfg {
    char path[LOG_PATH_MAX];
    int fd;
};

/* Обрабатывает запрос на перенаправление журнала; `requested` берётся из тела запроса. */
int rm_set_log_destination(struct rm_log_cfg *cfg, const char *requested)
{
    strcpy(cfg->path, requested);   /* нет проверки длины: длинный ввод выходит за границы path[] */
    cfg->fd = open(cfg->path, O_WRONLY | O_CREAT | O_APPEND, 0644);  /* любое расположение */
    return cfg->fd < 0 ? -1 : 0;
}
БЕЗОПАСНЫЙ ИСПРАВЛЕННЫЙ ВАРИАНТ
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>

#define LOG_NAME_MAX 32

struct rm_log_cfg {
    int dir_fd;                /* фиксированный каталог журналов, открываемый один раз при запуске */
    char name[LOG_NAME_MAX];
    int fd;
};

static int valid_log_name(const char *name, size_t len)
{
    if (len == 0 || len >= LOG_NAME_MAX || name[0] == '.')
        return 0;
    for (size_t i = 0; i < len; i++) {
        char c = name[i];
        int ok = (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') ||
                 c == '-' || c == '_' || c == '.';
        if (!ok)
            return 0;          /* отклоняет '/', поэтому имя не может выйти за пределы dir_fd */
    }
    return 1;
}

int rm_set_log_destination(struct rm_log_cfg *cfg, const char *requested)
{
    size_t len = strnlen(requested, LOG_NAME_MAX);
    if (!valid_log_name(requested, len))
        return -EINVAL;

    int fd = openat(cfg->dir_fd, requested,
                    O_WRONLY | O_CREAT | O_APPEND | O_NOFOLLOW | O_CLOEXEC, 0600);
    if (fd < 0)
        return -errno;

    memcpy(cfg->name, requested, len + 1);
    if (cfg->fd >= 0)
        close(cfg->fd);
    cfg->fd = fd;
    return 0;
}

Чек-лист по защите системы для инженеров

Источники