flawopen.com/Teardowns/cve-2021-3156-sudo-baron-samedit

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

CVE-2021-3156: Переполнение кучи в Sudo Baron Samedit

Технический анализ Baron Samedit (CVE-2021-3156): как завершающий обратный слэш в аргументах sudo позволял любому локальному пользователю стать root.

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

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

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

бинарник setuid
Исполняемый файл, запускающийся с привилегиями владельца (root), а не вызывающего пользователя.
переполнение кучи
Запись за пределы выделенного участка памяти в куче (heap overflow).
локальное повышение привилегий
Получение полного контроля уровня root из обычной непривилегированной учетной записи.

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

Основная причина заключается в невалидированных граничных параметрах в системах с открытым исходным кодом, что приводит к рассинхронизации состояний и обходу средств безопасности.

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

Step 1

Trailing Backslash Injection

Unprivileged user executes 'sudoedit -s \', bypassing normal argument escaping flags.

Step 2

Unterminated Buffer Traversal

The unescape pointer jumps past the null byte delimiter into uninitialized heap memory.

Step 3

Heap Corruption of Service Structures

The heap overflow overwrites the sudo_nss service structure in glibc.

Step 4

Root Privilege Escalation

Sudo loads an attacker-controlled shared library (/tmp/libnss_x.so.2) as root, granting instant root shell access.

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

✕ УЯЗВИМАЯ РЕАЛИЗАЦИЯ
/* VULNERABLE: Unescape loop skips past string termination null byte */
for (to = user_args, from = NewArgv[0]; *from != '\0'; from++) {
    if (from[0] == '\\' && !isspace((unsigned char)from[1]))
        from++; /* BUG: If from[1] == '\0', loop skips past null terminator! */
    *to++ = *from;
}
*to = '\0'; /* Corrupts adjacent heap chunks with root auth structures */
✓ БЕЗОПАСНЫЙ ИСПРАВЛЕННЫЙ ВАРИАНТ
/* FIXED: Explicitly check that from[1] is neither space nor the null byte */
for (to = user_args, from = NewArgv[0]; *from != '\0'; from++) {
    if (from[0] == '\\' && from[1] != '\0' && !isspace((unsigned char)from[1]))
        from++;
    *to++ = *from;
}
*to = '\0';

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

References