FlawOpen

flawopen.com/Incidents/postgresql-psql-injection-beyondtrust-treasury-december-2024

● PostgreSQL / BeyondTrust · CVE-2025-1094 · December 2024 – February 2025 · CVSS 8.1 · Tinggi
Riset Keamanan · FlawOpen

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.

💡 Penjelasan Sederhana (ELI5)

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

  • Referensi CWE untuk kelemahan yang dijelaskan dalam panduan ini: CWE-89 CWE-149

Kronologi Insiden

2024-12-16

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.

2024-12-19

CISA memasukkan CVE-2024-12356 ke katalog Known Exploited Vulnerabilities.

2025-02-13

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

Langkah 1

Masukan mencapai fungsi escape

Sebuah aplikasi mengambil teks yang dipengaruhi penyerang dan meneruskannya ke PQescapeLiteral atau fungsi libpq serupa untuk membangun pernyataan SQL.

Langkah 2

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.

Langkah 3

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.

Langkah 4

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.

IMPLEMENTASI RENTAN
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
PERBAIKAN AMAN & KUAT
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

Sumber