ファジングには危険が伴います。それは、侵害行為を試みることになるからです。
ファジングでは、ソフトウェアに意図的に不正なデータを入力し、ソフトウェアにエラーが発生するかどうかを確認します。エラーが発生した場合は、見つかった脆弱性をコードに戻って修正することができます。ファジングは、ソフトウェア開発においてセキュリティ上の弱点を修正するための優れた予防手段ではあるものの、ゼロデイ脆弱性を探している攻撃者が好んで用いる手法でもあります。そうです、ファジングはソフトウェア障害を発生させることを意図しているからです。
ファジングの標準的なガイドラインを次に示します。
ファジングテストは必ず、制御下にあり、分離された試験環境で実行することをお勧めします。ファジングツールは途中にシステムを介在させず、できればスイッチも使用したりせずに、ターゲットに直接接続するのが理想です。
試験は隔離環境で実行し、テストが予期せずブロードキャスト、増幅、または中継された場合に備えて、ネットワークおよびインターネットの他の部分から切り離しておく必要があります。
仮想マシンは制御された環境でファジングテストを行うための優れた方法です。仮想マシンでは、ホスト環境に影響する機能を設定によって限定し、仮想ネットワークを厳密に制御することができます。
場合によっては、ファジングツール(Defensics®など)とターゲットソフトウェアの両方を同じ仮想マシンに配置し、すべてのファジングを厳密に制限された環境内に維持することもできます。
代わりに、別の仮想マシンまたはホストシステムでファジング・ツールを使用して、独自の仮想マシン内にあるターゲットをテストすることもできます。
コンテナ化にはもう一つ利点があります。Linuxカーネル上で実行されるアプリケーションソフトウェアをテストする場合、コンテナ化すれば、わずかなリソース消費で仮想マシンを制御・分離することができます。
コンテナ化によって環境を制御・分離する以外に、構成とセットアップを(Dockerfile内で)コードとして指定することで、テストと結果の再現性と一貫性を確保する方法もあります。
たとえば、オープンソース・プロジェクトmosquitto(MQTTブローカー)をコンテナ内で実行するとします。以下では、さまざまな状況で、コンテナを使用してファジングテストを実行する方法について説明します。
まず、アプリケーションのバイナリ成果物を取得して実行する単純な例をご紹介します。
mosquittoでは、apt-getコマンドを使用してインストールするだけで、この例をシミュレーションできます。これを実行するDockerfileを以下に示します。
FROM ubuntu
RUN apt-get update
RUN apt-get install -y mosquitto
ENTRYPOINT mosquitto
管理しやすいように単純なディレクトリ構造を用いています。筆者は、ファジングターゲットとしてコンテナを作成するときはいつも、次のファイルを使用します。
この簡単な例では、name.shは次のように記述されています。
IMAGE=mosquitto-box
build.shスクリプトでは、name.shを呼び出してコンテナ・イメージを作成します。
source name.sh
docker build -t ${IMAGE} -f Dockerfile .
最後に、run.shスクリプトでイメージのインスタンスを作成し、MQTTポート1883を公開します。
source name.sh
docker run \
-it \
--rm \
-p 1883:1883 \
--hostname ${IMAGE} \
--name ${IMAGE} \
${IMAGE}
このコードをコピーして貼り付ける必要はありません。この記事に掲載されているすべてのコードは次のWebサイトから入手できます。
https://github.com/jknudsen-synopsys/blog-box
前述した最初の単純な例はmbox01です。
この例を使用するには、build.shでイメージを作成し、run.shで実行します。コンテナ内でmosquittoを実行し、ポート1883で接続を待機します。先ほどポート1883を開いたので、Defensics(または他のMQTTテストツール)を実行し、localhostポート1883でmosquittoと通信することができます。
ファジング・テストを開発プロセスに組み込む場合、ソースからアプリケーションをビルドして、最新のコードをテストできるようにします。
コンテナをテストのターゲットにする利点の1つは、一貫性があることです。コンテナ・イメージの構成が適切に取得されれば、ビルドしたアプリケーションが想定どおりに動作し、再現性と一貫性のある結果を得ることが容易になります。
ここでも、サンプルアプリケーションとしてmosquittoを使用します。mosquittoのビルドの依存関係を持つコンテナ・イメージを準備し、gitリポジトリからソースコードを取得してビルドします。
最初の例では、mosquitto 1.6.9がインストールされました。ソースからビルドする場合、現行のバージョンは2.0.6です。セキュリティが高めに設定されているため、mosquittoが外部ネットワークで待ち受けて、確実に匿名接続が受け入れられるようにするためにDockerfileに変更を加える必要があります。
この記事のサンプルコード・リポジトリではmbox02です。Dockerfileは次のようになります。
FROM ubuntu
RUN apt-get update
RUN apt-get install -y build-essential git \
libssl-dev libc-ares-dev uuid-dev libcjson-dev
RUN git clone https://github.com/eclipse/mosquitto.git && cd mosquitto && \
make WITH_DOCS=no
RUN sed -i 's/#listener/listener 1883 0.0.0.0/g' /mosquitto/mosquitto.conf
RUN sed -i 's/#allow_anonymous false/allow_anonymous true/g'
/mosquitto/mosquitto.conf
RUN useradd mosquitto
ENTRYPOINT /mosquitto/src/mosquitto -c /mosquitto/mosquitto.conf
AddressSanitizerをDefensics Agent Instrumentation Frameworkと組み合わせてファジングターゲットのメモリリークを監視する方法については既にご紹介しました。
Dockerコンテナでこれを設定するには多少の追加作業が必要ですが、その労力をかける価値は十分にあります。サンプルコードではmbox03です。ただし、ファイルディレクトリにDefensics Agent Instrumentation Frameworkエージェントサーバー(agent_linux_amd64)が配置されるまでは直ちに機能しません。このエージェントサーバーが配置されていれば、通常の方法でbuild.shを実行することによってコンテナイメージにコピーされます。
Dockerfileはエージェントサーバー上でコピーを処理し、AddressSanitizerを有効にしてmosquittoをコンパイルします。mosquittoを直接起動するのではなく、エージェントサーバーを起動します。
FROM ubuntu
RUN apt-get update
RUN apt-get install -y build-essential git \
libssl-dev libc-ares-dev uuid-dev libcjson-dev
RUN git clone https://github.com/eclipse/mosquitto.git && cd mosquitto && \
make CFLAGS=-fsanitize=address LDFLAGS=-fsanitize=address WITH_DOCS=no
RUN sed -i 's/#listener/listener 1883 0.0.0.0/g' /mosquitto/mosquitto.conf
RUN sed -i 's/#allow_anonymous false/allow_anonymous true/g'
/mosquitto/mosquitto.conf
RUN useradd mosquitto
COPY files /files
ENTRYPOINT /files/agent_linux_amd64 server –insecure
このコンテナを実行する場合は、エージェントサーバーに到達できるようにポート12345も公開する必要があります。更新後のrun.shは次のとおりです。
source name.sh
docker run \
-it \
--rm \
-p 1883:1883 \
-p 12345:12345 \
--hostname ${IMAGE} \
--name ${IMAGE} \
${IMAGE}
コンテナが実行されたら、/mosquitto/src/mosquitto -c /mosquitto/mosquitto.confコマンドを使用して、mosquittoを実行するようにDefensics SanitizerProcessMonitorAgentを構成するだけです。
詳細については、ブログ記事「Find more bugs by detecting failure better: An introduction to SanitizerProcessMonitorAgent(障害検出の向上によるバグ発見の強化:SanitizerProcessMonitorAgentの紹介)」をご覧ください。
この記事がコンテナ内でファジングターゲットを実行する可能性を検討する参考になれば幸いです。この方法には以下の重要な利点があります。
さあ、ファジングを始めましょう!