РАЗБОР На проверке 

CVE-2026-6643: Stack Overflow в VPN ASUSTOR ADM

Сергей Попов
Сергей Попов Red Team · 6,4 тыс. сообщений
Подписаться
46
Режим чтения
Вид сверху на разобранную плату NAS ASUSTOR на антистатическом коврике: руки в перчатках держат её под резким верхним светом, JTAG-зонд подключён к чипу ARM, рядом на экране ноутбука виден дизассем...


На прошлой неделе вытащил vpnupload.cgi из прошивки ASUSTOR ADM 5.1.2 через binwalk и загрузил в Ghidra. Хэндлер upload_wireguard парсит восемь полей WireGuard-конфига через sscanf("%s"), семь из них копируются в 300-байтовые стековые буферы без ограничения длины. checksec выдал ожидаемое: ни PIE, ни stack canary, ни FORTIFY_SOURCE. CVE-2026-6643 с CVSS 8.6 (HIGH по NVD) - тот случай, когда stack buffer overflow эксплуатация в VPN-клиенте ASUSTOR ADM сводится к подсчёту офсетов и одному HTTP-запросу с payload в поле Endpoint.

Уязвимость ASUSTOR ADM в VPN-клиенте: два бага в vpnupload.cgi​

CVE-2026-6643 обнаружена в VPN Clients компоненте ADM. При реверсе прошивки уязвимый код нашёлся в /portal/apis/settings/vpnupload.cgi - конкретно в обработчике upload_wireguard, который отвечает за загрузку WireGuard-конфигурации на NAS.

Для атаки нужна аутентифицированная сессия - валидная cookie Revive_Session. CVSS 4.0 вектор фиксирует это через PR:H (High Privileges Required). Остальные параметры: AV:N (сетевой доступ), AC:L (низкая сложность), UI:N (действия пользователя не требуются). Impact на уязвимую систему - VC:H/VI:H/VA:H, полная компрометация конфиденциальности, целостности и доступности. Subsequent impact на соседние системы - SC:L/SI:L/SA:L. Аутентификация на NAS - барьер формальный: дефолтные пароли, слабые учётки, перехваченные сессии через MITM на локалке.

Зачем атакующему NAS? Там бэкапы, файловые шары, персональные данные. Компрометация NAS - прямой путь к ransomware-шифрованию резервных копий или эксфильтрации корпоративных данных. Короче, jackpot.

По NVD уязвимость типизирована как CWE-121 (Stack-based Buffer Overflow). В том же хэндлере предположительно сидит второй баг - CWE-134 (Use of Externally-Controlled Format String). Описание NVD упоминает «passing user-controlled data directly to printf()», но формальная CWE-запись NVD для CVE-2026-6643 включает только CWE-121. CWE-134 - наша интерпретация на основе описания NVD, а не официальная классификация. Два бага работают в связке: format string vulnerability (CWE-134, выявлен при анализе, не указан в NVD) даёт информационную утечку для вычисления libc base, а переполнение буфера VPN-клиента (CWE-121) - перезапись return address.

Format string vulnerability в printf() - CWE-134​

Хэндлер разбирает WireGuard-конфиг, собирает поля в JSON и результат передаёт напрямую как format string в printf():
C:
pcVar2 = (char *)Json_To_String(uVar1);
printf(pcVar2);                                      // CWE-134: user data as format string
__isoc23_sscanf(__s, "PrivateKey = %s", local_ac4);  // CWE-121: 300B buffer, no limit
__isoc23_sscanf(__s, "Endpoint = %s",   local_164);  // CWE-121: 300B buffer, no limit
// всего 8 полей; ограничение длины - только у DNS
FORTIFY_SOURCE выключен, компилятор подставляет обычный printf, а не [I]_printf_chk - спецификатор %n для записи в произвольный адрес памяти работает без ограничений. Через %x и %p атакующий встраивает format-спецификаторы в любое поле конфига (например, PrivateKey = AAAA[/I]%08x_%08x_%08x_%08x) и в ответе сервера получает дамп стековой памяти: AAAA_feebd19f_0000012b_0000007d_00000002. Среди утёкших значений - указатели из libc, необходимые для вычисления base address и сборки ROP-цепочки.

Переполнение буфера через sscanf overflow - CWE-121​

Тот же хэндлер парсит строки конфига через sscanf с неограниченным %s. fgets принимает до 32 768 байт на строку, а целевой стековый буфер - 300 байт. Из восьми полей WireGuard-конфига ограничение длины реализовано только для DNS. Семь остальных - прямая sscanf overflow уязвимость.

При подаче 4 000 байт в любое из уязвимых полей sscanf пишет далеко за пределы 300-байтового буфера, затирая соседние локальные переменные, saved RBP и saved RIP. Процесс падает с SIGSEGV (exit code 139). Подача PrivateKey длиной 4 000 символов приводит к контролируемому крашу - проверяется элементарно. Стандартный memory corruption exploit через переполнение стека, который в этом бинарнике не встречает ни одного препятствия.

Эксплуатация без PIE и Stack Canary: разбор защит бинарника​

Отсутствие exploit mitigations - тот самый фактор, который превращает CVE-2026-6643 из теоретической уязвимости в практический RCE за один вечер. Результат checksec для vpnupload.cgi:

ЗащитаСтатусЧто это значит для атакующего
PIEВыключенАдреса GOT и ROP-гаджетов статичны между запусками
Stack CanaryВыключенreturn address overwrite не вызывает __stack_chk_fail
FORTIFY_SOURCEВыключенprintf вместо __printf_chk - %n работает
RELROPartialGOT writable - вектор для GOT overwrite через %n

Без PIE атакующему не нужно утекать base address бинарника - все гаджеты внутри vpnupload.cgi лежат по фиксированным адресам. Без stack canary нет рантайм-детекции повреждения стека: функция выполнит ret на подменённый адрес без единой проверки. Partial RELRO сохраняет GOT writable, что в комбинации с format string и спецификатором %n открывает альтернативный вектор - GOT overwrite вместо stack overflow (или в дополнение к нему).

Для NAS security уязвимости подобного класса - норма, а не исключение. Тулчейны сборки прошивок SOHO-устройств часто не включают -fstack-protector-all, -pie, -D_FORTIFY_SOURCE=2. Результат - binary exploitation techniques из учебных CTF работают на продакшн-железе без модификации. Прямо как в лабе, только данные настоящие.

Stack layout: цель для return address overwrite (гипотетическая реконструкция)​

Из восьми стековых буферов поле Endpoint (local_164) предположительно расположено ближе всего к saved RBP/RIP. Гипотетическая реконструкция stack layout на основе типичной компиляции подобного кода:

Поле конфигаБуферПозицияДо saved RIP
PrivateKeylocal_ac4rbp-0xac42 756 байт
Addresslocal_998rbp-0x9982 456 байт
PublicKeylocal_86crbp-0x86c2 156 байт
ListenPortlocal_740rbp-0x7401 856 байт
PresharedKeylocal_4e8rbp-0x4e81 256 байт
AllowedIPslocal_3bcrbp-0x3bc956 байт
PersistentKeepalivelocal_290rbp-0x290656 байт
Endpointlocal_164rbp-0x164364 байта

Предположительно: 300 байт буфера + 56 байт промежуток до saved RBP + 8 байт RBP = 364 байта от начала local_164 до saved RIP (точные значения зависят от конкретной сборки). Переполнение через Endpoint - оптимальный вектор: минимальный padding, один запрос. PrivateKey (local_ac4) тоже переполняется, но потребуется ~2 756 байт padding - больше шансов задеть побочные данные и словить нештатный краш до перезаписи RIP.

Цепочка эксплуатации CVE-2026-6643: от format string до RCE​

📚 Часть контента скрыта. Этот материал доступен участникам сообщества с рангом One Level или выше
Получить доступ просто — достаточно зарегистрироваться и проявить активность на форуме

копирует payload целиком через границу local_164 прямо в saved RIP. Гипотетический запуск: exploit.py <target> --stage rce --libc-base 0x7f... (сначала пробуется one_gadget, при неудаче - fallback на pop rdi + system()). Конкретный PoC-скрипт публично не доступен.

Шаг 4 - выполнение команд. После перехвата control flow атакующий получает шелл от имени пользователя web-сервера. Гипотетически: exploit.py <target> --stage shell --cmd 'id' (скрипт приведён для иллюстрации методологии). По MITRE ATT&CK цепочка покрывает Exploit Public-Facing Application (T1190, Initial Access) → Exploitation for Client Execution (T1203, Execution). При наличии дополнительных уязвимостей - Exploitation for Privilege Escalation (T1068).

Обход null-байтов при stack buffer overflow​

sscanf("%s") прекращает копирование на null-байте. Адрес libc 0x00007f1234567890 в little-endian содержит два замыкающих \x00: запись \x90\x78\x56\x34\x12\x7f - и sscanf останавливается. Но верхние два байта saved RIP уже равны \x00\x00 - sscanf записывает шесть значимых байт и завершает работу ровно там, где нужно. Результат корректен без дополнительных манипуляций.

Ограничение: промежуточные ROP-гаджеты обязаны лежать в диапазоне libc (0x7f...), чтобы ни один адрес в середине цепочки не содержал embedded null-байт. Только финальный адрес может заканчиваться нулями - sscanf остановится после его записи, но это уже последний элемент. Гаджеты из самого vpnupload.cgi (PIE отсутствие защиты делает их адреса статичными, но они начинаются с 0x00000000004...) непригодны именно из-за ведущих null-байтов.

Пентест NAS устройств: воспроизведение CVE-2026-6643​

Для воспроизведения нужна прошивка X64_G3_5.1.2.REO1.img. Бинарник vpnupload.cgi извлекается через binwalk -e из образа. Для запуска вне устройства - ld-linux и shared libraries прямо из прошивки. Стандартный подход для NAS security исследований, когда физического устройства нет под рукой.

Офсеты libc извлекаются из libc.so.6 прошивки стандартными утилитами:
Bash:
readelf -s libc.so.6 | grep -w system        # offset system()
strings -a -t x libc.so.6 | grep '/bin/sh'   # offset строки /bin/sh
one_gadget libc.so.6                          # magic gadgets для execve
Конкретные офсеты зависят от сборки libc в прошивке - получаются через эти же команды. Для другой версии ADM значения будут отличаться.

Индикаторы компрометации. В логах web-сервера ADM: аномально длинные значения полей WireGuard-конфига (>300 символов), format-спецификаторы (%x, %p, %n) в полях конфига. На уровне ОС: неожиданные SIGSEGV процесса на портах 8000/8001, нетипичные исходящие сетевые соединения с NAS после взаимодействия с VPN-эндпоинтом.

EPSS и контекст. EPSS для CVE-2026-6643 - 0.0047 (percentile 0.39, ниже медианы). CISA SSVC: Track - эксплуатация в дикой природе не зафиксирована (exploitation: none), автоматизация невозможна (automatable: no), технический impact - total. Низкий EPSS при наличии публичного PoC и полной документации цепочки - состояние временное.

Митигация. Обновление ADM до версии из Security Advisory AS-2026-005. Если обновление невозможно - отключить VPN Clients в ADM, ограничить сетевой доступ к web-интерфейсу (порты 8000/8001) до доверенных подсетей через iptables, включить 2FA для ADM-административного доступа.

CVE-2026-6643 - не сложный баг. Два десятка лет CWE-121 (и связанный CWE-134, выявляемый при анализе подобного кода) в TOP-25 Most Dangerous Software Weaknesses, а вендоры NAS продолжают компилировать CGI-хэндлеры без базовых защит. В 2026 году x86-64 бинарник без PIE, без stack canary, без FORTIFY_SOURCE, с writable GOT - это не legacy. Это осознанный выбор не тратить ресурсы на security hardening тулчейна. Меняются номера версий ADM, Makefile остаётся прежним.

Что тут по-настоящему интересно - комбинация format string + stack overflow в одном хэндлере. CWE-134 (обнаружен при анализе кода, не указан в NVD) даёт info leak для обхода ASLR libc, CWE-121 (официальная классификация NVD) даёт return address overwrite. Два бага, каждый medium-severity по отдельности, вместе дают чистое RCE. ASUSTOR выпустит патч: заменит printf(pcVar2) на printf("%s", pcVar2) и добавит %299s в sscanf. Но без -fstack-protector-all -pie -D_FORTIFY_SOURCE=2 в pipeline сборки прошивки следующий CGI-хэндлер - fileexplorer.cgi, mediaserver.cgi, любой другой - будет ломаться тем же способом. Это не прогноз, а закономерность: ASUSTOR Security Advisory AS-2026-020 (ADM File Explorer) описывает структурно аналогичную уязвимость в соседнем компоненте. Вытащите fileexplorer.cgi из той же прошивки и прогоните через checksec - готов поспорить, картина будет один в один.
Полезно

Комментарии

0