crowbar
crowbar
Prying your client since 2019

Crowbar is an all-purpose fuzzer built to help make bad data cases from sample input. It can be both used as a library, and also built into an application.
Overview
Crowbar uses selectors, mutators, and generators, to make input that potentially will make an application misbehave. In this system, selectors target and sample data, passes the data into a mutator to change it in some way, which uses generators to provide the underlying data to manipulate.
Installation
shards install 
Usage
Library
Sample usage
require "./crowbar"
sample_input = "{ \"json\" : \"A String\", \"x\" : 0x123AA }"
cr = Crowbar.new(sample_input) do |cr|
  # Selects quoted strings
  Crowbar::Selector::Regex.new(cr, Crowbar::Constants::Regex::IN_QUOTES) do |s|
    # Replace those strings with something else
    Crowbar::Mutator::Replacer.new(s) do |m|
      # Either a raw decimal number
      Crowbar::Generator::Decimal.new(m)
      # or one that is quoted
      Crowbar::Generator::Wrapper.new(m, Crowbar::Generator::Decimal.new(m, no_register: true))
      # Can add both at the same time, no_register keeps the Generator from registering to the mutator
      Crowbar::Generator::Wrapper.new(m, Crowbar::Generator::Decimal.new(m, float: true))
    end
    Crowbar::Mutator::Replacer.new(s) do |m|
      Crowbar::Generator::Wrapper.new(m, Crowbar::Generator::Bytes.new(m))
    end
    Crowbar::Mutator::Replacer.new(s) do |m|
      Crowbar::Generator::Wrapper.new(m, Crowbar::Generator::Naughty.new(m, types: [:null, :logic]))
    end
  end
  # Selects symbols/spaces, removes them and duplicates them
  s = Crowbar::Selector::Regex.new(cr, /\W/) do |s|
    Crowbar::Mutator::Remover.new(s) {|m|}.weight = 0.3_f32
    Crowbar::Mutator::Repeater.new(s) {|m|}.weight = 0.4_f32
  end
  # weigh the slector less so it doesn't go too wild
  s.weight = 0.7_f32
  s = Crowbar::Selector::Regex.new(cr, /[a-zA-Z0-9]{1}/) do |s|
    Crowbar::Mutator::Remover.new(s) {|m|}.weight = 0.1_f32
  end
  s.weight = 0.1_f32
end 
10.times do |x|
  pp cr.next
end
Sample output
[Running] crystal "/home/ian/Documents/crystal/crowbar/src/sandbox.cr"
"\xC1:::   : IL, NIL :  }"
"{ \"json\" : \"A String\", \"x\" : 0x123A }"
"  16.4 : \"True\", \"x\" :  "
"{ \u0001]\n" + "\xF7\xDEg : \"A String\", \"x\" : 0x123AA }"
"  \"\"json\" : \"A String\", \"x\" ::: }}}"
"   \"json\" : \"A String\", s\x99@5\xDE :  }"
"{ null : \"A String\", \"x\" : 0x123AA }"
" \"json\" : \"A String\", \"x\"\"\"  : }}}"
"{ \"false\"A String\", \"x\" : 0x123AA }"
"{ \"json\" : \"A String\",  x\"::: }""
[Done] exited with code=0 in 0.818 seconds
Real-world Example
require "./crowbar"
header = "\xFF\x01\x00\xFF\xFE\x02\x00\xFF\x00\x00\x00\x00\x00\x00\xFC\x03\x36\x00\x00\x00"
sample_input = header + "{\"Name\":\"SystemInfo\",\"SessionID\":\"0x00000000\"}"
cr = Crowbar.new(sample_input, seed: (:xiongmai.hash%Int32::MAX).to_i32) do |cr|
  # Type selector
  Crowbar::Selector::Range.new(cr, (0...3)) do |s|
    s.weight = 0.01
    Crowbar::Mutator::Replacer.new(s) do |m|
      Crowbar::Generator::Bytes.new(m, length_limit: (4..4))
    end
  end
  # SessionID selector
  Crowbar::Selector::Range.new(cr, (4...7)) do |s|
    s.weight = 0.01
    Crowbar::Mutator::Replacer.new(s) do |m|
      Crowbar::Generator::Bytes.new(m, length_limit: (4..4))
    end
  end
  # Unknown1 selector
  Crowbar::Selector::Range.new(cr, (8...11)) do |s|
    s.weight = 2.0
    Crowbar::Mutator::Replacer.new(s) do |m|
      Crowbar::Generator::Bytes.new(m, length_limit: (4..4))
    end
  end
  # Unknown2 selector
  Crowbar::Selector::Range.new(cr, (12...13)) do |s|
    s.weight = 2.0
    Crowbar::Mutator::Replacer.new(s) do |m|
      Crowbar::Generator::Bytes.new(m, length_limit: (2..2))
    end
  end
  # Magic selector
  Crowbar::Selector::Range.new(cr, (14...15)) do |s|
    s.weight = 0.1
    Crowbar::Mutator::Replacer.new(s) do |m|
      Crowbar::Generator::Bytes.new(m, length_limit: (2..2))
    end
  end
  # Size selector
  Crowbar::Selector::Range.new(cr, (16...19)) do |s|
    s.weight = 3.0
    Crowbar::Mutator::Replacer.new(s) do |m|
      Crowbar::Generator::Bytes.new(m, length_limit: (4..4))      
    end
  end
  # Message selector
  Crowbar::Selector::Header.new(cr, 20, invert: true) do |s|
    s.weight = 10.0
    Crowbar::Mutator::Crowbar.new(s) do |cr|
      cr.input = "{\"Name\":\"SystemInfo\",\"SessionID\":\"0x00000000\"}"
      cr.seed = (:new_crowbar.hash%Int32::MAX).to_i32
      # Selects quoted strings
      Crowbar::Selector::Regex.new(cr, Crowbar::Constants::Regex::IN_QUOTES) do |s|
        s.weight = 1.0
        # Replace those strings with something else
        Crowbar::Mutator::Replacer.new(s) do |m|
          Crowbar::Generator::Wrapper.new(m, Crowbar::Generator::Decimal.new(m))
          Crowbar::Generator::Wrapper.new(m, Crowbar::Generator::Decimal.new(m, float: true))
          Crowbar::Generator::Wrapper.new(m, Crowbar::Generator::Bytes.new(m))
          Crowbar::Generator::Wrapper.new(m, Crowbar::Generator::Naughty.new(m, types: [:null, :logic, :empty]))
        end
        Crowbar::Mutator::Remover.new(s) do |m|
          m.weight = 0.01
        end
      end
      # Mess with symbols
      Crowbar::Selector::Regex.new(cr, /\W/) do |s|
        Crowbar::Mutator::Remover.new(s) do |m|
          m.weight = 0.01
        end
        Crowbar::Mutator::Repeater.new(s) do |m|
          m.weight = 0.01
        end
      end
    end
  end
end
10.times do |x|
  pp cr.next
end
Output:
"\u0000\v\xA8\x9D\xFE\u0002\u0000\xFF\u0000\u0000\u0000\u0000\u0000\u0000\xFC\u00036\u0000\u0000\u0000{\"Name\":\"SystemInfo\",\"SessionID\":\"0x00000000\"}"
"\xFF\u0001\u0000\xFF\xFE\u0002\u0000\xFF\u0000\u0000\u0000\u0000\u0000\u0000\xFC\u00036\u0000\u0000\u0000{{True(((ݙ),:}"
"\xFF\u0001\u0000\xFF\xFE\u0002\u0000\xFF\u0000\u0000\u0000\u0000\u0000\u0000\xFC\u00036\u0000\u0000\u0000{'True':,:}"
"\xFF\u0001\u0000\xFF\xFE\u0002\u0000\xFF\u0002+\x8E\xBE\u0000\u0000\xFC\u00036\u0000\u0000\u0000{\"Name\":\"SystemInfo\",\"SessionID\":\"0x00000000\"}"
"\xFF\u0001\u0000\xFF\xFE\u0002\u0000\xFF\u0000\u0000\u0000\u0000\u0000\u0000\xFC\u00036\u0000\u0000\u0000{{12.0}:\"SystemInfo\",\"SessionID\":\"0x00000000\"}"
"\xFF\u0001\u0000\xFF\xFE\u0002\u0000\xFF\xBE\xC9\xF7\xA5\u0000\u0000\xFC\u00036\u0000\u0000\u0000{\"Name\":\"SystemInfo\",\"SessionID\":\"0x00000000\"}"
"\xFF\u0001\u0000\xFF\xFE\u0002\u0000\xFF\u0000\u0000\u0000\u0000\x9Dn\xFC\u00036\u0000\u0000\u0000{\"Name\":{()},\"SessionID\":\"0x00000000\"}"
"\xFF\u0001\u0000\xFF\xFE\u0002\u0000\xFF\u0000\u0000\u0000\u0000\u0000\u0000\xFC\u0003\x8E\xBE\xC9\xF7{\"Name\":\"SystemInfo\",\"SessionID\":\"0x00000000\"}"
"\xFF\u0001\u0000\xFF\xFE\u0002\u0000\xFFTn\x82\xE9\u0000\u0000\xFC\u00036\u0000\u0000\u0000{\"Name\":\"SystemInfo\",\"SessionID\":\"0x00000000\"}"
"\xFF\u0001\u0000\xFF\xFE\u0002\u0000\xFF\u0000\u0000\u0000\u0000\xC9\xF7\xFC\u00036\u0000\u0000\u0000{\"Name\":\"275252\",\"SessionID\":\"0x00000000\"}"
Application
- CLI examples
Development
Fork it and pull request, or complain in issues idk
Contributing
- Fork it (https://github.com/your-github-user/crowbar/fork)
- Create your feature branch (git checkout -b my-new-feature)
- Commit your changes (git commit -am 'Add some feature')
- Push to the branch (git push origin my-new-feature)
- Create a new Pull Request
Contributors
- Ian Rash - creator and maintainer
Repository
  crowbar
Owner
  
  Statistic
  - 8
- 0
- 0
- 0
- 0
- over 6 years ago
- April 28, 2019
License
  MIT License
Links
  
  Synced at
  Wed, 29 Oct 2025 12:27:39 GMT
Languages