
Análise técnica do CVE-2026-52885: uma condição de corrida TOCTOU no Notepad++ v8.9.6.2 que permite execução arbitrária de comandos por meio de bypass de integridade HMAC. Inclui causa raiz, cenário de ataque, PoC e análise de patch.
Notepad++ v8.9.6.2 — Execução de UserCommand Controlada pelo Atacante via Condição de Corrida no HMAC
| GHSA | GHSA-qm4c-qg8p-qfcr |
| CVE | CVE-2026-52885 |
| Gravidade | Alta |
| Afetado | v8.9.6.2 |
| Corrigido | v8.9.6.4 |
| Commit do Patch | 4f7563c |
| Arquivo Afetado | PowerEditor/src/NppCommands.cpp :4328–4359 |
| Plataforma | Windows 11 Pro x64 |
| Privilégio Necessário | Usuário padrão (acesso de escrita ao shortcuts.xml) |
| Pesquisador | v3s9er |
| Divulgado | 2026-06-05 |
O Notepad++ v8.9.6.2 introduziu uma verificação de integridade HMAC-SHA256 no shortcuts.xml para impedir a injeção de entradas arbitrárias de UserCommand.
A verificação apresenta uma falha de TOCTOU: o HMAC é verificado contra o arquivo em disco no momento do acionamento, mas o comando que é executado é lido do vetor _userCommands em memória carregado na inicialização. Essas duas fontes nunca são ressincronizadas.
Um atacante que possa gravar no shortcuts.xml pode plantar um comando malicioso antes da inicialização, deixar o Notepad++ carregá-lo na memória, restaurar o arquivo legítimo no disco e então acionar o comando. A verificação HMAC é aprovada (o disco está limpo), mas a carga maliciosa é executada (a memória está desatualizada).
O mecanismo de integridade valida o shortcuts.xml atual em disco, enquanto a execução de comandos usa uma representação em memória carregada anteriormente. Como as duas fontes de dados são independentes, um atacante pode alterar o arquivo antes da inicialização, permitir que ele seja parseado na memória e restaurar o arquivo original antes da execução do comando — fazendo com que a verificação HMAC seja aprovada enquanto a carga maliciosa é executada.
NppCommands.cpp linhas 4328–4359:
// TIME OF CHECK — reads on-disk file
std::string currentHMAC = computeHMAC(
getMachineGUID(),
getFileContent(nppParams.getShortcutsPath().c_str())
);
if (currentHMAC != nppGUI._shortcutsXmlHmacInConfig) { return; }
// validated against DISK
// TIME OF USE — reads in-memory vector (loaded at startup, never refreshed)
int i = id - ID_USER_CMD;
const vector<UserCommand>& cmds = nppParams.getUserCommandList();
UserCommand ucmd = cmds[i];
Command cmd(string2wstring(ucmd.getCmd(), CP_UTF8));
cmd.run(_pPublicInterface->getHSelf()); // executes payload from MEMORY
| Operação | Origem | Momento |
|---|---|---|
| VERIFICAÇÃO (HMAC) | Arquivo em disco | No momento do acionamento |
| USO (exec) | Vetor em memória | Carregado na inicialização |
| LACUNA | Controlado pelo atacante | Inicialização → Acionamento |
Pré-condição: acesso de escrita ao shortcuts.xml
notepad++.exe%AppData%\Notepad++\Passos:
shortcuts.xml em disco com uma versão maliciosa (cmd = calc.exe)_userCommands é preenchido a partir do arquivo maliciososhortcuts.xml legítimo para o disco — o HMAC agora corresponde ao config.xmlWM_COMMAND(21000) (ID_USER_CMD+0) ou pressione Ctrl+Alt+P_userCommands[0] da memória → calc.exe é executadoResultado: execução de comandos controlados pelo atacante sob os privilégios do usuário atual. Sem admin, sem UAC, sem aviso ao usuário.
| Tempo | Evento | Estado |
|---|---|---|
| T+0.0s | Atacante escreve shortcuts.xml MALICIOSO | disco=MALICIOSO |
| T+0.0s | Atacante inicia o Notepad++ | disco=MALICIOSO |
| T+0.1s | Notepad++ lê shortcuts.xml → _userCommands[0]="calc.exe" | mem=MALICIOSO |
| T+4.2s | Notepad++ totalmente carregado | mem=MALICIOSO |
| T+4.2s | Atacante restaura o shortcuts.xml LEGÍTIMO | disco=LEGÍTIMO / mem=MAL |
| T+4.7s | Atacante envia WM_COMMAND(21000) | |
| T+4.7s | Verificação HMAC: lê arquivo LEGÍTIMO do disco → APROVADA | VERIFICAÇÃO OK |
| T+4.7s | Exec: lê _userCommands[0] da MEMÓRIA → calc.exe | EXPLORAÇÃO |
| T+4.7s | calc.exe iniciado (PID 35932) | CONFIRMADO |
| Tipo | Execução Arbitrária de Comandos |
| Admin Necessário | Não |
| Solicitação UAC | Não |
| Detectabilidade | Baixa — o disco exibe o arquivo legítimo durante todo o processo; a carga útil está apenas em memória |
| CVSS (estimado) | AV:L / AC:H / PR:L / UI:N / S:U / C:H / I:H / A:H |
Veja poc_8962_toctou.ps1.
Requisitos:
doLocalConf.xml presente no diretório do Notepad++ (modo portátil)config.xml com um HMAC válido para o shortcuts.xml legítimo.\poc_8962_toctou.ps1 -NppPath "C:\path\to\notepad++.exe"
Verificado: calc.exe iniciado (PID 35932), o disco exibe o shortcuts.xml legítimo durante todo o processo.
A correção (commit 4f7563c) move a validação HMAC para a inicialização, junto com o parse inicial do arquivo. A verificação e o uso agora operam no mesmo objeto ao mesmo tempo, eliminando a janela de TOCTOU.
| v8.9.6.2 (vulnerável) | v8.9.6.4 (corrigido) | |
|---|---|---|
| Verificação HMAC | No acionamento, relê o disco | Na inicialização, mesmos bytes do parse |
| Origem do comando | Memória carregada na inicialização | Memória validada na inicialização |
| Janela TOCTOU | Inicialização → Acionamento | Eliminada |