emonti-buby 1.0.1 → 1.1.0.0

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 CHANGED
@@ -1,3 +1,14 @@
1
+ == 1.1.0 / 2009-06-18
2
+ * 1 major enhancement
3
+ * Support added for the new Burp API features added in Burp 1.2.09.
4
+ See http://releases.portswigger.net/2009/05/v1209.html
5
+ * 1 minor enhancement
6
+ * buby command-line tool exposes arguments for debugging and IRB
7
+
8
+ == 1.0.2 / 2009-06-02
9
+ * Enhancements
10
+ * Added a sample illustrating synching cookies with Mechanize
11
+
1
12
  == 1.0.1 / 2009-05-10
2
13
  * Enhancements
3
14
  * Added some sugar to make swapping Burp event handlers easier.
data/README.rdoc CHANGED
@@ -45,39 +45,36 @@ You should be able to get up and running with just the gem and a copy of Burp.
45
45
  I've packaged up a pre-built buby.jar file containing the required classes
46
46
  minus ofcourse, Burp itself.
47
47
 
48
- gem install emonti-buby
48
+ jruby -S gem sources -a http://gems.github.com # only have to do this once
49
+ jruby -S gem install emonti-buby
49
50
 
50
51
  * IMPORTANT: The buby gem doesn't include a copy of Burp! See manual step #5
51
- below. For best results, you'll still want to make your burp.jar available
52
- in the ruby runtime library path.
52
+ below. For best results, you'll still want to make your burp.jar available
53
+ in the ruby runtime library path.
53
54
 
54
55
 
55
56
  === Manual
56
57
  Here are manual instructions if you want or need to build things yourself:
57
58
 
58
- Step 1. Download buby from github
59
+ ==== Step 1. Download buby from github
59
60
  git clone git://github.com/emonti/buby.git
60
61
 
61
- Step 2. Compile BurpExtender.java. Include jruby.jar in the classpath:
62
+ ==== Step 2. Compile BurpExtender.java. Include jruby.jar in the classpath:
62
63
 
63
64
  cd buby/java/src
64
65
  javac -classpath (.../jruby/root)/lib/jruby.jar:. BurpExtender.java
65
66
 
66
- Step 3. Create a new lib/buby.jar
67
+ ==== Step 3. Create a new java/buby.jar
67
68
 
68
69
  jar cvf ../buby.jar .
69
70
 
70
- Note: At this point you can also just do a rake gem:install from the
71
- top-level, which will install a local 'buby' gem instead of 'emonti-buby'. If
72
- you do this, just skip the next step and move onto step #5.
73
-
74
- Step 4. Copy buby.rb and jar to your JRuby lib-path. Locations may vary:
71
+ ==== Step 4. Build a local gem and install it
75
72
 
76
73
  cd ../../
77
- cp lib/buby.rb (.../jruby)/lib/site_ruby/1.8/
78
- cp -p java/buby.jar (.../jruby)/lib/site_ruby/1.8/java/buby.jar
74
+ jruby -S gem build buby.gemspec
75
+ jruby -S gem install --local buby-*.gem
79
76
 
80
- Step 5.
77
+ ==== Step 5.
81
78
 
82
79
  The last part is a bit tricky. Burp Suite itself is obviously not included
83
80
  with buby. You'll want to somehow put your 'burp.jar' in a place where it
@@ -85,15 +82,15 @@ is visible in the JRuby RUBY-LIB paths. There are a few other ways of pulling
85
82
  in Burp during runtime, but this method probably involves the least amount of
86
83
  hassle in the long run.
87
84
 
88
- JRuby gives you a 'java' site_ruby directory for this kind of thing. Here's a
89
- quick way to see jruby's runtime lib-path:
85
+ JRuby usually gives you a 'java' lib directory for this kind of thing. Here's
86
+ a quick way to see jruby's runtime lib-path:
90
87
 
91
88
  jruby -e 'puts $:'
92
89
 
93
90
  There is usually a '.../jruby/lib/1.8/java' directory reference in there,
94
91
  though the actual directory may need to be created.
95
92
 
96
- Here's how I do it. I have jruby installation under my home directory.
93
+ Here's how I do it. I have my jruby installation under my home directory.
97
94
  Your configuration details can be substituted below.
98
95
 
99
96
  mkdir ~/jruby-1.1.5/lib/ruby/1.8/java
@@ -107,25 +104,26 @@ run 'buby' from the command-line.
107
104
  == TEST AND USAGE EXAMPLE:
108
105
 
109
106
  The gem includes a command-line tool called 'buby' but it doesn't do much right
110
- now. You can, however use this as a minimal test to confirm whether Burp can be
111
- launched from ruby and whether Buby and Burp are connected.
107
+ now. You can, however, use this as a minimal test to confirm whether Burp can
108
+ be launched from ruby and that Buby and Burp are connected.
112
109
 
113
- Here are some really simple test examples using Buby through IRB:
110
+ Launch buby for simple testing and debugging with the 'buby' command-line tool:
114
111
 
115
- $ jruby -S irb
112
+ $ buby -h
113
+ Usage: buby [options]
114
+ -i, --interactive Start IRB
115
+ -d, --debug Debug info
116
+ -B, --load-burp=PATH Load Burp Jar from PATH
117
+ -h, --help Show this help message
116
118
 
117
- require 'buby'
118
- $DEBUG = true
119
+ $ buby -i -d
120
+ [:got_extender, #<Java::Default::BurpExtender:0x80 ...>]
121
+ Global $burp is set to #<Buby:0x78de07 @burp_callbacks=#<#<Class:...>
122
+ [:got_callbacks, #<#<Class:01x38ba04>:0x90 ...>]
123
+ irb(main):001:0>
119
124
 
120
- # Here's one way to explicitely add burp.jar into the runtime if its not
121
- # already.
122
- Buby.load_burp("/path/to/burp.jar") if not Buby.burp_loaded?
123
- buby = Buby.start_burp()
124
125
 
125
- At this point, you should see Burp starting and with the $DEBUG flag, you'll
126
- also see several debug messages in IRB coming from Buby as various events are
127
- generated by the BurpExtender java implementation. Once Burp is running, click
128
- on the alerts tab.
126
+ Once Burp is running, click on the alerts tab.
129
127
 
130
128
  You should see now something like the following in alerts:
131
129
 
@@ -137,16 +135,19 @@ You should see now something like the following in alerts:
137
135
  2:46:01 PM suite [BurpExtender] registering JRuby handler callbacks
138
136
  2:46:01 PM suite [JRuby::Buby] registered callback
139
137
 
140
- To confirm you are connected back to Burp in IRB, do the following:
138
+ Here are some simple test examples using Buby through the IRB shell:
139
+
140
+ To confirm you are connected back to Burp in IRB, you can try writing to the
141
+ alerts panel with something like the following:
141
142
 
142
- buby.alert("hello Burp!")
143
+ $buby.alert("hello Burp!")
143
144
 
144
145
  Which should produce a new alert:
145
146
 
146
147
  2:47:00 PM suite hello Burp!
147
148
 
148
149
 
149
- Next, lets make an HTTP request through the proxy. We'll use Net:HTTP right
150
+ Next, try making an HTTP request through the proxy. We'll use Net:HTTP right
150
151
  in IRB for illustration purposes. However, you can just as easily perform this
151
152
  test through a browser configured to use Burp as its proxy.
152
153
 
@@ -204,7 +205,7 @@ Now, lets try something mildly interesting with the proxy. This contrived exampl
204
205
  # existing IRB session. Normally, you'd probably want to implement this as
205
206
  # an override in your Buby-derived class.
206
207
 
207
- buby.instance_eval do
208
+ $buby.instance_eval do
208
209
 
209
210
  def evt_proxy_message(*param)
210
211
  msg_ref, is_req, rhost, rport, is_https, http_meth, url, resourceType,
data/bin/buby CHANGED
@@ -2,15 +2,43 @@
2
2
 
3
3
  require File.expand_path(File.join(File.dirname(__FILE__), %w[.. lib buby]))
4
4
  require 'irb'
5
+ require 'optparse'
5
6
 
6
- unless Buby.burp_loaded?
7
- begin
8
- raise "You must specify the path to your burp.jar" unless jar=ARGV.shift
9
- raise "#{jar} did not provide burp.StartBurp" unless Buby.load_burp(jar)
10
- rescue
11
- STDERR.puts "Error: #{$!}"
12
- exit 1
7
+ args = {}
8
+
9
+ begin
10
+ opts = OptionParser.new do |o|
11
+ o.banner = "Usage: #{File.basename $0} [options]"
12
+
13
+ o.on_tail("-h", "--help", "Show this help message") do
14
+ raise opts.to_s
15
+ end
16
+
17
+ o.on("-i", "--interactive", "Start IRB") { args[:irb] = true }
18
+
19
+ o.on("-d", "--debug", "Debug info") { args[:debug] = true }
20
+
21
+ o.on("-B", "--load-burp=PATH", "Load Burp Jar from PATH") do |b|
22
+ args[:load_burp] = b
23
+ end
24
+ end
25
+
26
+ opts.parse!(ARGV)
27
+
28
+ if jar=args[:load_burp]
29
+ raise "Load Burp Error: #{jar} did not provide burp.StartBurp" unless Buby.load_burp(jar)
13
30
  end
31
+ raise "Load Burp Error: Specify a path to your burp.jar with -B" unless Buby.burp_loaded?
32
+ rescue
33
+ STDERR.puts $!
34
+ exit 1
14
35
  end
36
+
37
+ $DEBUG=true if args[:debug]
38
+
15
39
  $burp = Buby.start_burp()
16
- IRB.start if $DEBUG
40
+
41
+ if args[:irb]
42
+ puts "Global $burp is set to #{$burp.inspect}"
43
+ IRB.start
44
+ end
data/buby.gemspec CHANGED
@@ -2,36 +2,36 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{buby}
5
- s.version = "1.0.1"
5
+ s.version = "1.1.0.0"
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-05-10}
9
+ s.date = %q{2009-06-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", "lib/buby.rb", "samples/basic.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
- s.has_rdoc = true
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"]
17
16
  s.homepage = %q{http://github.com/emonti/buby}
18
17
  s.rdoc_options = ["--main", "README.rdoc"]
19
18
  s.require_paths = ["lib", "java"]
20
19
  s.rubyforge_project = %q{buby}
21
- s.rubygems_version = %q{1.3.1}
20
+ s.rubygems_version = %q{1.3.3}
22
21
  s.summary = %q{Buby is a mashup of JRuby with the popular commercial web security testing tool Burp Suite from PortSwigger}
23
22
  s.test_files = ["test/test_buby.rb"]
24
23
 
25
24
  if s.respond_to? :specification_version then
26
25
  current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
27
- s.specification_version = 2
26
+ s.specification_version = 3
28
27
 
29
28
  if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
30
- s.add_development_dependency(%q<bones>, [">= 2.5.0"])
29
+ s.add_development_dependency(%q<bones>, [">= 2.5.1"])
31
30
  else
32
- s.add_dependency(%q<bones>, [">= 2.5.0"])
31
+ s.add_dependency(%q<bones>, [">= 2.5.1"])
33
32
  end
34
33
  else
35
- s.add_dependency(%q<bones>, [">= 2.5.0"])
34
+ s.add_dependency(%q<bones>, [">= 2.5.1"])
36
35
  end
37
36
  end
37
+
data/java/buby.jar CHANGED
Binary file
@@ -2,6 +2,8 @@
2
2
 
3
3
  import burp.IBurpExtender;
4
4
  import burp.IBurpExtenderCallbacks;
5
+ import burp.IScanIssue;
6
+ import burp.IHttpRequestResponse;
5
7
 
6
8
  import org.jruby.*;
7
9
  import org.jruby.javasupport.JavaUtil;
@@ -16,11 +18,13 @@ import org.jruby.runtime.builtin.IRubyObject;
16
18
  * as of Burp Suite 1.2/1.2.05
17
19
  */
18
20
  public class BurpExtender implements IBurpExtender {
19
- public final static String INIT_METH = "evt_extender_init";
20
- public final static String PROXY_METH = "evt_proxy_message";
21
- public final static String MAINARGS_METH = "evt_commandline_args";
22
- public final static String REG_METH = "evt_register_callbacks";
23
- public final static String CLOSE_METH = "evt_application_closing";
21
+ public final static String INIT_METH = "evt_extender_init";
22
+ public final static String PROXYMSG_METH = "evt_proxy_message";
23
+ public final static String HTTPMSG_METH = "evt_http_message";
24
+ public final static String SCANISSUE_METH = "evt_scan_issue";
25
+ public final static String MAINARGS_METH = "evt_commandline_args";
26
+ public final static String REG_METH = "evt_register_callbacks";
27
+ public final static String CLOSE_METH = "evt_application_closing";
24
28
 
25
29
  // Internal reference to hold the ruby Burp handler
26
30
  private static IRubyObject r_obj = null;
@@ -108,7 +112,7 @@ public class BurpExtender implements IBurpExtender {
108
112
  * response is received.
109
113
  *
110
114
  * This implementation simply passes all arguments to the Ruby handler's
111
- * method defined by <code>PROXY_METH</code> if both the handler and
115
+ * method defined by <code>PROXYMSG_METH</code> if both the handler and
112
116
  * its ruby method are defined.
113
117
  *
114
118
  * This allows Ruby implementations to perform logging functions, modify
@@ -153,10 +157,10 @@ public class BurpExtender implements IBurpExtender {
153
157
  String statusCode,
154
158
  String responseContentType,
155
159
  byte[] message,
156
- int[] action
157
- ) {
160
+ int[] action )
161
+ {
158
162
 
159
- if (r_obj != null && r_obj.respondsTo(PROXY_METH)) {
163
+ if (r_obj != null && r_obj.respondsTo(PROXYMSG_METH)) {
160
164
  Ruby rt = rt(r_obj);
161
165
  // prepare an alternate action value to present to ruby
162
166
  IRubyObject r_action = to_ruby(rt, action);
@@ -182,7 +186,7 @@ public class BurpExtender implements IBurpExtender {
182
186
  // slurp back in the action value in-case it's been changed
183
187
  action[0] = ((int[]) JavaUtil.convertRubyToJava(r_action))[0];
184
188
 
185
- IRubyObject ret = r_obj.callMethod(ctx(r_obj), PROXY_METH, pxy_msg);
189
+ IRubyObject ret = r_obj.callMethod(ctx(r_obj), PROXYMSG_METH, pxy_msg);
186
190
  if(ret != r_msg)
187
191
  return ((RubyString) ret).getBytes();
188
192
  }
@@ -190,6 +194,46 @@ public class BurpExtender implements IBurpExtender {
190
194
  return message;
191
195
  }
192
196
 
197
+ /**
198
+ * Added in Burp 1.2.09
199
+ * No javadoc yet but here's what the PortSwigger dev blog has to say:
200
+ *
201
+ * The processHttpMessage method is invoked whenever any of Burp's tools
202
+ * makes an HTTP request or receives a response. This is effectively a
203
+ * generalised version of the existing processProxyMessage method, and
204
+ * can be used to intercept and modify the HTTP traffic of all Burp
205
+ * tools.
206
+ */
207
+ public void processHttpMessage(
208
+ String toolName,
209
+ boolean messageIsRequest,
210
+ IHttpRequestResponse messageInfo )
211
+ {
212
+ if (r_obj != null && r_obj.respondsTo(HTTPMSG_METH)) {
213
+ Ruby rt = rt(r_obj);
214
+ IRubyObject http_msg[] = {
215
+ to_ruby(rt, toolName),
216
+ to_ruby(rt, messageIsRequest),
217
+ to_ruby(rt, messageInfo)
218
+ };
219
+
220
+ r_obj.callMethod(ctx(r_obj), HTTPMSG_METH, http_msg);
221
+ }
222
+ }
223
+
224
+ /**
225
+ * Added in Burp 1.2.09
226
+ *
227
+ * The newScanIssue method is invoked whenever Burp Scanner discovers a
228
+ * new, unique issue, and can be used to perform customised reporting or
229
+ * logging of issues.
230
+ */
231
+ public void newScanIssue(IScanIssue issue) {
232
+ if (r_obj != null && r_obj.respondsTo(SCANISSUE_METH))
233
+ r_obj.callMethod(ctx(r_obj), SCANISSUE_METH, to_ruby(rt(r_obj), issue));
234
+ }
235
+
236
+
193
237
  /**
194
238
  * This method is invoked immediately before Burp Suite exits.
195
239
  * This implementation simply invokes the Ruby handler's method defined
@@ -223,25 +267,27 @@ public class BurpExtender implements IBurpExtender {
223
267
  return JavaUtil.convertJavaToUsableRubyObject(rt, obj);
224
268
  }
225
269
 
226
-
227
270
  /**
228
271
  * Causes Burp Proxy to follow the current interception rules to determine
229
272
  * the appropriate action to take for the message.
230
273
  */
231
274
  public final static int ACTION_FOLLOW_RULES = 0;
275
+
232
276
  /**
233
277
  * Causes Burp Proxy to present the message to the user for manual
234
278
  * review or modification.
235
279
  */
236
280
  public final static int ACTION_DO_INTERCEPT = 1;
281
+
237
282
  /**
238
283
  * Causes Burp Proxy to forward the message to the remote server or client.
239
284
  */
240
285
  public final static int ACTION_DONT_INTERCEPT = 2;
286
+
241
287
  /**
242
288
  * Causes Burp Proxy to drop the message and close the client connection.
243
289
  */
244
290
  public final static int ACTION_DROP = 3;
245
291
 
246
- }
292
+ }
247
293
 
@@ -154,4 +154,41 @@ public interface IBurpExtenderCallbacks
154
154
  * @param message The alert message to display.
155
155
  */
156
156
  public void issueAlert(String message);
157
+
158
+ /**
159
+ * The existing IBurpExtenderCallbacks interface adds several new methods
160
+ * which you can invoke to query and update Burp's state, and to parse raw
161
+ * HTTP messages for parameters and headers.
162
+ */
163
+
164
+ /**
165
+ * no javadoc yet from PortSwigger
166
+ */
167
+ public IHttpRequestResponse[] getProxyHistory();
168
+
169
+ /**
170
+ * no javadoc yet from PortSwigger
171
+ */
172
+ public IHttpRequestResponse[] getSiteMap(String urlPrefix);
173
+
174
+ /**
175
+ * no javadoc yet from PortSwigger
176
+ */
177
+ public void restoreState(java.io.File file) throws Exception;
178
+
179
+ /**
180
+ * no javadoc yet from PortSwigger
181
+ */
182
+ public void saveState(java.io.File file) throws Exception;
183
+
184
+ /**
185
+ * no javadoc yet from PortSwigger
186
+ */
187
+ public String[][] getParameters(byte[] request) throws Exception;
188
+
189
+ /**
190
+ * no javadoc yet from PortSwigger
191
+ */
192
+ public String[] getHeaders(byte[] message) throws Exception;
193
+
157
194
  }
@@ -0,0 +1,32 @@
1
+ package burp;
2
+
3
+ import java.net.URL;
4
+
5
+ public interface IHttpRequestResponse
6
+ {
7
+
8
+ public String getHost();
9
+
10
+ public int getPort();
11
+
12
+ public String getProtocol();
13
+
14
+ public void setHost(String host) throws Exception;
15
+
16
+ public void setPort(int port) throws Exception;
17
+
18
+ public void setProtocol(String protocol) throws Exception;
19
+
20
+ public byte[] getRequest() throws Exception;
21
+
22
+ public java.net.URL getUrl() throws Exception;
23
+
24
+ public void setRequest(byte[] message) throws Exception;
25
+
26
+ public byte[] getResponse() throws Exception;
27
+
28
+ public void setResponse(byte[] message) throws Exception;
29
+
30
+ public short getStatusCode() throws Exception;
31
+
32
+ }
@@ -0,0 +1,32 @@
1
+ package burp;
2
+
3
+ import java.net.URL;
4
+
5
+ public interface IScanIssue
6
+ {
7
+
8
+ public String getHost();
9
+
10
+ public int getPort();
11
+
12
+ public String getProtocol();
13
+
14
+ public java.net.URL getUrl();
15
+
16
+ public String getIssueName();
17
+
18
+ public String getSeverity();
19
+
20
+ public String getConfidence();
21
+
22
+ public String getIssueBackground();
23
+
24
+ public String getRemediationBackground();
25
+
26
+ public String getIssueDetail();
27
+
28
+ public String getRemediationDetail();
29
+
30
+ public IHttpRequestResponse[] getHttpMessages();
31
+
32
+ }
@@ -0,0 +1,20 @@
1
+ package burp;
2
+
3
+ public interface IScanQueueItem
4
+ {
5
+
6
+ public String getStatus();
7
+
8
+ public byte getPercentageComplete();
9
+
10
+ public int getNumRequests();
11
+
12
+ public int getNumErrors();
13
+
14
+ public int getNumInsertionPoints();
15
+
16
+ public void cancel();
17
+
18
+ public IScanIssue[] getIssues();
19
+
20
+ }
data/lib/buby.rb CHANGED
@@ -18,8 +18,14 @@ include_class 'BurpExtender'
18
18
  # * evt_register_callbacks
19
19
  # * evt_application_closing
20
20
  #
21
- # This class also exposes several methods used to access Burp functionality
22
- # and user interfaces (note also, abbreviated aliases exist for each):
21
+ # Buby also supports the newer event handlers available in Burp 1.2.09 and up:
22
+ # * evt_http_message
23
+ # * evt_scan_issue
24
+ #
25
+ #
26
+ # This class also exposes several methods to access Burp functionality
27
+ # and user interfaces through the IBurpExtenderCallbacks interface
28
+ # (note, several abbreviated aliases also exist for each):
23
29
  # * doActiveScan
24
30
  # * doPassiveScan
25
31
  # * excludeFromScope
@@ -31,6 +37,18 @@ include_class 'BurpExtender'
31
37
  # * sendToRepeater
32
38
  # * sendToSpider
33
39
  #
40
+ # Buby also provides front-end ruby methods for the new callback methods added
41
+ # since Burp 1.2.09:
42
+ # * getProxyHistory
43
+ # * getSiteMap
44
+ # * restoreState
45
+ # * saveState
46
+ # * getParameters
47
+ # * getHeaders
48
+ #
49
+ # If you wish to access any of the IBurpExtenderCallbacks methods directly.
50
+ # You can use 'burp_callbacks' to obtain a reference.
51
+ #
34
52
  # Credit:
35
53
  # * Burp and Burp Suite are trade-marks of PortSwigger Ltd.
36
54
  # Copyright 2008 PortSwigger Ltd. All rights reserved.
@@ -40,10 +58,10 @@ include_class 'BurpExtender'
40
58
  # were written by Eric Monti @ Matasano Security.
41
59
  #
42
60
  # Matasano claims no professional or legal affiliation with PortSwigger LTD.
43
- # nor do we sell or officially endorse their products.
61
+ # nor do we sell or officially endorse any of their products.
44
62
  #
45
63
  # However, this author would like to express his personal and professional
46
- # respect and appreciation for their making available the IBurpExtender
64
+ # respect and appreciation for their making available the BurpExtender
47
65
  # extension API. The availability of this interface in an already great tool
48
66
  # goes a long way to make Burp Suite a truly first-class application.
49
67
  #
@@ -54,7 +72,7 @@ include_class 'BurpExtender'
54
72
  class Buby
55
73
 
56
74
  # :stopdoc:
57
- VERSION = '1.0.1'
75
+ VERSION = '1.1.0'
58
76
  LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
59
77
  PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
60
78
  # :startdoc:
@@ -79,9 +97,12 @@ class Buby
79
97
 
80
98
  # Returns the internal reference to the IBupExtenderCallbacks instance.
81
99
  # This reference gets set from Java through the evt_register_callbacks
82
- # method.
100
+ # method. It is exposed to allow you to access the IBurpExtenderCallbacks
101
+ # instance directly if you so choose.
83
102
  def burp_callbacks; @burp_callbacks; end
84
103
 
104
+ # Internal method to check for the existence of the burp_callbacks reference
105
+ # before doing anything with it.
85
106
  def _check_cb
86
107
  @burp_callbacks or raise "Burp callbacks have not been set"
87
108
  end
@@ -95,7 +116,6 @@ class Buby
95
116
  def doActiveScan(host, port, https, req)
96
117
  _check_cb.doActiveScan(host, port, https, req.to_java_bytes)
97
118
  end
98
-
99
119
  alias do_active_scan doActiveScan
100
120
  alias active_scan doActiveScan
101
121
 
@@ -109,7 +129,6 @@ class Buby
109
129
  def doPassiveScan(host, port, https, req, rsp)
110
130
  _check_cb.doPassiveScan(host, port, https, req.to_java_bytes, rsp.to_java_bytes)
111
131
  end
112
-
113
132
  alias do_passive_scan doPassiveScan
114
133
  alias passive_scan doPassiveScan
115
134
 
@@ -118,7 +137,6 @@ class Buby
118
137
  def excludeFromScope(url)
119
138
  _check_cb.excludeFromScope(java.net.URL.new(url.to_s))
120
139
  end
121
-
122
140
  alias exclude_from_scope excludeFromScope
123
141
  alias exclude_scope excludeFromScope
124
142
 
@@ -127,7 +145,6 @@ class Buby
127
145
  def includeInScope(url)
128
146
  _check_cb.includeInScope(java.net.URL.new(url.to_s))
129
147
  end
130
-
131
148
  alias include_in_scope includeInScope
132
149
  alias include_scope includeInScope
133
150
 
@@ -138,7 +155,6 @@ class Buby
138
155
  def isInScope(url)
139
156
  _check_cb.isInScope(java.net.URL.new(url.to_s))
140
157
  end
141
-
142
158
  alias is_in_scope isInScope
143
159
  alias in_scope? isInScope
144
160
 
@@ -147,7 +163,6 @@ class Buby
147
163
  def issueAlert(msg)
148
164
  _check_cb.issueAlert(msg.to_s)
149
165
  end
150
-
151
166
  alias issue_alert issueAlert
152
167
  alias alert issueAlert
153
168
 
@@ -163,7 +178,6 @@ class Buby
163
178
  _check_cb.makeHttpRequest(host, port, https, req.to_java_bytes)
164
179
  )
165
180
  end
166
-
167
181
  alias make_http_request makeHttpRequest
168
182
  alias make_request makeHttpRequest
169
183
 
@@ -175,7 +189,6 @@ class Buby
175
189
  def sendToIntruder(host, port, https, req)
176
190
  _check_cb.sendToIntruder(host, port, https, req.to_java_bytes)
177
191
  end
178
-
179
192
  alias send_to_intruder sendToIntruder
180
193
  alias intruder sendToIntruder
181
194
 
@@ -188,7 +201,6 @@ class Buby
188
201
  def sendToRepeater(host, port, https, req, tab=nil)
189
202
  _check_cb.sendToRepeater(host, port, https, req.to_java_bytes, tab)
190
203
  end
191
-
192
204
  alias send_to_repeater sendToRepeater
193
205
  alias repeater sendToRepeater
194
206
 
@@ -197,10 +209,89 @@ class Buby
197
209
  def sendToSpider(url)
198
210
  _check_cb.includeInScope(java.net.URL.new(url.to_s))
199
211
  end
200
-
201
212
  alias send_to_spider sendToSpider
202
213
  alias spider sendToSpider
203
214
 
215
+ # This method is a __send__ call back gate for the IBurpExtenderCallbacks
216
+ # reference. It first checks to see if a method is available before calling
217
+ # with the specified arguments, and raises an exception if it is unavailable.
218
+ #
219
+ # This method was added for provisional calling of new callbacks added since
220
+ # Burp 1.2.09
221
+ #
222
+ # * meth = string or symbol name of method
223
+ # * args = variable length array of arguments to pass to meth
224
+ def _check_and_callback(meth, *args)
225
+ cb = _check_cb
226
+ unless cb.respond_to?(meth)
227
+ raise "#{meth} is not available in your version of Burp"
228
+ end
229
+ cb.__send__ meth, *args
230
+ end
231
+
232
+ # Returns a Java array of IHttpRequestResponse objects pulled directly from
233
+ # the Burp proxy history.
234
+ def getProxyHistory
235
+ _check_and_callback(:getProxyHistory)
236
+ end
237
+ alias proxy_history getProxyHistory
238
+ alias get_proxy_history getProxyHistory
239
+
240
+ # Returns a Java array of IHttpRequestResponse objects pulled directly from
241
+ # the Burp site map.
242
+ def getSiteMap
243
+ _check_and_callback(:getSiteMap)
244
+ end
245
+ alias site_map getSiteMap
246
+ alias get_site_map getSiteMap
247
+
248
+ # Restores Burp session state from a previously saved state file.
249
+ # See also: saveState
250
+ #
251
+ # IMPORTANT: This method is only available with Burp 1.2.09 and higher.
252
+ #
253
+ # * filename = path and filename of the file to restore from
254
+ def restoreState(filename)
255
+ _check_and_callback(:restoreState, java.io.File.new(filename))
256
+ end
257
+ alias restore_state restoreState
258
+
259
+ # Saves the current Burp session to a state file. See also restoreState.
260
+ #
261
+ # IMPORTANT: This method is only available with Burp 1.2.09 and higher.
262
+ #
263
+ # * filename = path and filename of the file to save to
264
+ def saveState(filename)
265
+ _check_and_callback(:saveState, java.io.File.new(filename))
266
+ end
267
+ alias save_state saveState
268
+
269
+ # Parses a raw HTTP request message and returns an associative array
270
+ # containing parameters as they are structured in the 'Parameters' tab in the
271
+ # Burp request UI.
272
+ #
273
+ # IMPORTANT: This method is only available with Burp 1.2.09 and higher.
274
+ #
275
+ # req = raw request string (converted to Java bytes[] in passing)
276
+ def getParameters(req)
277
+ _check_and_callback(:getParameters, req.to_s.to_java_bytes)
278
+ end
279
+ alias parameters getParameters
280
+ alias get_parameters getParameters
281
+
282
+ # Parses a raw HTTP message (request or response ) and returns an associative
283
+ # array containing the headers as they are structured in the 'Headers' tab
284
+ # in the Burp request/response viewer UI.
285
+ #
286
+ # IMPORTANT: This method is only available with Burp 1.2.09 and higher.
287
+ #
288
+ # msg = raw request/response string (converted to Java bytes[] in passing)
289
+ def getHeaders(msg)
290
+ _check_and_callback(:getHeaders, msg.to_s.to_java_bytes)
291
+ end
292
+ alias headers getHeaders
293
+ alias get_Headers getHeaders
294
+
204
295
 
205
296
  ### Event Handlers ###
206
297
 
@@ -283,8 +374,8 @@ class Buby
283
374
  # The requested URL. Set in both the request and response.
284
375
  #
285
376
  # * resourceType:
286
- # The filetype of the requested resource, or a zero-length string if the
287
- # resource has no filetype.
377
+ # The filetype of the requested resource, or nil if the resource has no
378
+ # filetype.
288
379
  #
289
380
  # * status:
290
381
  # The HTTP status code returned by the server. This value is nil for
@@ -379,6 +470,52 @@ class Buby
379
470
  return message
380
471
  end
381
472
 
473
+
474
+ # This method is invoked whenever any of Burp's tools makes an HTTP request
475
+ # or receives a response. This is effectively a generalised version of the
476
+ # pre-existing evt_proxy_message method, and can be used to intercept and
477
+ # modify the HTTP traffic of all Burp tools.
478
+ #
479
+ # IMPORTANT: This event handler is only used in Burp version 1.2.09 and
480
+ # higher.
481
+ #
482
+ # Note: this method maps to the processHttpMessage BurpExtender Java method.
483
+ #
484
+ # This method should be overridden if you wish to implement functionality
485
+ # relating to generalized requests and responses from any BurpSuite tool.
486
+ # You may want to use evt_proxy_message if you only intend to work with only
487
+ # proxied messages. Note, however, the IHttpRequestResponse Java object is
488
+ # not used in evt_proxy_http_message and gives evt_http_message a somewhat
489
+ # nicer interface to work with.
490
+ #
491
+ # Parameters:
492
+ # * tool_name = a string name of the tool that generated the message
493
+ #
494
+ # * is_request = boolean true = request / false = response
495
+ #
496
+ # * message_info = an instance of the IHttpRequestResponse Java class with
497
+ # methods for accessing and manipulating various attributes of the message.
498
+ #
499
+ def evt_http_message tool_name, is_request, message_info
500
+ pp([:got_http_message, tool_name, is_request, message_info]) if $DEBUG
501
+ end
502
+
503
+ # This method is invoked whenever Burp Scanner discovers a new, unique
504
+ # issue, and can be used to perform customised reporting or logging of
505
+ # detected issues.
506
+ #
507
+ # IMPORTANT: This event handler is only used in Burp version 1.2.09 and
508
+ # higher.
509
+ #
510
+ # Note: this method maps to the newScanIssue BurpExtender Java method.
511
+ #
512
+ # Parameters:
513
+ # * issue = an instance of the IScanIssue Java class with methods for viewing
514
+ # information on the scan issue that was generated.
515
+ def evt_scan_issue(issue)
516
+ pp([:got_scan_issue, issue]) if $DEBUG
517
+ end
518
+
382
519
  # This method is called by BurpExtender right before closing the
383
520
  # application. Implementations can use this method to perform cleanup
384
521
  # tasks such as closing files or databases before exit.
@@ -0,0 +1,65 @@
1
+ #!/usr/bin/env jruby
2
+
3
+ require 'rubygems'
4
+ require 'buby'
5
+ require 'mechanize'
6
+ require 'rbkb/http'
7
+ require 'irb'
8
+
9
+ include Java
10
+
11
+ # This Buby handler implementation simply keeps cookie state synched
12
+ # for a Mechanize agent by intercepting all requests sent through the
13
+ # Burp proxy. This lets you use Mechanize in tandem with your browser
14
+ # through Burp without having to fuss around with cookies.
15
+ class MechGlue < Buby
16
+ attr_accessor :mech_agent
17
+
18
+ def initialize(mech_agent, other=nil)
19
+ super(other)
20
+ @mech_agent = mech_agent
21
+ end
22
+
23
+ def evt_proxy_message(*param)
24
+ msg_ref, is_req, rhost, rport, is_https, http_meth, url,
25
+ resourceType, status, req_content_type, message, action = param
26
+
27
+ if (not is_req) and (message =~ /Set-Cookie/i)
28
+
29
+ begin
30
+ rsp = Rbkb::Http::Response.parse(message)
31
+ rescue
32
+ rsp = nil
33
+ end
34
+
35
+ if rsp
36
+ # Get an uri object ready for mechanize
37
+ uri = URI.parse(url)
38
+ uri.scheme = (is_https)? "https" : "http"
39
+ uri.host = rhost
40
+ uri.port = rport
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
47
+ end
48
+ end
49
+ end
50
+ return(message)
51
+ end
52
+ end
53
+
54
+
55
+ if __FILE__ == $0
56
+ $mech = WWW::Mechanize.new
57
+ #$mech.set_proxy('localhost', '8080')
58
+
59
+ $burp = MechGlue.new($mech)
60
+ $burp.start_burp
61
+
62
+ puts "$burp is set to #{$burp.class}"
63
+ puts "$mech is set to #{$mech.class}"
64
+ IRB.start
65
+ end
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env jruby
2
+ require 'rubygems'
3
+ require 'buby'
4
+
5
+ class VerbTamperer < Buby
6
+ def evt_proxy_message(*param)
7
+ msg_ref, is_req, rhost, rport, is_https, http_meth, url,
8
+ resourceType, status, req_content_type, message, action = param
9
+
10
+ if is_req and http_meth == "GET"
11
+ message[0,3] = "PET"
12
+ action[0] = Buby::ACTION_DONT_INTERCEPT
13
+
14
+ return super(*param).dup
15
+ else
16
+ return super(*param)
17
+ end
18
+ end
19
+ end
20
+
21
+ VerbTamperer.start_burp()
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.0.1
4
+ version: 1.1.0.0
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-05-10 00:00:00 -07:00
12
+ date: 2009-06-21 00:00:00 -07:00
13
13
  default_executable: buby
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -20,7 +20,7 @@ dependencies:
20
20
  requirements:
21
21
  - - ">="
22
22
  - !ruby/object:Gem::Version
23
- version: 2.5.0
23
+ version: 2.5.1
24
24
  version:
25
25
  description: 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.
26
26
  email: emonti@matasano.com
@@ -42,8 +42,12 @@ files:
42
42
  - java/src/BurpExtender.java
43
43
  - java/src/burp/IBurpExtender.java
44
44
  - java/src/burp/IBurpExtenderCallbacks.java
45
+ - java/src/burp/IHttpRequestResponse.java
46
+ - java/src/burp/IScanIssue.java
47
+ - java/src/burp/IScanQueueItem.java
45
48
  - lib/buby.rb
46
- - samples/basic.rb
49
+ - samples/mechanize_burp.rb
50
+ - samples/verb_tamperer.rb
47
51
  - spec/buby_spec.rb
48
52
  - spec/spec_helper.rb
49
53
  - tasks/ann.rake
@@ -60,7 +64,7 @@ files:
60
64
  - tasks/test.rake
61
65
  - tasks/zentest.rake
62
66
  - test/test_buby.rb
63
- has_rdoc: true
67
+ has_rdoc: false
64
68
  homepage: http://github.com/emonti/buby
65
69
  post_install_message:
66
70
  rdoc_options:
@@ -86,7 +90,7 @@ requirements: []
86
90
  rubyforge_project: buby
87
91
  rubygems_version: 1.2.0
88
92
  signing_key:
89
- specification_version: 2
93
+ specification_version: 3
90
94
  summary: Buby is a mashup of JRuby with the popular commercial web security testing tool Burp Suite from PortSwigger
91
95
  test_files:
92
96
  - test/test_buby.rb
data/samples/basic.rb DELETED
@@ -1,42 +0,0 @@
1
- #!/usr/bin/env jruby
2
- $: << File.join(File.dirname(__FILE__), %w[.. lib])
3
-
4
- require 'buby'
5
- $DEBUG = true
6
- Buby.load_burp("/path/to/burp.jar") if not Buby.burp_loaded?
7
- buby = Buby.start_burp()
8
-
9
- require 'net/http'
10
- p = Net::HTTP::Proxy("localhost", 8080).start("www.google.com")
11
-
12
- # Note: I'm using 'instance_eval' here only to stay with the flow of the
13
- # existing IRB session. Normally, you'd probably want to implement this as
14
- # an override in your Buby-derived class.
15
-
16
- buby.instance_eval do
17
-
18
- def evt_proxy_message(*param)
19
- msg_ref, is_req, rhost, rport, is_https, http_meth, url, resourceType,
20
- status, req_content_type, message, action = param
21
-
22
- if is_req and http_meth=="GET"
23
- # Change the HTTP request verb to something silly
24
- message[0,3] = "PET"
25
-
26
- # Forcibly disable interception in the Burp UI
27
- action[0] = Buby::ACTION_DONT_INTERCEPT
28
-
29
- # Return a new instance and still get $DEBUG info
30
- return super(*param).dup
31
- else
32
- # Just get $DEBUG info for all other requests
33
- return super(*param)
34
- end
35
- end
36
-
37
- end
38
-
39
- # Now, make another request using the Net::HTTP client
40
- p.get("/")
41
-
42
-