[or-cvs] r11044: fixed permutation bugs and added new general and control stu (in topf/trunk: . lib lib/fuzz-struct)
benedikt at seul.org
benedikt at seul.org
Sat Aug 4 11:54:44 UTC 2007
Author: benedikt
Date: 2007-08-04 07:54:43 -0400 (Sat, 04 Aug 2007)
New Revision: 11044
Added:
topf/trunk/LICENSE
topf/trunk/lib/state_pattern.rb
Removed:
topf/trunk/control.rb
topf/trunk/lib/fuzz-test.rb
Modified:
topf/trunk/TODO
topf/trunk/config.yml
topf/trunk/lib/control.rb
topf/trunk/lib/dir.rb
topf/trunk/lib/fuzz-generic.rb
topf/trunk/lib/fuzz-struct/fuzz-struct.rb
topf/trunk/lib/fuzz.rb
topf/trunk/lib/topf.rb
topf/trunk/tor-control-fuzz.rb
topf/trunk/tor-dir-fuzz.rb
Log:
fixed permutation bugs and added new general and control stuff
Added: topf/trunk/LICENSE
===================================================================
--- topf/trunk/LICENSE (rev 0)
+++ topf/trunk/LICENSE 2007-08-04 11:54:43 UTC (rev 11044)
@@ -0,0 +1,49 @@
+ This file contains the license for Tor,
+ a free software project to provide anonymity on the Internet.
+
+ It also lists the licenses for other components used by Tor.
+
+ For more information about Tor, see http://www.torproject.org/.
+
+ If you got this file as a part of a larger bundle,
+ there may be other license terms that you should be aware of.
+
+
+===============================================================================
+Tor is distributed under this license:
+
+Copyright (c) 2001-2004, Roger Dingledine
+Copyright (c) 2004-2007, Roger Dingledine, Nick Mathewson
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+
+ * Neither the names of the copyright owners nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+===============================================================================
+If you got Tor as a static binary with OpenSSL included, then you should know:
+ "This product includes software developed by the OpenSSL Project
+ for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+===============================================================================
Modified: topf/trunk/TODO
===================================================================
--- topf/trunk/TODO 2007-08-03 07:57:41 UTC (rev 11043)
+++ topf/trunk/TODO 2007-08-04 11:54:43 UTC (rev 11044)
@@ -1,7 +1,9 @@
+- FIX BitStruct Rest-Field problem
+
- Fix pkcs1 signature
- add more tests
- implement other tor protocols
-- calculate all possible permutations instead of random probing
+- calculate all possible permutations instead of random probing => DONE
- implement fancy web frontend
- easy to install and setup testing network
- distributed testing
Modified: topf/trunk/config.yml
===================================================================
--- topf/trunk/config.yml 2007-08-03 07:57:41 UTC (rev 11043)
+++ topf/trunk/config.yml 2007-08-04 11:54:43 UTC (rev 11044)
@@ -1,3 +1,8 @@
+
+############################################################
+# This file holds information about our running tor-service
+############################################################
+
DIRPORT: "2324"
CONTROLPORT: "2323"
HOST: "127.0.0.1"
@@ -2 +7,2 @@
KEYFILE: stuff/fuzz-private.pem
+DEBUG: true
Deleted: topf/trunk/control.rb
===================================================================
Modified: topf/trunk/lib/control.rb
===================================================================
--- topf/trunk/lib/control.rb 2007-08-03 07:57:41 UTC (rev 11043)
+++ topf/trunk/lib/control.rb 2007-08-04 11:54:43 UTC (rev 11044)
@@ -1,8 +1,96 @@
module TOPF
module Control
- class ConfItem < BitStruct
- text :item, 7
- text :keyword, 10
+ class ItemFuzz
+ attr_reader :item
+ def initialize(item, fields, values)
+ raise "item is not a BitStruct" if !item.is_a?(BitStruct)
+ @item = item
+ @fields = fields
+ @values = values
+ @count = 0
+ end
+
+ def set_next
+ @fields.each_with_index do |field, index|
+ method = field.to_s + "="
+ value = @values[@count][index]
+ raise "item has no method #{field}" if !@item.methods.include?(method)
+ @item.send(method, value )
+ end
+ @count += 1
+ end
+
+ def prepare!
+ @item.prepare!
+ end
+
+ def fuzz!
+ @item.fuzz!
+ end
+
+ end
+
+ SETCONF_KEYS = [
+ [ "version", "Tor 0.0.9.4" ],
+ [ "config-file", "PATH TO CONFIFILE" ],
+ [ "exit-policy/prepend", "NOT IMPLEMENTED"],
+ [ "exit-policy/default", ""],
+ [ "desc/id/", "or identity" ],
+ [ "desc/name", "or nickname" ],
+ [ "exit-policy/default", "" ],
+ [ "ns/id/", "or identity"],
+ [ "ns/name/", "or nickname" ],
+ [ "ns/all", "" ],
+ [ "desc/all-recent", "" ],
+ [ "network-status", "" ],
+ [ "address-mappings/all", "" ],
+ [ "address-mappings/config", "" ],
+ [ "address-mappings/cache", "" ],
+ [ "address-mappings/control", "" ]
+ [ "addr-mappings/*", "" ]
+ [ "address", "127.0.0.1" ]
+ [ "fingerprint", "contents of fingerprint file" ]
+ [ "circuit-status", "" ]
+=begin
+ A series of lines as for a circuit status event. Each line is of
+ the form:
+ CircuitID SP CircStatus [SP Path] CRLF
+
+ "stream-status"
+ A series of lines as for a stream status event. Each is of the form:
+ StreamID SP StreamStatus SP CircID SP Target CRLF
+
+ "orconn-status"
+ A series of lines as for an OR connection status event. Each is of the
+ form:
+ ServerID SP ORStatus CRLF
+
+ "entry-guards"
+ A series of lines listing the currently chosen entry guards, if any.
+ Each is of the form:
+ ServerID SP (Status-with-time / Status) CRLF
+
+ Status-with-time = ("down" / "unlisted") SP ISOTime
+ Status = ("up" / "never-connected")
+
+ [From 0.1.1.4-alpha to 0.1.1.10-alpha, this was called "helper-nodes".
+ Tor still supports calling it that for now, but support will be
+ removed in 0.1.3.x.]
+
+ "accounting/enabled"
+ "accounting/hibernating"
+ "accounting/bytes"
+ "accounting/bytes-left"
+ "accounting/interval-start"
+ "accounting/interval-wake"
+ "accounting/interval-end"
+
+=end
+ ]
+
+ class SetConfItem < BitStruct
+ text :item, 7, :fuzzable => true
+ text :keyword, 30, :fuzzable => false
text :assign, 1
rest :value
@@ -10,6 +98,13 @@
initial_value.assign = "="
end
+ SETCONF_REPLYS = [
+ "250 configuration values set",
+ "552 Unrecognized option",
+ "513 syntax error in configuration values",
+ "553 impossible configuration setting"
+ ]
+
class ResetConfItem < BitStruct
text :item, 9
text :keyword, 10
@@ -30,12 +125,95 @@
initial_value.assign = "="
end
+ SETEVENTS_REPLYS = [
+ "250 OK",
+ "552 Unrecognized event"
+ ]
+
+ SETEVENTS_CODES = [
+ "CIRC",
+ "STREAM",
+ "ORCONN",
+ "BW",
+ "DEBUG",
+ "INFO",
+ "NOTICE",
+ "WARN",
+ "ERR",
+ "NEWDESC",
+ "ADDRMAP",
+ "AUTHDIR_NEWDESCS",
+ "DESCCHANGED",
+ "STATUS_GENERAL",
+ "STATUS_CLIENT",
+ "STATUS_SERVER",
+ "GUARD",
+ "NS",
+ "STREAM_BW"
+ ]
+
+ class SetEventsItem < BitStruct
+ text :item, 9
+ text :extended, 8
+
+ rest :events
+
+ initial_value.item = "SETEVENTS"
+ initial_value.extended = " "*8
+ end
+
+ AUTHENTICATE_REPLYS = [
+ "250 OK",
+ "515 Bad authentication",
+ "514 authentication required"
+ ]
+
class AuthenticateItem < BitStruct
- text :item, 12
+ text :item, 13
+ text :password, 8
rest :crlf
- initial_value.item = "AUTHENTICATE"
- initial_value.crlf = "\n"
+ initial_value.item = "AUTHENTICATE "
+ initial_value.password = "\"foobar\""
+ initial_value.crlf = " \r\n"
end
+
+ SAVECONF_REPLYS = [
+ "250 OK",
+ "551 Unable to write configuration to disk"
+ ]
+
+ class SaveConfItem < BitStruct
+ text :item, 8
+ initial_value.item = "SAVECONF"
+ end
+
+ SIGNAL_ITEMS = [
+ "RELOAD",
+ "SHUTDOWN",
+ "DUMP",
+ "DEBUG",
+ "HALT",
+ "HUP",
+ "INT",
+ "USR1",
+ "USR2",
+ "TERM",
+ "NEWNYM",
+ "CLEARDNSCACHE"
+ ]
+
+ class SignalItem < BitStruct
+ text :item, 6
+ rest :signal
+
+ initial_value.item = "SIGNAL"
+ end
+
+ class Collection < Fuzz::Collection
+ end
+ begin
+ COLLECTION = Collection.new
+ end
end
end
Modified: topf/trunk/lib/dir.rb
===================================================================
--- topf/trunk/lib/dir.rb 2007-08-03 07:57:41 UTC (rev 11043)
+++ topf/trunk/lib/dir.rb 2007-08-04 11:54:43 UTC (rev 11044)
@@ -138,7 +138,7 @@
end
class RouterDescriptor
- def initialize(publicKey, host = "127.0.0.1", port = 80)
+ def initialize(publicKey)
@osslkey = OpenSSL::PKey::RSA.new(File.read(publicKey) )
@pkcs1 = PKCS1::SignatureScheme::RSASSAPKCS1v1_5.new(Digest::SHA1)
@@ -150,21 +150,26 @@
SigningKeyItem.new,
BandwidthItem.new,
]
-
- @host = host
- @port = port
-
- connect!
+ @prepared = false
end
- def connect!
- end
-
def add_item( item )
@items.push item
end
+ def prepare_for_test
+ @items.each do |item|
+ Fuzz::DEFAULT_TESTS.set_struct item
+ Fuzz::DEFAULT_TESTS.generate_test_data
+ end
+ end
+
def fuzz!
+ if !@prepared
+ prepare_for_test
+ @prepared = true
+ end
+
@items.each do |item|
item.fuzz!
end
@@ -185,4 +190,3 @@
end
end
end
-
Modified: topf/trunk/lib/fuzz-generic.rb
===================================================================
--- topf/trunk/lib/fuzz-generic.rb 2007-08-03 07:57:41 UTC (rev 11043)
+++ topf/trunk/lib/fuzz-generic.rb 2007-08-04 11:54:43 UTC (rev 11044)
@@ -2,5 +2,7 @@
$:.unshift(File.dirname(dir)) unless
$:.include?(File.dirname(dir)) || $:.include?(File.expand_path(File.dirname(dir)))
+require "timeout"
require "fuzz-struct"
require "fuzz"
+require "logger"
Modified: topf/trunk/lib/fuzz-struct/fuzz-struct.rb
===================================================================
--- topf/trunk/lib/fuzz-struct/fuzz-struct.rb 2007-08-03 07:57:41 UTC (rev 11043)
+++ topf/trunk/lib/fuzz-struct/fuzz-struct.rb 2007-08-04 11:54:43 UTC (rev 11044)
@@ -145,7 +145,7 @@
#
# ------------------------
- # Return the list of fields for this class.
+ # Return the list of fields for this class including the rest field.
def fields
@fields ||= self == BitStruct ? [] : superclass.fields.dup
end
@@ -228,7 +228,8 @@
# Length, in bits, of this object.
def bit_length
- @bit_length ||= fields.inject(0) {|a, f| a + f.length}
+ @bit_length ||= fields.inject(0) {|a, f|
+ a + f.length}
end
# Length, in bytes (rounded up), of this object.
@@ -252,9 +253,9 @@
end
- # Return the list of fields for this class.
+ # Return the list of fields(including the rest field) for this class.
def fields
- self.class.fields
+ [ self.class.fields, self.class.rest_field].flatten
end
# Return the field with the given name.
@@ -350,7 +351,14 @@
self.class.closed!
yield self if block_given?
-
+
+ # this is where our test_data goes
+ @tests = nil
+ # this is where we save our permutation indeces
+ @permutations
+ @permutation_index = 0
+ # dimension of our permutation
+ @dimension = 0
end
DEFAULT_TO_H_OPTS = {
@@ -483,18 +491,89 @@
opts[:format] % [self.class, body]
end
+ def prepare!(tests)
+ # build our testdata...
+ raise "argument must be of class Tests" if !tests.is_a?(Fuzz::Tests)
+ result = []
+ self.fields.each do |field|
+ arg = self.method(field.name).call
+ if field.fuzzable
+ temp = []
+ length = field.length
+ case field.class.to_s
+ when "BitStruct::SignedField"
+ tests.signed_tests.each do |test|
+ temp.push( test.run(arg, length) )
+ end
+ result.push(temp)
+ when "BitStruct::UnsignedField"
+ tests.unsigned_tests.each do |test|
+ temp.push( test.run(arg, length) )
+ end
+ result.push(temp)
+ when "BitStruct::TextField", "BitStruct::CharField", "BitStruct::Field"
+ tests.char_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
+ else
+ result.push( [ arg ] )
+ end
+ end
+ @tests = result
+
+ # build our permutations...
+ sizes = @tests.collect {|element| element.size}
+
+ @dimension = sizes.inject(1){|prod, element| prod*element }
+
+ permutations = Array.new(sizes.size, Array.new(@dimension, 0) )
+
+ result = []
+ permutations.each_with_index do |element, index|
+ count = 0
+ temp = 0
+
+ tempdimension = sizes[(index+1)..-1].inject(1){|prod, el| prod*el}-1
+ result.push element.collect{|entry|
+ if count == tempdimension
+ temp+= 1
+ temp = 0 if temp == (sizes[index])
+ count = -1
+ end
+ count+=1
+ temp
+ }
+ end
+
+ Fuzz::LOGGER.debug "[x] calculated %d permutations of struct %s" % [result.first.size, self.class]
+ @permutations = result
+=begin
+# debugging stuff
+ @permutations[0].each_with_index do |element, index|
+ pp @permutations.collect{|el| el[index] }
+ end
+=end
+ @permutation_index = 0
+ end
+
def fuzz!(opts = DEFAULT_INSPECT_OPTS)
- field_format = opts[:field_format]
- field_name_meth = opts[:field_name_meth]
-
- fields_for_inspect = fields.select {|field| field.inspectable?}
- if opts[:include_rest] and (rest_field = self.class.rest_field)
- fields_for_inspect << rest_field
- end
-
- fields_for_inspect.map do |field|
- field.fuzz(self, opts)
- end
+ raise "no tests have been generated yet" if !@permutations or !@tests
+ raise "end of tests" if @permutation_index.to_i == @dimension.to_i
+ test = []
+ perm = @permutations.collect{|element| element[@permutation_index] }
+ @permutation_index += 1
+
+ tempcount = 0
+ ret = @tests.collect{ |element|
+ result = element[ perm[tempcount] ]
+ tempcount+=1
+ result
+ }
+ ret
end
def format(opts = DEFAULT_INSPECT_OPTS)
Deleted: topf/trunk/lib/fuzz-test.rb
===================================================================
--- topf/trunk/lib/fuzz-test.rb 2007-08-03 07:57:41 UTC (rev 11043)
+++ topf/trunk/lib/fuzz-test.rb 2007-08-04 11:54:43 UTC (rev 11044)
@@ -1,17 +0,0 @@
-# This file includes a default test-case object
-#
-# test template
-# default_tests.register Fuzz::Test.new("") {|arg| }
-
-default_tests = Tests.new
-# Tests for character fields aka strings
-default_tests.register Fuzz::Test.new("char") {|arg, size| arg } # Return string
-default_tests.register Fuzz::Test.new("char") {|arg, size| "" } # Return empty String
-default_tests.register Fuzz::Test.new("char") {|arg, size| "A"*Fuzz::MAX_RAND } # LONG STRING
-default_tests.register Fuzz::Test.new("char") {|arg, size| "%n"*Fuzz::MAX_RAND } # FORMAT STRING
-
-# Tests for signed numbers
-default_tests.register Fuzz::Test.new("signed") {|arg, size| rand(5) } # return a small number
-default_tests.register Fuzz::Test.new("signed") {|arg, size| -1 } # return -1
-default_tests.register Fuzz::Test.new("signed") {|arg, size| (2.power!(size)/2)-1 } # biggest 2s complement number
-default_tests.register Fuzz::Test.new("signed") {|arg, size| -(2.power!(size)/2) } # smallest 2s complement number
Modified: topf/trunk/lib/fuzz.rb
===================================================================
--- topf/trunk/lib/fuzz.rb 2007-08-03 07:57:41 UTC (rev 11043)
+++ topf/trunk/lib/fuzz.rb 2007-08-04 11:54:43 UTC (rev 11044)
@@ -1,11 +1,64 @@
module Fuzz
MAX_RAND = 1000
- MAX_STRING_PERMUTATIONS = 3
+ class Collection
+ def initialize
+ @structs = []
+ end
+ def add(struct)
+ raise "argument must be a Fuzz::Test object" if !struct.is_a?(BitStruct)
+ @structs.push struct
+ end
+ # fuzzes only one struct at the time
+ def linear_fuzz
+ @structs.each do |struct|
+
+ end
+ end
+ # joins all structs together but only fuzzes one struct after another
+ def join_fuzz
+ end
+ end
+
+ class Observer
+ def initialize
+ end
+ end
+
+ class BinaryObserver < Observer
+ def initialize( programname, *arguments )
+ @programname = programname
+ @arguments = arguments.to_a
+ @pid = nil
+ end
+ def observe!
+ Process.fork do
+ @pid = Process.fork do
+ exec("#{@programname} #{@arguments.join(" ")} ")
+ end
+ Process.wait
+ process_status = $?
+ # 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?
+ end
+ end
+ def get_pid
+ @pid
+ end
+ def exit
+ Process.kill "KILL", @pid
+ end
+ end
+
+ class ProcessObserver < Observer
+ end
+
# This Class holds all tests to related to a given field-type
class Tests
- attr_reader :tests, :permutations
- def initialize(struct)
+ attr_reader :tests, :permutations, :signed_tests, :char_tests, :unsigned_tests
+ def initialize(struct=nil)
@char_tests = []
@unsigned_tests = []
@signed_tests = []
@@ -14,7 +67,10 @@
@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
@@ -28,14 +84,20 @@
@octet_tests.push test
end
end
- def generate_test
- generate_test_data
+
+ # 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
- def get_test
+ # 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
@@ -45,10 +107,26 @@
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
+ def generate_test_data!
result = []
raise "argument must be a BitStruct object" if !@struct.is_a?(BitStruct)
@struct.fields.each do |field|
@@ -71,20 +149,23 @@
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
+
+ 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) )
+ @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 = 1
+ temp = 0
tempdimension = sizes[(index+1)..-1].inject(1){|prod, el| prod*el}
result.push element.collect{|entry|
if count == tempdimension
@@ -97,9 +178,9 @@
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
@@ -125,93 +206,7 @@
@test.call arg, size
end
end
- # sample test-case
- # Fuzz::Test.new("char") {|arg| arg.insert( rand(arg.size), "A"*rand(1024) ) }
-
- def Fuzz.fuzzField(type, length, value)
- case type.to_s
- when "BitStruct::CharField"
- return Fuzz::fuzzString(value, length )
- when "BitStruct::UnsignedField"
- return Fuzz::fuzzUnsignedNumber(length.to_i)
- when "BitStruct::SignedField"
- return Fuzz::fuzzSignedNumber(length.to_i)
- when "BitStruct::OctetField"
- return value.split(".").collect{ |octet| Fuzz::fuzzString(octet, 2) }.join( "." )
- else
- if value.class.to_s == "String"
- return Fuzz::fuzzString(value, length/8 )
- else
- return value
- end
- end
- end
-
- def Fuzz.fuzzString(string, length)
- if Fuzz::MAX_STRING_PERMUTATIONS > 0
- rand( Fuzz::MAX_STRING_PERMUTATIONS ).times do |i|
- case rand(5)
- when 0
- string.insert( rand(string.size), "A"*rand( length ))
- when 1
- string.insert( rand(string.size), "%n"*rand( length ))
- when 2
- string.insert( rand(string.size), Fuzz::randCharacter( string[rand(string.size)] )*rand( length ))
- when 3
- rand(5) == 0 ? string = "" : nil
- end
- end
- end
- string.gsub(/\\+/, "\\")
- end
-
- def Fuzz.randCharacter(default)
- case rand(9)
- when 0
- return '\0'
- when 1
- return 0x0.chr
- when 2
- return ']'
- when 3
- return ')'
- when 4
- return '}'
- when 5
- return '>'
- when 6
- return '\n'
- when 7
- return '\''
- when 8
- return '\"'
- else
- return default
- end
- end
-
- def Fuzz.fuzzSignedNumber(bits)
- case rand(3)
- when 0
- rand(5).to_i # small numbers
- when 1
- return -1.to_i
- when 2
- return (2.power!(bits)-1)/2 #biggest 2s complement number
- when 3
- return -(2.power!(bits))/2 #smallest 2s complement number
- end
- end
-
- def Fuzz.fuzzUnsignedNumber(bits)
- case rand(1)
- when 0
- rand(5).to_i # small numbers
- when 1
- return 2.power!(bits)-1 #biggest number
- end
- end
-
+
def Fuzz.coreObserver(file)
if Dir.new(File.expand_path(File.dirname(file)) ).entries.select{|x| x=~/\.core/}.size != 0
return true
@@ -222,7 +217,7 @@
# makes a Connection to a given target and sends our raw data to it
# see yourself what options are needed :>
- class Host
+ class Connection
def initialize(args)
@type = args[:type]
@host = args[:host]
@@ -231,14 +226,13 @@
@http_direction = args[:http_direction]
@http_url = args[:http_url]
@object = args[:object]
+ args[:timeout] ? @timeout = args[:timeout] : @timeout = 0.2
- @socket = connect
+ Fuzz::LOGGER.level = Logger::INFO if !args[:debug]
+
+ @socket = connect
end
- def fuzz
- send @object.to_s
- end
-
def send( data )
case @type
when :http
@@ -252,8 +246,34 @@
@socket.write data
end
end
-
- def stop
+
+ def fuzz!(struct, join_character="", args={})
+ begin
+ while true
+ data = struct.fuzz!.join( join_character )
+ Fuzz::LOGGER.debug "sending data: %s" % data
+ self.send data
+ assert(args[:assert] )
+ end
+ rescue Exception
+ puts "[!] ERROR: %s" % $!
+ end
+ 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 = @socket.readline()
+ raise "ASSERTION %s FAILED" % reply.join(",") if !reply.include?(reply_data.strip)
+ Fuzz::LOGGER.debug "reply: %s" % reply_data
+ end
+ rescue Exception
+ Fuzz::LOGGER.debug "[!] Exception: %s" % $!
+ end
+ end
+
+ def close
@socket.close
end
private
@@ -270,13 +290,39 @@
raise "not implemented yet"
end
rescue Exception
- puts "Exception: " + $!
- raise
+ Fuzz::LOGGER.debug "[!] Exception: %s" % $!
+ exit 0
end
end
+ end
+
+ begin
+ DEFAULT_TESTS = Tests.new
+ # Tests for character fields aka strings
+ DEFAULT_TESTS.register Fuzz::Test.new("char") {|arg, size| arg } # Return string
+ DEFAULT_TESTS.register Fuzz::Test.new("char") {|arg, size| "" } # Return empty String
+ DEFAULT_TESTS.register Fuzz::Test.new("char") {|arg, size| "A"*arg.size } # FAULTING ARGUMENT STRING
+ DEFAULT_TESTS.register Fuzz::Test.new("char") {|arg, size| "A"*Fuzz::MAX_RAND } # LONG STRING
+ DEFAULT_TESTS.register Fuzz::Test.new("char") {|arg, size| "%n"*Fuzz::MAX_RAND } # FORMAT STRING
+
+ # Tests for signed numbers
+ DEFAULT_TESTS.register Fuzz::Test.new("signed") {|arg, size| 0 } # return zero
+ DEFAULT_TESTS.register Fuzz::Test.new("signed") {|arg, size| rand(5) } # return a small number
+ DEFAULT_TESTS.register Fuzz::Test.new("signed") {|arg, size| -1 } # return -1
+ DEFAULT_TESTS.register Fuzz::Test.new("signed") {|arg, size| (2.power!(size)/2)-1 } # biggest 2s complement number
+ DEFAULT_TESTS.register Fuzz::Test.new("signed") {|arg, size| -(2.power!(size)/2) } # smallest 2s complement number
+
+ # Tests for unsigned numbers
+ DEFAULT_TESTS.register Fuzz::Test.new("unsigned") {|arg, size| 0 } # return zero
+ 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!(bits) } # 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
end
end
-
-begin
-
-end
Added: topf/trunk/lib/state_pattern.rb
===================================================================
--- topf/trunk/lib/state_pattern.rb (rev 0)
+++ topf/trunk/lib/state_pattern.rb 2007-08-04 11:54:43 UTC (rev 11044)
@@ -0,0 +1,110 @@
+#! /usr/bin/ruby
+
+# Copyright (C) 2006 Maurice Codik - maurice.codik at gmail.com
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+# associated documentation files (the "Software"), to deal in the Software without restriction,
+# including without limitation the rights to use, copy, modify, merge, publish, distribute,
+# sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all copies or substantial
+# portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
+# LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+
+# an example:
+#
+# class Connection
+# include StatePattern
+# state :initial do # you always need a state named initial. this is where you begin.
+# def connect
+# puts "connected"
+# # move to state :connected. all other args to transition_to are passed to the new state's constructor
+# transition_to :connected, "hello from initial state"
+# end
+# def disconnect
+# puts "not connected yet"
+# end
+# end
+# state :connected do
+# def initialize(msg)
+# puts "initialize got msg: #{msg}"
+# end
+# def connect
+# puts "already connected"
+# end
+# def disconnect
+# puts "disconnecting"
+# transition_to :initial
+# end
+# end
+# def reset
+# puts "reseting outside a state"
+# # you can also change the state from outside of the state objects
+# transition_to :initial
+# end
+# end
+
+# how's it work:
+# Each call to state defines a new subclass of Connection that is stored in a hash.
+# Then, a call to transition_to instantiates one of these subclasses and sets it to the be the active state.
+# Method calls to Connection are delegated to the active state object via method_missing.
+
+module StatePattern
+ class UnknownStateException < Exception
+ end
+
+ def StatePattern.included(mod)
+ mod.extend StatePattern::ClassMethods
+ end
+
+ module ClassMethods
+ attr_reader :state_classes
+ def state(state_name, &block)
+ @state_classes ||= {}
+
+ new_klass = Class.new(self, &block)
+ new_klass.class_eval do
+ alias_method :__old_init, :initialize
+ def initialize(context, *args, &block)
+ @context = context
+ __old_init(*args, &block)
+ end
+ end
+
+ @state_classes[state_name] = new_klass
+ end
+ end
+
+ attr_accessor :current_state, :current_state_obj
+
+ def transition_to(state_name, *args, &block)
+ new_context = @context || self
+
+ klass = new_context.class.state_classes[state_name]
+ if klass
+ new_context.current_state = state_name
+ new_context.current_state_obj = klass.new(new_context, *args, &block)
+ else
+ raise UnknownStateException, "tried to transition to unknown state, #{state_name}"
+ end
+ end
+
+ def method_missing(method, *args, &block)
+ unless @current_state_obj
+ transition_to :initial
+ end
+ if @current_state_obj
+ @current_state_obj.send(method, *args, &block)
+ else
+ super
+ end
+ end
+
+end
Modified: topf/trunk/lib/topf.rb
===================================================================
--- topf/trunk/lib/topf.rb 2007-08-03 07:57:41 UTC (rev 11043)
+++ topf/trunk/lib/topf.rb 2007-08-04 11:54:43 UTC (rev 11044)
@@ -2,9 +2,15 @@
$:.unshift(File.dirname(dir)) unless
$:.include?(File.dirname(dir)) || $:.include?(File.expand_path(File.dirname(dir)))
+require "pkcs1"
+require "base64"
+require "logger"
+require "yaml"
+require "net/http"
+require "timeout"
+
require "fuzz-struct"
require "fuzz"
-require "pkcs1"
-require "base64"
+
require "dir"
require "control"
Modified: topf/trunk/tor-control-fuzz.rb
===================================================================
--- topf/trunk/tor-control-fuzz.rb 2007-08-03 07:57:41 UTC (rev 11043)
+++ topf/trunk/tor-control-fuzz.rb 2007-08-04 11:54:43 UTC (rev 11044)
@@ -1,24 +1,50 @@
require "lib/topf"
-require "net/http"
-require "base64"
-require "yaml"
+begin
+ Fuzz::LOGGER.debug "[x] starting tor"
+ observer = Fuzz::BinaryObserver.new "tor", "-f torrc", "&> /dev/null"
+ observer.observe!
+
+ Fuzz::LOGGER.debug "[x] tor pid: %d" % observer.get_pid
+ sleep 1
+
+ Fuzz::LOGGER.debug "[x] loading options"
-begin
config = YAML::load_file "config.yml"
- setconf = TOPF::Control::ConfItem.new
- setconf.keyword = "blah"
- setconf.value = "test"
-
options = {
- :object => setconf,
:host => config["HOST"],
:port => config["CONTROLPORT"],
- :type => :tcp
+ :type => :tcp,
+ :debug => true
}
- fuzzer = Fuzz::Host.new( options )
- fuzzer.send TOPF::Control::AuthenticateItem.new
- fuzzer.fuzz
+ Fuzz::LOGGER.debug "[x] connecting to control port"
+ fuzzer = Fuzz::Connection.new( options )
+
+ Fuzz::LOGGER.debug "[x] sending authentication"
+ auth = TOPF::Control::AuthenticateItem.new
+
+ fuzzer.send auth
+ fuzzer.assert ["250 OK"]
+
+ setconf = TOPF::Control::SetConfItem.new
+
+ setconf.keyword = "blah"
+ setconf.value = "test"
+ setconf.prepare! Fuzz::DEBUG_TESTS
+
+ Fuzz::LOGGER.debug "[x] start fuzzing #{setconf.class}"
+
+ fuzzer.fuzz! setconf, " ", { :append => "\r\n",
+ :assert => TOPF::Control::SETCONF_REPLYS }
+ fuzzer.close
+
+ observer.exit
+rescue Exception => blah
+ Fuzz::LOGGER.debug "[!] ERROR: %s" % $!
+ Fuzz::LOGGER.debug "[!] \n%s" % blah.backtrace.join("\n")
+ Fuzz::LOGGER.debug "[!] closing everything down"
+ fuzzer.close if fuzzer
+ observer.exit if observer
end
Modified: topf/trunk/tor-dir-fuzz.rb
===================================================================
--- topf/trunk/tor-dir-fuzz.rb 2007-08-03 07:57:41 UTC (rev 11043)
+++ topf/trunk/tor-dir-fuzz.rb 2007-08-04 11:54:43 UTC (rev 11044)
@@ -1,13 +1,9 @@
require "lib/topf"
-require "net/http"
-require "base64"
-require "yaml"
-
begin
config = YAML::load_file "config.yml"
- rd = TOPF::Dir::RouterDescriptor.new( config["KEYFILE"], config["HOST"], config["PORT"] )
+ rd = TOPF::Dir::RouterDescriptor.new( config["KEYFILE"])
options = {
:object => rd,
@@ -15,10 +11,11 @@
:port => config["DIRPORT"],
:type => :http,
:http_direction => :post,
- :http_url => "/tor/"
+ :http_url => "/tor/",
+ :debug => config["DEBUG"]
}
- fuzzer = Fuzz::Host.new( options )
- fuzzer.fuzz
+ fuzzer = Fuzz::Host.new( options )
+ fuzzer.fuzz!
fuzzer.stop
end
More information about the tor-commits
mailing list