Skip to content
KitploitKITPLOIT
OutilsBlog
Soumettre
OutilsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

··Flux·Contact·Confidentialité·© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
ruzzy — Un fuzzer guidé par la couverture pour le code Ruby pur et les extensions C de Ruby | Kitploit
Outils/GitHubGitHub/trailofbits/ruzzy
Analyse Dynamique (Sandboxing)Analyse des VulnérabilitésAnalyse de CodeFuzzingAnalyse de BinairesApprentissage et Éducation
GitHubtrailofbits/ruzzy

ruzzy

Un fuzzer guidé par la couverture pour le code Ruby pur et les extensions C de Ruby

Voir le dépôt
12374il y a 2 moisVérifié par Kitploit

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Partager

Ruzzy

Test Gem Version

Un fuzzer guidé par la couverture pour le code Ruby pur et les extensions C de Ruby.

Ruzzy est fortement inspiré par Atheris de Google, un fuzzer pour Python. Ruzzy utilise libFuzzer (ou LibAFL) pour son instrumentation de couverture et son moteur de fuzzing. Ruzzy prend également en charge AddressSanitizer et UndefinedBehaviorSanitizer lors du fuzzing d'extensions C. Si vous souhaitez en savoir plus sur ce qui a inspiré Ruzzy, consultez notre article : Design and Implementation of a Coverage-Guided Ruby Fuzzer.

Table des matières :

  • Installer
  • Utilisation
    • Pour commencer
    • Fuzzing de code Ruby pur
    • Fuzzing d'extensions C Ruby
  • API
    • Ruzzy
    • FuzzedDataProvider
  • Notes pour les utilisateurs de macOS
  • Tableau des bugs
  • Développement
    • Compilation
    • Tests
    • Linting
    • Publication
  • Pour aller plus loin
  • Installer

    Ruzzy prend en charge Linux (x86-64, AArch64/ARM64) et macOS (Apple Silicon). Sous Windows, vous pouvez construire le Dockerfile et/ou utiliser l'environnement de développement. Ruzzy nécessite une version récente de clang (testée jusqu'à 14.0.0), de préférence la dernière version. Pour une configuration spécifique à macOS, voir notes pour les utilisateurs de macOS.

    Installez Ruzzy avec la commande suivante :

    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
    

    Il y a beaucoup de choses ici, alors décomposons-les :

    • La variable d'environnement MAKE remplace la commande make lors de la compilation de l'extension C de Ruzzy. Cela indique à make de respecter les variables d'environnement suivantes lors de la compilation de l'extension.
    • Les autres variables d'environnement sont utilisées pendant la compilation pour garantir l'utilisation des bons binaires clang. Cela nous assure de disposer des dernières fonctionnalités de clang, nécessaires pour un fuzzing correct.

    Si vous rencontrez des problèmes d'installation, vous pouvez exécuter la commande suivante pour obtenir une sortie de débogage :

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

    Si votre cible de fuzzing en Ruby pur utilise massivement des expressions régulières, installez regexp_parser :

    root@kitploit:~
    gem install regexp_parser
    

    Une fois installé, Ruzzy utilisera automatiquement cette fonctionnalité pour échantillonner (c'est-à-dire résoudre) les expressions régulières qu'il rencontre lors du fuzzing. Cela permet au fuzzer de dépasser les conditions liées aux expressions régulières et de débloquer une couverture supplémentaire.

    Utilisation

    Pour commencer

    Ruzzy inclut un exemple jouet pour démontrer son fonctionnement. Tout d'abord, définissez la variable d'environnement suivante :

    root@kitploit:~
    export ASAN_OPTIONS="allocator_may_return_null=1:detect_leaks=0:use_sigaltstack=0"
    
    Comprendre ces options n'est pas nécessaire, mais si vous êtes curieux, cliquez ici.

    ASAN_OPTIONS

    1. Les échecs d'allocation mémoire sont courants et à faible impact (DoS), alors ignorez-les pour le moment.
    2. Comme Python, l'interpréteur Ruby fuit des données, alors ignorez cela pour le moment.
    3. Ruby recommande de désactiver sigaltstack.

    Vous pouvez ensuite exécuter l'exemple avec la commande suivante :

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

    LD_PRELOAD est requis pour les mêmes raisons qu'Atheris. Cependant, contrairement à ASAN_OPTIONS, vous ne voulez probablement pas l'exporter car cela pourrait interférer avec d'autres programmes.

    Il devrait rapidement produire un crash comme celui-ci :

    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=
    

    Nous pouvons voir qu'il a correctement trouvé l'entrée ("HI") qui a produit une violation mémoire. Pour plus d'informations, voir dummy.c pour comprendre pourquoi cette violation s'est produite.

    Vous pouvez ré-exécuter le cas de crash avec la commande suivante :

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

    Les sanitizers suivants sont disponibles :

    • Ruzzy::ASAN_PATH pour AddressSanitizer
    • Ruzzy::UBSAN_PATH pour UndefinedBehaviorSanitizer

    Fuzzing de code Ruby pur

    Fuzzeons un petit script Ruby comme exemple. Le fuzzing de code Ruby pur nécessite deux scripts Ruby : un script de trace et un harnais de fuzzing. Le script de trace est nécessaire en raison d'un détail d'implémentation de l'interpréteur Ruby.

    Tout d'abord, le script de trace, appelons-le test_tracer.rb :

    root@kitploit:~
    # frozen_string_literal: true
    
    require 'ruzzy'
    
    Ruzzy.trace('test_harness.rb')
    

    Ensuite, le harnais de fuzzing, appelons-le 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)
    

    Vous pouvez exécuter ce fichier et commencer le fuzzing avec la commande suivante :

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

    Il devrait rapidement produire un crash comme celui-ci :

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

    Nous pouvons voir qu'il a correctement trouvé l'entrée ("FUZZ") qui a produit une exception.

    Pour fuzzer votre propre cible, modifiez le lambda test_one_input pour appeler votre fonction cible.

    Fuzzing d'extensions C Ruby

    Fuzzeons la bibliothèque msgpack-ruby comme exemple. Tout d'abord, installez la gemme :

    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
    

    En plus des variables d'environnement utilisées lors de la compilation de Ruzzy, nous spécifions CFLAGS et CXXFLAGS. Ces drapeaux aident au processus de fuzzing. Ils activent des fonctionnalités utiles comme un détecteur d'adresses et une meilleure information de trace de pile. Pour plus d'informations, voir AddressSanitizerFlags.

    Ensuite, nous avons besoin d'un harnais de fuzzing pour msgpack. Ce qui suit peut être familier à ceux qui ont de l'expérience avec 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)
    

    Appelons ce fichier fuzz_msgpack.rb. Vous pouvez exécuter ce fichier et commencer le fuzzing avec la commande suivante :

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

    Les options de libFuzzer peuvent être passées au script Ruby comme ceci :

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

    Voir options de libFuzzer pour plus d'informations.

    Pour fuzzer votre propre cible, modifiez le lambda test_one_input pour appeler votre fonction cible.

    API

    Ruzzy

    Le module Ruzzy expose les points d'entrée de plus haut niveau.

    MéthodeDescription
    Ruzzy.fuzz(test_one_input, args = DEFAULT_ARGS)Fuzze test_one_input (un proc/lambda prenant des octets bruts).
    Ruzzy.trace(harness_script)Enveloppe harness_script avec l'instrumentation de couverture de branches de Ruby, puis require celle-ci. Requis pour le fuzzing de Ruby pur.
    Ruzzy.dummyFuzze le harnais jouet fourni (démo heap-use-after-free).
    Ruzzy.dummy_test_one_input(data)Le harnais jouet lui-même.
    ConstanteDescription
    Ruzzy::ASAN_PATHChemin vers le wrapper ASan + fuzzer. À utiliser avec LD_PRELOAD (Linux) / DYLD_INSERT_LIBRARIES (macOS).
    Ruzzy::UBSAN_PATHIdem, pour UBSan.
    Ruzzy::EXT_PATHChemin vers le répertoire de construction ext/cruzzy.
    Ruzzy::DEFAULT_ARGSArguments par défaut passés au fuzzer.

    FuzzedDataProvider

    Ruzzy::FuzzedDataProvider divise les octets bruts du fuzzer en valeurs Ruby typées.

    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)
    
    MéthodeDescriptionRetourne
    remaining_bytesNombre d'octets non consommés restantsInteger
    consume_bytes(count)Consomme jusqu'à count octets brutsString binaire
    consume_random_length_string(max_length)Consomme une chaîne de longueur variable ; se termine sur \ + octet non-\String
    consume_remaining_bytesConsomme tous les octets restantsString binaire
    consume_remaining_as_stringAlias pour consume_remaining_bytesString binaire
    consume_uint(count)Entier non signé à partir de count octetsInteger
    consume_int(count)Entier signé (complément à deux) à partir de count octetsInteger
    consume_int_in_range(min, max)Entier distribué uniformément dans [min, max]Integer
    consume_boolBooléen à partir d'un octet (LSB)true/false
    consume_floatFlottant couvrant toute la plage des doublesFloat
    consume_float_in_range(min, max)Flottant dans [min, max]Float
    consume_probabilityFlottant dans [0.0, 1.0]Float
    pick_value_in_list(list)Élément aléatoire de list

    Toutes les méthodes retournent des valeurs par défaut (0, "", false, min) lorsque les données sont épuisées.

    Notes pour les utilisateurs de macOS

    Ruzzy sur macOS nécessite LLVM installé via Homebrew (Apple Clang n'inclut pas libFuzzer) et un Ruby non système (le Ruby système à /usr/bin/ruby est protégé par SIP, ce qui supprime les variables d'environnement DYLD_* avant le démarrage de Ruby).

    Prérequis

    root@kitploit:~
    brew install llvm ruby
    

    Tout Ruby non système fonctionne (brew, rbenv, asdf), mais voir les mises en garde ci-dessous pour les gestionnaires de versions basés sur des shims.

    Installation

    Utilisez les chemins Clang de Homebrew et les drapeaux de liaison appropriés pour 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
    

    Exécution

    Utilisez DYLD_INSERT_LIBRARIES au lieu de LD_PRELOAD :

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

    Ruzzy::ASAN_PATH et Ruzzy::UBSAN_PATH se résolvent en fichiers .dylib sur macOS.

    Mises en garde

    • Les shims de gestionnaires de versions (asdf, rbenv) suppriment les variables d'environnement DYLD_*. Ces shims utilisent #!/usr/bin/env bash et /usr/bin/env est protégé par SIP, donc macOS supprime DYLD_INSERT_LIBRARIES avant le démarrage de Ruby. Utilisez soit le Ruby de Homebrew (qui n'a pas de shim), soit invoquez le chemin absolu vers le binaire Ruby installé :
      root@kitploit:~
      DYLD_INSERT_LIBRARIES=$(/path/to/ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
          /path/to/ruby your_fuzzer.rb
      
    • LLVM récent requis. Certaines versions plus anciennes de LLVM de Homebrew (notamment 19.x) ont un bug où DYLD_INSERT_LIBRARIES avec la dylib ASan bloque le processus au démarrage. Si vous voyez Ruzzy se bloquer au lancement, mettez à jour LLVM de Homebrew (brew upgrade llvm).

    Tableau des bugs

    Bugs trouvés en utilisant Ruzzy :

    • gemme toml : #76
    • gemme toml-rb : #150
    • gemme ox : #351, #410
    • Crash du ramasse-miettes de Marshal de Ruby : #20941
    • Différentiel d'analyseur XML : REXML vs. Nokogiri
    • gemme redcarpet : #813

    Développement

    Le développement peut être fait localement, ou en utilisant le Dockerfile fourni dans ce dépôt.

    Vous pouvez construire l'image Docker de Ruzzy avec la commande suivante :

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

    Ensuite, vous pouvez ouvrir un shell dans le conteneur en utilisant la commande suivante :

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

    Compilation

    Nous utilisons rake-compiler pour compiler les extensions C de Ruzzy.

    Vous pouvez compiler les extensions C dans le conteneur avec la commande suivante :

    root@kitploit:~
    rake compile
    

    Tests

    Nous utilisons des tests unitaires rake pour tester le code Ruby.

    Vous pouvez exécuter les tests dans le conteneur avec la commande suivante :

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

    Linting

    Nous utilisons rubocop pour lint le code Ruby.

    Vous pouvez exécuter rubocop dans le conteneur avec la commande suivante :

    root@kitploit:~
    rubocop
    

    Publication

    Ruzzy est automatiquement publié sur RubyGems lorsqu'un nouveau tag git est poussé.

    Pour publier une nouvelle version, exécutez les commandes suivantes :

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

    Pour aller plus loin

    • Extensions C de 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 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
      • 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
    • Couverture
      • 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
    Télécharger l’outil
    élément