
ProFTPD 1.3.9d - Alta - Remoto - Crash - RewriteMap int:utf8trans estouro de BSS
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · proftpd-rewrite-utf8trans
Write-up: https://abraxaslabs.tech/research/proftpd-rewrite-utf8trans
Classe: Crash Alcance: Remoto
ProFTPD 1.3.9d (f59f248) - ProFTPD (proftpd.org)
O contrib mod_rewrite inclui RewriteMap int:utf8trans. Esse builtin copia um argumento FTP do cliente (até CommandBufferSize, 512 KiB) para dois buffers BSS de 1024 slots sem limite de destino. Um nome STOR ASCII longo gera um WRITE de global-buffer-overflow no ASan de tamanho 8. O processo filho da sessão aborta. O daemon permanece ativo. Classe Crash. Não é RCE.
| ID | sem CVE ainda |
| Classe | Crash |
| Alcance | Remoto (argumento FTP enviado para int:utf8trans) |
| CWE | CWE-120 |
| CVSS | Alto: 7.5 CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H se a RewriteRule for pré-autenticação. O laboratório usou STOR após login, então PR:L é honesto para essa execução (AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H). |
| Produto | ProFTPD |
| Afetado | 1.3.9d (f59f248e26bdfa514443e42bf72a145641df635d) contrib mod_rewrite |
| Autenticação | o laboratório usa STOR autenticado. Uma RewriteRule pré-autenticação em USER ou similar seria PR:N. |
| Licença | GNU Affero GPL v3.0 |
| Laboratório | apenas 127.0.0.1 |
RewriteEngine fica desativado até ser configurado. O padrão documentado é RewriteRule (.*) ${map:$1}. Uma vez que uma RewriteRule encaminha o argumento do cliente através de int:utf8trans, uma chave maior que 1024 bytes transborda dois buffers estáticos no processo filho da sessão.
| Método | Sink | Privilégio |
|---|---|---|
| Comando FTP cujo argumento é a chave do mapa utf8trans, comprimento > 1024 | rewrite_utf8_to_ucs4 e então utf8_val[i] = ucs4_longs[i] | Disponibilidade (comprovado em laboratório): derruba o processo filho da sessão. ASan: global-buffer-overflow WRITE of size 8, seguido de ABORTING. Prefork: um novo login ainda funcionou; o daemon permaneceu ativo. Um STOR curto de 200 bytes ASCII sobreviveu. A integridade do BSS de rewrite nas proximidades é inferida e depende do layout do compilador. |
| RIP / execução de código | nada alegado | Fechado. Sem payload. Classe Crash. Não é RCE. |
Plantio de RewriteMap em .ftpaccess | CONF_DYNDIR | Fechado. RewriteMap não é permitido em .ftpaccess. |
Shell prg: | não existe esse tipo de mapa | Fechado. FIFO é I/O por linha. |
Comprovado em laboratório vs inferido: o WRITE do ASan de tamanho 8, o aborto do processo filho da sessão, o controle com argumento curto sobrevivente e o login pós-disparo são comprovados em laboratório. RIP/RCE não é alegado.
A Issue 2173 corrigiu o OOB de um byte em int:unescape neste pin. Este resíduo é int:utf8trans. Builtin diferente. Bug diferente.
Eu fixei a tag v1.3.9d de proftpd/proftpd. A safra de CVEs de 2026 e as issues públicas do GitHub ainda presentes nesse tarball (2170, 2173, 2175, 2180, 2095, 2256, 2286, 2319, 2330, 2301) foram a lista de exclusão. O FTP core padrão com o basic.conf de exemplo não me deu um Crit/High não publicado. O contrib rewrite deu.
rewrite_map_int_utf8trans (contrib/mod_rewrite.c) tem:
static unsigned char utf8_val[PR_TUNABLE_BUFFER_SIZE]; /* 1024 */
static unsigned long ucs4_longs[PR_TUNABLE_BUFFER_SIZE]; /* 1024 */
ucs4strlen = rewrite_utf8_to_ucs4(ucs4_longs, strlen(key), (unsigned char *) key);
rewrite_utf8_to_ucs4 grava um unsigned long por byte ASCII sem limite. PR_TUNABLE_CMD_BUFFER_SIZE é 512 KiB. A issue 2173 já corrigiu o unescape. Este map não estava nessa correção.
Caminhos errados: tratar a 2173 como este bug; alegar RIP porque o ASan indicou WRITE de tamanho 8; esperar que .ftpaccess pudesse plantar um RewriteMap. O primeiro é uma função diferente. O segundo ainda é Crash. O terceiro é CONF_DYNDIR.
ASan mais a libcrypt padrão causam SIGSEGV em PASS antes do sink de rewrite. O laboratório pré-carrega um pequeno stub de crypt(3) para que o login funcione. Esse stub não é um exploit.
python3 proftpd-rewrite-utf8trans-Abraxas-Labs.py
ou:
cd lab
./run.sh
Loopback 127.0.0.1:18740 mais passivo 18741-18750. Projeto Compose proftpd-rewrite-utf8trans. Witness PROFTPD-REWRITE-UTF8TRANS-WITNESS. A imagem é uma build ASan do mod_rewrite do 1.3.9d. O STOR de controle de 200 bytes ASCII é bem-sucedido. O STOR de 2048 bytes ASCII é um global-buffer-overflow WRITE de tamanho 8 do ASan e o processo filho da sessão aborta. Um novo login após o gatilho ainda funciona.
SUCCESS PROFTPD-REWRITE-UTF8TRANS asan=global-buffer-overflow write=yes child-dead=yes PROFTPD-REWRITE-UTF8TRANS-WITNESS
Limitar o comprimento de destino de rewrite_utf8_to_ucs4 para PR_TUNABLE_BUFFER_SIZE-1. Parar de escrever além de ucs4_longs / utf8_val. Rejeitar ou truncar uma chave de mapa que não caiba.
f59f248e26bdfa514443e42bf72a145641df635d)contrib/mod_rewrite.c rewrite_utf8_to_ucs4 / rewrite_map_int_utf8transint:unescapeGNU Affero GPL v3.0. Consulte LICENSE. Apenas laboratório loopback. Sem garantia.