サイト内の現在位置を表示しています。

PostgreSQLの脆弱性とBeyondTrust社製品の脆弱性から考える根本原因の対処の困難さ

サイバーインテリジェンス

2025年3月27日

2025年2月13日に、データベースソフトウェアの「PostgreSQL」のライブラリlibpqにSQLインジェクションが可能となる脆弱性「CVE-2025-1094」が公開されました [1]。このlibpqの脆弱性はBeyondTrust社の製品であるPRA(以下、BeyondTrust PRA)の脆弱性「CVE-2024-12356」について、Rapid7社が調査した際に発見したものです [2]。BeyondTrust PRAの脆弱性はリモートからの任意コード実行(RCE)の脆弱性ですが、脆弱性の根本的な原因はlibpqにありました。BeyondTrust社が出した「CVE-2024-12356」の脆弱性の修正パッチでは任意コードの実行を防ぐことはできていましたが、根本原因であるlibpqの解決とはなっていませんでした。そのため、Rapid7社がPostgreSQLに報告するまで「CVE-2025-1094」の脆弱性はゼロデイ脆弱性の状態となってしまっていました。

本記事では、この脆弱性がどのような脆弱性であったのかについて紹介するとともに、この事例のように一つの事象に対して修正パッチが複数回にわたってリリースされることになった事例を通して、利用者や開発者が脆弱性に対してどのように対応すべきかを考察します。

エグゼクティブサマリー

  • PostgreSQLのlibpqに存在する脆弱性(CVE-2025-1094)はBeyondTrust社の製品に存在した脆弱性(CVE-2024-12356)と関連するものであり、CVE-2024-12356を悪用した任意コード実行にはCVE-2025-1094の悪用が必須であった。
  • この事例のように、脆弱性の根本原因が修正に至らなかったため、一つの事象に対して複数回修正パッチがリリースされる事例は過去にも存在している。代表的なものとしてはLog4ShellやDrupageddon2.0がある。
  • 今後も、根本原因の修正には至らず、別の脆弱性が発見される/修正パッチがでるといった事例の発生が考えられる。
  • 利用者としては、注目度の高い脆弱性については続報についても注意を払う必要がある。開発者・メーカーとしては根本原因を見誤らないように、リサーチャーとの連携やテストコードの網羅性などを考慮した対応を行う必要があると言える。

目次

libpqおよびBeyondTrust PRAの脆弱性について

BeyondTrust PRAの脆弱性「CVE-2024-12356」およびlibpqの脆弱性「CVE-2025-1094」の技術的詳細については、脆弱性を発見したRapid7社から報告がされています [3]。本記事ではRapid7社の報告からかいつまんで紹介します。

Beyond Trust PRAの脆弱性はSQLインジェクションを経由した任意コード実行が可能となるものでした。脆弱性悪用の流れとしては、まずSQLインジェクションを発生させるために攻撃者は細工したデータを送り込みます。Beyond Trust PRAのプログラムがこのデータを処理する際に実行する「echoコマンドが実行する引数の処理」と「dbquoteスクリプトが実行するエスケープ処理」に脆弱な点があります。その結果SQLインジェクションを経由した任意コード実行が可能となりました。dbquoteスクリプトはスクリプト内部の処理でlibpqの関数を呼び出しており、この関数に脆弱性が存在していました。

図 1 攻撃の流れのイメージ図

echoコマンドが実行する引数の処理の脆弱性

BeyondTrust PRAの脆弱性「CVE-2024-12356」の修正パッチによって変更された点に以下の内容が含まれます。これはthin-scc-wrapper関数内の処理となります。

変更前と変更後の違いは、echoコマンドで実行する変数をダブルクォーテーションで囲っているか否かです。$gskeyの内容が「-e \x31\x32」となっていた場合、ダブルクォーテーションで囲わないと、「-e」がechoコマンドのオプションとして評価されます。その結果、続く文字列の「\x31\x32」が16進の文字列として評価されることになります。

この処理の後、「echo “$gskey”」の結果は「$ingrediRoot/app/dbquote」というPHPスクリプトファイルの引数として渡されます。

dbquoteの処理とマルチバイト文字列

dbquoteスクリプトは、渡された文字列をPostgreSQLのlibpqライブラリが用意した関数でエスケープ処理を行うスクリプトです。libpqライブラリのエスケープ処理の途中でpg_utf_mblen関数が呼び出され、この処理に渡った結果意図しない結果となります。この関数はUTF-8の文字の最初のバイトが「0xC0」の場合、その次の文字含めマルチバイトで2バイトのUTF-8と認識する処理となっています。そのため、「\xC0’」という文字列を渡された場合、「\xC0、\x27」の2バイトの文字として処理されます。しかし、2バイトのUTF-8では2バイト目は\x80より大きい値でなければいけません。

CVE-2025-1094はマルチバイトのUTF-8文字列をエスケープする際に無効なUTF-8文字列を無効と処理していない脆弱性です。

SQLインジェクションによる任意コード実行

これまでの説明で、echoコマンドを実行する引数処理に脆弱性があり、「-e」オプションが使用できること、それにより細工した文字列をdbquoteスクリプトに渡すことができ、その結果無効なUTF-8マルチバイトを含んだ文字列が返却されることが分かりました。最終的なSQLインジェクションは、dbquoteによって返却された文字列がpostgresqlのクライアントとして実行されることにより発生し、最終的に任意コード実行が可能となります。以下が任意コード実行となる原因部分のコードです。

この処理はdbquoteで処理された文字列が、quoted変数に格納、その後echoコマンドを用いて、SQLで実行する文字列が連結され、パイプ処理で$db変数に格納されているpostgresqlクライアントが実行されています。
もし、quoted変数に無効なUTF-8のマルチバイト文字列が含まれている場合、PostgresSQL側で処理される際にエラーが発生し、その後の文字列が別途実行されることになります。PostgreSQLでは「\!」を使うことでOSコマンドが実行できるため、quoted変数に「\xC0’; \! id #」という文字列が含まれていると「\xC0’」がマルチバイトUTF-8に変換されますが、無効なUTF-8文字列となるためエラーが発生、その後の文字列「; \! id #」がSQLコマンドとして実行されます。セミコロンはSQL文の終わりを意味し、その後idコマンドを実行、「#」はその後の文字列をコメントとして評価することで、後続の文字列(AND session_type以降の文字列)が無視されることになります。

Rapid7社の報告によると、libpqの脆弱性悪用無しではBeyondTrust PRAで報告された任意コード脆弱性の実行には至りません。また、BeyondTrust PRAの修正パッチでは、本記事で説明した以外のサニタイズ処理もあり、libpqの脆弱性を単独で悪用する攻撃を防ぐことができていました。

これらのことをまとめると、本事例は脆弱性の根本となる原因の特定に至らなかったため、libpqの修正パッチがBeyondTrust PRAの修正パッチと同時に出なかったと言えます。一方、最初の修正パッチで攻撃やテストコードが防げていることから、根本原因の特定は難しいものであったと考えられます。

類似事例について

libpqおよびBeyondTrust PRAの脆弱性の件であったような、一度脆弱性に対する修正パッチを出したものの、根本原因の特定に至らずで再度パッチが出た事例は過去にも複数存在しています。

Log4Shell(CVE-2021-44228、CVE-2021-45046、CVE-2021-45105、CVE-2021-44832) [4] [5] [6]

Apache Log4jの脆弱性、CVE-2021-44228(通称:Log4Shell)については、当初2.15.0のバージョンで修正パッチが公開されました。しかし、その後修正が不十分であったためにCVE-2021-45046の脆弱性が新たに割り当てられ、2.16.0のバージョンで修正されました。また、その後もCVE-2021-45105が発見され、2.17.0バージョンで修正、2.17.1バージョンにてCVE-2021-44832が修正されたことで一連の脆弱性の修正が完了しています。
Log4Shellの脆弱性は、Apache Log4jのlookup関数が、攻撃者が送信した悪意のあるJNDI URLを埋め込んだ文字列を処理することで攻撃が行われます。2.16.0ではLDAP検索のみに限定しましたが、コンテキストルックアップやコンテキストマップパターンを使用することで、攻撃が引継ぎ可能でした。

なお、Log4jの2.17.0バージョン以降では、JNDIの検索が無効になっています。 [7]

Drupageddon2.0(CVE-2018-7600、CVE-2018-7602) [8]

Drupalは任意コード実行の脆弱性CVE-2018-7600の修正パッチを公開しましたが、追加されたサニタイズ用関数でカバーされない修正があることが発覚し、CVE-2018-7602の修正パッチを公開したことがあります。新たに割り当てられたCVE-2018-7602は修正された処理をバイパスするものであり、ログインが不要でした。CVE-2018-7600に対して、CVE-2018-7602ではログイン可能であることが前提条件となっていることから条件がやや厳しくなっています。しかし、Drupalのサイトによっては任意のユーザ作成が許可されている場合もあることから影響は少なからずあったと考えられます。

脆弱性の根本原因対処の難しさについて認識する

libpqおよびBeyondTrust PRAの脆弱性やその他の事例から、脆弱性の根本原因の特定は時に難しい場合があるということを認識しておくべきと考えます 。また、特に攻撃の容易性が高いものや、複数製品に採用されている脆弱性の場合、攻撃者やリサーチャーの注目も高くなり、修正パッチを解析することによる別の攻撃手法の発見されることがあります。今後も紹介した事例のように一度の修正で対応完了とならずに、複数回対応が必要となる事例が発生することは十分考えられます。

では、このような事例が発生した場合の対応としては何が考えられるでしょうか。
利用者側の対策としては、他の脆弱性対応と大きな対応の変更は不要であると思われます。脆弱性情報の収集やパッチの適応方針を定めておき、できる限り早いタイミングでのパッチを適用することが対策となるからです。修正パッチが複数回発生する場合に備え、注目の大きい脆弱性についてはより情報収集に余念を欠かさないことが重要です。
開発者側の対策としても、脆弱性を作りこまないように開発・修正を行うという点では変わりないですが、根本原因を見誤らないように、脆弱性を報告したリサーチャーとの連携やテストコードの網羅性などを考慮した対応を行う必要があるでしょう。

参照文献

この記事を執筆したアナリスト

竹内 俊輝(Takeuchi Toshiki)
専門分野:脅威インテリジェンス、マルウェア解析

脅威情報の収集・分析やマルウェア解析業務を担当。
CISSP、情報処理安全確保支援士(登録番号014728号)、GIAC(GPEN)を保持