Skip to content
KitploitKITPLOIT
ツールブログ
提出
ツールブログ
提出

ハッキング、侵入テスト、サイバーセキュリティツールをあなたのセキュリティアーセナルに!

Kitploitはハッキング、サイバーセキュリティ、ペネトレーションテストのツールディレクトリです。最新のプロジェクトアップデートを見つけて、脆弱性の発見、システム分析、テストの自動化、セキュリティの強化を行いましょう。

··フィード·お問い合わせ·プライバシー·© 2026 Kitploit

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
ruzzy — 純RubyコードとRuby C拡張のためのカバレッジガイドファザー | Kitploit
ツール/GitHubGitHub/trailofbits/ruzzy
動的分析 (サンドボックス)脆弱性分析コード分析ファジングバイナリ解析学習と教育
GitHubtrailofbits/ruzzy

ruzzy

純RubyコードとRuby C拡張のためのカバレッジガイドファザー

リポジトリを見る
123742ヶ月前Kitploit レビュー済み

人気

すべて見る →

コミュニティで最も使われているツールを見つけましょう。

すべてのツールを探索

ツールコレクションを閲覧

すべてのツールを見る →
共有

Ruzzy

Test Gem Version

純粋なRubyコードおよびRuby C拡張向けのカバレッジガイドファザーです。

Ruzzyは、GoogleのAtheris(Pythonファザー)に大きく触発されています。Ruzzyは、カバレッジの計装とファジングエンジンにlibFuzzer(またはLibAFL)を使用しています。また、C拡張のファジング時にはAddressSanitizerおよびUndefinedBehaviorSanitizerもサポートしています。Ruzzyの背後にある着想について詳しく知りたい場合は、論文「Design and Implementation of a Coverage-Guided Ruby Fuzzer」をご覧ください。

目次:

  • インストール
  • 使い方
    • はじめに
    • 純粋なRubyコードのファジング
    • Ruby C拡張のファジング
  • API
    • Ruzzy
    • FuzzedDataProvider
  • macOSユーザー向けの注意
  • 成果一覧
  • 開発
    • コンパイル
    • テスト
    • リント
    • リリース
  • 参考文献

インストール

RuzzyはLinux(x86-64、AArch64/ARM64)およびmacOS(Apple Silicon)をサポートしています。Windowsでは、Dockerfileをビルドするか、開発環境を使用できます。Ruzzyには、比較的新しいバージョンのclang(14.0.0までテスト済み)が必要です。できれば最新リリースを使用してください。macOS固有の設定については、macOSユーザー向けの注意を参照してください。

次のコマンドでRuzzyをインストールします:

root@kitploit:~
MAKE="make --environment-overrides V=1" \
CC="/path/to/clang" \
CXX="/path/to/clang++" \
LDSHARED="/path/to/clang -shared" \
LDSHAREDXX="/path/to/clang++ -shared" \
    gem install ruzzy

ここでは多くの設定を行っていますので、分解して説明します:

  • MAKE環境変数は、Ruzzy C拡張をコンパイルする際のmakeコマンドを上書きします。これにより、拡張機能のコンパイル時に後続の環境変数が尊重されるようにmakeに指示します。
  • 残りの環境変数は、コンパイル時に適切なclangバイナリを使用するために使用されます。これにより、適切なファジングに必要な最新のclang機能が確実に使用されます。

インストールで問題が発生した場合は、次のコマンドを実行してデバッグ出力を取得できます:

root@kitploit:~
RUZZY_DEBUG=1 gem install --verbose ruzzy

純粋なRubyファジングターゲットが正規表現を多用する場合は、regexp_parserをインストールしてください:

root@kitploit:~
gem install regexp_parser

インストール後、Ruzzyはこの機能を自動的に使用して、ファジング中に遭遇した正規表現をサンプリング(解決)します。これにより、ファザーは正規表現条件を通過して、追加のカバレッジを獲得できます。

使い方

はじめに

Ruzzyには、その動作を示すおもちゃの例が含まれています。最初に、次の環境変数を設定します:

root@kitploit:~
export ASAN_OPTIONS="allocator_may_return_null=1:detect_leaks=0:use_sigaltstack=0"
これらのオプションを理解する必要はありませんが、気になる場合はここをクリックしてください。

ASAN_OPTIONS

  1. メモリ割り当ての失敗は一般的で影響が低い(DoS)ため、今はスキップします。
  2. Pythonと同様に、Rubyインタプリタはデータをリークするため、今は無視します。
  3. Rubyはsigaltstackの無効化を推奨しています。

次に、次のコマンドで例を実行できます:

root@kitploit:~
LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
    ruby -e 'require "ruzzy"; Ruzzy.dummy'

LD_PRELOADは、Atherisと同じ理由で必要です。ただし、ASAN_OPTIONSとは異なり、exportすることはおそらく避けるべきです。他のプログラムに干渉する可能性があるためです。

次のようなクラッシュがすぐに発生するはずです:

root@kitploit:~
INFO: Running with entropic power schedule (0xFF, 100).
INFO: Seed: 2527961537
...
==45==ERROR: AddressSanitizer: heap-use-after-free on address 0x50c0009bab80 at pc 0xffff99ea1b44 bp 0xffffce8a67d0 sp 0xffffce8a67c8
...
SUMMARY: AddressSanitizer: heap-use-after-free /var/lib/gems/3.1.0/gems/ruzzy-0.8.0/ext/dummy/dummy.c:18:24 in _c_dummy_test_one_input
...
==45==ABORTING
MS: 4 EraseBytes-CopyPart-CopyPart-ChangeBit-; base unit: 410e5346bca8ee150ffd507311dd85789f2e171e
0x48,0x49,
HI
artifact_prefix='./'; Test unit written to ./crash-253420c1158bc6382093d409ce2e9cff5806e980
Base64: SEk=

メモリ違反を引き起こす入力("HI")が正しく見つかったことがわかります。詳細については、dummy.cを参照して、この違反が発生した理由を確認してください。

次のコマンドでクラッシュケースを再実行できます:

root@kitploit:~
LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
    ruby -e 'require "ruzzy"; Ruzzy.dummy' \
    ./crash-253420c1158bc6382093d409ce2e9cff5806e980

以下のサニタイザーが利用可能です:

  • Ruzzy::ASAN_PATH:AddressSanitizer用
  • Ruzzy::UBSAN_PATH:UndefinedBehaviorSanitizer用

純粋なRubyコードのファジング

例として、小さなRubyスクリプトをファジングしてみましょう。純粋なRubyコードのファジングには、トレーサースクリプトとファジングハーネスの2つのRubyスクリプトが必要です。トレーサースクリプトは、Rubyインタプリタの実装の詳細のために必要です。

まず、トレーサースクリプトです。test_tracer.rbという名前にしましょう:

root@kitploit:~
# frozen_string_literal: true

require 'ruzzy'

Ruzzy.trace('test_harness.rb')

次に、ファジングハーネスです。test_harness.rbという名前にしましょう:

root@kitploit:~
# frozen_string_literal: true

require 'ruzzy'

def fuzzing_target(input)
  if input.length == 4
    if input[0] == 'F'
      if input[1] == 'U'
        if input[2] == 'Z'
          if input[3] == 'Z'
            raise
          end
        end
      end
    end
  end
end

test_one_input = lambda do |data|
  fuzzing_target(data) # ここにファジングターゲットを記述
  return 0
end

Ruzzy.fuzz(test_one_input)

次のコマンドでこのファイルを実行し、ファジングを開始できます:

root@kitploit:~
LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
    ruby test_tracer.rb

次のようなクラッシュがすぐに発生するはずです:

root@kitploit:~
INFO: Running with entropic power schedule (0xFF, 100).
INFO: Seed: 2311041000
...
/app/ruzzy/bin/test_harness.rb:12:in `block in <top (required)>': unhandled exception
	from /var/lib/gems/3.1.0/gems/ruzzy-0.8.0/lib/ruzzy.rb:15:in `c_fuzz'
	from /var/lib/gems/3.1.0/gems/ruzzy-0.8.0/lib/ruzzy.rb:15:in `fuzz'
	from /app/ruzzy/bin/test_harness.rb:35:in `<top (required)>'
	from bin/test_tracer.rb:7:in `require_relative'
	from bin/test_tracer.rb:7:in `<main>'
...
SUMMARY: libFuzzer: fuzz target exited
MS: 1 CopyPart-; base unit: 24b4b428cf94c21616893d6f94b30398a49d27cc
0x46,0x55,0x5a,0x5a,
FUZZ
artifact_prefix='./'; Test unit written to ./crash-aea2e3923af219a8956f626558ef32f30a914ebc
Base64: RlVaWg==

例外を発生させる入力("FUZZ")が正しく見つかったことがわかります。

独自のターゲットをファジングするには、test_one_input lambdaを変更して、ターゲット関数を呼び出します。

Ruby C拡張のファジング

例として、msgpack-rubyライブラリをファジングしてみましょう。まず、gemをインストールします:

root@kitploit:~
MAKE="make --environment-overrides V=1" \
CC="/path/to/clang" \
CXX="/path/to/clang++" \
LDSHARED="/path/to/clang -shared" \
LDSHAREDXX="/path/to/clang++ -shared" \
CFLAGS="-fsanitize=address,fuzzer-no-link -fno-omit-frame-pointer -fno-common -fPIC -g" \
CXXFLAGS="-fsanitize=address,fuzzer-no-link -fno-omit-frame-pointer -fno-common -fPIC -g" \
    gem install msgpack

Ruzzyのコンパイル時に使用した環境変数に加えて、CFLAGSとCXXFLAGSを指定しています。これらのフラグはファジングプロセスを支援します。アドレスサニタイザーや改善されたスタックトレース情報などの便利な機能を有効にします。詳細については、AddressSanitizerFlagsを参照してください。

次に、msgpack用のファジングハーネスが必要です。以下は、libFuzzerに詳しい方にはおなじみかもしれません:

root@kitploit:~
# frozen_string_literal: true

require 'msgpack'
require 'ruzzy'

test_one_input = lambda do |data|
  begin
    MessagePack.unpack(data)
  rescue Exception
    # メモリ破損を探しているため、Rubyの例外は無視
  end
  return 0
end

Ruzzy.fuzz(test_one_input)

このファイルをfuzz_msgpack.rbという名前で保存しましょう。次のコマンドでこのファイルを実行し、ファジングを開始できます:

root@kitploit:~
LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
    ruby fuzz_msgpack.rb

libFuzzerオプションは、次のようにRubyスクリプトに渡すことができます:

root@kitploit:~
LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
    ruby fuzz_msgpack.rb /path/to/corpus

詳細については、libFuzzerオプションを参照してください。

独自のターゲットをファジングするには、test_one_input lambdaを変更して、ターゲット関数を呼び出します。

API

Ruzzy

Ruzzyモジュールは、トップレベルのエントリポイントを公開します。

FuzzedDataProvider

Ruzzy::FuzzedDataProviderは、生のファザーバイトを分割して、型付きのRuby値に変換します。

root@kitploit:~
test_one_input = lambda do |data|
  fdp = Ruzzy::FuzzedDataProvider.new(data)
  name = fdp.consume_random_length_string(50)
  age = fdp.consume_int_in_range(0, 150)
  score = fdp.consume_float_in_range(0.0, 100.0)
  role = fdp.pick_value_in_list(['admin', 'user', 'guest'])
  User.new(name: name, age: age, score: score, role: role).validate!
end

Ruzzy.fuzz(test_one_input)

すべてのメソッドは、データが尽きた場合にデフォルト値(0、""、false、min)を返します。

macOSユーザー向けの注意

macOS上のRuzzyには、HomebrewでインストールしたLLVM(Apple ClangにはlibFuzzerが含まれていません)と、システム以外のRuby(/usr/bin/rubyのシステムRubyはSIPで保護されており、Ruby起動前にDYLD_*環境変数が削除されます)が必要です。

前提条件

root@kitploit:~
brew install llvm ruby

システム以外のRuby(brew、rbenv、asdf)はどれでも動作しますが、以下の注意事項をシムベースのバージョンマネージャーについて参照してください。

インストール

Homebrew ClangのパスとmacOSに適したリンカーフラグを使用します:

root@kitploit:~
MAKE="make --environment-overrides V=1" \
CC="$(brew --prefix llvm)/bin/clang" \
CXX="$(brew --prefix llvm)/bin/clang++" \
LDSHARED="$(brew --prefix llvm)/bin/clang -dynamic -bundle -undefined dynamic_lookup" \
LDSHAREDXX="$(brew --prefix llvm)/bin/clang++ -dynamic -bundle -undefined dynamic_lookup" \
    gem install ruzzy

実行

LD_PRELOADの代わりにDYLD_INSERT_LIBRARIESを使用します:

root@kitploit:~
DYLD_INSERT_LIBRARIES=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
    ruby -e 'require "ruzzy"; Ruzzy.dummy'

Ruzzy::ASAN_PATHおよびRuzzy::UBSAN_PATHは、macOSでは.dylibファイルに解決されます。

注意事項

  • バージョンマネージャーのシム (asdf、rbenv) はDYLD_*環境変数を削除します。 これらのシムは#!/usr/bin/env bashを使用し、/usr/bin/envはSIPで保護されているため、macOSはRuby起動前にDYLD_INSERT_LIBRARIESを削除します。Homebrew Ruby(シムなし)を使用するか、インストールされているRubyバイナリへの絶対パスを呼び出します:
    root@kitploit:~
    DYLD_INSERT_LIBRARIES=$(/path/to/ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
        /path/to/ruby your_fuzzer.rb
    
  • 最新のLLVMが必要です。 一部の古いバージョンのHomebrew LLVM(特に19.x)には、DYLD_INSERT_LIBRARIESでASan dylibをロードすると、起動時にプロセスがハングするバグがあります。Ruzzyが起動時にハングする場合は、Homebrew LLVMを更新してください(brew upgrade llvm)。

成果一覧

Ruzzyを使用して発見されたバグ:

  • toml gem: #76
  • toml-rb gem: #150
  • ox gem: #351、#410
  • Ruby Marshalガベージコレクタークラッシュ: #20941
  • XMLパーサーの差分: REXML vs. Nokogiri
  • redcarpet gem: #813

開発

開発はローカルで行うか、このリポジトリに用意されているDockerfileを使用して行うことができます。

次のコマンドでRuzzy Dockerイメージをビルドできます:

root@kitploit:~
docker build --tag ruzzy .

次に、次のコマンドでコンテナにシェルアクセスできます:

root@kitploit:~
docker run -it -v $(pwd):/app/ruzzy --entrypoint /bin/bash ruzzy

コンパイル

RuzzyのC拡張をコンパイルするために、rake-compilerを使用しています。

コンテナ内で次のコマンドを使用してC拡張をコンパイルできます:

root@kitploit:~
rake compile

テスト

Rubyコードのテストには、rakeユニットテストを使用しています。

コンテナ内で次のコマンドを使用してテストを実行できます:

root@kitploit:~
LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
    rake test

リント

Rubyコードのリントには、rubocopを使用しています。

コンテナ内で次のコマンドを使用してrubocopを実行できます:

root@kitploit:~
rubocop

リリース

新しいgitタグがプッシュされると、Ruzzyは自動的にRubyGemsにリリースされます。

新しいバージョンをリリースするには、次のコマンドを実行します:

root@kitploit:~
git tag vX.X.X
root@kitploit:~
git push --tags

参考文献

  • Ruby C拡張
    • https://guides.rubygems.org/gems-with-extensions/
    • https://www.rubyguides.com/2018/03/write-ruby-c-extension/
    • https://rubyreferences.github.io/rubyref/advanced/extensions.html
    • https://silverhammermba.github.io/emberb/c/
    • https://ruby-doc.org/3.3.0/extension_rdoc.html
    • https://ruby-doc.org/3.3.0/stdlibs/mkmf/MakeMakefile.html
    • https://github.com/flavorjones/ruby-c-extensions-explained
    • https://github.com/ruby/ruby/blob/v3_3_0/lib/mkmf.rb
  • Rubyファジング
    • https://github.com/twistlock/kisaten
    • https://github.com/richo/afl-ruby
    • https://github.com/krypt/FuzzBert
    • https://z2-2z.github.io/2024/jan/16/fuzzing-ruby-c-extensions-with-coverage-and-asan.html
    • https://bsidessf2018.sched.com/event/E6jC/fuzzing-ruby-and-c-extensions
  • Atheris
    • https://github.com/google/atheris/blob/master/native_extension_fuzzing.md
    • https://security.googleblog.com/2020/12/how-atheris-python-fuzzer-works.html
    • https://github.com/google/atheris/blob/2.3.0/setup.py
    • https://github.com/google/atheris/blob/2.3.0/src/native/core.cc
ツールをダウンロード
メソッド説明
Ruzzy.fuzz(test_one_input, args = DEFAULT_ARGS)test_one_input(生のバイトを受け取るproc/lambda)をファジングします。
Ruzzy.trace(harness_script)harness_scriptをRubyのブランチカバレッジ計装でラップし、その後requireします。純粋なRubyファジングに必要です。
Ruzzy.dummyバンドルされているおもちゃのハーネス(heap-use-after-freeデモ)をファジングします。
Ruzzy.dummy_test_one_input(data)おもちゃのハーネス自体。
定数説明
Ruzzy::ASAN_PATHASan + ファザーラッパーへのパス。LD_PRELOAD(Linux) / DYLD_INSERT_LIBRARIES(macOS)とともに使用します。
Ruzzy::UBSAN_PATH同上、UBSan用。
Ruzzy::EXT_PATHext/cruzzyビルドディレクトリへのパス。
Ruzzy::DEFAULT_ARGSファザーに渡されるデフォルトの引数。
メソッド説明戻り値
remaining_bytes未消費の残りバイト数Integer
consume_bytes(count)最大countバイトの生のバイトを消費バイナリString
consume_random_length_string(max_length)可変長の文字列を消費;\ + 非\バイトで終了String
consume_remaining_bytes残りのすべてのバイトを消費バイナリString
consume_remaining_as_stringconsume_remaining_bytesのエイリアスバイナリString
consume_uint(count)countバイトからの符号なし整数Integer
consume_int(count)countバイトからの符号付き(2の補数)整数Integer
consume_int_in_range(min, max)[min, max]の範囲で一様分布する整数Integer
consume_bool1バイト(LSB)からのブール値true/false
consume_float完全な倍精度範囲にわたる浮動小数点数Float
consume_float_in_range(min, max)[min, max]の範囲の浮動小数点数Float
consume_probability[0.0, 1.0]の範囲の浮動小数点数Float
pick_value_in_list(list)listからランダムな要素要素
  • https://github.com/google/atheris/blob/2.3.0/src/native/tracer.cc
  • https://github.com/google/atheris/blob/2.3.0/src/native/counters.cc
  • https://github.com/google/atheris/blob/2.3.0/src/instrument_bytecode.py
  • カバレッジ
    • https://calabi-yau.space/blog/sanitizer-coverage-interface.html
    • https://carstein.github.io/2020/05/21/writing-simple-fuzzer-4.html
    • https://h0mbre.github.io/Fuzzing-Like-A-Caveman-5/
    • https://github.com/mirrorer/afl/blob/master/docs/technical_details.txt
    • https://lcamtuf.coredump.cx/afl/historical_notes.txt
    • https://www.code-intelligence.com/blog/the-magic-behind-feedback-based-fuzzing
    • https://blog.includesecurity.com/2024/04/coverage-guided-fuzzing-extending-instrumentation/
    • https://git.sr.ht/~myrrc/ba-thesis/blob/master/thesis.pdf
    • https://www.politesi.polimi.it/bitstream/10589/173614/3/2021_04_Frighetto.pdf
    • https://wcventure.github.io/FuzzingPaper/Paper/SP18_ColLAFL.pdf
    • https://www.ndss-symposium.org/wp-content/uploads/2020/02/24422.pdf
    • https://mboehme.github.io/paper/ICSE22.pdf
    • https://www.usenix.org/system/files/raid2019-wang-jinghan.pdf