上級
ターゲットへの入力方法¶
このレッスンでは、ファイル入力、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