emonti-buby 1.1.3.1 → 1.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +11 -0
- data/README.rdoc +12 -15
- data/bin/buby +55 -0
- data/buby.gemspec +3 -3
- data/lib/buby/extends/buby_array_wrapper.rb +41 -0
- data/lib/buby/extends/http_request_response.rb +95 -0
- data/lib/buby/extends/scan_issue.rb +36 -0
- data/lib/buby/extends.rb +4 -0
- data/lib/buby.rb +33 -31
- data/samples/drb_buby.rb +31 -0
- data/samples/drb_sample_cli.rb +14 -0
- data/samples/mechanize_burp.rb +17 -25
- data/samples/verb_tamperer.rb +6 -2
- data/samples/watch_scan.rb +21 -0
- metadata +9 -2
data/History.txt
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
== 1.1.4 / 2009-09-14
|
2
|
+
* enhancements
|
3
|
+
* buby got implants! (har har)
|
4
|
+
* Ruby wrapper classes added for proxy_history, site_map, and scan_issues
|
5
|
+
* Extensions module for IHttpRequestResponse burp's class implementation
|
6
|
+
* Extensions module for IScanIssue burp's class implementation
|
7
|
+
* Added -s/--state, -r/--require, -e/--extend to buby cmd-line executable
|
8
|
+
* Added -v/--version buby cmd-line flag
|
9
|
+
* Modified samples for use as modules with -r/-e as well as run standalone
|
10
|
+
* Added drb client and server sample
|
11
|
+
|
1
12
|
== 1.1.3.1 / 2009-09-09
|
2
13
|
* fix
|
3
14
|
* fixed a typo in the String type-check for Buby.getParameters()
|
data/README.rdoc
CHANGED
@@ -34,8 +34,7 @@ The java BurpExtender included with Buby is an implementation of IBurpExtender w
|
|
34
34
|
The C version of ruby will not work.
|
35
35
|
|
36
36
|
* Burp (pro or free version): Buby is useless without a copy of Burp.
|
37
|
-
Buby has been tested successfully with
|
38
|
-
As of version 1.1.0, Buby supports both pre and post 1.2.09 Burp extensions.
|
37
|
+
Buby has been tested successfully with Burp 1.2.x.
|
39
38
|
|
40
39
|
|
41
40
|
== BUILD/INSTALL:
|
@@ -97,24 +96,22 @@ Your configuration details can be substituted below.
|
|
97
96
|
ln -s ~/tools/burp.jar ~/jruby-1.1.5/lib/ruby/1.8/java/burp.jar
|
98
97
|
|
99
98
|
Now everything should be ready to go. Try at least the first few parts of the
|
100
|
-
test below to confirm everything is set up.
|
101
|
-
run 'buby' from the command-line.
|
102
|
-
|
99
|
+
test below to confirm everything is set up.
|
103
100
|
|
104
101
|
== TEST AND USAGE EXAMPLE:
|
105
102
|
|
106
|
-
The gem includes a command-line
|
107
|
-
|
108
|
-
be launched from ruby and that Buby and Burp are connected.
|
109
|
-
|
110
|
-
Launch buby for simple testing and debugging with the 'buby' command-line tool:
|
103
|
+
The gem includes a command-line executable called 'buby'. You can use this to
|
104
|
+
test your Buby set-up and try out a few features.
|
111
105
|
|
112
106
|
$ buby -h
|
113
107
|
Usage: buby [options]
|
114
|
-
-i, --interactive
|
115
|
-
-d, --debug
|
116
|
-
-B, --load-burp=PATH
|
117
|
-
-
|
108
|
+
-i, --interactive Start IRB
|
109
|
+
-d, --debug Debug info
|
110
|
+
-B, --load-burp=PATH Load Burp Jar from PATH
|
111
|
+
-s, --state=FILE Restore burp state file on startup
|
112
|
+
-r, --require=LIB load a ruby lib (or jar) after Burp loads
|
113
|
+
-e, --extend=MOD Extend Buby with a module (loaded via -r?)
|
114
|
+
-h, --help Show this help message
|
118
115
|
|
119
116
|
$ buby -i -d
|
120
117
|
[:got_extender, #<Java::Default::BurpExtender:0x80 ...>]
|
@@ -157,7 +154,7 @@ test through a browser configured to use Burp as its proxy.
|
|
157
154
|
|
158
155
|
|
159
156
|
With $DEBUG = true, you should see the debugging output from Ruby as the proxy
|
160
|
-
passes your request back to your
|
157
|
+
passes your request back to your HTTP client/browser.
|
161
158
|
|
162
159
|
It will look something like the following in IRB:
|
163
160
|
|
data/bin/buby
CHANGED
@@ -21,6 +21,25 @@ begin
|
|
21
21
|
o.on("-B", "--load-burp=PATH", "Load Burp Jar from PATH") do |b|
|
22
22
|
args[:load_burp] = b
|
23
23
|
end
|
24
|
+
|
25
|
+
o.on('-s', '--state=FILE', "Restore burp state file on startup") do |r|
|
26
|
+
args[:restore] = r
|
27
|
+
end
|
28
|
+
|
29
|
+
o.on('-r', '--require=LIB',
|
30
|
+
'load a ruby lib (or jar) after Burp loads') do |i|
|
31
|
+
(args[:requires] ||= []).push(i)
|
32
|
+
end
|
33
|
+
|
34
|
+
o.on('-e', '--extend=MOD',
|
35
|
+
'Extend Buby with a module (loaded via -r?)') do |m|
|
36
|
+
(args[:extensions] ||= []).push(m)
|
37
|
+
end
|
38
|
+
|
39
|
+
o.on('-v', '--version', 'Prints version and exits.') do
|
40
|
+
puts "#{File.basename $0} v#{Buby::VERSION}"
|
41
|
+
exit 0
|
42
|
+
end
|
24
43
|
end
|
25
44
|
|
26
45
|
opts.parse!(ARGV)
|
@@ -28,7 +47,9 @@ begin
|
|
28
47
|
if jar=args[:load_burp]
|
29
48
|
raise "Load Burp Error: #{jar} did not provide burp.StartBurp" unless Buby.load_burp(jar)
|
30
49
|
end
|
50
|
+
|
31
51
|
raise "Load Burp Error: Specify a path to your burp.jar with -B" unless Buby.burp_loaded?
|
52
|
+
|
32
53
|
rescue
|
33
54
|
STDERR.puts $!
|
34
55
|
exit 1
|
@@ -38,6 +59,39 @@ $DEBUG=true if args[:debug]
|
|
38
59
|
|
39
60
|
$burp = Buby.start_burp()
|
40
61
|
|
62
|
+
if libs=args[:requires]
|
63
|
+
libs.each {|lib| STDERR.puts "Loading: #{lib.inspect}"; require(lib)}
|
64
|
+
end
|
65
|
+
|
66
|
+
def resolve_const(str)
|
67
|
+
raise "can't resolve empty name #{str.inspect}" if str.empty?
|
68
|
+
names = str.split('::')
|
69
|
+
obj = ::Object
|
70
|
+
names.each do |name|
|
71
|
+
raise "#{name.inspect} is not defined" unless obj.const_defined?(name)
|
72
|
+
obj = obj.const_get(name)
|
73
|
+
end
|
74
|
+
return obj if obj != ::Object
|
75
|
+
end
|
76
|
+
|
77
|
+
if mods=args[:extensions]
|
78
|
+
mods.each do |mod|
|
79
|
+
obj = resolve_const(mod)
|
80
|
+
raise "#{obj.name} is not a module" unless obj.kind_of? Module
|
81
|
+
STDERR.puts "Extending $burp with: #{obj.name}"
|
82
|
+
$burp.extend(obj)
|
83
|
+
if $burp.respond_to?(imeth=:"init_#{mod.split('::').last}")
|
84
|
+
$burp.__send__ imeth
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
if f=args[:restore]
|
90
|
+
raise "no such file #{f.inspect}" unless File.exists?(f)
|
91
|
+
STDERR.puts "Restoring burp state from: #{f.inspect}"
|
92
|
+
$burp.restore_state(f)
|
93
|
+
end
|
94
|
+
|
41
95
|
if args[:irb]
|
42
96
|
# yucky hack...
|
43
97
|
IRB.setup(nil)
|
@@ -51,3 +105,4 @@ if args[:irb]
|
|
51
105
|
" Important Note: You'll need to exit by closing the burp window."
|
52
106
|
IRB.start()
|
53
107
|
end
|
108
|
+
|
data/buby.gemspec
CHANGED
@@ -2,17 +2,17 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{buby}
|
5
|
-
s.version = "1.1.
|
5
|
+
s.version = "1.1.4"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Eric Monti - Matasano Security"]
|
9
|
-
s.date = %q{2009-
|
9
|
+
s.date = %q{2009-09-21}
|
10
10
|
s.default_executable = %q{buby}
|
11
11
|
s.description = %q{Buby is a mashup of JRuby with the popular commercial web security testing tool Burp Suite from PortSwigger. Burp is driven from and tied to JRuby with a Java extension using the BurpExtender API. This extension aims to add Ruby scriptability to Burp Suite with an interface comparable to the Burp's pure Java extension interface.}
|
12
12
|
s.email = %q{emonti@matasano.com}
|
13
13
|
s.executables = ["buby"]
|
14
14
|
s.extra_rdoc_files = ["History.txt", "README.rdoc", "bin/buby"]
|
15
|
-
s.files = ["History.txt", "README.rdoc", "Rakefile", "bin/buby", "buby.gemspec", "java/buby.jar", "java/src/BurpExtender.java", "java/src/burp/IBurpExtender.java", "java/src/burp/IBurpExtenderCallbacks.java", "java/src/burp/IHttpRequestResponse.java", "java/src/burp/IScanIssue.java", "java/src/burp/IScanQueueItem.java", "lib/buby.rb", "samples/mechanize_burp.rb", "samples/verb_tamperer.rb", "spec/buby_spec.rb", "spec/spec_helper.rb", "tasks/ann.rake", "tasks/bones.rake", "tasks/gem.rake", "tasks/git.rake", "tasks/notes.rake", "tasks/post_load.rake", "tasks/rdoc.rake", "tasks/rubyforge.rake", "tasks/setup.rb", "tasks/spec.rake", "tasks/svn.rake", "tasks/test.rake", "tasks/zentest.rake", "test/test_buby.rb"]
|
15
|
+
s.files = ["History.txt", "README.rdoc", "Rakefile", "bin/buby", "buby.gemspec", "java/buby.jar", "java/src/BurpExtender.java", "java/src/burp/IBurpExtender.java", "java/src/burp/IBurpExtenderCallbacks.java", "java/src/burp/IHttpRequestResponse.java", "java/src/burp/IScanIssue.java", "java/src/burp/IScanQueueItem.java", "lib/buby.rb", "lib/buby/extends.rb", "lib/buby/extends/buby_array_wrapper.rb", "lib/buby/extends/http_request_response.rb", "lib/buby/extends/scan_issue.rb", "samples/drb_buby.rb", "samples/drb_sample_cli.rb", "samples/mechanize_burp.rb", "samples/verb_tamperer.rb", "samples/watch_scan.rb", "spec/buby_spec.rb", "spec/spec_helper.rb", "tasks/ann.rake", "tasks/bones.rake", "tasks/gem.rake", "tasks/git.rake", "tasks/notes.rake", "tasks/post_load.rake", "tasks/rdoc.rake", "tasks/rubyforge.rake", "tasks/setup.rb", "tasks/spec.rake", "tasks/svn.rake", "tasks/test.rake", "tasks/zentest.rake", "test/test_buby.rb"]
|
16
16
|
s.homepage = %q{http://emonti.github.com/buby}
|
17
17
|
s.rdoc_options = ["--main", "README.rdoc"]
|
18
18
|
s.require_paths = ["lib", "java"]
|
@@ -0,0 +1,41 @@
|
|
1
|
+
|
2
|
+
class Buby
|
3
|
+
class BubyArrayWrapper
|
4
|
+
include Enumerable
|
5
|
+
|
6
|
+
attr_reader :array_obj
|
7
|
+
|
8
|
+
def initialize(obj)
|
9
|
+
@array_obj = obj
|
10
|
+
end
|
11
|
+
|
12
|
+
def [](*args)
|
13
|
+
if args.size == 1 and args.first.kind_of? Numeric
|
14
|
+
self.array_obj[args[0]]
|
15
|
+
else
|
16
|
+
self.to_a(*args)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def each
|
21
|
+
self.array_obj.size.times do |idx|
|
22
|
+
yield self.array_obj[idx]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def size
|
27
|
+
self.array_obj.size
|
28
|
+
end
|
29
|
+
alias length size
|
30
|
+
|
31
|
+
def first
|
32
|
+
return(self.array_obj[0]) if(self.size > 0)
|
33
|
+
end
|
34
|
+
|
35
|
+
def last
|
36
|
+
return self.array_obj[self.size - 1] if(self.size > 0)
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'uri'
|
2
|
+
|
3
|
+
class Buby
|
4
|
+
|
5
|
+
class HttpRequestResponseList < BubyArrayWrapper
|
6
|
+
def initialize(obj)
|
7
|
+
HttpRequestResponseHelper.implant(obj[0]) if obj.size > 0
|
8
|
+
super(obj)
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
module HttpRequestResponseHelper
|
15
|
+
|
16
|
+
# returns the response as a Ruby String object - returns an empty string
|
17
|
+
# if response is nil.
|
18
|
+
def response_str
|
19
|
+
return response().nil? ? "" : ::String.from_java_bytes(response())
|
20
|
+
end
|
21
|
+
alias response_string response_str
|
22
|
+
alias rsp_str response_str
|
23
|
+
|
24
|
+
|
25
|
+
# returns an array of response headers split into header name and value.
|
26
|
+
# For example:
|
27
|
+
# [
|
28
|
+
# ["HTTP/1.1 301 Moved Permanently"],
|
29
|
+
# ["Server", "Apache/1.3.41 ..."],
|
30
|
+
# ...
|
31
|
+
# ]
|
32
|
+
def response_headers
|
33
|
+
if headers=(@rsp_split ||= rsp_str.split(/\r?\n\r?\n/, 2))[0]
|
34
|
+
@rsp_headers ||= headers.split(/\r?\n/).map {|h| h.split(/\s*:\s*/,2)}
|
35
|
+
end
|
36
|
+
end
|
37
|
+
alias rsp_headers response_headers
|
38
|
+
|
39
|
+
# Returns the message body of the response, minus headers
|
40
|
+
def response_body
|
41
|
+
(@rsp_split ||= rsp_str.split(/\r?\n\r?\n/, 2))[1]
|
42
|
+
end
|
43
|
+
alias rsp_body response_body
|
44
|
+
|
45
|
+
|
46
|
+
# Returns the full request as a Ruby String - returns an empty string if
|
47
|
+
# request is nil.
|
48
|
+
def request_str
|
49
|
+
return request().nil? ? "" : ::String.from_java_bytes(request())
|
50
|
+
end
|
51
|
+
alias request_string request_str
|
52
|
+
alias req_str request_str
|
53
|
+
|
54
|
+
|
55
|
+
# Returns a split array of headers. Example:
|
56
|
+
# [
|
57
|
+
# ["GET / HTTP/1.1"],
|
58
|
+
# ["Host", "www.example.org"],
|
59
|
+
# ["User-Agent", "Mozilla/5.0 (..."],
|
60
|
+
# ...
|
61
|
+
# ]
|
62
|
+
def request_headers
|
63
|
+
if headers=(@req_split ||= req_str.split(/\r?\n\r?\n/, 2))[0]
|
64
|
+
@req_headers ||= headers.split(/\r?\n/).map {|h| h.split(/\s*:\s*/,2)}
|
65
|
+
end
|
66
|
+
end
|
67
|
+
alias req_headers request_headers
|
68
|
+
|
69
|
+
|
70
|
+
# Returns the request message body or an empty string if there is none.
|
71
|
+
def request_body
|
72
|
+
(@req_split ||= req_str.split(/\r?\n\r?\n/, 2))[1]
|
73
|
+
end
|
74
|
+
alias req_body request_body
|
75
|
+
|
76
|
+
|
77
|
+
# Returns a Ruby URI object derived from the java.net.URL object
|
78
|
+
def uri
|
79
|
+
@uri ||= URI.parse url.to_s if not url.nil?
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
# one-shot method to implant ourselves onto a target object's class
|
84
|
+
# interface in ruby. All later instances will also get 'us' for free!
|
85
|
+
def self.implant(base)
|
86
|
+
return if @implanted
|
87
|
+
base.class.instance_eval { include(HttpRequestResponseHelper) }
|
88
|
+
@implanted = true
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
def self.implanted? ; @implanted; end
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'uri'
|
2
|
+
|
3
|
+
class Buby
|
4
|
+
|
5
|
+
class ScanIssuesList < BubyArrayWrapper
|
6
|
+
def initialize(obj)
|
7
|
+
ScanIssueHelper.implant(obj[0]) if obj.size > 0
|
8
|
+
super(obj)
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
12
|
+
|
13
|
+
module ScanIssueHelper
|
14
|
+
# Returns a Ruby URI object derived from the java.net.URL object
|
15
|
+
def uri
|
16
|
+
@uri ||= URI.parse url.to_s if not url.nil?
|
17
|
+
end
|
18
|
+
|
19
|
+
# one-shot method to implant ourselves onto a target object's class
|
20
|
+
# interface in ruby. All later instances will also get 'us' for free!
|
21
|
+
def self.implant(base)
|
22
|
+
return if @implanted
|
23
|
+
base.class.instance_eval { include(ScanIssueHelper) }
|
24
|
+
@implanted = true
|
25
|
+
end
|
26
|
+
|
27
|
+
def http_messages
|
28
|
+
HttpRequestResponseList.new( self.getHttpMessages() )
|
29
|
+
end
|
30
|
+
alias messages http_messages
|
31
|
+
alias messages http_messages
|
32
|
+
|
33
|
+
def self.implanted? ; @implanted; end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
data/lib/buby/extends.rb
ADDED
data/lib/buby.rb
CHANGED
@@ -2,6 +2,7 @@ include Java
|
|
2
2
|
|
3
3
|
require 'pp'
|
4
4
|
require "buby.jar"
|
5
|
+
require 'buby/extends.rb'
|
5
6
|
|
6
7
|
include_class 'BurpExtender'
|
7
8
|
|
@@ -78,7 +79,7 @@ include_class 'BurpExtender'
|
|
78
79
|
class Buby
|
79
80
|
|
80
81
|
# :stopdoc:
|
81
|
-
VERSION = '1.1.
|
82
|
+
VERSION = '1.1.4'
|
82
83
|
LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
|
83
84
|
PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
|
84
85
|
# :startdoc:
|
@@ -226,7 +227,7 @@ class Buby
|
|
226
227
|
alias send_to_spider sendToSpider
|
227
228
|
alias spider sendToSpider
|
228
229
|
|
229
|
-
# This method is a __send__
|
230
|
+
# This method is a __send__ callback gate for the IBurpExtenderCallbacks
|
230
231
|
# reference. It first checks to see if a method is available before calling
|
231
232
|
# with the specified arguments, and raises an exception if it is unavailable.
|
232
233
|
#
|
@@ -243,33 +244,37 @@ class Buby
|
|
243
244
|
cb.__send__ meth, *args
|
244
245
|
end
|
245
246
|
|
247
|
+
|
246
248
|
# Returns a Java array of IHttpRequestResponse objects pulled directly from
|
247
249
|
# the Burp proxy history.
|
248
250
|
def getProxyHistory
|
249
|
-
_check_and_callback(:getProxyHistory)
|
251
|
+
HttpRequestResponseList.new(_check_and_callback(:getProxyHistory))
|
250
252
|
end
|
251
253
|
alias proxy_history getProxyHistory
|
252
254
|
alias get_proxy_history getProxyHistory
|
253
255
|
|
256
|
+
|
254
257
|
# Returns a Java array of IHttpRequestResponse objects pulled directly from
|
255
258
|
# the Burp site map for all urls matching the specified literal prefix.
|
256
259
|
# The prefix can be nil to return all objects.
|
257
260
|
def getSiteMap(urlprefix=nil)
|
258
|
-
_check_and_callback(:getSiteMap, urlprefix)
|
261
|
+
HttpRequestResponseList.new(_check_and_callback(:getSiteMap, urlprefix))
|
259
262
|
end
|
260
263
|
alias site_map getSiteMap
|
261
264
|
alias get_site_map getSiteMap
|
262
265
|
|
266
|
+
|
263
267
|
# This method returns all of the current scan issues for URLs matching the
|
264
268
|
# specified literal prefix. The prefix can be nil to match all issues.
|
265
269
|
#
|
266
270
|
# IMPORTANT: This method is only available with Burp 1.2.15 and higher.
|
267
271
|
def getScanIssues(urlprefix=nil)
|
268
|
-
_check_and_callback(:getScanIssues, urlprefix)
|
272
|
+
ScanIssuesList.new( _check_and_callback(:getScanIssues, urlprefix) )
|
269
273
|
end
|
270
274
|
alias scan_issues getScanIssues
|
271
275
|
alias get_scan_issues getScanIssues
|
272
276
|
|
277
|
+
|
273
278
|
# Restores Burp session state from a previously saved state file.
|
274
279
|
# See also: saveState
|
275
280
|
#
|
@@ -281,6 +286,7 @@ class Buby
|
|
281
286
|
end
|
282
287
|
alias restore_state restoreState
|
283
288
|
|
289
|
+
|
284
290
|
# Saves the current Burp session to a state file. See also restoreState.
|
285
291
|
#
|
286
292
|
# IMPORTANT: This method is only available with Burp 1.2.09 and higher.
|
@@ -291,6 +297,7 @@ class Buby
|
|
291
297
|
end
|
292
298
|
alias save_state saveState
|
293
299
|
|
300
|
+
|
294
301
|
# Parses a raw HTTP request message and returns an associative array
|
295
302
|
# containing parameters as they are structured in the 'Parameters' tab in the
|
296
303
|
# Burp request UI.
|
@@ -305,6 +312,7 @@ class Buby
|
|
305
312
|
alias parameters getParameters
|
306
313
|
alias get_parameters getParameters
|
307
314
|
|
315
|
+
|
308
316
|
# Parses a raw HTTP message (request or response ) and returns an associative
|
309
317
|
# array containing the headers as they are structured in the 'Headers' tab
|
310
318
|
# in the Burp request/response viewer UI.
|
@@ -510,7 +518,8 @@ class Buby
|
|
510
518
|
#
|
511
519
|
# This method should be overridden if you wish to implement functionality
|
512
520
|
# relating to generalized requests and responses from any BurpSuite tool.
|
513
|
-
#
|
521
|
+
#
|
522
|
+
# You may want to use evt_proxy_message if you only intend to work on
|
514
523
|
# proxied messages. Note, however, the IHttpRequestResponse Java object is
|
515
524
|
# not used in evt_proxy_message and gives evt_http_message a somewhat
|
516
525
|
# nicer interface to work with.
|
@@ -523,7 +532,8 @@ class Buby
|
|
523
532
|
# * message_info = an instance of the IHttpRequestResponse Java class with
|
524
533
|
# methods for accessing and manipulating various attributes of the message.
|
525
534
|
#
|
526
|
-
def evt_http_message
|
535
|
+
def evt_http_message(tool_name, is_request, message_info)
|
536
|
+
HttpRequestResponseHelper.implant(message_info)
|
527
537
|
pp([:got_http_message, tool_name, is_request, message_info]) if $DEBUG
|
528
538
|
end
|
529
539
|
|
@@ -540,6 +550,7 @@ class Buby
|
|
540
550
|
# * issue = an instance of the IScanIssue Java class with methods for viewing
|
541
551
|
# information on the scan issue that was generated.
|
542
552
|
def evt_scan_issue(issue)
|
553
|
+
ScanIssueHelper.implant(issue)
|
543
554
|
pp([:got_scan_issue, issue]) if $DEBUG
|
544
555
|
end
|
545
556
|
|
@@ -561,7 +572,7 @@ class Buby
|
|
561
572
|
# Yields each entry in the site map to a block (which is required)
|
562
573
|
def with_site_map(urlprefix=nil, statefile=nil)
|
563
574
|
with_statefile(statefile) do |this|
|
564
|
-
this.site_map(urlprefix).
|
575
|
+
this.site_map(urlprefix).each {|h| yield h }
|
565
576
|
end
|
566
577
|
end
|
567
578
|
|
@@ -574,14 +585,13 @@ class Buby
|
|
574
585
|
# Yields each entry in the proxy history to a block (which is required)
|
575
586
|
def with_proxy_history(statefile=nil)
|
576
587
|
with_statefile(statefile) do |this|
|
577
|
-
this.proxy_history.
|
588
|
+
this.proxy_history.each {|h| yield h }
|
578
589
|
end
|
579
590
|
end
|
580
591
|
|
581
592
|
# This is a convenience wrapper which loads a given burp statefile and lets
|
582
|
-
# its caller
|
583
|
-
#
|
584
|
-
# of the statefile load.
|
593
|
+
# its caller perform actions via burp while its loaded on it inside of a
|
594
|
+
# block. The old state is restored after the block completes.
|
585
595
|
#
|
586
596
|
# It can safely be used without a statefile argument, in which case the
|
587
597
|
# current session state is used.
|
@@ -593,10 +603,9 @@ class Buby
|
|
593
603
|
# save current state:
|
594
604
|
old_state=".#{$$}.#{Time.now.to_i}.state.bak"
|
595
605
|
self.alert "Saving current state to temp statefile: #{old_state}"
|
596
|
-
self.save_state
|
597
|
-
|
606
|
+
self.save_state(old_state)
|
598
607
|
self.alert "Restoring state: #{statefile}"
|
599
|
-
self.restore_state
|
608
|
+
self.restore_state(statefile)
|
600
609
|
end
|
601
610
|
|
602
611
|
yield self
|
@@ -619,17 +628,10 @@ class Buby
|
|
619
628
|
# This method also accepts an optional block which is passed each of the
|
620
629
|
# matched history members.
|
621
630
|
def search_proxy_history(statefile=nil, urlrx=nil)
|
622
|
-
ret =
|
623
|
-
|
624
|
-
|
625
|
-
if
|
626
|
-
true if r.url.to_s =~ urlrx
|
627
|
-
else
|
628
|
-
true
|
629
|
-
end
|
630
|
-
end
|
631
|
-
if block_given?
|
632
|
-
ret.each {|r| yield r }
|
631
|
+
ret = []
|
632
|
+
with_proxy_history(statefile) do |r|
|
633
|
+
if (not urlrx) or r.url.to_s =~ urlrx
|
634
|
+
ret << r if (not block_given?) or yield(r)
|
633
635
|
end
|
634
636
|
end
|
635
637
|
return ret
|
@@ -644,11 +646,10 @@ class Buby
|
|
644
646
|
# and harvest from.
|
645
647
|
def harvest_cookies_from_history(cookie=nil, urlrx=nil, statefile=nil)
|
646
648
|
ret = []
|
647
|
-
search_proxy_history(statefile, urlrx) do |
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
ret += found.map {|f| f << msg }
|
649
|
+
search_proxy_history(statefile, urlrx) do |hrr|
|
650
|
+
ret += hrr.rsp_headers.select do |h|
|
651
|
+
h[0].downcase == 'set-cookie'
|
652
|
+
end.map{|h| h[1]}
|
652
653
|
end
|
653
654
|
return ret
|
654
655
|
end
|
@@ -737,6 +738,7 @@ class Buby
|
|
737
738
|
|
738
739
|
end # Buby
|
739
740
|
|
741
|
+
|
740
742
|
# Try requiring 'burp.jar' from the Ruby lib-path
|
741
743
|
unless Buby.burp_loaded?
|
742
744
|
begin require "burp.jar"
|
data/samples/drb_buby.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
|
2
|
+
require 'rubygems'
|
3
|
+
require 'buby'
|
4
|
+
require 'drb'
|
5
|
+
|
6
|
+
module DrbBuby
|
7
|
+
attr_reader :drb_server
|
8
|
+
|
9
|
+
def evt_register_callbacks(cb)
|
10
|
+
super(cb)
|
11
|
+
# cb.issueAlert("[DrbBuby] Service on: #{@drb_server.uri}")
|
12
|
+
end
|
13
|
+
|
14
|
+
def init_DrbBuby
|
15
|
+
## want to bind the DRb service on a specific socket?
|
16
|
+
uri ='druby://127.0.0.1:9999'
|
17
|
+
## or let it choose one automatically:
|
18
|
+
# uri = nil
|
19
|
+
@drb_server = DRb.start_service uri, self
|
20
|
+
puts "[DrbBuby] Service on: #{@drb_server.uri}"
|
21
|
+
self.alert("[DrbBuby] Service on: #{@drb_server.uri}")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
if __FILE__ == $0
|
26
|
+
$burp = Buby.new
|
27
|
+
$burp.extend(DrbBuby)
|
28
|
+
$burp.start_burp()
|
29
|
+
$burp.init_DrbBuby
|
30
|
+
end
|
31
|
+
|
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# notice... we're using MRI ruby here, not JRuby (but either will work)
|
3
|
+
|
4
|
+
require 'drb'
|
5
|
+
|
6
|
+
unless drb_uri = ARGV.shift
|
7
|
+
STDERR.puts "Usage: #{File.basename $0} druby://<addr>:<port>"
|
8
|
+
exit 1
|
9
|
+
end
|
10
|
+
|
11
|
+
drb = DRbObject.new nil, drb_uri
|
12
|
+
rsp=drb.make_http_request 'example.com', 80, false, "GET / HTTP/1.0\r\n\r\n"
|
13
|
+
|
14
|
+
puts rsp
|
data/samples/mechanize_burp.rb
CHANGED
@@ -12,38 +12,27 @@ include Java
|
|
12
12
|
# for a Mechanize agent by intercepting all requests sent through the
|
13
13
|
# Burp proxy. This lets you use Mechanize in tandem with your browser
|
14
14
|
# through Burp without having to fuss around with cookies.
|
15
|
-
|
15
|
+
module MechGlue
|
16
16
|
attr_accessor :mech_agent
|
17
17
|
|
18
|
-
def initialize(mech_agent, other=nil)
|
19
|
-
super(other)
|
20
|
-
@mech_agent = mech_agent
|
21
|
-
end
|
22
|
-
|
23
18
|
def evt_proxy_message(*param)
|
24
19
|
msg_ref, is_req, rhost, rport, is_https, http_meth, url,
|
25
20
|
resourceType, status, req_content_type, message, action = param
|
26
21
|
|
27
22
|
if (not is_req) and (message =~ /Set-Cookie/i)
|
28
23
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
uri
|
40
|
-
|
41
|
-
|
42
|
-
# Grab cookies from headers:
|
43
|
-
rsp.headers.get_header_value('Set-Cookie').each do |cookie|
|
44
|
-
WWW::Mechanize::Cookie.parse(uri, cookie) do |c|
|
45
|
-
$mech.cookie_jar.add(uri, c)
|
46
|
-
end
|
24
|
+
rsp = Rbkb::Http::Response.new(message, :ignore_content_length => true)
|
25
|
+
|
26
|
+
# Get an uri object ready for mechanize
|
27
|
+
uri = URI.parse(url)
|
28
|
+
uri.scheme = (is_https)? "https" : "http"
|
29
|
+
uri.host = rhost
|
30
|
+
uri.port = rport
|
31
|
+
|
32
|
+
# Grab cookies from headers:
|
33
|
+
rsp.headers.get_header_value('Set-Cookie').each do |cookie|
|
34
|
+
WWW::Mechanize::Cookie.parse(uri, cookie) do |c|
|
35
|
+
@mech_agent.cookie_jar.add(uri, c)
|
47
36
|
end
|
48
37
|
end
|
49
38
|
end
|
@@ -56,10 +45,13 @@ if __FILE__ == $0
|
|
56
45
|
$mech = WWW::Mechanize.new
|
57
46
|
#$mech.set_proxy('localhost', '8080')
|
58
47
|
|
59
|
-
$burp =
|
48
|
+
$burp = Buby.new()
|
49
|
+
$burp.extend(MechGlue)
|
50
|
+
$burp.mech_agent = $mech
|
60
51
|
$burp.start_burp
|
61
52
|
|
62
53
|
puts "$burp is set to #{$burp.class}"
|
63
54
|
puts "$mech is set to #{$mech.class}"
|
64
55
|
IRB.start
|
65
56
|
end
|
57
|
+
|
data/samples/verb_tamperer.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
require 'rubygems'
|
3
3
|
require 'buby'
|
4
4
|
|
5
|
-
|
5
|
+
module VerbTamperer
|
6
6
|
def evt_proxy_message(*param)
|
7
7
|
msg_ref, is_req, rhost, rport, is_https, http_meth, url,
|
8
8
|
resourceType, status, req_content_type, message, action = param
|
@@ -18,4 +18,8 @@ class VerbTamperer < Buby
|
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
|
-
|
21
|
+
if __FILE__ == $0
|
22
|
+
$burp = Buby.new()
|
23
|
+
$burp.extend(VerbTamperer)
|
24
|
+
$burp.start_burp()
|
25
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
|
2
|
+
module WatchScan
|
3
|
+
def evt_http_message(tool_name, is_request, message_info)
|
4
|
+
super(tool_name, is_request, message_info)
|
5
|
+
if tool_name == 'scanner'
|
6
|
+
if is_request
|
7
|
+
puts "#"*70, "# REQUEST: #{message_info.url.toString}", "#"*70
|
8
|
+
puts message_info.req_str
|
9
|
+
puts
|
10
|
+
else
|
11
|
+
puts "#"*70, "# RESPONSE: #{message_info.url.toString}", "#"*70
|
12
|
+
puts message_info.rsp_str
|
13
|
+
puts
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def init_WatchScan
|
19
|
+
puts "WatchScan module initialized"
|
20
|
+
end
|
21
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: emonti-buby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1.
|
4
|
+
version: 1.1.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Eric Monti - Matasano Security
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-09-21 00:00:00 -07:00
|
13
13
|
default_executable: buby
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -46,8 +46,15 @@ files:
|
|
46
46
|
- java/src/burp/IScanIssue.java
|
47
47
|
- java/src/burp/IScanQueueItem.java
|
48
48
|
- lib/buby.rb
|
49
|
+
- lib/buby/extends.rb
|
50
|
+
- lib/buby/extends/buby_array_wrapper.rb
|
51
|
+
- lib/buby/extends/http_request_response.rb
|
52
|
+
- lib/buby/extends/scan_issue.rb
|
53
|
+
- samples/drb_buby.rb
|
54
|
+
- samples/drb_sample_cli.rb
|
49
55
|
- samples/mechanize_burp.rb
|
50
56
|
- samples/verb_tamperer.rb
|
57
|
+
- samples/watch_scan.rb
|
51
58
|
- spec/buby_spec.rb
|
52
59
|
- spec/spec_helper.rb
|
53
60
|
- tasks/ann.rake
|