AFL for Ruby! You can learn more about AFL itself here.
afl-ruby
is not yet available on Rubygems, so for now you'll have to clone and build it yourself.
git clone git@github.com:richo/afl-ruby.git
You will need to manually build the native extension to the Ruby interpreter in order to allow AFL to instrument your Ruby code. To do this:
cd lib/afl
ruby ../../ext/afl/extconf.rb
make
To instrument your code for AFL, call AFL.init
when you're ready to initialize the AFL forkserver,
then wrap the block of code that you want to fuzz in AFL.with_exceptions_as_crashes { ... }
. For
example:
def byte
$stdin.read(1)
end
def c
r if byte == 'r'
end
def r
s if byte == 's'
end
def s
h if byte == 'h'
end
def h
raise "Crashed"
end
require 'afl'
unless ENV['NO_AFL']
AFL.init
end
AFL.with_exceptions_as_crashes do
c if byte == 'c'
exit!(0)
end
AFL checks if you're an instrumented binary by seeing if you have the AFL environment variable anywhere in your binary. We're using a bog stock ruby interpreter, so we can't do that. Apply afl-fuzz.c.patch
before building AFL to remove this check. Assuming you have cloned afl
and afl-ruby
in the same directory (i.e. in ~/MYCODE/afl
and ~/MYCODE/afl-ruby
) you can do this by:
cd ../afl
git checkout -b apply-ruby-patch
git apply ../afl-fuzz.c.patch
git add .
git commit -m "Apply Ruby patch"
make install
# Check that this did indeed update your AFL
ls -la $(which afl-fuzz)
You should then be able to run the sample harness in the example/
directory:
/path/to/afl/afl-fuzz -i example/work/input -o example/work/output -- /usr/bin/ruby example/harness.rb
It should only take a few seconds to find a crash. Once a crash is found it should be written to example/work/output/crashes/
for you to inspect.
If AFL complains that Program '/usr/bin/ruby' is not a 64-bit Mach-O binary
then this may be because your system Ruby has the old Mach-O magic header bytes, which AFL does not accept. You should try running afl-fuzz
using a different Ruby interpreter. For example, you can use an rbenv Ruby like so:
# Find out which versions rbenv has available
ls ~/.rbenv/versions
# Pick an available version, then run something like this:
/path/to/afl/afl-fuzz -i work/input -o work/output -- ~/.rbenv/versions/2.4.1/bin/ruby harness.rb
Be sure to build the C extension (see "Build the extension" above).
To run the basic test suite, simply run:
rake test
Make sure you have built the extension and patched AFL first, as above.
Substantial portions of afl-ruby are either inspired by, or transposed directly from afl-python by Jakub Wilk jwilk@jwilk.net licensed under MIT.
Stripe allowed both myself and rob to spend substantial amounts of company time developing afl-ruby.