Skip to content
KitploitKITPLOIT
StrumentiBlog
Invia
StrumentiBlog
Invia

Strumenti di Hacking, PenTest e Cybersecurity per il tuo Arsenale di Sicurezza!

Kitploit è una directory di strumenti di hacking, cybersecurity e pentesting. Scopri gli ultimi aggiornamenti dei progetti per trovare vulnerabilità, analizzare sistemi, automatizzare i test e rafforzare la tua sicurezza.

··Feed·Contatto·Privacy·© 2026 Kitploit

Directory degli strumenti

Categorie

Vedi tutte le categorie
Loading categories
ruzzy — Un fuzzer guidato dalla copertura per codice Ruby puro ed estensioni C di Ruby. | Kitploit
Strumenti/GitHubGitHub/trailofbits/ruzzy
Analisi Dinamica (Sandboxing)Analisi delle VulnerabilitàAnalisi del CodiceFuzzingAnalisi di BinariApprendimento e Formazione
GitHubtrailofbits/ruzzy

ruzzy

Un fuzzer guidato dalla copertura per codice Ruby puro ed estensioni C di Ruby.

Vedi Repository
12371 mese faRevisionato da Kitploit

Più Popolari

Vedi tutti →

Scopri gli strumenti più utilizzati dalla nostra community.

Esplora tutti gli strumenti

Sfoglia la nostra collezione di strumenti

Vedi tutti gli strumenti →
Condividi

Ruzzy

Test Gem Version

Un fuzzer guidato dalla copertura per codice Ruby puro ed estensioni C di Ruby.

Ruzzy è fortemente ispirato ad Atheris di Google, un fuzzer per Python. Ruzzy usa libFuzzer (o LibAFL) per la strumentazione della copertura e il motore di fuzzing. Ruzzy supporta anche AddressSanitizer e UndefinedBehaviorSanitizer quando si esegue il fuzzing di estensioni C. Se vuoi saperne di più sull'ispirazione alla base di Ruzzy, consulta il nostro articolo: Design and Implementation of a Coverage-Guided Ruby Fuzzer.

Indice dei contenuti:

  • Installazione
  • Utilizzo
    • Per iniziare
    • Fuzzing di codice Ruby puro
    • Fuzzing di estensioni C di Ruby
  • API
    • Ruzzy
    • FuzzedDataProvider
  • Note per gli utenti macOS
  • Bacheca dei trofei
  • Sviluppo
    • Compilazione
    • Test
    • Linting
    • Rilascio
  • Ulteriori letture

Installazione

Ruzzy supporta Linux (x86-64, AArch64/ARM64) e macOS (Apple Silicon). Su Windows, puoi creare il Dockerfile e/o usare l'ambiente di sviluppo. Ruzzy richiede una versione recente di clang (testata fino alla 14.0.0), preferibilmente l'ultima release. Per la configurazione specifica di macOS, vedi note per gli utenti macOS.

Installa Ruzzy con il seguente comando:

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

C'è molto da spiegare qui, quindi analizziamolo:

  • La variabile d'ambiente MAKE sovrascrive il comando make durante la compilazione dell'estensione C di Ruzzy. Questo dice a make di rispettare le successive variabili d'ambiente durante la compilazione dell'estensione.
  • Il resto delle variabili d'ambiente viene usato durante la compilazione per garantire l'uso dei binari clang corretti. Questo assicura di avere le funzionalità più recenti di clang, necessarie per un corretto fuzzing.

Se riscontri problemi durante l'installazione, puoi eseguire il seguente comando per ottenere un output di debug:

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

Se il tuo target di fuzzing in Ruby puro fa un uso intensivo delle regexp, installa regexp_parser:

root@kitploit:~
gem install regexp_parser

Una volta installato, Ruzzy userà automaticamente questa funzionalità per campionare (cioè risolvere) le regexp che incontra durante il fuzzing. Questo permette al fuzzer di superare le condizioni basate su regexp e sbloccare ulteriore copertura.

Utilizzo

Per iniziare

Ruzzy include un esempio giocattolo per dimostrare come funziona. Per prima cosa, imposta la seguente variabile d'ambiente:

root@kitploit:~
export ASAN_OPTIONS="allocator_may_return_null=1:detect_leaks=0:use_sigaltstack=0"
Capire queste opzioni non è necessario, ma se sei curioso clicca qui.

ASAN_OPTIONS

  1. I fallimenti di allocazione della memoria sono comuni e a basso impatto (DoS), quindi saltali per ora.
  2. Come Python, l'interprete Ruby disperde dati, quindi ignora questi per ora.
  3. Ruby raccomanda di disabilitare sigaltstack.

Puoi quindi eseguire l'esempio con il seguente comando:

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

LD_PRELOAD è richiesto per gli stessi motivi di Atheris. Tuttavia, a differenza di ASAN_OPTIONS, probabilmente non vorrai esportarlo con export poiché potrebbe interferire con altri programmi.

Dovrebbe produrre rapidamente un crash come il seguente:

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=

Possiamo vedere che ha trovato correttamente l'input ("HI") che ha prodotto una violazione di memoria. Per maggiori informazioni, vedi dummy.c per capire perché si è verificata questa violazione.

Puoi rieseguire il caso di crash con il seguente comando:

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

I seguenti sanitizer sono disponibili:

  • Ruzzy::ASAN_PATH per AddressSanitizer
  • Ruzzy::UBSAN_PATH per UndefinedBehaviorSanitizer

Fuzzing di codice Ruby puro

Facciamo il fuzzing di un piccolo script Ruby come esempio. Il fuzzing di codice Ruby puro richiede due script Ruby: uno script tracer e un harness di fuzzing. Lo script tracer è necessario a causa di un dettaglio implementativo dell'interprete Ruby.

Prima, lo script tracer, chiamiamolo test_tracer.rb:

root@kitploit:~
# frozen_string_literal: true

require 'ruzzy'

Ruzzy.trace('test_harness.rb')

Poi, l'harness di fuzzing, chiamiamolo 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) # Your fuzzing target would go here
  return 0
end

Ruzzy.fuzz(test_one_input)

Puoi eseguire questo file e iniziare il fuzzing con il seguente comando:

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

Dovrebbe produrre rapidamente un crash come il seguente:

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==

Possiamo vedere che ha trovato correttamente l'input ("FUZZ") che ha prodotto un'eccezione.

Per fare il fuzzing del tuo target, modifica la lambda test_one_input per chiamare la tua funzione target.

Fuzzing di estensioni C di Ruby

Facciamo il fuzzing della libreria msgpack-ruby come esempio. Per prima cosa, installa la gemma:

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

Oltre alle variabili d'ambiente usate per compilare Ruzzy, specifichiamo CFLAGS e CXXFLAGS. Questi flag aiutano nel processo di fuzzing. Abilitano funzionalità utili come l'address sanitizer e migliori informazioni sullo stack trace. Per maggiori informazioni vedi AddressSanitizerFlags.

Successivamente, abbiamo bisogno di un harness di fuzzing per msgpack. Quanto segue potrebbe essere familiare a chi ha esperienza con libFuzzer:

root@kitploit:~
# frozen_string_literal: true

require 'msgpack'
require 'ruzzy'

test_one_input = lambda do |data|
  begin
    MessagePack.unpack(data)
  rescue Exception
    # We're looking for memory corruption, not Ruby exceptions
  end
  return 0
end

Ruzzy.fuzz(test_one_input)

Chiamiamo questo file fuzz_msgpack.rb. Puoi eseguire questo file e iniziare il fuzzing con il seguente comando:

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

Le opzioni di libFuzzer possono essere passate allo script Ruby in questo modo:

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

Vedi opzioni di libFuzzer per maggiori informazioni.

Per fare il fuzzing del tuo target, modifica la lambda test_one_input per chiamare la tua funzione target.

API

Ruzzy

Il modulo Ruzzy espone i punti di ingresso di livello superiore.

FuzzedDataProvider

Ruzzy::FuzzedDataProvider divide i byte grezzi del fuzzer in valori Ruby tipizzati.

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)

Tutti i metodi restituiscono valori predefiniti (0, "", false, min) quando i dati sono esauriti.

Note per gli utenti macOS

Ruzzy su macOS richiede LLVM installato tramite Homebrew (Apple Clang non include libFuzzer) e un Ruby non di sistema (il Ruby di sistema in /usr/bin/ruby è protetto da SIP, che rimuove le variabili d'ambiente DYLD_* prima che Ruby venga avviato).

Prerequisiti

root@kitploit:~
brew install llvm ruby

Qualsiasi Ruby non di sistema funziona (brew, rbenv, asdf), ma vedi le avvertenze qui sotto per i gestori di versioni basati su shim.

Installazione

Usa i percorsi di Clang di Homebrew e i flag di linker appropriati per 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

Esecuzione

Usa DYLD_INSERT_LIBRARIES invece di LD_PRELOAD:

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

Ruzzy::ASAN_PATH e Ruzzy::UBSAN_PATH puntano a file .dylib su macOS.

Avvertenze

  • Gli shim dei gestori di versioni (asdf, rbenv) rimuovono le variabili d'ambiente DYLD_*. Questi shim usano #!/usr/bin/env bash e /usr/bin/env è protetto da SIP, quindi macOS rimuove DYLD_INSERT_LIBRARIES prima che Ruby venga avviato. Usa Ruby di Homebrew (che non ha shim) oppure invoca il percorso assoluto del binario Ruby installato:
    root@kitploit:~
    DYLD_INSERT_LIBRARIES=$(/path/to/ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
        /path/to/ruby your_fuzzer.rb
    
  • È richiesto un LLVM recente. Alcune versioni meno recenti di LLVM di Homebrew (in particolare 19.x) hanno un bug per cui l'iniezione tramite DYLD_INSERT_LIBRARIES della dylib ASan blocca il processo durante l'avvio. Se Ruzzy si blocca all'avvio, aggiorna LLVM di Homebrew (brew upgrade llvm).

Bacheca dei trofei

Bug trovati usando Ruzzy:

  • gemma toml: #76
  • gemma toml-rb: #150
  • gemma ox: #351, #410
  • Crash del garbage collector di Ruby Marshal: #20941
  • Differenziale del parser XML: REXML vs. Nokogiri
  • gemma redcarpet: #813

Sviluppo

Lo sviluppo può essere fatto localmente, oppure usando il Dockerfile fornito in questo repository.

Puoi creare l'immagine Docker di Ruzzy con il seguente comando:

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

Poi, puoi entrare nella shell del container usando il seguente comando:

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

Compilazione

Usiamo rake-compiler per compilare le estensioni C di Ruzzy.

Puoi compilare le estensioni C all'interno del container con il seguente comando:

root@kitploit:~
rake compile

Test

Usiamo i test unitari rake per testare il codice Ruby.

Puoi eseguire i test all'interno del container con il seguente comando:

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

Linting

Usiamo rubocop per il linting del codice Ruby.

Puoi eseguire rubocop all'interno del container con il seguente comando:

root@kitploit:~
rubocop

Rilascio

Ruzzy viene rilasciato automaticamente su RubyGems quando viene pushato un nuovo tag git.

Per rilasciare una nuova versione esegui i seguenti comandi:

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

Ulteriori letture

  • Estensioni C di Ruby
    • 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
  • Fuzzing di 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
Scarica lo strumento
MetodoDescrizione
Ruzzy.fuzz(test_one_input, args = DEFAULT_ARGS)Esegue il fuzzing di test_one_input (una proc/lambda che accetta byte grezzi).
Ruzzy.trace(harness_script)Avvolge harness_script con la strumentazione di copertura dei rami di Ruby, quindi lo carica con require. Necessario per il fuzzing di puro Ruby.
Ruzzy.dummyEsegue il fuzzing dell'harness giocattolo incluso (demo di heap-use-after-free).
Ruzzy.dummy_test_one_input(data)L'harness giocattolo stesso.
CostanteDescrizione
Ruzzy::ASAN_PATHPercorso del wrapper ASan + fuzzer. Da usare con LD_PRELOAD (Linux) / DYLD_INSERT_LIBRARIES (macOS).
Ruzzy::UBSAN_PATHIdem, per UBSan.
Ruzzy::EXT_PATHPercorso della directory di build di ext/cruzzy.
Ruzzy::DEFAULT_ARGSArgomenti predefiniti passati al fuzzer.
MetodoDescrizioneRestituisce
remaining_bytesNumero di byte non consumati rimanentiInteger
consume_bytes(count)Consuma fino a count byte grezziString binaria
consume_random_length_string(max_length)Consuma una stringa a lunghezza variabile; termina su \ + byte diverso da \String
consume_remaining_bytesConsuma tutti i byte rimanentiString binaria
consume_remaining_as_stringAlias di consume_remaining_bytesString binaria
consume_uint(count)Intero senza segno da count byteInteger
consume_int(count)Intero con segno (complemento a due) da count byteInteger
consume_int_in_range(min, max)Intero distribuito uniformemente in [min, max]Integer
consume_boolBooleano da un byte (LSB)true/false
consume_floatFloat che copre l'intero intervallo del doubleFloat
consume_float_in_range(min, max)Float in [min, max]Float
consume_probabilityFloat in [0.0, 1.0]Float
pick_value_in_list(list)Elemento casuale da listelemento
https://github.com/google/atheris/blob/2.3.0/src/native/core.cc
  • 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
  • Copertura
    • 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