diff --git a/README.md b/README.md index d84a319..da4a6ce 100644 --- a/README.md +++ b/README.md @@ -5,16 +5,62 @@ 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 and whatever, or build from binary +``` +shards install +``` ## Usage ### Library -- Code examples +Sample usage + +```crystal +require "./crowbar" + +# Make a new crowbar, send it the sample input +cr = Crowbar.new("{ \"json\" : \"A String\", \"x\" : 0x123AA }") do |cr| + # Searches the text and splits it by regex + Crowbar::Selector::Regex.new(cr, Crowbar::Constants::Regex::IN_QUOTES) do |s| + # Replaces matched data from the selector + Crowbar::Mutator::Replacer.new(s) do |m| + # Possible generators to use for replacement data + Crowbar::Generator::Decimals.new(m) + Crowbar::Generator::Decimals.new(m, quoted: true) + Crowbar::Generator::Decimals.new(m, float: true) + Crowbar::Generator::Decimals.new(m, quoted: true, float: true) + Crowbar::Generator::Decimals.new(m, quoted: true, float: true) + Crowbar::Generator::BytesGen.new(m, quoted: true) + Crowbar::Generator::BytesGen.new(m) + end + end +end + +10.times do |x| + pp cr.next +end +``` +Sample output +``` +[Running] crystal "/home/ian/Documents/crystal/crowbar/src/sandbox.cr" +"{ 4.0 : \"A String\", \"\xFA\xCF\" : 0x123AA }" +"{ \"0.5\" : \"A String\", \"x\" : 0x123AA }" +"{ \"json\" : \"A String\", \"x\" : 0x123AA }" +"{ \"json\" : \"L\xB07\u001F1\a\", \"x\" : 0x123AA }" +"{ \"json\" : \"A String\", \"x\" : 0x123AA }" +"{ \"json\" : \"A String\", \"\x918\xD3|\xE3\" : 0x123AA }" +"{ \"json\" : \"A String\", \"x\" : 0x123AA }" +"{ \"json\" : 2228.0, \"x\" : 0x123AA }" +"{ \"3653\" : \"g\x8A\xE0\u000F\", \"x\" : 0x123AA }" +"{ \xC9\xF58\xF9 : \"6.53\", \"x\" : 0x123AA }" +[Done] exited with code=0 in 0.818 seconds +``` ### Application - CLI examples diff --git a/src/crowbar.cr b/src/crowbar.cr index 1fa50c5..16337fe 100644 --- a/src/crowbar.cr +++ b/src/crowbar.cr @@ -40,7 +40,7 @@ class Crowbar noise.shuffle(@iteration, selectors)[0..noise.int(@iteration, 0, @selectors.size)].each do |selector| noise.shuffle(@iteration, selector.mutators)[0..noise.int(@iteration, 0, selector.mutators.size)].each do |mutator| mutants = selector.matches.map_with_index do |match, index| - if match.matched? && noise.bool(@iteration, index, 1, 5) + if match.matched? && noise.bool(@iteration, index, 1, 4) string = mutator.mutate(match) match.string = string end diff --git a/src/generators/bytes.cr b/src/generators/bytes.cr index e69de29..e3f0d14 100644 --- a/src/generators/bytes.cr +++ b/src/generators/bytes.cr @@ -0,0 +1,18 @@ +class Crowbar::Generator::BytesGen < Crowbar::Generator + property? quoted = false + + def initialize(mutator, length_limit = (2..6), @quoted = false) + super mutator, length_limit + end + + def make : String + length = self.crowbar.noise.int(self.crowbar.iteration, self.length_limit.begin, self.length_limit.end) + output = "" + length.times do |x| + byte = self.crowbar.noise.int(self.crowbar.iteration + x, self.iteration, 0, 256) + output += String.new(Bytes[byte.to_u8]) + end + @iteration += 1 + quoted? ? "\"" + output + "\"" : output + end +end \ No newline at end of file diff --git a/src/generators/decimals.cr b/src/generators/decimals.cr index 6213369..ec2f34c 100644 --- a/src/generators/decimals.cr +++ b/src/generators/decimals.cr @@ -1,7 +1,7 @@ class Crowbar::Generator::Decimals < Crowbar::Generator property? quoted = false property? float = false - def initialize(mutator, length_limit = (0..10)) + def initialize(mutator, length_limit = (2..6), @quoted = false, @float = false) super mutator, length_limit end @@ -18,6 +18,10 @@ class Crowbar::Generator::Decimals < Crowbar::Generator end end @iteration += 1 - quoted? ? "\"" + output.to_i.to_s + "\"" : output.to_i.to_s + if float? + quoted? ? "\"" + output.to_f.to_s + "\"" : output.to_f.to_s + else + quoted? ? "\"" + output.to_i.to_s + "\"" : output.to_i.to_s + end end end \ No newline at end of file diff --git a/src/sandbox.cr b/src/sandbox.cr index 8b10771..9b96f68 100644 --- a/src/sandbox.cr +++ b/src/sandbox.cr @@ -4,16 +4,16 @@ cr = Crowbar.new("{ \"json\" : \"A String\", \"x\" : 0x123AA }") do |cr| Crowbar::Selector::Regex.new(cr, Crowbar::Constants::Regex::IN_QUOTES) do |s| Crowbar::Mutator::Replacer.new(s) do |m| Crowbar::Generator::Decimals.new(m) - end - end - - Crowbar::Selector::Regex.new(cr, Crowbar::Constants::Regex::EACH_CHAR) do |s| - Crowbar::Mutator::Replacer.new(s) do |m| - Crowbar::Generator::Decimals.new(m) + Crowbar::Generator::Decimals.new(m, quoted: true) + Crowbar::Generator::Decimals.new(m, float: true) + Crowbar::Generator::Decimals.new(m, quoted: true, float: true) + Crowbar::Generator::Decimals.new(m, quoted: true, float: true) + Crowbar::Generator::BytesGen.new(m, quoted: true) + Crowbar::Generator::BytesGen.new(m) end end end -20.times do |x| - puts cr.next +10.times do |x| + pp cr.next end