[or-cvs] r11289: cleaned up the source and added some examples (in topf/trunk: . binary doc examples lib lib/fuzz utils)

benedikt at seul.org benedikt at seul.org
Mon Aug 27 16:54:33 UTC 2007


Author: benedikt
Date: 2007-08-27 12:54:30 -0400 (Mon, 27 Aug 2007)
New Revision: 11289

Added:
   topf/trunk/binary/argument_example.c
   topf/trunk/examples/
   topf/trunk/examples/argument_fuzz_example.rb
   topf/trunk/examples/example1.rb
   topf/trunk/lib/fuzz/
   topf/trunk/lib/fuzz/collection.rb
   topf/trunk/lib/fuzz/connection.rb
   topf/trunk/lib/fuzz/core.rb
   topf/trunk/lib/fuzz/helper.rb
   topf/trunk/lib/fuzz/observer.rb
   topf/trunk/lib/fuzz/test.rb
   topf/trunk/lib/fuzz/tests.rb
   topf/trunk/utils/set_core_pattern
Modified:
   topf/trunk/README
   topf/trunk/doc/tutorial.tex
   topf/trunk/lib/fuzz.rb
   topf/trunk/tor-control-fuzz.rb
   topf/trunk/tor-dir-fuzz.rb
Log:
cleaned up the source and added some examples

Modified: topf/trunk/README
===================================================================
--- topf/trunk/README	2007-08-27 15:38:17 UTC (rev 11288)
+++ topf/trunk/README	2007-08-27 16:54:30 UTC (rev 11289)
@@ -1,3 +1,6 @@
+Pointer for Google: The newest version is always on the subversion repo at:
+https://tor-svn.freehaven.net/svn/topf/trunk
+
 (T)he (O)nion (P)rotocol (F)uzzer
 
 This is my Google Summer of Code Project where I try to build a

Added: topf/trunk/binary/argument_example.c
===================================================================
--- topf/trunk/binary/argument_example.c	                        (rev 0)
+++ topf/trunk/binary/argument_example.c	2007-08-27 16:54:30 UTC (rev 11289)
@@ -0,0 +1,17 @@
+/*
+ * DANGER !!! THIS FILE IS VULNERABLE TO A VERY SIMPLE BUG :) 
+ * DONT USE THIS IN PRODUCTIVE ENVIRONMENTS.. THIS IS ONLY AN EXAMPLE,
+ * TO USE WITH THE T.O.P.F FUZZER EXAMPLES
+ */
+void vuln(char *ptr)
+{
+    char buffer[20];
+    strcpy(&buffer, ptr); 
+}
+
+int main(int argc, char *argv[])
+{
+    if(argc > 1)
+        vuln(argv[1]);
+    return 0;
+}

Modified: topf/trunk/doc/tutorial.tex
===================================================================
--- topf/trunk/doc/tutorial.tex	2007-08-27 15:38:17 UTC (rev 11288)
+++ topf/trunk/doc/tutorial.tex	2007-08-27 16:54:30 UTC (rev 11289)
@@ -12,6 +12,7 @@
 \tableofcontents
 \newpage
 \section{Introduction}
+\label{working}
 T.O.P.F is a fuzzing Framework written in Ruby and developed to test the
 Tor protocol-suite.  It uses a block-based approch like the famous SPIKE
 fuzzer written by Dave-Aitel.  Block-based means that data is divided into
@@ -22,14 +23,11 @@
 you should read into the links listed in Appendix \ref{links}.
 
 \section{Working with T.O.P.F}
-\label{working}
 To use T.O.P.F a few basic steps described in this section are necessary.
 \subsection{Setting up a working Environment}
-As my aim is to make the Installation of T.O.P.F as easy as possible,
-a working Ruby Interpreter and a checkout of  the latest T.O.P.F
-trunk should be enough to setup up a working Test-Environment on most
-systems. If you have any problems or errors you are encouraged to email
-me to benedikt.boss (at) gmail (dot) com .
+T.O.P.F needs Ruby and the Ruby-SSL library which is on some systems supplied 
+as standart-library and not on others. On Debian you need to run
+"apt-get install ruby libruby-openssl" beside the normal Ruby library.
 
 \subsubsection{Checking out the current T.O.P.F trunk}
 Checking out T.O.P.F is as simple as starting a
@@ -86,91 +84,59 @@
 the tests against the Dir-Port. If you're sure you did all config options
 right you can execute "ruby tor-control-fuzz.rb" and the rest is done
 automatically.
-\section{Writing T.O.P.F Structures}
-As described in Section~\ref{working} (yeah? where? -RD), T.O.P.F
-organizes its data in blocks. These blocks can have different types
-which are described in detail in Section~\ref{types}. For example you
-can use char, signed, and unsigned types.
-
+\subsection{Writing tests for TOR}
+To give you a more tor-specific example of how such a test might look i give you
+an example out of control.rb that helds the structures to fuzz the Tor
+control-port. From the control-spec we take the "SIGNAL" keyword and check out
+the syntax of the command: \begin{varbatim}"SIGNAL" SP Signal CRLF\end{verbatim}
+If we now want to check if the parsing of the given signal has a bug we also
+want to set the initial "SIGNAL" keyword and the appended crlf field to non-fuzzable.
+Implementing this as a FuzzStruct could look like this:\\
 \begin{verbatim}
-#example1.rb
-require "lib/fuzz-generic"
+class SignalItem < FuzzStruct
+    text :item, 6, :fuzzable => false
+    text :signal, 13
+    char :crlf, 2*8, :fuzzable => false
 
-class Example < FuzzStruct
-    text :example, 7, :fuzzable => false
-    unsigned :version, 8
-
-    initial_value.example = "example"
-    initial_value.version   = 1
+    initial_value.item = "SIGNAL" 
+    initial_value.crlf = "\r\n"
 end
-
-begin
-    e = Example.new
-    e.version = 2
-    pp e
-end
 \end{verbatim}
-This creates a Class called "Example" with the fields of a 8*8Bit long String,
-a 8Bit unsigned integer. and the initial values "example" and 1 for these.
-Also the Text-Field is declared as not fuzzable which means that later the
-value assigned to it remains the same. Next in the begin/end block the
-programm creates a Example object and sets the value of the version field to 2.
-This also demonstrates how you are able to access all fields after you created
-a fuzz-struct object.
-
-
-\subsection{Writing T.O.P.F Tests}
-Tests in the Framework are organized on a field-type base. This means
-that you write tests for a specific field. To generate a Test you must
-create a Fuzz::Test object and assign a type and code-block to
-it. For example if you want to test a char-field and assign many many
-"A"'s to the Field, which is a very common test :), you could write
-something like this:
+The signal-field is chosen to be 13 bytes long as the longest signal-string
+("CLEARDNSCACHE") is 13 bytes long.\\
+Now we want to test the signal "RELOAD" so we create a SignalItem object and set
+signal to "RELOAD".
 \begin{verbatim}
-    a_test = Fuzz::Test.new("char") {|arg, size|  "A"*1000}
+si = SignalItem.new
+si.signal = "RELOAD"
 \end{verbatim}
-To apply this test to a fuzz-struct you actually need another object which
-acts as a collector for many tests. This object is called Fuzz::Tests and
-is later applied to a fuzz-struct. The next example shows how you write some
-tests, assign them to the collector object and apply all tests to a structure
-and output all permutations calculateable through these tests.
-
+Next we want to apply two tests for the signal-field, a very long string and
+a format-string.
 \begin{verbatim}
-#example2.rb
-require "lib/fuzz-generic"
+t = Fuzz::Tests.new
+t.register Fuzz::Test.new("char") {|arg, size| arg }
+t.register Fuzz::Test.new("char") {|arg, size| "A"*1000 }  # long-string
+t.register Fuzz::Test.new("char") {|arg, size| "%n"*1000 } # format-string
 
-class Example < FuzzStruct
-    text :example, 7
-    unsigned :version, 8
-
-    initial_value.example = "example"
-    initial_value.version   = 1
-end
-
-begin
-    example_tests = Fuzz::Tests.new
-
-    # tests for the text field
-    example_tests.register Fuzz::Test.new("char") {|arg, size|  arg} # return argument
-    example_tests.register Fuzz::Test.new("char") {|arg, size|  ""}    # return empty string
-    example_tests.register Fuzz::Test.new("char") {|arg, size|  "A"*1000} # return many many A's
-
-    # tests for unsigned numbers
-    example_tests.register Fuzz::Test.new("unsigned") {|arg, size|  arg } # return argument
-    example_tests.register Fuzz::Test.new("unsigned") {|arg, size|  0 } # return zero
-    example_tests.register Fuzz::Test.new("unsigned") {|arg, size|  rand(5) } # return a small number
-    example_tests.register Fuzz::Test.new("unsigned") {|arg, size|  2.power!(size) } # return biggest number
-
-    e = Example.new
-    e.prepare! example_tests
-end
+si.prepare! t
 \end{verbatim}
-
-\subsection{Some example tests on Tor itself}
-
-[Show a good example of a fuzz test on one of Tor's structs, to
-make things more concrete.]
-
+Now we need a connection to the control-port through which we can send our data.
+\begin{verbatim}
+options = {
+    :host => "127.0.0.1",    # ip where our tor process is running
+    :port => "2323",         # number of the control-port
+    :debug => true,          # much output but shows the permutations
+    :type => :tcp,           # tcp-connection
+    :timeout => 0.5          # timeout between each sending
+}
+c = Fuzz::Connection.new(options)
+c.fuzz!( si, " " )
+\end{verbatim}
+This is allready enough to fuzz the Signal Item but it doesnt give us any
+information when the tor-process has been crashed by the fuzzer. Cause
+this is very important when running a larg amount of tests automatically
+one can use the Observer and Coremanager classes.\\
+To start a binary as a child of the observer class 
 \subsection{Do the Fuzz!}
 
 \section{T.O.P.F Reference}
@@ -186,8 +152,9 @@
 \subsection{Backtrace}
 \subsection{Proxy}
 \subsubsection{Http-Proxy}
+Not yet finished but should act as a fuzzing-proxy in the future.
 \subsubsection{Https-Proxy}
-
+Not yet finished but should act as a fuzzing-proxy in the future.
 \section{Fuzz-Struct Reference}
 \subsection{Types}
 \label{types}
@@ -205,7 +172,6 @@
 \subsubsection{nested}
 \subsubsection{pad}
 
-
 \section{Appendix}
 \section{Links}
 \label{links}

Added: topf/trunk/examples/argument_fuzz_example.rb
===================================================================
--- topf/trunk/examples/argument_fuzz_example.rb	                        (rev 0)
+++ topf/trunk/examples/argument_fuzz_example.rb	2007-08-27 16:54:30 UTC (rev 11289)
@@ -0,0 +1,16 @@
+require "../lib/fuzz-generic"
+
+class Argument < FuzzStruct
+    text :argument, 20
+    initial_value.argument = "BLAH" 
+end
+
+begin
+    config = YAML::load_file "../config/config.yml"
+    app = config["BINDIR"]+"/argument_example"
+    
+    arg = Argument.new
+    arg.prepare! Fuzz::DEFAULT_TESTS
+
+    Fuzz::argument(app, arg, config)
+end

Added: topf/trunk/examples/example1.rb
===================================================================
--- topf/trunk/examples/example1.rb	                        (rev 0)
+++ topf/trunk/examples/example1.rb	2007-08-27 16:54:30 UTC (rev 11289)
@@ -0,0 +1,17 @@
+#!/usr/bin/ruby 
+require "../lib/fuzz-generic"
+
+class Example < FuzzStruct
+    text :example, 7, :fuzzable => false
+    unsigned :version, 8
+
+    initial_value.example = "example"
+    initial_value.version   = 1
+end
+
+begin
+    e = Example.new
+    e.version = 2
+    pp e
+end
+

Added: topf/trunk/lib/fuzz/collection.rb
===================================================================
--- topf/trunk/lib/fuzz/collection.rb	                        (rev 0)
+++ topf/trunk/lib/fuzz/collection.rb	2007-08-27 16:54:30 UTC (rev 11289)
@@ -0,0 +1,53 @@
+module Fuzz
+    # This Class collects many FuzzStructs and takes a block to calculate the
+    # wanted output of everything.
+    class Collection
+        attr_reader :structs, :number_of_tests
+        def initialize(join_character = "")
+            @join_character = join_character
+            @structs = Array.new 
+            @format_block = nil
+            @prepared = false
+            @fuzz_index = 0
+            @number_of_tests = 0
+        end
+
+        # adds a FuzzStruct to the collection
+        def add_struct(struct)
+            @structs << struct if struct.is_a?(FuzzStruct)
+        end
+
+        # apply tests to all objects in the collection
+        def add_tests(tests)
+            raise "argument must be a Fuzz::Tests object" if !tests.is_a?(Fuzz::Tests)
+            @structs.each do |struct|
+                struct.prepare! tests
+                @number_of_tests += struct.permutations
+            end
+            @prepared = true
+        end
+    
+        # add the format block to the class
+        def add_format_block(&block)
+            @format_block = block
+        end
+
+        # take some arguments and call the format block with these for the correct output
+        def fuzz!(args)
+            raise "no tests have been added yet" if !@prepared
+            args[:fuzz_index] = @fuzz_index
+            resultString, @fuzz_index = to_s( args )
+            if @fuzz_index == @structs.size
+                raise "finished all tests"
+            end
+            @number_of_tests-=1
+            [ resultString, @number_of_tests]
+        end
+
+        # supply a block on howto format the collection 
+        def to_s(args)
+            raise "no format block given yet!" if !@format_block
+            @format_block.call(args, @structs, @join_character) 
+        end
+    end
+end

Added: topf/trunk/lib/fuzz/connection.rb
===================================================================
--- topf/trunk/lib/fuzz/connection.rb	                        (rev 0)
+++ topf/trunk/lib/fuzz/connection.rb	2007-08-27 16:54:30 UTC (rev 11289)
@@ -0,0 +1,90 @@
+module Fuzz
+    # makes a Connection to a given target and sends our raw data to it
+    # see yourself what options are needed :>
+    class Connection
+        def initialize(args)
+            @type = args[:type]
+            @host = args[:host]
+            @port = args[:port]
+            @path = args[:path]
+            @http_direction = args[:http_direction]
+            @http_url       = args[:http_url]
+            @observer       = args[:observer]
+            @coremanager    = @observer.coremanager if @observer.is_a?(BinaryObserver)
+            args[:timeout] ? @timeout = args[:timeout] : @timeout = 0.2
+
+            Fuzz::LOGGER.level = Logger::INFO if !args[:debug]
+
+            @socket = connect
+        end
+    
+        # Send the data given as string to the configured target
+        def send( data )
+            begin
+                case @type
+                when :http
+                    case @http_direction
+                    when :post
+                        @socket.post @http_url ,data
+                    when :get
+                        @socket.get @http_url, data 
+                    end
+                else
+                    @socket.write data
+                end
+            rescue Exception => exception
+                Fuzz::output_crash_info(@coremanager) if @coremanager.new_corefile?
+                Kernel::exit
+            end
+        end
+
+        def fuzz!(structs, join_character="", args={})
+            structs = [structs] if !structs.is_a? Array
+            structs.each_with_index do |struct, index|
+                Fuzz::LOGGER.info "[x] fuzzing struct %d of %d with %d permutations" % [index+1, structs.size, 0]
+
+                Fuzz.fuzz(@observer, struct){|struct|
+                    data = struct.join( join_character )
+                    Fuzz::LOGGER.debug "sending data: %s" % data
+                    self.send data
+                    #assert(args[:assert] )
+                }
+            end
+            raise "finished all tests"
+        end
+
+        # receives data from the socket and tests it against a supplied array of strings, values 
+        def assert(reply = [])
+            begin
+                timeout(@timeout) do 
+                    reply_data = Regexp.new( @socket.readline().to_regexp )
+                    raise "ASSERTION %s FAILED\nreceived %s" % [ reply.join(","), reply_data] if !reply.find_all{|x| x=~ reply_data}
+                end
+            rescue Exception
+                Fuzz::LOGGER.debug "[!] Exception: %s" % $!
+            end
+        end
+
+        def close
+            @socket.close if @type != :http && @type != :tls
+        end
+    private
+        def connect
+            begin
+                case @type
+                when :tcp
+                    return TCPSocket.new(@host, @port)
+                when :unix
+                    return UNIXSocket.open( @path )
+                when :http
+                    return Net::HTTP.new(@host, @port)
+                when :tls
+                    raise "not implemented yet"
+                end 
+            rescue Exception
+                Fuzz::LOGGER.info "[!] Exception: %s" % $!
+                exit 0
+            end         
+        end        
+    end
+end

Added: topf/trunk/lib/fuzz/core.rb
===================================================================
--- topf/trunk/lib/fuzz/core.rb	                        (rev 0)
+++ topf/trunk/lib/fuzz/core.rb	2007-08-27 16:54:30 UTC (rev 11289)
@@ -0,0 +1,41 @@
+module Fuzz
+    class CoreManager
+        def initialize(executable, corepath)
+            @executable = executable
+            @corepath = corepath
+            @list = get_corefiles
+            enable_coredump
+        end
+
+        def latest_corefile
+            @list.last
+        end
+
+        def new_corefile?
+            new = get_corefiles
+            if new.size > 0 && new != @list
+                @list = new
+                true
+            else
+                false
+            end
+        end       
+
+        def get_latest_backtrace
+            GDB::Interface.new( {:executable => @executable, :core => @corepath+"/"+ at list.last} ).bt if @list
+        end 
+
+        def get_latest_registers
+            GDB::Interface.new( {:executable => @executable, :core => @corepath+"/"+ at list.last} ).info("registers") if @list
+        end
+
+        def enable_coredump
+            system("ulimit -c unlimited")
+        end
+        private
+
+        def get_corefiles
+            Dir.new(File.expand_path(@corepath)).entries.select{|entry| entry=~/core/ }.sort{|x, y| File.mtime(@corepath+"/"+x) <=> File.mtime(@corepath+"/"+y)}
+        end
+    end
+end

Added: topf/trunk/lib/fuzz/helper.rb
===================================================================
--- topf/trunk/lib/fuzz/helper.rb	                        (rev 0)
+++ topf/trunk/lib/fuzz/helper.rb	2007-08-27 16:54:30 UTC (rev 11289)
@@ -0,0 +1,10 @@
+class String
+    # insert! copies the string before altering it compared to the normal insert
+    # method
+    def insert!(index, inject)
+        self.clone.insert(index, inject)
+    end
+    def to_regexp
+        self.to_s.gsub("{", "\{").gsub("}", "\}").gsub("[", "\[").gsub("]", "\]").gsub("(", "\(").gsub(")", "\)")
+    end
+end

Added: topf/trunk/lib/fuzz/observer.rb
===================================================================
--- topf/trunk/lib/fuzz/observer.rb	                        (rev 0)
+++ topf/trunk/lib/fuzz/observer.rb	2007-08-27 16:54:30 UTC (rev 11289)
@@ -0,0 +1,47 @@
+module Fuzz
+    class BinaryObserver
+        attr_reader :coremanager
+        def initialize( programname, corepath, *arguments )
+            @programname = programname
+            @arguments = arguments.to_a
+            @pid = nil
+            @coremanager = Fuzz::CoreManager.new(@programname, corepath)
+            @running = false
+        end
+
+        def observe!
+            if !is_running?
+                Thread.new do 
+                    @pid = fork do 
+                        Fuzz::LOGGER.info "[x] starting #{@programname} #{@arguments.join(" ")}"
+                        exec("#{@programname} #{@arguments.join(" ")} ")
+                    end
+                    @running = true
+                    Process.wait
+                    @running = false
+                end
+            else
+                Fuzz::LOGGER.info "[x] #{@programname} allready running"
+            end
+        end
+
+        def get_pid
+            @pid
+        end
+
+        def exit
+            Process.kill "KILL", @pid if @running 
+        end
+
+        def is_running?
+            reg = Regexp.new( @programname.split("/").last )
+            result = IO.popen("ps faux").readlines.find_all{|x| x=~ reg }
+            if result.size > 0
+                true
+            else
+                false
+            end
+        end
+
+    end
+end

Added: topf/trunk/lib/fuzz/test.rb
===================================================================
--- topf/trunk/lib/fuzz/test.rb	                        (rev 0)
+++ topf/trunk/lib/fuzz/test.rb	2007-08-27 16:54:30 UTC (rev 11289)
@@ -0,0 +1,25 @@
+module Fuzz
+    # This Class holds our test which is a ruby-block that must be able to process one argument
+    # which is the default value of the Field to be tested. This argument can be ignored if wanted.
+    class Test
+        attr_reader :type
+        def initialize(type, &block)
+            case type.downcase
+                when "char"
+                    @type = "char"
+                when "unsigned"
+                    @type = "unsigned"
+                when "signed"
+                    @type = "signed"
+                when "octet"
+                    @type = "octet"
+                else
+                    raise "unknown type"
+                end
+            @test = block
+        end
+        def run(arg, size)
+            @test.call arg, size
+        end
+    end
+end

Added: topf/trunk/lib/fuzz/tests.rb
===================================================================
--- topf/trunk/lib/fuzz/tests.rb	                        (rev 0)
+++ topf/trunk/lib/fuzz/tests.rb	2007-08-27 16:54:30 UTC (rev 11289)
@@ -0,0 +1,135 @@
+module Fuzz
+    # This Class holds all tests to related to a given field-type
+    class Tests
+        attr_reader :tests, :permutations, :signed_tests, :char_tests, :unsigned_tests
+        def initialize(struct=nil)
+            @char_tests      = []
+            @unsigned_tests  = []
+            @signed_tests    = []
+            @octet_tests     = []
+            @permutations    = [] 
+            @tests           = []
+            @struct          = struct
+            @count           = 0
+            @dimension       = nil
+        end
+
+        # register a new test to a given type
+        def register(test)
+            raise "argument must be a Fuzz::Test object" if !test.is_a?(Fuzz::Test)
+            case test.type
+            when "char"
+                @char_tests.push test
+            when "unsigned"
+                @unsigned_tests.push test
+            when "signed"
+                @signed_tests.push test
+            when "octet"
+                @octet_tests.push test
+            end
+        end
+
+        # generate all possible permutations
+        def generate_test_data
+            Fuzz::LOGGER.debug "[x] generating %d char %d unsigned %d signed tests" % [@char_tests.size, @unsigned_tests.size, @signed_tests.size]
+
+            generate_test_data!
+            permutate
+            @count = 0
+        end
+
+        # get the next permutation
+        def get_permutation
+            raise "no tests have been generated yet" if !@permutations or !@tests
+            raise "end of tests" if @count.to_i == @dimension.to_i
+            test = []
+            perm = @permutations.collect{|element| element[@count] }
+            tempcount = 0
+            @count += 1
+            @tests.collect{ |element| 
+                result = element[ perm[tempcount] ]
+                tempcount+=1
+                result
+            }
+        end
+
+        def get_all
+        end
+
+        def set_struct(struct)
+            raise "argument not a bitstruct!" if !struct.is_a?(BitStruct)
+            @struct = struct
+            generate_test_data!
+            permutate!
+        end
+
+        # debug function...
+        def show_permutation_indices
+            @permutations[0].each_with_index do |element, index|
+                pp @permutations.collect{|el| el[index] }
+            end
+        end
+        private
+        def generate_test_data!
+            result = []
+            raise "argument must be a BitStruct object" if !@struct.is_a?(BitStruct)
+            @struct.fields.each do |field|
+                temp = []
+                arg = @struct.method(field.name).call
+                length = field.length
+                case field.class.to_s
+                when "BitStruct::SignedField"
+                    @signed_tests.each do |test|
+                    temp.push( test.run(arg, length) )
+                    end
+                result.push(temp)
+                when "BitStruct::UnsignedField"
+                    @unsigned_tests.each do |test|
+                    temp.push( test.run(arg, length) )
+                    end
+                result.push(temp)
+                when "BitStruct::TextField" || "BitStruct::CharField"
+                    @char_tests.each do |test|
+                    temp.push( test.run(arg, length) )
+                    end
+                result.push(temp)
+                when "BitStruct::HexOctetField"
+                    @hex_tests.each do |test|
+                    temp.push( test.run(arg, length) )
+                    end
+                result.push(temp)
+                else
+                    Fuzz::LOGGER.debug "new field-type: %s" % field.class.to_s
+                end
+            end
+            @tests = result
+        end
+
+        def permutate!
+            raise "tests have not been generated yet" if !@tests
+
+            sizes =  @tests.collect {|element| element.size}
+            @dimension = sizes.inject(1){|prod, element| prod*element }
+            permutations = Array.new(sizes.size, Array.new(@dimension+1, 0) )
+            result = []
+            permutations.each_with_index do |element, index|
+                count = 0 
+                temp  = 0 
+                tempdimension = sizes[(index+1)..-1].inject(1){|prod, el| prod*el}
+                result.push element.collect{|entry|
+                    if count == tempdimension
+                        temp+=1
+                        temp = 1 if temp == (sizes[index]+1) 
+
+                        count = 0
+                    end
+                    count+=1
+                    temp  
+                }
+            end
+            Fuzz::LOGGER.debug "[x] calculated %d permutations of struct %s" % [result.first.size, self.class]
+            @permutations = result
+        end
+    end
+
+end

Modified: topf/trunk/lib/fuzz.rb
===================================================================
--- topf/trunk/lib/fuzz.rb	2007-08-27 15:38:17 UTC (rev 11288)
+++ topf/trunk/lib/fuzz.rb	2007-08-27 16:54:30 UTC (rev 11289)
@@ -1,312 +1,58 @@
-class String
-    # insert! copies the string before altering it compared to the normal insert
-    # method
-    def insert!(index, inject)
-        self.clone.insert(index, inject)
-    end
-    def to_regexp
-        self.to_s.gsub("{", "\{").gsub("}", "\}").gsub("[", "\[").gsub("]", "\]").gsub("(", "\(").gsub(")", "\)")
-    end
-end
+###################################################
+# INCLUDE SECTION
+###################################################
+require "fuzz/helper"
+require "fuzz/observer"
+require "fuzz/core"
+require "fuzz/connection"
+require "fuzz/collection"
+require "fuzz/test"
+require "fuzz/tests"
 
 module Fuzz
-    # define your own if you want :)
+    ###################################################
+    # GLOBAL VARIABLES SECTION
+    ###################################################
     MAX_RAND = 1000
 
-    # This Class collects many FuzzStructs and takes a block to calculate the
-    # wanted output of everything.
-    class Collection
-        attr_reader :structs, :number_of_tests
-        def initialize(join_character = "")
-            @join_character = join_character
-            @structs = Array.new 
-            @format_block = nil
-            @prepared = false
-            @fuzz_index = 0
-            @number_of_tests = 0
-        end
 
-        # adds a FuzzStruct to the collection
-        def add_struct(struct)
-            @structs << struct if struct
-        end
+    ###################################################
+    # MODULE METHODS SECTION 
+    ###################################################
 
-        # apply tests to all objects in the collection
-        def add_tests(tests)
-            raise "argument must be a Fuzz::Tests object" if !tests.is_a?(Fuzz::Tests)
-            @structs.each do |struct|
-                struct.prepare! tests
-                @number_of_tests += struct.permutations
-            end
-            @prepared = true
-        end
-
-        def add_format_block(&block)
-            @format_block = block
-        end
-
-        def fuzz!(args)
-            raise "no tests have been added yet" if !@prepared
-            args[:fuzz_index] = @fuzz_index
-            resultString, @fuzz_index = to_s( args )
-            if @fuzz_index == @structs.size
-                raise "finished all tests"
-            end
-            @number_of_tests-=1
-            [ resultString, @number_of_tests]
-        end
-
-        # supply a block on howto format the collection 
-        def to_s(args)
-            raise "no format block given yet!" if !@format_block
-            @format_block.call(args, @structs, @join_character) 
-        end
+    # dumps a backtrace and register info to the log 
+    def Fuzz.output_crash_info(coremanager)
+        Fuzz::LOGGER.info "[?] found new corefile(%s)\nprinting backtrace:\n%s\nprinting registers:\n%s" %  [ coremanager.latest_corefile, coremanager.get_latest_backtrace, coremanager.get_latest_registers ]
     end
 
-    class BinaryObserver
-        attr_reader :coremanager
-        def initialize( programname, corepath, *arguments )
-            @programname = programname
-            @arguments = arguments.to_a
-            @pid = nil
-            @coremanager = Fuzz::CoreManager.new(@programname, corepath)
-            @running = false
+    # This method iterates the given block endless and gives each iteration 
+    # a permutation of struct as argument.
+    # After the last permutation struct.fuzz! will raise an exception and so
+    # leaving the loop. 
+    # If you dont catch this exception the execution will be stoped.
+    def Fuzz.fuzz_iterator(struct, coremanager, &block)
+        while true
+            block.call( struct.fuzz!, coremanager )
         end
-        
-        def observe!
-            Thread.new do 
-                @pid = fork do 
-                    Fuzz::LOGGER.info "[x] starting #{@programname} #{@arguments.join(" ")}"
-                    exec("#{@programname} #{@arguments.join(" ")} ")
-                end
-                @running = true
-                Process.wait
-                Fuzz::LOGGER.debug "[!] %d coredumped? %s" % [@pid, process_status.coredump?]
-                Fuzz::LOGGER.debug "[!] %d get uncaught signal %d" % [@pid, process_status.termsig] if process_status.signaled?
-                Fuzz::LOGGER.debug "[!] %d stopped by signal %d" % [@pid, process_status.stopsig] if process_status.stopped?
-                Fuzz::LOGGER.debug "[!] %d exited %d" % [@pid, process_status.exitstatus] if process_status.exited?
-                @running = false
-            end
-        end
-        def get_pid
-            @pid
-        end
-        def exit
-           Process.kill "KILL", @pid if @running 
-        end
     end
 
-    class CoreManager
-        def initialize(executable, corepath)
-            @executable = executable
-            @corepath = corepath
-            @list = get_corefiles
-            enable_coredump
-        end
-
-        def latest_corefile
-            @list.last
-        end
-
-        def new_corefile?
-            new = get_corefiles
-            if new.size > 0 && new != @list
-                @list = new
-                true
-            else
-                false
-            end
-        end       
-
-        def get_latest_backtrace
-            GDB::Interface.new( {:executable => @executable, :core => @corepath+"/"+ at list.last} ).bt if @list
+    # This method combines the fuzz_iterator with a default exception handling
+    # which looks for a new corefile and if one is found prints out
+    # a backtrace and the last register state.
+    def Fuzz.fuzz(observerOrCoremanager, struct, &block)
+        if observerOrCoremanager.is_a?(BinaryObserver)
+            coremanager = observerOrCoremanager.coremanager 
+        elsif observerOrCoremanager.is_a?(CoreManager)
+            coremanager = observerOrCoremanager
         end 
-   
-        def get_latest_registers
-            GDB::Interface.new( {:executable => @executable, :core => @corepath+"/"+ at list.last} ).info("registers") if @list
-        end
 
-        def enable_coredump
-            system("ulimit -c unlimited")
-        end
-    private
-
-        def get_corefiles
-            Dir.new(File.expand_path(@corepath)).entries.select{|entry| entry=~/core/ }.sort{|x, y| File.mtime(@corepath+"/"+x) <=> File.mtime(@corepath+"/"+y)}
-        end
-    end
-
-    # This Class holds all tests to related to a given field-type
-    class Tests
-        attr_reader :tests, :permutations, :signed_tests, :char_tests, :unsigned_tests
-        def initialize(struct=nil)
-            @char_tests      = []
-            @unsigned_tests  = []
-            @signed_tests    = []
-            @octet_tests     = []
-            @permutations    = [] 
-            @tests           = []
-            @struct          = struct
-            @count           = 0
-            @dimension       = nil
-        end
-
-        # register a new test to a given type
-        def register(test)
-            raise "argument must be a Fuzz::Test object" if !test.is_a?(Fuzz::Test)
-            case test.type
-                when "char"
-                    @char_tests.push test
-                when "unsigned"
-                    @unsigned_tests.push test
-                when "signed"
-                    @signed_tests.push test
-                when "octet"
-                    @octet_tests.push test
-            end
-        end
-        
-        # generate all possible permutations
-        def generate_test_data
-            Fuzz::LOGGER.debug "[x] generating %d char %d unsigned %d signed tests" % [@char_tests.size, @unsigned_tests.size, @signed_tests.size]
-
-            generate_test_data!
-            permutate
-            @count = 0
-        end
-
-        # get the next permutation
-        def get_permutation
-            raise "no tests have been generated yet" if !@permutations or !@tests
-            raise "end of tests" if @count.to_i == @dimension.to_i
-            test = []
-            perm = @permutations.collect{|element| element[@count] }
-            tempcount = 0
-            @count += 1
-            @tests.collect{ |element| 
-                result = element[ perm[tempcount] ]
-                tempcount+=1
-                result
-            }
-        end
-
-        def get_all
-        end
-
-        def set_struct(struct)
-            raise "argument not a bitstruct!" if !struct.is_a?(BitStruct)
-            @struct = struct
-            generate_test_data!
-            permutate!
-        end
-
-        # debug function...
-        def show_permutation_indices
-            @permutations[0].each_with_index do |element, index|
-                pp @permutations.collect{|el| el[index] }
-            end
-        end
-    private
-        def generate_test_data!
-            result = []
-            raise "argument must be a BitStruct object" if !@struct.is_a?(BitStruct)
-            @struct.fields.each do |field|
-                temp = []
-                arg = @struct.method(field.name).call
-                length = field.length
-                case field.class.to_s
-                when "BitStruct::SignedField"
-                    @signed_tests.each do |test|
-                        temp.push( test.run(arg, length) )
-                    end
-                    result.push(temp)
-                when "BitStruct::UnsignedField"
-                    @unsigned_tests.each do |test|
-                        temp.push( test.run(arg, length) )
-                    end
-                    result.push(temp)
-                when "BitStruct::TextField" || "BitStruct::CharField"
-                    @char_tests.each do |test|
-                        temp.push( test.run(arg, length) )
-                    end
-                    result.push(temp)
-                when "BitStruct::HexOctetField"
-                    @hex_tests.each do |test|
-                        temp.push( test.run(arg, length) )
-                    end
-                    result.push(temp)
-                else
-                    Fuzz::LOGGER.debug "new field-type: %s" % field.class.to_s
-                end
-            end
-            @tests = result
-        end
-    
-        def permutate!
-            raise "tests have not been generated yet" if !@tests
-
-            sizes =  @tests.collect {|element| element.size}
-            @dimension = sizes.inject(1){|prod, element| prod*element }
-            permutations = Array.new(sizes.size, Array.new(@dimension+1, 0) )
-            result = []
-            permutations.each_with_index do |element, index|
-                count = 0 
-                temp  = 0 
-                tempdimension = sizes[(index+1)..-1].inject(1){|prod, el| prod*el}
-                result.push element.collect{|entry|
-                    if count == tempdimension
-                       temp+=1
-                       temp = 1 if temp == (sizes[index]+1) 
-                       
-                       count = 0
-                    end
-                    count+=1
-                    temp  
-                }
-            end
-            Fuzz::LOGGER.debug "[x] calculated %d permutations of struct %s" % [result.first.size, self.class]
-            @permutations = result
-        end
-    end
-
-    # This Class holds our test which is a ruby-block that must be able to process one argument
-    # which is the default value of the Field to be tested. This argument can be ignored if wanted.
-    class Test
-        attr_reader :type
-        def initialize(type, &block)
-            case type.downcase
-                when "char"
-                    @type = "char"
-                when "unsigned"
-                    @type = "unsigned"
-                when "signed"
-                    @type = "signed"
-                when "octet"
-                    @type = "octet"
-                else
-                    raise "unknown type"
-                end
-            @test = block
-        end
-        def run(arg, size)
-                @test.call arg, size
-        end
-    end
-
-    def Fuzz.fuzz_iterator(struct, &block)
-        while true
-            block.call( struct.fuzz! )
-        end
-    end
-
-    def Fuzz.fuzz(observer, struct, &block)
         begin
-            Fuzz::fuzz_iterator(struct, &block)
+            Fuzz::fuzz_iterator(struct, coremanager, &block)
         rescue Exception => exception
-            Fuzz::LOGGER.info "[?] error while sending data:\n%s\n" % data
-            Fuzz::LOGGER.info "[?] locking for new corefiles.."
-            if observer.coremanager.new_corefile?
-                Fuzz::LOGGER.info "[?] found new corefile(%s)\nprinting backtrace:\n%s\nprinting registers:\n%s" %  [ observer.coremanager.latest_corefile, observer.coremanager.get_latest_backtrace, observer.coremanager.get_latest_registers ]
+            # TODO: IF NOT END OF FUZZ
+#            Fuzz::LOGGER.info "[?] error while sending data:\n%s\n" % data
+            if coremanager.new_corefile? or exception.message == "core found"
+                Fuzz::output_crash_info(coremanager) 
             else
                 Fuzz::LOGGER.info "[?] no new corefile found"
             end
@@ -314,130 +60,23 @@
         end
     end
 
+    # This method implements a simple argument fuzzer 
     def Fuzz.argument(application, struct, config)
-        reg = Regexp.new "outch!" 
+        raise "application \"%s\" not existent or not executable" % application if !File.executable?(application)
         coremanager = Fuzz::CoreManager.new(application, config["COREDIR"])
-        begin
-            Fuzz::fuzz_iterator(struct){|argument|
-                argument = argument.join if argument.is_a?(Array)
-                system(application + " " + argument)
-                raise "outch!\n%s" % argument if coremanager.new_corefile?
-            }
-        rescue Exception => exception
-            if exception.to_s =~ reg
-                argument = exception.to_s.gsub("outch!", "")
-                puts "!"*40
-                puts "argument:\n%s \nkilled the application!" % argument
-                puts "backtrace:"
-                puts coremanager.get_latest_backtrace
-                puts "_"*40
-                puts "registers:"
-                puts coremanager.get_latest_registers
-                puts "writing POC"
-                File.open("POC", "w+").write "#!/bin/sh\n#{application.strip} #{argument.strip}"
-                puts "!"*40 
-            end
-            Kernel::exit
-        end
-    end
 
-    # makes a Connection to a given target and sends our raw data to it
-    # see yourself what options are needed :>
-    class Connection
-        def initialize(args)
-            @type = args[:type]
-            @host = args[:host]
-            @port = args[:port]
-            @path = args[:path]
-            @http_direction = args[:http_direction]
-            @http_url       = args[:http_url]
-            @observer       = args[:observer]
-            @coremanager    = @observer.coremanager
-            args[:timeout] ? @timeout = args[:timeout] : @timeout = 0.2
-
-            Fuzz::LOGGER.level = Logger::INFO if !args[:debug]
-
-            @socket = connect
-        end
-
-        def send( data )
-            begin
-            case @type
-                when :http
-                    case @http_direction
-                        when :post
-                            @socket.post @http_url ,data
-                        when :get
-                            @socket.get @http_url, data 
-                    end
-                else
-                    @socket.write data
-            end
-            rescue Exception => exception
-                if @coremanager.new_corefile?
-                    puts "argument:\n%s \nkilled the application!" % data 
-                    puts "backtrace:"
-                    puts @coremanager.get_latest_backtrace
-                    puts "_"*40
-                    puts "registers:"
-                    puts @coremanager.get_latest_registers
-                    puts "writing POC"
-                end
-                Kernel::exit
-            end
-        end
-
-        def fuzz!(structs, join_character="", args={})
-            structs = [structs] if !structs.is_a? Array
-            structs.each_with_index do |struct, index|
-                Fuzz::LOGGER.info "[x] fuzzing struct %d of %d with %d permutations" % [index+1, structs.size, 0]
-  
-                Fuzz.fuzz(@observer, struct){|struct|
-                    data = struct.join( join_character )
-                    Fuzz::LOGGER.debug "sending data: %s" % data
-                    self.send data
-                    #assert(args[:assert] )
-                }
-            end
-            raise "finished all tests"
-        end
-
-        # receives data from the socket and tests it against a supplied array of strings, values 
-        def assert(reply = [])
-            begin
-                timeout(@timeout) do 
-                    reply_data = Regexp.new( @socket.readline().to_regexp )
-                    raise "ASSERTION %s FAILED\nreceived %s" % [ reply.join(","), reply_data] if !reply.find_all{|x| x=~ reply_data}
-                end
-            rescue Exception
-                Fuzz::LOGGER.debug "[!] Exception: %s" % $!
-            end
-        end
-
-        def close
-            @socket.close if @type != :http && @type != :tls
-        end
-private
-        def connect
-            begin
-                case @type
-                    when :tcp
-                        return TCPSocket.new(@host, @port)
-                    when :unix
-                        return UNIXSocket.open( @path )
-                    when :http
-                        return Net::HTTP.new(@host, @port)
-                    when :tls
-                        raise "not implemented yet"
-                end 
-            rescue Exception
-                Fuzz::LOGGER.info "[!] Exception: %s" % $!
-                exit 0
-            end         
-        end        
+        Fuzz::fuzz(coremanager, struct){|argument, coremanager|
+            argument = argument.join if argument.is_a?(Array)
+            system( application + " " + argument)
+            raise "core found" if coremanager.new_corefile?
+        }
     end
 
     begin
+        ###################################################
+        # TESTS SECTION 
+        ###################################################
+
         DEFAULT_TESTS = Tests.new
         # Tests for character fields aka strings
         DEFAULT_TESTS.register Fuzz::Test.new("char") {|arg, size|  arg     } # Return string
@@ -477,10 +116,6 @@
         DEFAULT_TESTS.register Fuzz::Test.new("unsigned") {|arg, size|  rand(5) } # return a small number 
         DEFAULT_TESTS.register Fuzz::Test.new("unsigned") {|arg, size|  2.power!(size) } # return biggest number 
 
-        DEBUG_TESTS = Tests.new
-        DEBUG_TESTS.register Fuzz::Test.new("char") {|arg, size|  arg     } # Return string
-        DEBUG_TESTS.register Fuzz::Test.new("char") {|arg, size|  ""      } # Return empty String 
-
         # debugging output
         LOGGER = Logger.new(STDOUT)
         LOGGER.level = Logger::DEBUG

Modified: topf/trunk/tor-control-fuzz.rb
===================================================================
--- topf/trunk/tor-control-fuzz.rb	2007-08-27 15:38:17 UTC (rev 11288)
+++ topf/trunk/tor-control-fuzz.rb	2007-08-27 16:54:30 UTC (rev 11289)
@@ -61,7 +61,6 @@
                                    :assert => TOPF::Control::SETCONF_REPLYS } )
     
 rescue Exception => error
-    #Fuzz::LOGGER.info "[x] %s\n%s\nclosing everything down" % [ $!, error.backtrace.join("\n") ]
     Fuzz::LOGGER.info "[x] closing everything down" 
     fuzzer.close if fuzzer
     observer.exit if observer and started

Modified: topf/trunk/tor-dir-fuzz.rb
===================================================================
--- topf/trunk/tor-dir-fuzz.rb	2007-08-27 15:38:17 UTC (rev 11288)
+++ topf/trunk/tor-dir-fuzz.rb	2007-08-27 16:54:30 UTC (rev 11289)
@@ -16,7 +16,8 @@
         :http_direction => :post,
         :http_url       => "/tor/",
         :debug => config["DEBUG"],
-        :observer => observer
+        :observer => observer,
+        :timeout => 0.01
     }
 
     osslkey = OpenSSL::PKey::RSA.new(1024)

Added: topf/trunk/utils/set_core_pattern
===================================================================
--- topf/trunk/utils/set_core_pattern	                        (rev 0)
+++ topf/trunk/utils/set_core_pattern	2007-08-27 16:54:30 UTC (rev 11289)
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+echo "$PWD/../core/core" > /proc/sys/kernel/core_pattern


Property changes on: topf/trunk/utils/set_core_pattern
___________________________________________________________________
Name: svn:executable
   + *



More information about the tor-commits mailing list