
ProFTPD 1.3.9d - High - Remote - Crash - RewriteMap int:utf8trans BSS overflow
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · proftpd-rewrite-utf8trans
Class: Crash Reach: Remote
ProFTPD 1.3.9d (f59f248) - ProFTPD (proftpd.org)
contrib mod_rewrite ships RewriteMap int:utf8trans. That builtin copies a client FTP argument (up to CommandBufferSize, 512 KiB) into two 1024-slot BSS buffers with no dest cap. A long ASCII STOR name is an ASan global-buffer-overflow WRITE of size 8. The session child aborts. The daemon stays up. Class Crash. Not RCE.
| ID | no CVE yet |
| Class | Crash |
| Reach | Remote (FTP argument fed to int:utf8trans) |
| CWE | CWE-120 |
| CVSS | High: 7.5 CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H if the RewriteRule is pre-auth. The lab used STOR after login, so PR:L is honest for that run (AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H). |
| Product | ProFTPD |
| Affected | 1.3.9d (f59f248e26bdfa514443e42bf72a145641df635d) contrib mod_rewrite |
| Auth | lab is authenticated STOR. A pre-auth RewriteRule on USER or similar would be PR:N. |
| License | GNU Affero GPL v3.0 |
| Lab | 127.0.0.1 only |
RewriteEngine is off until configured. The documented pattern is RewriteRule (.*) ${map:$1}. Once a RewriteRule feeds the client argument through int:utf8trans, a key longer than 1024 bytes overflows two static buffers in the session child.
| Method | Sink | Privilege |
|---|---|---|
| FTP command whose arg is the utf8trans map key, length > 1024 | rewrite_utf8_to_ucs4 then utf8_val[i] = ucs4_longs[i] | Availability (lab-proven): crash the session child. ASan: global-buffer-overflow WRITE of size 8, then ABORTING. Prefork: a fresh login still worked; the daemon stayed up. A short STOR of 200 ASCII bytes survived. Nearby rewrite BSS integrity is inferred and compiler-layout dependent. |
| RIP / code execution | none claimed | Closed. No payload. Class Crash. Not RCE. |
.ftpaccess plant of RewriteMap | CONF_DYNDIR | Closed. RewriteMap is not allowed in .ftpaccess. |
prg: shell | no such map type | Closed. FIFO is line I/O. |
Lab-proven vs inferred: ASan WRITE of size 8, session-child abort, surviving short-arg control, and post-trigger login are lab-proven. RIP/RCE is not claimed.
Issue 2173 patched int:unescape one-byte OOB on this pin. This leftover is int:utf8trans. Different builtin. Different bug.
I pinned proftpd/proftpd tag v1.3.9d. The 2026 CVE crop and the public GitHub issues still sitting in that tarball (2170, 2173, 2175, 2180, 2095, 2256, 2286, 2319, 2330, 2301) were the skip list. Default core FTP with sample basic.conf did not give me an unpublished Crit/High. Contrib rewrite did.
rewrite_map_int_utf8trans (contrib/mod_rewrite.c) has:
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 writes one unsigned long per ASCII byte with no cap. PR_TUNABLE_CMD_BUFFER_SIZE is 512 KiB. Issue 2173 already fixed unescape. This map was not in that fix.
Wrong turns: treating 2173 as this bug; claiming RIP because ASan said WRITE of size 8; hoping .ftpaccess could plant RewriteMap. The first is a different function. The second is still Crash. The third is CONF_DYNDIR.
ASan plus stock libcrypt SIGSEGVs on PASS before the rewrite sink. The lab preloads a tiny crypt(3) stub so login works. That stub is not an exploit.
python3 proftpd-rewrite-utf8trans-Abraxas-Labs.py
or:
cd lab
./run.sh
Loopback 127.0.0.1:18740 plus passive 18741-18750. Compose project proftpd-rewrite-utf8trans. Witness PROFTPD-REWRITE-UTF8TRANS-WITNESS. Image is an ASan build of 1.3.9d mod_rewrite. Control STOR of 200 ASCII bytes succeeds. STOR of 2048 ASCII bytes is ASan global-buffer-overflow WRITE of size 8 and the session child aborts. Fresh login after the trigger still works.
SUCCESS PROFTPD-REWRITE-UTF8TRANS asan=global-buffer-overflow write=yes child-dead=yes PROFTPD-REWRITE-UTF8TRANS-WITNESS
Cap rewrite_utf8_to_ucs4 dest length to PR_TUNABLE_BUFFER_SIZE-1. Stop writing past ucs4_longs / utf8_val. Reject or truncate a map key that does not fit.
f59f248e26bdfa514443e42bf72a145641df635d)contrib/mod_rewrite.c rewrite_utf8_to_ucs4 / rewrite_map_int_utf8transint:unescapeGNU Affero GPL v3.0. See LICENSE. Loopback lab only. No warranty.