上級
ターゲットへの入力方法¶
このレッスンでは、ファイル入力、stdin、TCP/UDP など、さまざまなタイプの入力を使用するバイナリを Mayhem でテストする方法を説明します。bacsrv や lighttpd などの一般的なネットワーク アプリケーションをパッケージ化してテストする方法を順を追って学びましょう。
学習時間の目安: 20 分
このレッスンを完了すると、以下のことができるようになります。
- 異なるタイプの入力を必要とするバイナリの Mayhemfile を比較する。
bacsrvネットワーク アプリケーションを分析し、リスニング ポートを特定する。Mayhemfileでネットワーク オプションを構成する。bacsrvに対して Mayhem ランを実行する。lighttpdの依存関係を手動でパッケージ化する。lighttpdに対して Mayhem ランを実行する。
レッスンを駆け足で
始める前に前提条件を確認します。
-
Mayhem は以下の入力を使用してターゲット バイナリをファジングできます。
- ファイル入力
- 標準入力
- TCP/UDP 入力
-
Mayhem CLI を使用して
bacsrvターゲットをパッケージ化します。mayhem package ./bacsrv -o /tmp/bacsrv-pkg -
mayhem runコマンドに次の Mayhemfile を指定して、bacsrvターゲットに対して Mayhem ランを実行します。1 2 3 4 5 6 7 8 9 10 11 12 13
project: bacsrv target: bacsrv duration: 90 advanced_triage: true cmds: - cmd: /root/tutorial/bacsrv/bacsrv # For a network program, you add a "network" specification block network: url: udp://localhost:47808 # protocol, host and port to analyze client: false # target is not a client program timeout: 2.0 # max seconds before timing out on network -
mayhem packageコマンドを使用してlighttpdターゲットをパッケージ化します。# Run the package command mayhem package ./1.4.15/sbin/lighttpd -o /tmp/lighttpd-pkg # Copy over all dependencies manually cp -R ./1.4.15 /tmp/lighttpd-pkg/root/root/tutorial/lighttpd/ cp -R /www /tmp/lighttpd-pkg/root/ -
mayhem runコマンドに次の Mayhemfile を指定して、lighttpdターゲットに対して Mayhem ランを実行します。1 2 3 4 5 6 7 8 9 10
project: lighttpd target: lighttpd-1-4 duration: 90 cmds: - cmd: /root/tutorial/lighttpd/1.4.15/sbin/lighttpd -D -f /root/tutorial/lighttpd/1.4.15/etc/lighttpd.conf network: client: false timeout: 5.0 url: tcp://localhost:8080
以下が必要です。
- The Mayhem CLI がインストールされ、Mayhem サーバーで認証済みであること。
-
あらかじめビルドされた Docker イメージを実行し、チュートリアル サンプルにアクセスできること、
docker pull forallsecure/tutorial:2.10 docker run -ti --privileged --rm forallsecure/tutorial:2.10
入力タイプに対応した Mayhemfile¶
Mayhem は次の入力を使用してターゲット バイナリをファジングできます。
- ファイル入力
- 標準入力
- TCP/UDP 入力
いくつかのサンプルを提示して、Mayhemfile 構成の違いを説明します。自由にサンプルの Mayhemfile を使って Mayhem ランを実行してみてください。
Info
テスト対象はもっと複雑なカスタム ターゲットでしょうか? Mayhemfile の構成に関する詳細は、「Mayhemfile の構成」ページを参照してください。
ファイル入力¶
コマンドライン上で単一の入力を受け取ります (objdump から)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | |
標準入力 (stdin)¶
/dev/stdin から入力を受け取るあいだ、ずっと djpeg に対してテストを実行します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | |
TCP/UDP 入力¶
パブリックな Docker Hub イメージを使用し、TCP ポートの 80 でネットワークから単一の入力を受け取ります (sebp/lighttpd から)。
1 2 3 4 5 6 7 8 9 10 | |
bacsrv の解析¶
bacsrv (bacserv とも呼ばれます) は BACnet ツール スイートの一部です。 BACnet のWeb サイトには次のように記載されています。
American Society of Heating, Refrigerating and Air-Conditioning Engineers (ASHRAE) の後援の下で開発された BACnet は、アメリカの国家規格、欧州規格、30 以上の国々での国家規格、そして ISO のグローバル規格です。このプロトコルは、ASHRAE Standing Standard Project Committee 135 のメンバーによってサポートおよびメンテナンスが行われています。
今回は bacsrv を解析しますが、このアプリケーションは UDP ポートの 47808 で待機します。Mayhem の利点の 1 つは、TCP および UDP サーバーについても、特別なテスト ドライバーを作成する必要がないことです。バイナリを変更せず、そのまま解析します。
アプリケーションを解析する際の最初のステップは、アプリケーションを実行できるかを確認することです。examples/bacsrv ディレクトリに移動し、bacsrv を実行します。
$ cd ~/tutorial/bacsrv
$ ./bacsrv &
BACnet Server Demo
BACnet Stack Version 0.9.1
BACnet Device ID: 260001
Max APDU: 1476
ネットワーク アプリケーションが使用するポートがわからない場合はどうすればよいのでしょうか? netstat、lsof、または strace を使用するなど、調べる方法は複数あります。strace を使って、bacsrv がポート 47808 で動作していることを確認しましょう。
たとえば、bind への呼び出しを探すことで、bacsrv がポート 47808 で動作していることがわかります。
# strace -Tfe trace=bind ./bacsrv
BACnet Server Demo
BACnet Stack Version 0.9.1
BACnet Device ID: 260001
Max APDU: 1476
bind(3, {sa_family=AF_INET, sin_port=htons(47808), sin_addr=inet_addr("0.0.0.0")}, 16) = 0 <0.000018>
Note
Docker でレッスンを進める場合、必ず --privileged フラグを指定して呼び出してください。そうでなければ strace は動作しません。
Mayhemfile bacsrv¶
これまでのレッスンでは、Mayhemfile の cmd パラメーターのターゲット パスに @@ を付加することで、testme アプリケーションはファイルを読み取ることを Mayhem に通知しました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | |
一方、ネットワーク アプリケーションを解析する場合は、アプリケーションがどのネットワーク ポートを使用するか、また TCP と UDP のどちらを使用するかを Mayhem に通知する必要があります。この情報を指定する方法を示した bacsrv の Mayhemfile をサンプルとして挙げます。
1 2 3 4 5 6 7 8 9 10 11 12 13 | |
urlはTCP|UDP://<HOST>:PORTという形式で指定されます。Mayhem は同一ホスト上で実行されているサービスに接続するため、ほとんどの場合、HOSTはlocalhostになるでしょう。clientは、アプリケーションがcurlやwgetのようにネットワーク越しに通信するか、それともサーバーであるかを指定します。今回はサーバーを解析するため、値としてfalseを設定します。timeoutは、リクエストを送信した後、サービスが応答していないと判断するまでにどれほど待機する必要があるかを指定します。1.0 または 2.0 が適切な値ですが、解析中にネットワーク サービスがタイムアウトする問題が発生する場合は、値を増やすことを検討するべきです。
Mayhem bacsrv¶
Mayhemfile を作成したら、他のプログラムと同様に、パッケージ化して Mayhem ランを実行することで bacsrv を解析します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | |
ハードウェアにもよりますが、10 分もかからないうちに、無効な読み取り (CWE-125) によるクラッシュが再現され、その他、未初期化変数が使用されているというエラーがいくつか再現されるはずです。
lighttpd¶
lighttpd は高速で標準に準拠した柔軟な Web サーバーであり、他の Web サーバーに比べて何倍もスケール性に優れています。
このサンプルでは、lighttpd のパッケージ化と実行の方法を示し、パッケージ化で遭遇しやすいエラーについて説明します。Mayhem パッケージとは、実行可能プログラムと共有オブジェクトや構成ファイルを含む実行環境全体であることを思い出してください。
lighttpd を実行できることを確認する¶
tutorial/lighttpd にあるサンプルには、lighttpd の悪用可能な脆弱性を持つバージョンである lighttpd-1.4.15 が事前インストールされています。
./1.4.15/sbin/lighttpd -D -f ./1.4.15/etc/lighttpd.conf
2019-09-02 23:22:20: (log.c.75) server started
2019-09-02 23:22:21: (server.c.1252) [note] graceful shutdown started
2019-09-02 23:22:21: (log.c.135) server stopped
Info
Ctrl+C キーを押して lighttpd に SIGINT (signal interrupt) を送信すると、グレースフルにシャットダウンできます。
初回のトライ: lighttpd をパッケージ化する¶
mayhem package コマンドは、実行ファイルを検査して、静的に解決可能なすべての依存関係を特定します。しかし、多くの Web サーバーと同様に、lighttpd は実行時にライブラリを解決します。共有ライブラリ自体が問題なのではないことに注意してください。dlopen() などによる実行時の動的解決がいつ行われるかが問題なのです。
残念ながら、lighttpd は mayhem package が静的に発見できない依存関係を使用しています。理由を知るため、以下を実行します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | |
mayhem run は Mayhem ランを開始しますが、mayhem wait はランが失敗したことを示します。UI に移動して [Event Log] をクリックすると、lighttpd のランが失敗した理由が次のように表示されます。
- Mayhem ランのビヘイビア テストが失敗しました。
- Mayhem はプログラムが入力を読み取っていないことを検出しました。
lighttpdがエラーを出力しました。
lighttpd の動作を少し調べてみると、理由がわかります。
- アップロードしたパッケージは、すべての lighttpd の依存関係を含んではいませんでした。特に、このランでは、lighttpd の起動時に構成ファイルが見つからず、いくつかの dlopen() によって動的にロードされる動的ライブラリがありませんでした。結果として、
mayhem packageはlighttpdターゲットを適切にパッケージ化できませんでした。 - デフォルトの
Mayhemfileには、lighttpdターゲットと通信するためのネットワーク プロトコルが指定されていませんでした。
mayhem package コマンドを使用して生成された Mayhemfile を見ると、このパッケージ化方法の限界が明らかになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | |
生成された Mayhemfile が lighttpd に必要なネットワーク オプションを指定していなかったことがわかります
二回目のトライ: lighttpd を正常に解析する¶
正常に lighttpd を解析するには、以下を行う必要があります。
- 正しく TCP の 8080 ポートで
lighttpdをテストするよう指示するMayhemfileを作成します。 - すべての依存関係を Mayhem パッケージにコピーします。
一般的に、すべての依存関係を洗い出すのは少々やっかいです。このレッスンでは、すべての依存関係を 1 つのディレクトリの下に配置することで、問題を単純化してあります。現実では、依存関係はファイル システムのあちこちに散らばっている場合もあります。上で触れた strace などのツールは、そういった依存関係を見つけるのに役立ちます。
次の Mayhemfile は、Mayhem に lighttpd の解析方法を指示します。
1 2 3 4 5 6 7 8 9 10 | |
次のスクリプトを実行すると、lighttpd と依存関係が正しくパッケージ化されます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | |
Warning
Mayhem は特権なしのユーザーとして実行されることを思い出してください。ネットワーク サービスが 1024 未満のポートにバインドされる場合、Mayhemfile の最上位レベルで uid: 0 を指定して、root としてプログラムを実行する必要があります。
✏️ まとめと振り返り¶
このレッスンでは、bacsrv や lighttpd などのネットワーク ターゲットをファジングする方法を学びました。
学習内容
1.さまざまな入力を必要とするバイナリの Mayhemfile 構成を比較します。
-
コマンドライン上で単一の入力を受け取ります (
objdumpから)。1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
# Project name that the target belongs to project: objdump # Target name (should be unique within the project) target: objdump # Base image to run the binary in. image: forallsecure/debian-buster:latest # Time that analysis will run for in seconds - if absent, run forever duration: 90 # List of commands used to test the target cmds: # Command used to start the target, "@@" is the input file - cmd: /usr/bin/objdump -x @@ -
/dev/stdinから入力を受け取るあいだ、ずっと djpeg に対してテストを実行します。1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
# Mayhemfile: configuration file for testing your target with Mayhem # Format: YAML 1.1 # Project name that the target belongs to project: libjpeg # Target name (should be unique within the project) target: djpeg # Base image to run the binary in. image: forallsecure/debian-buster:latest # Commented out duration to run forever # duration: 90 # List of commands used to test the target cmds: # Command used to start the target. "@@" is missing so # input will be read from /dev/stdin. - cmd: /usr/bin/djpeg -
パブリックな Docker Hub イメージを使用し、TCP ポートの 80 でネットワークから単一の入力を受け取ります (
sebp/lighttpdから)。1 2 3 4 5 6 7 8 9 10
project: lighttpd-docker target: lighttpd image: sebp/lighttpd duration: 90 cmds: - cmd: /usr/sbin/lighttpd -D -f /etc/lighttpd/lighttpd.conf network: client: false url: tcp://127.0.0.1:80 timeout: 1.0
2.bacsrv ネットワーク アプリケーションを解析し、リスニング ポートを特定します。
straceユーティリティを使用してbacsrvがポート 47808 で待機することを確認できます。
$ strace -Tfe trace=bind ./bacsrv
BACnet Server Demo
BACnet Stack Version 0.9.1
BACnet Device ID: 260001
Max APDU: 1476
bind(3, {sa_family=AF_INET, sin_port=htons(47808), sin_addr=inet_addr("0.0.0.0")}, 16) = 0 <0.000018>
3.Mayhemfile でネットワーク オプションを構成します。
- ネットワーク アプリケーションを解析する場合は、アプリケーションがどのネットワーク ポートを使用するか、また TCP と UDP のどちらを使用するかを Mayhem に通知する必要があります。この情報を指定する方法を示した bacsrv の Mayhemfile をサンプルとして挙げます。
1 2 3 4 5 6 7 8 9 10 11 12 13 | |
4.bacsrv に対して Mayhem ランを実行します。
-
次のスクリプトは、
bacsrvターゲットに対して Mayhem ランを実行します。#!/bin/sh # Package bacsrv mayhem package ./bacsrv -o /tmp/bacsrv-pkg # Write your Mayhemfile (here copying over provided one) cp Mayhemfile /tmp/bacsrv-pkg/Mayhemfile # Run Mayhem! id=$(mayhem run /tmp/bacsrv-pkg) # Wait for the run to finish mayhem wait $id # Sync the test suite to the "testsuite" directory. mayhem sync /tmp/bacsrv-pkg
5.lighttpd の依存関係を手動でパッケージ化します。
-
次のスクリプトは、
lighttpdの依存関係を正しくパッケージ化します。1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
#!/bin/sh # Run the package command mayhem package ./1.4.15/sbin/lighttpd -o /tmp/lighttpd-pkg # Copy over all dependencies manually cp -R ./1.4.15 /tmp/lighttpd-pkg/root/root/tutorial/lighttpd/ cp -R /www /tmp/lighttpd-pkg/root/ # Copy over the Mayhemfile needed to run lighttpd cp Mayhemfile /tmp/lighttpd-pkg/ # Copy over an example test suite. This speeds up the example by # seeding analysis with an example input. cp testsuite/* /tmp/lighttpd-pkg/testsuite/ # Run mayhem on the package id=$(mayhem run /tmp/lighttpd-pkg/) # Wait for Mayhem to finish. It will succeed this time because we included # lighttpd's dependencies. mayhem wait $id
6.lighttpd に対して Mayhem ランを実行します。
-
次のスクリプトは、
lighttpdに対して Mayhem ランを実行します。1 2 3 4 5 6 7 8 9 10
project: lighttpd target: lighttpd-1-4 duration: 90 cmds: - cmd: /root/tutorial/lighttpd/1.4.15/sbin/lighttpd -D -f /root/tutorial/lighttpd/1.4.15/etc/lighttpd.conf network: client: false timeout: 5.0 url: tcp://localhost:8080

