Ruby模糊测试工具RuzzySkill ruzzy

Ruzzy是由Trail of Bits开发的覆盖引导Ruby模糊测试工具,专用于模糊测试纯Ruby代码和Ruby C扩展,支持地址消毒器和未定义行为消毒器,帮助发现内存腐蚀、未定义行为等安全漏洞,提升软件质量和安全测试效率。关键词:Ruzzy、Ruby模糊测试、覆盖引导模糊测试、内存安全、漏洞挖掘、安全测试、软件测试、C扩展测试。

漏洞挖掘 0 次安装 0 次浏览 更新于 3/14/2026

名称: ruzzy 类型: fuzzer 描述: > Ruzzy 是由 Trail of Bits 开发的一个覆盖引导的 Ruby 模糊测试工具。 用于模糊测试纯 Ruby 代码和 Ruby C 扩展。

Ruzzy

Ruzzy 是一个基于 libFuzzer 构建的覆盖引导模糊测试器,适用于 Ruby。它支持模糊测试纯 Ruby 代码和 Ruby C 扩展,并集成消毒器以检测内存腐蚀和未定义行为。

使用时机

Ruzzy 是目前唯一生产就绪的覆盖引导模糊测试器,专为 Ruby 设计。

选择 Ruzzy 当您需要:

  • 模糊测试 Ruby 应用程序或库
  • 测试 Ruby C 扩展的内存安全问题
  • 为 Ruby 代码进行覆盖引导模糊测试
  • 处理具有原生扩展的 Ruby gem

快速开始

设置环境:

export ASAN_OPTIONS="allocator_may_return_null=1:detect_leaks=0:use_sigaltstack=0"

使用内置的示例进行测试:

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

这应该快速找到一个崩溃,证明 Ruzzy 工作正常。

安装

平台支持

Ruzzy 支持 Linux x86-64 和 AArch64/ARM64。对于 macOS 或 Windows,使用 Dockerfile开发环境

前提条件

  • Linux x86-64 或 AArch64/ARM64
  • 最近版本的 clang(测试支持到 14.0.0,推荐使用最新版本)
  • 安装有 gem 的 Ruby

安装命令

使用 clang 编译器标志安装 Ruzzy:

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:覆盖 make 以尊重后续的环境变量
  • CCCXXLDSHAREDLDSHAREDXX:确保使用正确的 clang 二进制文件以支持最新功能

安装故障排除

如果安装失败,启用调试输出:

RUZZY_DEBUG=1 gem install --verbose ruzzy

验证

通过运行示例验证安装(见快速开始部分)。

编写测试套件

模糊测试纯 Ruby 代码

纯 Ruby 模糊测试由于 Ruby 解释器的实现细节,需要两个脚本。

跟踪脚本(test_tracer.rb):

# frozen_string_literal: true

require 'ruzzy'

Ruzzy.trace('test_harness.rb')

测试套件脚本(test_harness.rb):

# 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)

运行:

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

模糊测试 Ruby C 扩展

C 扩展可以用单个测试套件文件进行模糊测试,无需跟踪脚本。

msgpack 示例测试套件(fuzz_msgpack.rb):

# 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)

运行:

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

测试套件规则

如果测试 C 扩展,捕获 Ruby 异常 让 Ruby 异常导致模糊测试器崩溃
从 test_one_input lambda 返回 0 返回其他值
保持测试套件确定性 使用随机性或基于时间的逻辑
纯 Ruby 代码使用跟踪脚本 纯 Ruby 代码跳过跟踪脚本

另请参见: 关于详细的测试套件编写技巧、处理复杂输入的模式和高级策略,请参阅 fuzz-harness-writing 技能。

编译

使用消毒器安装 Gems

为模糊测试安装带有 C 扩展的 Ruby gem 时,使用消毒器标志编译:

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 <gem-name>

构建标志

标志 目的
-fsanitize=address,fuzzer-no-link 启用 AddressSanitizer 和模糊测试器仪器
-fno-omit-frame-pointer 提高堆栈跟踪质量
-fno-common 与消毒器更好的兼容性
-fPIC 位置无关代码,适用于共享库
-g 包含调试符号

运行测试活动

环境设置

在运行任何模糊测试活动之前,设置 ASAN_OPTIONS:

export ASAN_OPTIONS="allocator_may_return_null=1:detect_leaks=0:use_sigaltstack=0"

选项解释:

  1. allocator_may_return_null=1:跳过常见的低影响分配失败(DoS)
  2. detect_leaks=0:Ruby 解释器泄漏数据,暂时忽略这些
  3. use_sigaltstack=0:Ruby 建议在使用 ASan 时禁用 sigaltstack

基本运行

LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
    ruby harness.rb

注意: LD_PRELOAD 是消毒器注入所必需的。与 ASAN_OPTIONS 不同,不要导出它,因为它可能干扰其他程序。

使用语料库

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

传递 libFuzzer 选项

所有 libFuzzer 选项可以作为参数传递:

LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
    ruby harness.rb /path/to/corpus -max_len=1024 -timeout=10

参见 libFuzzer 选项 获取完整参考。

重现崩溃

通过传递崩溃文件重新运行崩溃案例:

LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
    ruby harness.rb ./crash-253420c1158bc6382093d409ce2e9cff5806e980

解释输出

输出 含义
INFO: Running with entropic power schedule 模糊测试活动已启动
ERROR: AddressSanitizer: heap-use-after-free 检测到内存腐蚀
SUMMARY: libFuzzer: fuzz target exited 发生 Ruby 异常
artifact_prefix='./'; Test unit written to ./crash-* 崩溃输入已保存
Base64: ... 崩溃输入的 Base64 编码

消毒器集成

AddressSanitizer (ASan)

Ruzzy 包含预编译的 AddressSanitizer 库:

LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
    ruby harness.rb

使用 ASan 检测:

  • 堆缓冲区溢出
  • 栈缓冲区溢出
  • 使用后释放
  • 双重释放
  • 内存泄漏(Ruzzy 中默认禁用)

UndefinedBehaviorSanitizer (UBSan)

Ruzzy 也包含 UBSan:

LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::UBSAN_PATH') \
    ruby harness.rb

使用 UBSan 检测:

  • 有符号整数溢出
  • 空指针解引用
  • 内存访问未对齐
  • 除以零

常见消毒器问题

问题 解决方案
Ruby 解释器泄漏警告 使用 ASAN_OPTIONS=detect_leaks=0
Sigaltstack 冲突 使用 ASAN_OPTIONS=use_sigaltstack=0
分配失败垃圾信息 使用 ASAN_OPTIONS=allocator_may_return_null=1
LD_PRELOAD 干扰工具 不要导出;在 ruby 命令中内联设置

另请参见: 关于详细的消毒器配置、常见问题和高级标志,请参阅 address-sanitizerundefined-behavior-sanitizer 技能。

真实世界示例

示例: msgpack-ruby

模糊测试 msgpack MessagePack 解析器以检测内存腐蚀。

使用消毒器安装:

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

测试套件(fuzz_msgpack.rb):

# 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)

运行:

export ASAN_OPTIONS="allocator_may_return_null=1:detect_leaks=0:use_sigaltstack=0"
LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
    ruby fuzz_msgpack.rb

示例: 纯 Ruby 目标

模糊测试带有自定义解析器的纯 Ruby 代码。

跟踪脚本(test_tracer.rb):

# frozen_string_literal: true

require 'ruzzy'

Ruzzy.trace('test_harness.rb')

测试套件(test_harness.rb):

# frozen_string_literal: true

require 'ruzzy'
require_relative 'my_parser'

test_one_input = lambda do |data|
  begin
    MyParser.parse(data)
  rescue StandardError
    # 来自格式错误输入的预期异常
  end
  return 0
end

Ruzzy.fuzz(test_one_input)

运行:

export ASAN_OPTIONS="allocator_may_return_null=1:detect_leaks=0:use_sigaltstack=0"
LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
    ruby test_tracer.rb

故障排除

问题 原因 解决方案
安装失败 错误的 clang 版本或路径 验证 clang 路径,使用 clang 14.0.0+
cannot open shared object file LD_PRELOAD 未设置 在 ruby 命令中内联设置 LD_PRELOAD
模糊测试器立即退出 缺少语料库目录 创建语料库目录或作为参数传递
无覆盖进展 纯 Ruby 需要跟踪脚本 纯 Ruby 代码使用跟踪脚本
泄漏检测垃圾信息 Ruby 解释器泄漏 设置 ASAN_OPTIONS=detect_leaks=0
需要安装调试 编译错误 使用 RUZZY_DEBUG=1 gem install --verbose ruzzy

相关技能

技术技能

技能 用例
fuzz-harness-writing 编写有效测试套件的详细指导
address-sanitizer 模糊测试期间的内存错误检测
undefined-behavior-sanitizer 检测 C 扩展中的未定义行为
libfuzzer 理解 libFuzzer 选项(Ruzzy 基于 libFuzzer 构建)

相关模糊测试器

技能 何时考虑
libfuzzer 直接在 C/C++ 中模糊测试 Ruby C 扩展代码时
aflpp 通过仪器 Ruby 解释器模糊测试 Ruby 的替代方法

资源

关键外部资源

介绍 Ruzzy,一个覆盖引导的 Ruby 模糊测试器 Trail of Bits 官方博客文章,介绍 Ruzzy 的动机、架构和初步结果。

Ruzzy GitHub 仓库 源代码、额外示例和开发说明。

libFuzzer 文档 由于 Ruzzy 基于 libFuzzer 构建,理解 libFuzzer 选项和行为很有价值。

模糊测试 Ruby C 扩展 关于使用编译标志和示例模糊测试 C 扩展的详细指南。

模糊测试纯 Ruby 代码 关于纯 Ruby 模糊测试所需的跟踪模式的详细指南。