XdebugとNetBeansを使ったDrupalのデバッグ環境をdocker-composeのみで立てる
昨年の末ごろにデバッガを使って脆弱性検証を行う勉強会に参加させていただきました。
※好評につき追加開催※ デバッガでWordPress本体やプラグインの脆弱性を追いかけてみよう - connpass
とても参考になりました。その時の内容は下記の記事がとても詳しくまとめてくれています。
自分が脆弱性検証をやるときにデバッガを使うことはやったことがなかったのですが、そういう方法があるというのは新しかったです。
脆弱性検証の場合、別に開発するわけではないのであくまでプロジェクトは一時的なもので、また複数のバージョンを立てて壊してとしていくので、そういう点でDockerとの相性がよく、自分もかなりの頻度で使っています。 Dockerを使ってこういう環境を立てておくと、後々応用が利きそうだなと思いました。
ということで今回はXdebugとNetBeansを使ったデバッグ環境を立てます。
対象としては先日 Drupalgeddon2(CVE-2018-7600) の脆弱性が見つかったDrupalのデバッグ環境を立ててみます。
NetBeansのDockerコンテナとしては以下を参考にしました。
Dockerを使ってNetBeans IDEをGUIで起動できます。
- 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
NetBeansのPHPのIDEをインストールしています。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の設定ファイルは以下になります。
これをビルドします。結構時間かかります。
docker-compose build docker-compose up
あと、ローカルホストに行くとDrupalのインストーラが起動します。 そのままだとベースになるコンテナのイメージは drupal:7.57-apache になっています。
データベースはMySQLのコンテナが同時に立ちます。 パラメータは以下になっているので、入力してインストールします。
インストールが終わったら、NetBeansの設定です。 まずは新規プロジェクトを作ります。 PHPの既存のソースを選択します。
ソースのフォルダにはDrupalのコンテンツがマウントしてある「/root/project/drupal」を指定します。
ローカルのWebサイトとして、プロジェクトURLは対象となるDrupalのホスト(ここでは「http://drupal-vuln/」)とします。
設定が終わったらデバッグを開始します。 メニューバーの一番右にあるデバッグ開始のボタンを押します。
リクエストを待ち受けているので、この状態で、攻撃コードを打てば、デバッグが開始されます。 その前にブレークポイントを設定しましょう。
三井物産セキュアディレクション (MBSD) の検証レポートによると、「includes/common.inc」の「#post_render」を処理する箇所でコード実行が行われるようなので、ここにブレークポイントを設定します。 Drupal 7系への攻撃ではリクエストは2回あり、1回目でキャッシュに実行するコマンドを仕込み、2回目で実行します。
これで実行すると、1回目のリクエストでは何度もこの関数を通るのですが、そのうちの1回でパラメータで指定した値が変数に入っている処理があります。2回目のリクエストで1回目のリクエストでキャッシュされた値が取り出され、コード実行が行われることが確認できます。
- 2回目のリクエストで呼び出されている変数
ここまでやってあれですが、結構処理が分かりにくい上に、リクエストが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のコンテンツで上書きされます。 ので、先に作ったボリュームは削除しておきましょう。
同じように「docker-compose up」のコマンドだけで、NetBeansが起動し、Drupal 8が立ちました。
後の流れは同じです。ブレークポイントを張って、デバッグを開始して、攻撃コードを打ちます。
ということで、簡単にXdebugとNetBeansを使った脆弱性検証の環境が立ちました。
Drupalの脆弱性の攻撃コードが出る前に用意しとけよ、という話ですね。 まったくもって、その通りです。
これ自体はもう少し応用が利きそうなので、PHP系のCMSやJAVAのミドルウェアを使ったアプリケーションは同じことができそうだなーと思っています。 そのへんは今後、頑張っていきたいです。
参考
デバッガを利用してWebアプリの脆弱性を分析してみた - とある診断員の備忘録
Dockerを用いたGUIアプリケーションの実行 | POSTD