
Prova de conceito de exploit para CVE-2026-6471, demonstrando escalonamento de privilégios no PostgreSQL via dlopen de decodificação lógica para alcançar execução arbitrária de código e backdoor de superusuário.
A decodificação lógica do PostgreSQL permite que uma função não-superusuário que possua o
privilégio REPLICATION crie um slot de replicação lógica e escolha o
plugin de saída. Nas versões afetadas não há verificação de autorização nessa
escolha, então o servidor executa dlopen() no que quer que o nome do plugin aponte. Nomear
um caminho de biblioteca executa o código dessa biblioteca dentro do backend do postgres, como a
conta do sistema operacional que executa o servidor. Isso é execução arbitrária de código
como o usuário do SO do servidor de banco de dados, o que para um banco que contém os
dados da aplicação é efetivamente uma tomada de controle do servidor.
Corrigido no PostgreSQL 18.6, 17.11, 16.15, 15.19 e 14.24 pela
lista de permissões output_plugin_libraries (padrão pgoutput, test_decoding).
Qualquer coisa que não esteja nessa lista agora gera erro com library "X" may not be used as an output plugin antes de qualquer dlopen.
Execute os mesmos passos contra ambas as builds e apenas a versão do PostgreSQL muda. Uma conta de baixo privilégio (LOGIN + REPLICATION, não superusuário, sem acesso ao SO) faz o que um assinante normal de decodificação lógica faz e então pede ao servidor para carregar uma biblioteca arbitrária como o plugin de saída. Na build vulnerável, essa biblioteca é executada como o usuário postgres do SO e planta uma função backdoor superusuária persistente, então uma conta somente de replicação termina a execução com um login superusuário funcional.
cve-2026-6471-postgres-logical-decoding-dlopen.txt é uma solução Exploitmatic
(.txt): dados mais asserções, sem código. O runtime a reproduz contra
a máquina. A solução entrega pwn.so em tempo de execução (base64 no arquivo),
conduz o SQL como a função de replicação de baixo privilégio e então faz login como a
função backdoor superusuária que o payload plantou.pwn.c é o código-fonte da biblioteca do payload e pwn.so sua build: um único
construtor ELF que é executado como o usuário postgres do SO, conecta-se pelo
socket local como o superusuário do banco (peer/trust) e cria a função
persistente cve6471_backdoor LOGIN SUPERUSER PASSWORD 'BackdoorPass1'. Ela é executada
apenas se o servidor realmente carregar a biblioteca, ou seja, apenas em uma build
vulnerável. Compile com gcc -Os -shared -fPIC -o pwn.so pwn.c em uma libc Linux
correspondente à imagem do servidor.Pré-condições: você tem acesso ao docker.
A pasta lab/ contém a réplica exata usada para verificar este PoC. Compile e
execute as duas máquinas (vulnerável = postgres 16.14, corrigido = postgres 16.15):
docker build -t pg-6471-vuln -f lab/Dockerfile.vuln lab
docker build -t pg-6471-fixed -f lab/Dockerfile.fixed lab
docker run -d --name pg-6471-vuln -p 15432:5432 -e POSTGRES_PASSWORD=lab-super-pw pg-6471-vuln
docker run -d --name pg-6471-fixed -p 15433:5432 -e POSTGRES_PASSWORD=lab-super-pw pg-6471-fixed
Ambas as máquinas executam a imagem oficial padrão do postgres com wal_level=logical.
O script de inicialização lab/01-repro.sh cria a função de baixo privilégio que a
solução usa, repro_rep LOGIN REPLICATION PASSWORD 'repropass', que não é
superusuária.
Em seguida, reproduza a solução:
exploitmatic run cve-2026-6471-postgres-logical-decoding-dlopen.txt 127.0.0.1
Aponte para a máquina corrigida com uma substituição de variável, sem editar arquivo:
exploitmatic run cve-2026-6471-postgres-logical-decoding-dlopen.txt 127.0.0.1 \
--var ctr=pg-6471-fixed
ctr é o contêiner docker, pw é a senha da função de replicação.
| alvo | resultado |
|---|---|
| postgres 16.14 (vulnerável), wal_level=logical | 4/4 verificado, login backdoor superusuário funciona |
| postgres 16.15 (corrigido), wal_level=logical | 3/4 não verificado, sem backdoor |
Apenas para testes autorizados e pesquisa, em sistemas que você possui ou tem permissão para testar. Este PoC demonstra uma escalada de privilégio pós-autenticação: exige uma conta de banco de baixo privilégio existente com o atributo REPLICATION, além de uma forma de colocar código controlado pelo atacante onde o usuário postgres do SO possa carregá-lo. Não é um ataque remoto não autenticado. O código carregado alcança o superusuário do banco porque a conta do SO que possui o servidor pode se conectar pelo socket local como o superusuário (peer/trust), o que é prática padrão de implantação do PostgreSQL.
| etapa | vulnerável 16.14 | corrigido 16.15 |
|---|
| reconhecimento (função é de replicação, não superusuário) | passa | passa |
| linha de base (slot lógico com pgoutput integrado) | passa | passa |
| gatilho (plugin do slot = caminho da biblioteca do atacante) | servidor a carrega | rejeitada antes do carregamento |
| tomada de controle (login como backdoor superusuário plantado) | superusuário | função inexistente |