flawopen.com/Incidents/postgresql-psql-injection-beyondtrust-treasury-december-2024
CVE-2025-1094: injeksi SQL di psql PostgreSQL
UTF-8 tidak valid melewati escape libpq saat aplikasi membuat input psql dari teks escape: SQL atau \! dapat disisipkan. Diperbaiki 13 Feb 2025.
Bayangkan seorang penerjemah yang tugasnya membungkus setiap ucapan Anda dengan tanda kutip agar tidak pernah dikira perintah. Anda mendapati bahwa jika Anda memberinya kata dalam abjad yang tidak ia kenal, ia bingung dan menjatuhkan salah satu tanda kutip. Ucapan Anda pun lolos dari tanda kutip dan dibaca sebagai instruksi, padahal si penerjemah bekerja persis sesuai rancangannya untuk setiap masukan yang pernah diuji siapa pun.
Konsep Kunci & Istilah
PQescapeLiteral- Fungsi libpq yang membungkus nilai dengan tanda kutip dan meng-escape-nya agar bisa disisipkan ke teks SQL. PQescapeIdentifier, PQescapeString, dan PQescapeStringConn juga terdampak.
UTF-8 tidak valid- Rangkaian byte yang tidak terbentuk dengan benar dalam pengodean yang dinyatakan. Kode escape dan psql berbeda pendapat tentang berapa karakter berikutnya yang 'ditelan' oleh byte semacam itu.
Meta-command psql- Perintah berawalan garis miring terbalik yang ditangani klien psql, bukan server. \! menjalankan sisa baris sebagai perintah shell sistem operasi.
CVE-2024-12356- Celah injeksi perintah kritis di BeyondTrust Privileged Remote Access dan Remote Support. Dalam uji Rapid7, mencapai eksekusi kode melalui celah ini memerlukan
CVE-2025-1094. Parameter terikat- Nilai yang dikirim ke server terpisah dari teks SQL, sehingga tidak pernah ada keputusan tanda kutip atau escape atasnya.
Pemetaan kerangka kerja
Kronologi Insiden
BeyondTrust menerbitkan imbauan BT24-10 untuk CVE-2024-12356 setelah menyelidiki pembobolan sejumlah instans SaaS Remote Support; Departemen Keuangan AS kemudian melaporkan bahwa insiden itu mencapai sistemnya.
CISA memasukkan CVE-2024-12356 ke katalog Known Exploited Vulnerabilities.
PostgreSQL merilis 17.3, 16.7, 15.11, 14.16, dan 13.19 yang memperbaiki CVE-2025-1094, dan Rapid7 menerbitkan analisisnya.
Alur Serangan Langkah demi Langkah
Masukan mencapai fungsi escape
Sebuah aplikasi mengambil teks yang dipengaruhi penyerang dan meneruskannya ke PQescapeLiteral atau fungsi libpq serupa untuk membangun pernyataan SQL.
UTF-8 tidak valid menyembunyikan tanda kutip
Menurut imbauan PostgreSQL, rangkaian multibyte tidak valid yang dirakit dan diletakkan sebelum tanda kutip tunggal membuat rutinitas escape membiarkan tanda kutip itu tanpa escape.
psql menutup literal terlalu cepat
Saat pernyataan diteruskan ke psql, tanda kutip tanpa escape menutup literal string dan sisa masukan diurai sebagai SQL atau perintah psql.
Meta-command menjalankan shell
Rapid7 menunjukkan bahwa teks yang disuntikkan dapat memuat meta-command \!, yang dijalankan psql sebagai perintah sistem operasi di mesin tempat ia berjalan.
Kode Sumber: Rentan vs Aman
Python ilustratif dengan psycopg 3, bukan kode BeyondTrust. Versi rentan meniru pola berisiko yang disebut imbauan: meng-escape nilai dengan libpq, menyisipkannya ke teks SQL, lalu mengalirkan teks itu ke psql. Versi yang diperkuat menghapus kedua bagian itu: menolak UTF-8 yang cacat sebelum diproses apa pun, dan mengirim nilai sebagai parameter terikat lewat driver sungguhan, sehingga tidak ada langkah escape yang bisa dikelabui dan tidak ada pengurai meta-command psql di jalurnya. Memperbarui libpq tetap penting bagi kode yang masih melakukan escape.
import subprocess
import psycopg
def lookup_user(conn: psycopg.Connection, name: bytes) -> bytes:
# PQescapeLiteral libpq (sebelum 17.3/16.7/15.11/14.16/13.19) tidak
# menetralkan tanda kutip yang tersembunyi setelah urutan byte UTF-8 yang tidak valid.
literal = conn.pgconn.escape_literal(name)
script = b"SELECT id FROM users WHERE name = " + literal + b";\n"
# psql menjalankan input sebagai skrip, termasuk metaperintah seperti \!
result = subprocess.run(["psql", "-At", "-d", "app"], input=script,
capture_output=True, check=True)
return result.stdout
import psycopg
MAX_NAME_CHARS = 128
def lookup_user(conn: psycopg.Connection, name: bytes) -> list[int]:
try:
text = name.decode("utf-8") # reject malformed input at the boundary
except UnicodeDecodeError:
raise ValueError("name is not valid UTF-8") from None
if len(text) > MAX_NAME_CHARS:
raise ValueError("name too long")
with conn.cursor() as cur:
# Nilai dikirim sebagai parameter terikat, terpisah dari teks SQL,
# dan tidak ada proses psql (sehingga tidak ada pengurai metaperintah) yang terlibat.
cur.execute("SELECT id FROM users WHERE name = %s", (text,))
return [row[0] for row in cur.fetchall()]
Daftar Periksa Penguatan Sistem Rekayasa
- ✓Cari di basis kode pemanggilan psql lewat subprocess yang masukannya dibangun dari data aplikasi, ganti dengan driver basis data yang memakai parameter terikat, dan tambahkan aturan CI yang gagal jika muncul pemanggilan baru.
- ✓Tolak di perbatasan setiap masukan yang tidak terbentuk dengan benar dalam pengodean yang dinyatakan, sebelum mencapai pengurai, fungsi escape, atau panggilan basis data; tambahkan uji yang mengirim b'\xc0\'' dan mengharapkan galat validasi.
- ✓Perbarui libpq dan alat klien, bukan hanya server:
CVE-2025-1094diperbaiki di PostgreSQL 17.3, 16.7, 15.11, 14.16, dan 13.19, dan paket klien di host aplikasi juga harus diperbarui. - ✓Di tempat escape belum bisa dihapus, tambahkan uji regresi yang memasukkan UTF-8 tidak valid diikuti tanda kutip ke jalur escape dan memastikan hasilnya ditolak atau dikutip dengan aman.
- ✓Perlakukan alat akses jarak jauh istimewa sebagai bagian dari permukaan serangan: batasi antarmuka manajemennya, pasang patch begitu vendor memberi tahu, dan pantau penggunaan kunci API-nya dari lokasi yang tidak terduga.
Sumber
- PostgreSQL — imbauan keamanan untuk CVE-2025-1094
- Rapid7 — CVE-2025-1094: injeksi SQL di psql PostgreSQL, ditemukan saat menganalisis CVE-2024-12356 milik BeyondTrust
- Injeksi SQL — rujukan lengkap kelas ini di 11 bahasa
- Injeksi perintah — rujukan lengkap kelas ini
- Apakah stored procedure mencegah injeksi SQL?