生産性のない話

趣味の範囲でサイバーセキュリティの話

XdebugとNetBeansを使ったDrupalのデバッグ環境をdocker-composeのみで立てる

昨年の末ごろにデバッガを使って脆弱性検証を行う勉強会に参加させていただきました。

※好評につき追加開催※ デバッガでWordPress本体やプラグインの脆弱性を追いかけてみよう - connpass

とても参考になりました。その時の内容は下記の記事がとても詳しくまとめてくれています。

tigerszk.hatenablog.com

自分が脆弱性検証をやるときにデバッガを使うことはやったことがなかったのですが、そういう方法があるというのは新しかったです。

脆弱性検証の場合、別に開発するわけではないのであくまでプロジェクトは一時的なもので、また複数のバージョンを立てて壊してとしていくので、そういう点でDockerとの相性がよく、自分もかなりの頻度で使っています。 Dockerを使ってこういう環境を立てておくと、後々応用が利きそうだなと思いました。

ということで今回はXdebugNetBeansを使ったデバッグ環境を立てます。

対象としては先日 Drupalgeddon2(CVE-2018-7600) の脆弱性が見つかったDrupalデバッグ環境を立ててみます。

NetBeansのDockerコンテナとしては以下を参考にしました。

postd.cc

Dockerを使ってNetBeans IDEGUIで起動できます。

  • Dockerfile
FROM debian:latest

RUN apt-get update && apt-get install -y wget openjdk-8-jdk && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/* && \
    rm -rf /tmp/*

ADD state.xml /tmp/state.xml

RUN wget http://download.netbeans.org/netbeans/8.2/final/bundles/netbeans-8.2-php-linux-x64.sh -O /tmp/netbeans.sh -q && \
    chmod +x /tmp/netbeans.sh && \
    echo 'Installing netbeans' && \
    /tmp/netbeans.sh --silent --state /tmp/state.xml && \
    rm -rf /tmp/*

CMD /usr/local/netbeans-8.2/bin/netbeans

NetBeansPHPIDEをインストールしています。state.xmlというのは一回インストールしたときに「--record」というオプションを付けて出力したファイルで、これを指定して 「--silent」オプションを付けることでGUIなしでインストールできます。

実行時にはGUIで起動するためにホスト側で「xhost +」とか実行してX Window Systemの認証を通しておく必要があります (終わったら「xhost -」とかで認証拒否の状態に戻すことを推奨します)。

次にDrupalのDockerコンテナです。公式のものにXdebugをインストールしています。

FROM drupal:7.57-apache

RUN pecl install xdebug
・・・

Xdebugの設定は以下の通りです。

[xdebug]
zend_extension=/usr/local/lib/php/extensions/no-debug-non-zts-20151012/xdebug.so
xdebug.remote_enable=1
xdebug.remote_handler=dbgp
xdebug.remote_connect_back=0
xdebug.remote_autostart=1
xdebug.remote_host=172.42.0.4
xdebug.remote_port=9000
xdebug.max_nesting_level=1000
xdebug.idekey="netbeans-xdebug"

設定についてはいろいろと必要なオプションがあります。 また、デバッガの接続元のIPを指定する必要があるので、NetBeansのIPを指定する必要があります。 そのため、docker-composeでネットワークを作成し、IPを固定しています。

また、デバッグ対象となるアプリケーションのファイルを共有しておく必要があるので、ボリュームを作成しています。 このボリュームを触るときに権限の設定が面倒なので、NetBeansはrootで動かしています。

以上から出来上がったDockerの設定ファイルは以下になります。

github.com

これをビルドします。結構時間かかります。

docker-compose build
docker-compose up

うまく起動すると、NetBeans IDEが起動します。

f:id:blueBLUE:20180523231849p:plain

あと、ローカルホストに行くとDrupalインストーラが起動します。 そのままだとベースになるコンテナのイメージは drupal:7.57-apache になっています。

f:id:blueBLUE:20180523231911p:plain

データベースはMySQLのコンテナが同時に立ちます。 パラメータは以下になっているので、入力してインストールします。

  • データベース名:drupal
  • データベースのユーザ名:drupal
  • データベースのパスワード:password
  • データベースのホスト:drupal-db
  • データベースホストのポート:3306

インストールが終わったら、NetBeansの設定です。 まずは新規プロジェクトを作ります。 PHPの既存のソースを選択します。

f:id:blueBLUE:20180523231932p:plain

ソースのフォルダにはDrupalのコンテンツがマウントしてある「/root/project/drupal」を指定します。

f:id:blueBLUE:20180523232014p:plain

ローカルのWebサイトとして、プロジェクトURLは対象となるDrupalのホスト(ここでは「http://drupal-vuln/」)とします。

f:id:blueBLUE:20180523232024p:plain

設定が終わったらデバッグを開始します。 メニューバーの一番右にあるデバッグ開始のボタンを押します。

リクエストを待ち受けているので、この状態で、攻撃コードを打てば、デバッグが開始されます。 その前にブレークポイントを設定しましょう。

三井物産セキュアディレクション (MBSD) の検証レポートによると、「includes/common.inc」の「#post_render」を処理する箇所でコード実行が行われるようなので、ここにブレークポイントを設定します。 Drupal 7系への攻撃ではリクエストは2回あり、1回目でキャッシュに実行するコマンドを仕込み、2回目で実行します。

f:id:blueBLUE:20180523232059p:plain

これで実行すると、1回目のリクエストでは何度もこの関数を通るのですが、そのうちの1回でパラメータで指定した値が変数に入っている処理があります。2回目のリクエストで1回目のリクエストでキャッシュされた値が取り出され、コード実行が行われることが確認できます。

f:id:blueBLUE:20180523232139p:plain

  • 2回目のリクエストで呼び出されている変数

f:id:blueBLUE:20180523232149p:plain

ここまでやってあれですが、結構処理が分かりにくい上に、リクエストが2つに分かれているので、初心者の勉強にはあまりいい例ではないのかな……と。

ただ、任意のコードが実行される個所は分かりました。

せっかくなのでDrupal 8系でもやってみました。

DrupalのDockerfileとdocker-compose.ymlのバージョン(7.57-apache ⇒ 8.5.0-apache)を書き換えてビルドするだけ…… と思ったらXdebugのインストールパスがかわっていました、、、

DrupalのDockerfileのphp.iniの値も書き換える必要があります。 (何かオプションとかで固定できそう?)

また、Dockerで共有したボリュームが残っているので、このままやると、Drupal 8のコンテンツがDrupal 7のコンテンツで上書きされます。 ので、先に作ったボリュームは削除しておきましょう。

f:id:blueBLUE:20180523232211p:plain

同じように「docker-compose up」のコマンドだけで、NetBeansが起動し、Drupal 8が立ちました。

f:id:blueBLUE:20180523232222p:plain

後の流れは同じです。ブレークポイントを張って、デバッグを開始して、攻撃コードを打ちます。

f:id:blueBLUE:20180523232306p:plain

ということで、簡単にXdebugNetBeansを使った脆弱性検証の環境が立ちました。

Drupal脆弱性の攻撃コードが出る前に用意しとけよ、という話ですね。 まったくもって、その通りです。

これ自体はもう少し応用が利きそうなので、PHP系のCMSJAVAミドルウェアを使ったアプリケーションは同じことができそうだなーと思っています。 そのへんは今後、頑張っていきたいです。

参考

デバッガを利用してWebアプリの脆弱性を分析してみた - とある診断員の備忘録

Dockerを用いたGUIアプリケーションの実行 | POSTD

GitHub - fgrehm/docker-netbeans: NetBeans in a container

NetBeans NetBeans 日本語サイト

NBIFAQ - NetBeans Wiki

Docker for Windowsでxdebugを使う

Drupalgeddon2に関する検証レポート(CVE-2018-7600)