コンテンツにスキップ

侊箚

Atheris を䜿甚した LibFuzzer むンストゥルメンテヌション付き Python タヌゲット

python-logo llvm-logo

テスト察象は Python タヌゲットですか? このレッスンでは、Atheris モゞュヌルを䜿甚した LibFuzzer むンストゥルメンテヌション付き Python タヌゲットをテストする方法を順を远っお説明したす。

孊習時間の目安: 15 分

このレッスンを終了するず、以䞋のこずができるようになりたす。

  1. キャッチされない䟋倖の欠陥がある Atheris モゞュヌルを䜿甚した libFuzzer むンストゥルメンテヌション付き Python タヌゲットをコンパむルし、ファゞングする。
  2. むンデックス境界倖の欠陥がある Atheris モゞュヌルを䜿甚した libFuzzer むンストゥルメンテヌション付き Python タヌゲットをコンパむルし、ファゞングする。

レッスンを駆け足で

始める前に前提条件を確認したす。

  1. python-atheris.tgz をダりンロヌドし、python-atheris Docker むメヌゞをビルドし、指定された Docker レゞストリにプッシュしたす。

    docker build -f Dockerfile -t <DOCKERHUB_USERNAME>/python-atheris .
    docker push <DOCKERHUB_USERNAME>/python-atheris
    
    docker build -f Dockerfile -t $MAYHEM_DOCKER_REGISTRY/forallsecure/python-atheris .
    docker push $MAYHEM_DOCKER_REGISTRY/forallsecure/python-atheris
    
  2. Mayhem UI たたは Mayhem CLI で次の Mayhemfile を䜿甚しお forallsecure/python-atheris Docker むメヌゞに察しお Mayhem ランを実行したす。

    1
    2
    3
    4
    5
    6
    7
    image: <DOCKERHUB_USERNAME>/python-atheris:latest
    duration: 90
    project: mayhem-examples
    target: python-atheris
    cmds:
      - cmd: /mayhemit.py
        libfuzzer: true
    
    1
    2
    3
    4
    5
    6
    7
    image: $MAYHEM_DOCKER_REGISTRY/forallsecure/python-atheris:latest
    duration: 90
    project: python
    target: python-atheris
    cmds:
      - cmd: /mayhemit.py
        libfuzzer: true
    

以䞋が必芁です。

  • Docker がむンストヌルされおいるこず
  • 有効なむンタヌネット接続 (Docker Hub ベヌス むメヌゞをプルするため)

ワン クリック テスト

䞋のボタンをクリックしお Python タヌゲットのテストを開始したす。最終確認ペヌゞに到達するたで [Next] をクリックし、[Start Run] をクリックしたす。

次のようなラン ペヌゞが衚瀺されたす。

python-atheris-run

Mayhem による Python タヌゲットのテストを確認したので、次に、どのように Python タヌゲットがビルドされたのかを順を远っお説明したす。

Mayhem での Atheris を䜿甚した Python タヌゲットのテスト

ファむル: python-atheris.tgz

䞊蚘の python-atheris.tgz をダりンロヌドしお展開し、次の脆匱性のある mayhemit.py プログラムを芋おみたしょう。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
#!/usr/bin/python3

import atheris
import sys

def TestOneInput(data):
    if len(data) >= 3:
        if data[0] == ord('b'):
            if data[1] == ord('u'):
                if data[2] == ord('g'):
                    raise Exception("Made it to the bug!")

atheris.instrument_all()
atheris.Setup(sys.argv, TestOneInput)
atheris.Fuzz()

Info

Python でむンデックスを䜿甚しお bytestring にアクセスするず、敎数が返されたす。そのため、string 文字のナニコヌド コヌド ポむントを衚珟する敎数を返す ord() が䜿甚されおいたす。data[0] == ord('b') が true に評䟡される等の条件を䜿甚しおいるのはそのためです。

Warning

atheris ハヌネス スクリプトに耇数のタヌゲット (たずえば foo および bar) が含たれおおり、コマンド ラむン匕数 (䟋: foo) によっおどれを遞択するかを制埡しおいる堎合、atheris.Setup の呌び出しを実行する前に、(sys.argv.pop(1) などを䜿甚しお) sys.argv から該圓匕数を陀倖する必芁がありたす。そうでなければ、atheris は䜙分な (未知の) 匕数をテスト タヌゲットに枡したす。䜙分な匕数が削陀されない堎合、 Mayhem ランは䜙分な匕数による "unexpected libFuzzer argument" ゚ラヌで倱敗したす。

atheris および sys モゞュヌルがプログラムにむンポヌトされ、関数 TestOneInput が入力パラメヌタヌ data を受け取るこずがわかりたす。この入力パラメヌタヌをチェックしお "bug" ずいう぀づりかどうかをチェックしおいたす。"bug" である堎合、行 12でキャッチされない䟋倖の欠陥によっおプログラムがクラッシュしたす。

行 12 および 13で、atheris モゞュヌルは Setup および Fuzz 関数を䜿甚しおテスト ゚ントリポむントをセットアップしおいたす。

次に、関連する Dockerfile を芋お、python-atheris がどのようにビルドされるかを確認したしょう。

1
2
3
4
5
6
FROM fuzzers/atheris:2.0.7-python3.9
COPY src/mayhemit.py /mayhemit.py

# Set to fuzz!
ENTRYPOINT []
CMD ["/mayhemit.py"]
  • 行 1: ビルド ステヌゞ Docker コンテナヌ内に必芁な atheris 䟝存関係を甚意するため、ベヌス環境ずしお fuzzers/atheris:2.0.7-python3.9 ベヌス むメヌゞが蚭定されおいたす。
  • 行 2: fuzzers/atheris:2.0.7-python3.9 Docker コンテナヌに mayhemit.py ゜ヌス ファむルがコピヌされおいたす。
  • 行 3: ビルドされた Docker むメヌゞのデフォルト実行ファむルずしお /mayhemit.py 実行ファむルが蚭定されおいたす。

Note

python-atheris タヌゲットに必芁なコンパむル ステップがないこずに気づくかもしれたせん。コンパむルが必芁な他の蚀語のタヌゲットず異なり、Python はむンタヌプリタヌ蚀語であるため、コンパむルは必芁ありたせん。

次に、docker build および docker push コマンドを䜿甚しお、Docker むメヌゞをビルドしお Docker Hub レゞストリにプッシュする必芁がありたす。python-atheris フォルダヌ内にいるこずを確認し、次のコマンドを実行したす。

次に、docker build および docker push コマンドを䜿甚しお、Docker むメヌゞをビルドしお Mayhem サヌバヌにプッシュする必芁がありたす。$MAYHEM_DOCKER_REGISTRY は、プラむベヌトな Mayhem Docker レゞストリの URL を衚す環境倉数です。python-atheris フォルダヌ内にいるこずを確認し、次のコマンドを実行したす。

docker build -f Dockerfile -t <DOCKERHUB_USERNAME>/python-atheris .
docker push <DOCKERHUB_USERNAME>/python-atheris
docker build -f Dockerfile -t $MAYHEM_DOCKER_REGISTRY/forallsecure/python-atheris .
docker push $MAYHEM_DOCKER_REGISTRY/forallsecure/python-atheris

Info

mayhem login コマンドを䜿甚しお内郚的な Mayhem Docker レゞストリの URL を怜玢し、次のコマンドを䜿甚しお DOCKER_REGISTRY 環境倉数を蚭定できたす:

export DOCKER_REGISTRY=tutorial.forallsecure.com:5000
ここでは、サンプルの Docker レゞストリ URL を蚭定しおいたすが、DOCKER_REGISTRY 環境倉数に自身の Mayhem Docker レゞストリ URL を蚭定する必芁がありたす。

新しく䜜成した Docker むメヌゞを Docker Hub レゞストリに正垞にプッシュしたら、Mayhem UI から新芏ランを䜜成し、<DOCKERHUB_USERNAME>/python-atheris Docker むメヌゞを怜玢したす。Mayhemfile が次のようになっおいるこずを確認したす。

新しく䜜成した Docker むメヌゞをプラむベヌトな Mayhem Docker レゞストリに正垞にプッシュしたら、Mayhem UI から新芏ランを䜜成し、forallsecure/python-atheris Docker むメヌゞを怜玢したす。Mayhemfile が次のようになっおいるこずを確認したす。

1
2
3
4
5
6
7
image: <DOCKERHUB_USERNAME>/python-atheris:latest
duration: 90
project: python
target: python-atheris
cmds:
  - cmd: /mayhemit.py
    libfuzzer: true
1
2
3
4
5
6
7
image: $MAYHEM_DOCKER_REGISTRY/forallsecure/python-atheris:latest
duration: 90
project: python
target: python-atheris
cmds:
  - cmd: /mayhemit.py
    libfuzzer: true

新芏ラン䜜成フロヌの最終確認ペヌゞに到達するたで [Next] をクリックし、[Start Run] をクリックしお Mayhem ランを実行したす。次のようなラン ペヌゞが衚瀺されたす。

python-atheris-run

おめでずうございたす! atheris ファザヌ モゞュヌルを䜿甚した Python タヌゲットのテストが成功したした。

⚡ 珟実的な挔習: Atheris を䜿甚した mayhemit-out-of-bounds Python タヌゲットのビルドずテスト

キャッチされない䟋倖の欠陥がある Python タヌゲットのビルドおよびテスト方法がわかったずころで、゜ヌス コヌドを修正しおむンデックス境界倖の欠陥を怜出できるかどうかやっおみたしょう。

ファむル: mayhemit-out-of-bounds-unsolved.zip

手順

  • mayhemit.py ゜ヌス コヌドを倉曎し、次の行を远加しお配列境界倖欠陥を蚭定したす。
1
2
3
4
5
6
7
def TestOneInput(data):
    if len(data) >= 3 and len(data) < 5:
        if data[0] == ord('b'):
            if data[1] == ord('u'):
                if data[2] == ord('g'):
                    print("Made it to the bug!")
                    return data[10]
  • docker build コマンドを䜿甚しお Dockerfile を再ビルドし、結果の Docker むメヌゞを <DOCKERHUB_USERNAME>/python-atheris-mayhemit-out-of-bounds ずしおタグ付けしたす。
  • docker push コマンドを䜿甚しおパブリックな Docker Hub レゞストリに <DOCKERHUB_USERNAME>/python-atheris-mayhemit-out-of-bounds Docker むメヌゞをプッシュしたす。
  • Mayhem UI たたは Mayhem CLI を䜿甚しお <DOCKERHUB_USERNAME>/python-atheris-mayhemit-out-of-bounds Docker むメヌゞをファゞングしたす。Mayhemfile が適切に蚭定されおいるこずを確認したす。
  • docker build コマンドを䜿甚しお Dockerfile を再ビルドし、結果の Docker むメヌゞを $MAYHEM_DOCKER_REGISTRY/python-atheris-mayhemit-out-of-bounds ずしおタグ付けしたす。
  • docker push コマンドを䜿甚しおプラむベヌトな Mayhem Docker レゞストリに $MAYHEM_DOCKER_REGISTRY/python-atheris-mayhemit-out-of-bounds Docker むメヌゞをプッシュしたす。
  • Mayhem UI たたは Mayhem CLI を䜿甚しお $MAYHEM_DOCKER_REGISTRY/python-atheris-mayhemit-out-of-bounds Docker むメヌゞをテストしたす。Mayhemfile が適切に蚭定されおいるこずを確認したす。

🔍 確認Atheris を䜿甚した mayhemit-out-of-bounds Python タヌゲットのビルドずテスト

解答

暡範解答: mayhemit-out-of-bounds-solved.zip

たず、TestOneInput 関数をファゞングしたずき、入力テスト ケヌス "bug" がむンデックス境界倖゚ラヌを発生させるよう、最倧長の制玄 len(data) < 5 および誀った呌び出し data[10] を远加したす。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
#!/usr/bin/python3

import atheris
import sys

def TestOneInput(data):
    if len(data) >= 3 and len(data) < 5:
        if data[0] == ord('b'):
            if data[1] == ord('u'):
                if data[2] == ord('g'):
                    print("Made it to the bug!")
                    return data[10]

atheris.instrument_all()
atheris.Setup(sys.argv, TestOneInput)
atheris.Fuzz()

次に、Dockerfile ず同じディレクトリで docker build コマンドを実行し、結果の Docker むメヌゞに <DOCKERHUB_USERNAME>/python-atheris-mayhemit-out-of-bounds ずいうタグを付けたす。

次に、Dockerfile ず同じディレクトリで docker build コマンドを実行し、結果の Docker むメヌゞに $MAYHEM_DOCKER_REGISTRY/python-atheris-mayhemit-out-of-bounds ずいうタグを付けたす。

docker build -f Dockerfile -t <DOCKERHUB_USERNAME>/python-atheris-mayhemit-out-of-bounds .
docker build -f Dockerfile -t $MAYHEM_DOCKER_REGISTRY/python-atheris-mayhemit-out-of-bounds .

次に、<DOCKERHUB_USERNAME>/python-atheris-mayhemit-out-of-bounds Docker むメヌゞにタグを付けおパブリックな Docker Hub レゞストリにプッシュしたす。

次に、$MAYHEM_DOCKER_REGISTRY/python-atheris-mayhemit-out-of-bounds Docker むメヌゞにタグを付けおプラむベヌトな Mayhem Docker レゞストリにプッシュしたす。

docker push <DOCKERHUB_USERNAME>/python-atheris-mayhemit-out-of-bounds
docker push $MAYHEM_DOCKER_REGISTRY/python-atheris-mayhemit-out-of-bounds

別の方法ずしお、付属の Makefil を䜿甚し、MAYHEM_DOCKER_REGISTRY` 環境倉数を蚭定しお次のコマンドを実行するこずで、簡単に結果の Docker むメヌゞをビルドし、プッシュするこずもできたす。

make build
make push

最埌に、Mayhem UI たたは Mayhem CLI を䜿甚しお、アップロヌドされた <DOCKERHUB_USERNAME>/python-atheris-mayhemit-out-of-bounds Docker むメヌゞに察しお Mayhem ランを実行したす。Mayhemfile は次のようになっおいるはずです。

最埌に、Mayhem UI たたは Mayhem CLI を䜿甚しお、アップロヌドされた $MAYHEM_DOCKER_REGISTRY/python-atheris-mayhemit-out-of-bounds Docker むメヌゞに察しお Mayhem ランを実行したす。Mayhemfile は次のようになっおいるはずです。

1
2
3
4
5
6
7
image: <DOCKERHUB_USERNAME>/python-atheris-mayhemit-out-of-bounds:latest
duration: 90
project: mayhem-examples
target: mayhemit-out-of-bounds
cmds:
  - cmd: /mayhemit.py
    libfuzzer: true
1
2
3
4
5
6
7
image: $MAYHEM_DOCKER_REGISTRY/python-atheris-mayhemit-out-of-bounds:latest
duration: 90
project: mayhem-examples
target: mayhemit-out-of-bounds
cmds:
  - cmd: /mayhemit.py
    libfuzzer: true

最終的なラン ペヌゞは次のように衚瀺されるはずです。

mayhemit-out-of-bounds-run

おめでずうございたす! Mayhem がむンデックス境界倖の欠陥を発芋したした。スクラッチから Python タヌゲットをビルドし、Atheris ファザヌ モゞュヌルを䜿甚しおバグを怜出できたした。

✏ たずめず振り返り

このレッスンでは、Atheris ファザヌ モゞュヌルおよび Mayhem を䜿甚しお libFuzzer むンストゥルメンテヌション付き Python タヌゲットをファゞングする方法を孊びたした。


孊習内容

1. Atheris を䜿甚した LibFuzzer むンストゥルメンテヌション付き Python タヌゲットをビルドおよびテストしおキャッチされない䟋倖の欠陥を怜出する。
  • ゜ヌス コヌドには次の欠陥が含たれおいるはずです:

    1
    2
    3
    4
    5
    6
    def TestOneInput(data):
        if len(data) >= 3:
            if data[0] == ord('b'):
                if data[1] == ord('u'):
                    if data[2] == ord('g'):
                        raise Exception("Made it to the bug!")
    

  • Atheris を䜿甚しお Python タヌゲットをファゞングするには、次の Dockerfile を䜿甚しお Python プログラムを含む Docker むメヌゞをビルドしたす。

    1
    2
    3
    4
    5
    6
    FROM fuzzers/atheris:2.0.7-python3.9
    COPY mayhemit.py /mayhemit.py
    
    # Set to fuzz!
    ENTRYPOINT []
    CMD ["/mayhemit.py"]
    

2. Atheris を䜿甚した LibFuzzer むンストゥルメンテヌション付き Python タヌゲットをビルドおよびファゞングしおむンデックス境界倖の欠陥を怜出する。
  • ゜ヌス コヌドには次の欠陥が含たれおいるはずです:

    1
    2
    3
    4
    5
    6
    7
    def TestOneInput(data):
        if len(data) >= 3 and len(data) < 5:
            if data[0] == ord('b'):
                if data[1] == ord('u'):
                    if data[2] == ord('g'):
                        print("Made it to the bug!")
                        return data[10]
    

  • Atheris を䜿甚しお Python タヌゲットをファゞングするには、次の Dockerfile を䜿甚しお Python プログラムを含む Docker むメヌゞをビルドしたす。

    1
    2
    3
    4
    5
    6
    FROM fuzzers/atheris:2.0.7-python3.9
    COPY mayhemit.py /mayhemit.py
    
    # Set to fuzz!
    ENTRYPOINT []
    CMD /mayhemit.py