
PoC и анализ локального переполнения буфера стека в dataSIMS Avionics ARINC 664-1 v4.5.3, с разбором полезной нагрузки, скриптом воспроизведения и исправлениями записей CVE.
Локальное переполнение буфера стека в dataSIMS Avionics ARINC 4.5.3 (Data Device Corporation)
Привет, я Kağan Çapar. В феврале 2020 года я нашёл локальное переполнение буфера стека в авиационном ПО dataSIMS для databus от DDC и в феврале 2021 года опубликовал proof of concept на Exploit-DB. Почти пять лет спустя, в январе 2026 года, VulnCheck присвоил ему CVE-2021-47881 как ретроактивный CVE — о присвоении я узнал постфактум, а не от них.
Этот репозиторий — архивная запись об этой находке: оригинальный PoC, сохранённый в том виде, в котором он был опубликован, байт-идентичный порт на Python 3, аннотированный разбор полезной нагрузки и исправления двух проблем в опубликованной записи CVE.
Сразу об объёме. Это запись, а не анализ первопричины. dataSIMS — это коммерческое ПО с закрытым исходным кодом, патча от вендора нет, и я не перепроверял это на текущем релизе. Что здесь можно проверить — проверено и показано; всё остальное отмечено в Ограничениях. Если вы пришли сюда в ожидании глубины CVE-2026-5201, сначала прочтите эту заметку.
| CVE | CVE-2021-47881 |
| CWE | CWE-121 — переполнение буфера на основе стека |
| CVSS v4.0 | 6.7 СРЕДНИЙ — AV:L/AC:L/AT:N/PR:N/UI:A/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N (VulnCheck) |
| CVSS v3.1 | 8.4 ВЫСОКИЙ — AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H (VulnCheck) |
| Затронуто | dataSIMS Avionics ARINC 664-1, версия 4.5.3 |
| Вендор | Data Device Corporation |
| CNA | VulnCheck |
| Обнаружено | 2020-02-17 |
| PoC опубликован | 2021-02-19 — EDB-49577 |
| CVE опубликован | 2026-01-23 (NVD) |
| Патч вендора | не опубликован |
| Протестировано на | Windows 10 Enterprise x64 |
Затронутый компонент — модуль ARINC 664-1 в dataSIMS 4.5.3. Он считывает файл результатов, который — несмотря на модуль, к которому он относится, — называется milstd1553result.txt; это имя — артефакт вендора, доставшийся от линии MIL-STD-1553 этого пакета, а не указание на то, какой модуль затронут. Подача чрезмерно длинной версии этого файла, сформированной атакующим, переполняет буфер стека фиксированного размера на пути чтения и перезаписывает сохранённый обратный адрес. Крах происходит при полном контроле над EIP:
EIP 42424242 <- 'BBBB' from the payload
ECX 42424242
C0000005 <- STATUS_ACCESS_VIOLATION
Опубликованный PoC имеет размер 1040 байт и останавливается на перезаписи EIP. Он не достигает выполнения кода и никогда не был для этого предназначен — см. Эксплуатируемость.
Раскладка полей PoC, проверенная запуском порта (py poc/poc_py3.py --layout):
| Поле | Смещение | Длина | Содержимое |
|---|---|---|---|
junk | 0 / 0x000 | 600 | заполнитель 0x41 |
align | 600 / 0x258 | 8 | "22221111" |
prop | 608 / 0x260 | 380 | заполнитель 0x43 |
imp | 988 / 0x3dc | 10 | "bzhrturlu2" |
imp2 | 998 / 0x3e6 | 9 | "aracag" 0x13 "1z" |
overwrite | 1007 / 0x3ef | 4 | 0x42 × 4 → сохранённый обратный адрес |
buf | 1011 / 0x3f3 | 29 | заглушка-декодер shikata_ga_nai |
| итого | 1040 | sha256 530efb5efef917082e40dcf379f5e0a526375724af18aba6f0270f794f96d066 |
Смещение до EIP — 1007. Это не число, которое вы получите от !mona findmsp или pattern_offset.rb, — это сумма пяти полей, настроенных вручную. Оригинальный PoC был собран путём расширения данных до тех пор, пока не сдвинулся обратный адрес, а не путём аналитического определения смещения. Я отмечаю это, а не приукрашиваю: аккуратный переписанный вариант нашёл бы истинное расстояние до сохранённого обратного адреса и полностью отбросил бы align, imp и imp2, поскольку ни одно из них не несёт смысла. imp/imp2 — это строки-заполнители, а не импорты.
buf — это 29-байтная заглушка shikata_ga_nai от msfvenom. Дизассемблировано с помощью ndisasm -b32:
00000000 DAC1 fcmovb st1 ; junk FPU op (sgn signature)
00000002 D97424F4 fnstenv [esp-0xc] ; GetPC
00000006 58 pop eax ; eax = &stub
00000007 BB0B7E9762 mov ebx,0x62977e0b ; XOR key
0000000C 33C9 xor ecx,ecx
0000000E B101 mov cl,0x1 ; <-- ONE 4-byte block
00000010 315819 xor [eax+0x19],ebx ; decode block at +0x19
00000013 83E8FC sub eax,-4 ; eax += 4
00000016 035815 add ebx,[eax+0x15] ; key schedule
00000019 E9 db 0xe9 ; <-- encoded block, not code
0000001A 8B db 0x8b
0000001C 7C9C jl 0xffffffb9
Из этого вытекают две вещи, и обе означают, что полезная нагрузка никогда не сможет выполниться:
mov cl,0x1 — цикл декодирования настроен на один 4-байтный блок. За ним нет реальной полезной нагрузки, только эти 4 байта.
Терминатор \xe2\xf4 (loop) отсутствует. Полная заглушка sgn завершает цикл декодирования инструкцией loop перед закодированным телом. Здесь выполнение падает прямо с add ebx,[eax+0x15] на E9 8B 7C 9C — которая в этот момент всё ещё закодирована и в любом случае не является валидной последовательностью инструкций.
Итак, заглушка — это заполнитель, занимающий хвост полезной нагрузки. Это соответствует тому, как PoC был описан на Exploit-DB, и это честное прочтение: это демонстрация контроля над EIP, а не рабочий эксплойт.
Оценивая это так, как это сделал бы брокер или вендор, а не так, как вектор CVSS v3.1:
Ни одна граница привилегий не пересекается. milstd1553result.txt — это файл, который создаёт само приложение, в месте, которым тот же пользователь уже управляет. Атакующий, способный перезаписать его, как правило, уже может выполнять код от имени этого пользователя. Это делает данную ошибку скорее ошибкой надёжности, чем ошибкой безопасности.
PoC не опережает время. Контроль над EIP в x86-сборке эпохи 2020 года сам по себе мало о чём говорит. Превращение его в выполнение кода требует истории с DEP/ASLR — модуля без /DYNAMICBASE, ROP-цепочки или частичной перезаписи. Ничего из этого не было сделано, и я не проверял, с какими механизмами смягчения поставляется текущая сборка.
Она локальна и требует, чтобы оператор загрузил файл. UI:A в CVSS v4.0 отражает реальность; UI:N в v3.1 — нет.
Если кто-то хочет сделать это по-настоящему интересным, продуктивные поверхности атаки — вовсе не этот файл: драйвер ядра, который DDC поставляет для своих PCIe-карт 1553/664 (обработка IOCTL → LPE), любой сетевой разбор кадров ARINC 664/AFDX и входные форматы файлов, которые пакет потребляет из недоверенных источников. Они пересекают реальные границы. Этот — нет.
В записи CVE есть два дефекта, о которых стоит сказать прямо, поскольку она опубликована под моим именем.
Обозначение продукта в записи — "dataSIMS Avionics ARINC 664-1 версия 4.5.3" — корректно. Затронутый компонент — модуль ARINC 664, как указано в моём оригинальном заголовке на Exploit-DB.
Дефект — в ссылке на вендора, которую прикрепил CNA. NVD ссылается на BU-69414, что является страницей программного продукта DDC MIL-STD-1553 — другого стека databus, не того, которого касается эта находка. ARINC 664 — это AFDX (профилированный коммутируемый Ethernet, ARINC 664 Part 7); MIL-STD-1553 — это двухрезервированная шина «команда/ответ» со скоростью 1 Мбит/с. Это несвязанные стандарты.
Вероятная причина неверной ссылки — имя файла результатов. dataSIMS называет файл результатов модуля ARINC 664 milstd1553result.txt — пережиток линии MIL-STD-1553 этого пакета. Любой, кто читает описание CVE и ищет подходящую страницу продукта вендора, проследует за этой строкой прямиком к линейке 1553 — что, судя по всему, и произошло. Имя файла не является доказательством затронутого модуля, и запись, указывающая на страницу продукта 1553, отправляет защитников аудитировать не тот компонент.
Оба вектора взяты от VulnCheck, и они противоречат друг другу в двух главных вещах:
| v3.1 (8.4 ВЫСОКИЙ) | v4.0 (6.7 СРЕДНИЙ) | |
|---|---|---|
| Взаимодействие с пользователем | UI:N — нет | UI:A — требуется |
| Влияние | C:H/I:H/A:H — полная CIA | VC:N/VI:N/VA:H — только доступность |
Оба не могут быть верными. Вектор v4.0 — тот, который можно защитить: PoC демонстрирует крах, а не раскрытие или потерю целостности. Оценка v3.1 в 8.4 преувеличивает находку, и я лучше скажу об этом здесь, чем буду извлекать из неё выгоду.
Здесь ничто не требует целевого ПО — PoC только записывает повреждённый файл. Для срабатывания переполнения требуется dataSIMS 4.5.3 — лицензионное коммерческое ПО, которое этот репозиторий не распространяет.
# print the field map, write nothing
py poc/poc_py3.py --layout
# write the 1040-byte payload
py poc/poc_py3.py -o milstd1553result.txt
Затем загрузите файл в затронутой сборке под отладчиком и наблюдайте перезапись EIP. poc/49577.py — это оригинальный исходник на Python 2, заархивированный дословно; на Python 3 он не запустится.
Порт создаёт байт-идентичный файл размером 1040 байт (sha256 530efb5e…). Три вещи пришлось изменить, и одна вещь, которая выглядит как баг, багом не является:
print len(win32) — это оператор (statement) в Python 2 и SyntaxError в Python 3.str с шеллкодом bytes. Python 2 позволял это, потому что str и был байтами; Python 3 вызывает TypeError.open(..., "w") должен стать "wb". В текстовом режиме Python 3 кодировал бы в UTF-8 каждый байт ≥ 0x80 в заглушке — 0xda → 0xc3 0x9a — незаметно повреждая полезную нагрузку и меняя её длину.imp2 = "\x61\x72\x61\x63\x61\x67\x131\x7a" — это не причуда, зависящая от версии. \x принимает ровно две шестнадцатеричные цифры и в Python 2, и в Python 3, поэтому \x131 — это 0x13, за которым следует символ 1. Поле занимает 9 байт в обоих случаях. Просто читается оно плохо.Изложено явно, чтобы никому не пришлось гадать, что было сделано, а что нет:
EIP — это весь результат.| Дата | Событие |
|---|---|
| 2020-02-17 | Уязвимость обнаружена |
| 2021-02-19 | Опубликован PoC — EDB-49577 |
| 2026-01-22 | Опубликовано уведомление VulnCheck |
| 2026-01-23 | CVE-2021-47881 опубликован в NVD |
| 2026-06-17 | Запись в NVD последний раз изменена |
Kağan Çapar — GitHub · Exploit-DB · LinkedIn · X
Разборы: Английский · Турецкий