Table of Contents

    ファジングには危険が伴います。それは、侵害行為を試みることになるからです。

    ファジングでは、ソフトウェアに意図的に不正なデータを入力し、ソフトウェアにエラーが発生するかどうかを確認します。エラーが発生した場合は、見つかった脆弱性をコードに戻って修正することができます。ファジングは、ソフトウェア開発においてセキュリティ上の弱点を修正するための優れた予防手段ではあるものの、ゼロデイ脆弱性を探している攻撃者が好んで用いる手法でもあります。そうです、ファジングはソフトウェア障害を発生させることを意図しているからです。

    ファジングのガイドライン

    ファジングの標準的なガイドラインを次に示します。

    • 本番環境をファジングのターゲットにしない:ファジングによって、ターゲットにリソース使用量の増加などの軽度の不都合が生じる可能性があります。場合によっては重大な障害が発生することもあります。実際の業務に使用されているシステムをファジングのターゲットにすることはお勧めできません。
    • ファジングツールをターゲットの近くに配置する:ファジング・テストケースがターゲットに到達するまでの経路で中間システムを介さないようにするか、少なくとも中間システムの数を最小限に留めるように心がけましょう。中間システムでテストケースが変更または削除されたり、障害が発生する可能性があります。

    ファジングテストは必ず、制御下にあり、分離された試験環境で実行することをお勧めします。ファジングツールは途中にシステムを介在させず、できればスイッチも使用したりせずに、ターゲットに直接接続するのが理想です。

    試験は隔離環境で実行し、テストが予期せずブロードキャスト、増幅、または中継された場合に備えて、ネットワークおよびインターネットの他の部分から切り離しておく必要があります。

    仮想化の利点

    仮想マシンは制御された環境でファジングテストを行うための優れた方法です。仮想マシンでは、ホスト環境に影響する機能を設定によって限定し、仮想ネットワークを厳密に制御することができます。

    場合によっては、ファジングツール(Defensics®など)とターゲットソフトウェアの両方を同じ仮想マシンに配置し、すべてのファジングを厳密に制限された環境内に維持することもできます。

    代わりに、別の仮想マシンまたはホストシステムでファジング・ツールを使用して、独自の仮想マシン内にあるターゲットをテストすることもできます。

    コンテナ化にはもう一つ利点があります。Linuxカーネル上で実行されるアプリケーションソフトウェアをテストする場合、コンテナ化すれば、わずかなリソース消費で仮想マシンを制御・分離することができます。

    Dockerコンテナをファジングの対象として使用する

    コンテナ化によって環境を制御・分離する以外に、構成とセットアップを(Dockerfile内で)コードとして指定することで、テストと結果の再現性と一貫性を確保する方法もあります。

    サンプル:mosquitto

    たとえば、オープンソース・プロジェクトmosquitto(MQTTブローカー)をコンテナ内で実行するとします。以下では、さまざまな状況で、コンテナを使用してファジングテストを実行する方法について説明します。

    まず、アプリケーションのバイナリ成果物を取得して実行する単純な例をご紹介します。

    mosquittoでは、apt-getコマンドを使用してインストールするだけで、この例をシミュレーションできます。これを実行するDockerfileを以下に示します。

    FROM ubuntu

    RUN apt-get update
    RUN apt-get install -y mosquitto

    ENTRYPOINT mosquitto

    管理しやすいように単純なディレクトリ構造を用いています。筆者は、ファジングターゲットとしてコンテナを作成するときはいつも、次のファイルを使用します。

    • コンテナイメージを定義するDockerfile
    • 実際にDockerfileからイメージを作成するbuild.sh
    • イメージ名を定義するname.sh(build.shとrun.shの両方で使用)
    • コンテナイメージをインスタンス化し、ネットワークポートを公開するrun.sh

    この簡単な例では、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でパワーアップ

    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の紹介)」をご覧ください。

    適切なものを適切な場所に

    この記事がコンテナ内でファジングターゲットを実行する可能性を検討する参考になれば幸いです。この方法には以下の重要な利点があります。

    • 構成の一貫性
    • セットアップと破棄が容易
    • ネットワークトラフィックの分離
    • ビルドの一貫性

    さあ、ファジングを始めましょう!