bscan 1.4.5 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -91,7 +91,12 @@ to 'true', the detailed zipped report will be attached. You'll ned
91
91
  It's important not to exceed the maximum file number on your
92
92
  client, otherwise it might not work. It's also important to
93
93
  set up a correct timeout (sleep_time) that should not be
94
- bigger than server's read timeout.
94
+ bigger than server's read or write timeout. The timeouts are different
95
+ for different servers and attack types: for slow reads the
96
+ timeout is usally bigger (100-200-.. secs), while for
97
+ slow writes it worked well for 5 - 10 sec interval. I general,
98
+ I found that slow writes are far more dangerous than slow reads
99
+ and that's why I set the default for 'delay_on_write' to 'true'.
95
100
 
96
101
  * bscan.slowloris.hostport=<host>:<port>
97
102
  no defaults, must provide both
@@ -100,23 +105,29 @@ bigger than server's read timeout.
100
105
  * bscan.slowloris.method=<http method>
101
106
  POST or GET, default - GET
102
107
  * bscan.slowloris.threads=n
103
- Thread number, default - 20
108
+ Thread number, default - 20 for reads, 500 for writes
104
109
  * bscan.slowloris.con_nbr_per_thread=n
105
- Number of connections per thread, default - 50
110
+ Number of connections per thread.
111
+ Default - 50 for reads, 1 for writes
106
112
  * bscan.slowloris.pack_per_con=n
107
113
  Max number of data packets to be sent in each connection
108
- default - 5 (duration of test: pack_per_con*sleep_time)
114
+ Default - 5 for reads, 50 - for writes
109
115
  * bscan.slowloris.response_time_factor=n
110
116
  Normal response time will be multipled by this number to determine
111
117
  when report an issue, e.g. if normal reposne time is 2 sec then if
112
118
  a response time under attack is bigger than 2*n, it will
113
119
  be logged as an issue. Default - 5
114
120
  * bscan.slowloris.sleep_time=n
115
- number of seconds to sleep
116
- after beginning of a request has been send, default 100
121
+ number of seconds to sleep after beginning of a request has been send
122
+ for reads or a delay to read message body for writes.
123
+ Default: 100 - for reads, 5 - for writes
117
124
  * bscan.slowloris.static_request=true
118
125
  Must be always set to 'true' for this module
119
-
126
+ * delay_on_write=<true|false>
127
+ Make delays on server's writes if true. Default: true
128
+ * health_check_int=n
129
+ Health check interval in seconds. Default: 2
130
+
120
131
  == kill_apache.rb Module Parameters
121
132
  Similar to slowloris a monitoring thread will be checking
122
133
  a response time and log an issue if a threshold is reached
@@ -28,14 +28,13 @@ Burp Suite from PortSwigger and Buby from Eric Monti and Timur Duehr
28
28
  == REQUIREMENTS:
29
29
  * JRuby - http://jruby.org
30
30
  * Burp pro if you want to use default Burp's scanners
31
- * Burp free if you want to run BScan's modules only
32
- * Buby 1.3.1 (see http://emonti.github.com/buby/)
31
+ * Buby 1.3.1 (see http://emonti.github.com/buby/) (not neccessary for modules_only mode)
33
32
 
34
33
  == BUILD/INSTALL:
35
34
 
36
35
  === Gem
37
36
 
38
- sudo jruby -S gem install buby -d --source=http://gemcutter.org
37
+ sudo jruby -S gem install buby -d --source=http://gemcutter.org (not necessary for modules_only)
39
38
  sudo jruby -S gem install bscan --source=http://gemcutter.org
40
39
 
41
40
  After Buby and BScan are installed, you'll need to link BScan to Burp's JAR (see below)
@@ -51,6 +50,8 @@ Burp Suite from PortSwigger and Buby from Eric Monti and Timur Duehr
51
50
 
52
51
  ==== Linking BScan and Buby to Burp's JAR.
53
52
 
53
+ * This step is not neccessary for modules_only mode
54
+
54
55
  After Buby and BScan are installed (either manually or by gem)
55
56
  you'll need to link them to a Burp's JAR.
56
57
 
@@ -81,6 +82,8 @@ To get help for config layout run:
81
82
  == RUNNING, REGISTERING Burp Pro:
82
83
  You need to register you burp.jar before you can run it headless
83
84
 
85
+ * Not neccessary for modules_only mode
86
+
84
87
  * Run your Burp as usual with GUI and provide you license.
85
88
  After this is done, you can run it headless using 'bscan'
86
89
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.4.5
1
+ 2.0.0
data/bin/bscan CHANGED
@@ -3,10 +3,9 @@
3
3
  #require File.expand_path(File.join(File.dirname(__FILE__), %w[.. lib bscan]))
4
4
  $: << File.expand_path(File.join(File.dirname(__FILE__), %w[.. lib]))
5
5
 
6
- require 'buby'
7
6
  require 'getoptlong'
8
- require 'bscan'
9
7
  require 'bscan/utils/bscan_helper'
8
+ require 'json'
10
9
 
11
10
  include BscanHelper
12
11
 
@@ -29,6 +28,35 @@ USAGE: jruby [-J-Xmx<nnn>M] [-J-Djava.awt.headless=true] -S bscan --config path_
29
28
  exit(1)
30
29
  end
31
30
 
31
+ def read_config file
32
+
33
+ burp_config = {}
34
+ bscan_config = {}
35
+
36
+ begin
37
+ open_in_path(file).each_line do |line|
38
+ line.chomp!
39
+ line.strip!
40
+ next if (line =~ /^#/ or line.length < 1)
41
+ data = line.split(/=/)
42
+ val = nil
43
+ val = data[1..-1].join('=') if data.size > 1
44
+ if data[0] =~ /^bscan./
45
+ add_multi(bscan_config,data[0],val)
46
+ else
47
+ burp_config[data[0]] = val
48
+ end
49
+ end
50
+ rescue Exception => e
51
+ $stderr.puts("BScan.read_config Error: can't read config file '#{file}', exception: #{e.message}")
52
+ $stderr.puts(e.backtrace.join("\n"))
53
+ Process.exit(3)
54
+ end
55
+ [burp_config, bscan_config]
56
+ end
57
+
58
+
59
+
32
60
  def get_cmd_params
33
61
  params = {}
34
62
 
@@ -74,6 +102,16 @@ def get_cmd_params
74
102
  params
75
103
  end
76
104
 
105
+ params = get_cmd_params
106
+
107
+ init_internals params
108
+ run_modules self
109
+ exit 0 if @modules_only
110
+
111
+ require 'buby'
112
+ require 'burp'
113
+ require 'bscan'
114
+
77
115
  $burp = Buby.new()
78
116
  $burp.extend(BScan)
79
- $burp.start_burp([get_cmd_params.to_json])
117
+ $burp.start_burp([params.to_json])
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "bscan"
8
- s.version = "1.4.5"
8
+ s.version = "2.0.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Oleg Gryb (ogryb)"]
12
- s.date = "2012-08-15"
12
+ s.date = "2012-08-22"
13
13
  s.description = "BScan is a configurable and extendable web application security scanner that can be run from a command line headless (without UI). It's built on top of arguably the most popular commercial security testing tool Burp Suite from PortSwigger and Buby from Eric Monti and Timur Duehr"
14
14
  s.email = "oleg@gryb.info"
15
15
  s.executables = ["bscan"]
@@ -1,75 +1,20 @@
1
1
  #!/usr/bin/env jruby
2
2
 
3
- require 'pathname'
4
3
  require 'buby'
5
4
  require 'getoptlong'
6
- require 'json'
7
5
  require 'bscan/utils/bscan_helper'
8
6
  require 'bscan/utils/mailer'
9
7
  require 'java'
10
-
11
- class String
12
- def camelize
13
- self.split(/[^a-z0-9]/i).map{|w| w.capitalize}.join
14
- end
15
- def camelize!
16
- self.replace(self.split(/[^a-z0-9]/i).map{|w| w.capitalize}.join)
17
- end
18
- end
8
+ require 'json'
19
9
 
20
10
  module BScan
21
11
 
22
12
  include BscanHelper
23
13
  include Mailer
24
14
 
25
- attr_accessor :activity
26
- attr_reader :modules_only
27
- attr_reader :bscan_config
28
- attr_accessor :stat
29
15
 
30
- def Log (mtype, *msgs)
31
- pr = "Unknown:"
32
- case mtype
33
- when 0
34
- pr = "ERROR:"
35
- when 1
36
- pr = "WARN:"
37
- when 2
38
- pr = "INFO:"
39
- when 3
40
- pr = "DEBUG:"
41
- end
42
- msgs.each do |msg|
43
- if (@ll >= mtype)
44
- dt = Time.now.strftime("%y%m%d %H%M%S")
45
- @log.println "#{dt} #{pr} #{msg}"
46
- end
47
- end
48
- @log.flush
49
- end
50
-
51
16
  def evt_commandline_args args
52
- init_stat
53
- @cmd_params ||= JSON.parse args[0]
54
- @ll = @cmd_params['loglevel'].to_i
55
-
56
- lfile = @cmd_params['logfile']
57
- if lfile != nil
58
- begin
59
- @log = java.io.PrintStream.new(lfile)
60
- rescue Exception => e
61
- $stderr.puts("BScan.evt_register_callbacks Error: can't open log file '#{lfile}', exception: #{e.message}")
62
- $stderr.puts(e.backtrace.join("\n"))
63
- Process.exit!(2)
64
- end
65
- else
66
- @log = $stdout
67
- end
68
-
69
- Log 2, "BScan.evt_commandline_args CMD_PARAMS: #{@cmd_params}"
70
- @cmd_params.each_pair do |k,v|
71
- Log 2,"BScan.evt_commandline_args #{k}:#{v}"
72
- end
17
+ init_internals JSON.parse(args[0])
73
18
  end
74
19
 
75
20
 
@@ -95,50 +40,13 @@ module BScan
95
40
  Log 2, "BScan.evt_http_message Actively scanning: #{message_info.url.to_string}"
96
41
  isqi = do_active_scan(message_info.getHost(), message_info.getPort(), https, message_info.getRequest(), [])
97
42
  @queue.push(isqi)
98
- run_modules message_info
43
+ run_modules self, message_info
99
44
  end
100
45
  end
101
46
  end
102
47
  end
103
48
 
104
- def is_module_static n,p
105
- pref = 'bscan.' + n + '.'
106
- pref += p + '.' if p and p.length > 0
107
- @bscan_config[pref + 'static_request'] == 'true'
108
- end
109
-
110
-
111
- def run_modules msg=nil
112
- if @modules
113
- @modules.each do |m|
114
- begin
115
- mod,prop=m.split(':',2)
116
- prop ||=''
117
- mn = File.basename(mod,".rb")
118
- is_static = is_module_static(mn,prop)
119
- Log 2, "BScan.run_modules executing module #{mod}:#{prop} #{is_static}"
120
- mn.camelize!
121
- if (is_static && !msg) || (!is_static && msg)
122
- eval("
123
- # puts '=====================MODULE PATH: ' + $:.join(':')
124
- require '#{mod}'
125
- require 'bscan/utils/bscan_helper.rb'
126
-
127
- class #{mn}#{prop}Class
128
- include #{mn}
129
- include BscanHelper
130
- end
131
- #{mn}#{prop}Class.new.run(self, msg, prop)
132
- ")
133
- end
134
- rescue Exception => e
135
- Log 1, "BScan.run_modules Can't exceute module #{mod}, Exception: #{e.message}"
136
- Log 1, e.backtrace.join("\n")
137
- end
138
- end
139
- end
140
- end
141
-
49
+
142
50
  def evt_scan_issue issue
143
51
  super(issue)
144
52
  # Buby::HttpRequestResponseHelper.implant(issue.http_messages)
@@ -152,32 +60,7 @@ module BScan
152
60
  }
153
61
  end
154
62
 
155
- def write_issue_state issue
156
- # Log 2,"INSPECT: #{issue.http_messages[0].methods} #{issue.http_messages[0].inspect} #{issue.http_messages[0].to_s} "
157
-
158
- @stat['high'] += 1 if issue.severity =~ /High/i
159
- @stat['med'] += 1 if issue.severity =~ /Med/i
160
- @stat['low'] += 1 if issue.severity =~ /Low/i
161
- @stat['urls'] += " #{issue.url}\n"
162
-
163
- Log 2,"BScan.write_issue_state #{not @istream} #{issue.http_messages[0].methods} #{issue.http_messages[0].to_s} "
164
- @istream or return
165
- begin
166
- @istream.println '#'*70
167
- @istream.println "#{issue.issue_name} : #{issue.url}"
168
- @istream.println "Severity: #{issue.severity}(#{issue.confidence})"
169
- @istream.println "Background: #{issue.issue_background}"
170
- @istream.println "Details: #{issue.issue_detail}"
171
- @istream.println "Remediation: #{issue.remediation_background}"
172
- @istream.println "Request: #{issue.http_messages[0].req_str}"
173
- @istream.println "Response: #{issue.http_messages[0].rsp_str}"
174
- # sync_save_state issue throws exceptions
175
- @istream.flush
176
- rescue Exception => e
177
- Log 0, "BScan.write_issue_state Can't write issue #{issue.issue_name}, Exception: #{e.message}"
178
- Log 0, e.backtrace.join("\n")
179
- end
180
- end
63
+
181
64
  def evt_application_closing
182
65
  begin
183
66
  Log 2,"BScan.evt_application_closing #{@bscan_config['bscan.smtp.server']} #{@bscan_config['bscan.smtp.to']}"
@@ -193,32 +76,12 @@ module BScan
193
76
 
194
77
  def evt_register_callbacks cb
195
78
  super(cb)
79
+ @burp ||= self
196
80
  begin
197
-
198
81
  Log 2, "="*30, "BScan.evt_register_callbacks registring, log = #{@cmd_params['logfile']} ", "="*30
199
- @bscan_config = @cmd_params['bscan_config']
200
- @burp_config = @cmd_params['burp_config']
201
- @issues = @bscan_config['bscan.issues']
202
- @modules_only = (@bscan_config['bscan.modules_only'] and @bscan_config['bscan.modules_only'] == 'true')
203
-
204
- Log 1, "BScan.evt_register_callbacks No issues dir provided. Issues will not be logged." if not @issues
205
- if (@issues)
206
- begin
207
- dt = Time.now.strftime("%y%m%d_%H%M%S")
208
- File.directory? @issues or %x{mkdir -p "#{@issues}"}
209
- @sstream = "#{@issues}/session.#{dt}.zip"
210
- ifile = "#{@issues}/issues.#{dt}.txt"
211
- @istream = java.io.PrintStream.new(ifile)
212
- @stat['issues'] = ifile
213
- rescue Exception => e
214
- Log 0, "BScan.evt_register_callbacks Can't create issues or session files, Exception: #{e.message}"
215
- Log 0, e.backtrace.join("\n")
216
- exit_suite
217
- end
218
- end
82
+
219
83
 
220
84
  @queue ||= []
221
- @activity = [false]
222
85
  @inactivity_to = @bscan_config['bscan.inactivity_to']
223
86
  @inactivity_to ||= '30'
224
87
  @inactivity_to = @inactivity_to.to_i
@@ -255,22 +118,11 @@ module BScan
255
118
  load_config params
256
119
  params.each_pair {|k,v| Log 2,"#{k}:#{v}"} # if k =~ /^(scanner|spider)/}
257
120
 
258
- @modules ||= @bscan_config['bscan.modules']
259
- @modules ||= [] if not @modules
260
- @modules = [@modules] if not @modules.kind_of?(Array)
261
-
262
- mods = []
263
- @modules.each do |m|
264
- mods << m.split(',')
265
- end
121
+ # run_modules
122
+ # exit_suite
266
123
 
267
- @modules = mods.flatten
268
-
269
- urls = @bscan_config['bscan.url']
270
- Log 2, "BScan.evt_register_callbacks urls: #{@modules_only} #{urls}"
271
-
272
- run_modules # run_modules without 'msg' will do static reqs only
273
- return if @modules_only
124
+ urls = @bscan_config['bscan.url']
125
+ Log 2, "BScan.evt_register_callbacks urls: #{@modules_only} #{urls}"
274
126
 
275
127
  if not urls
276
128
  Log 0, "BScan.evt_register_callbacks No URL's provided in config. Use bscan.url param. Multiple entries are OK"
@@ -297,58 +149,4 @@ module BScan
297
149
  end
298
150
 
299
151
 
300
- def log ll, stream
301
- stream.puts if true
302
- end
303
-
304
- def add_multi map,k,v
305
- if (map[k])
306
- ov = map[k];
307
- if (ov.kind_of?(Array))
308
- map[k] << v
309
- else
310
- map[k] = [ov,v]
311
- end
312
- else
313
- map[k] = v
314
- end
315
- end
316
-
317
- def init_stat
318
- @stat ||= {}
319
- @stat['start_time'] = Time.now.strftime("%Y-%m-%d %H:%M:%S")
320
- @stat['end_time'] = ''
321
- @stat['high'] = 0
322
- @stat['med'] = 0
323
- @stat['low'] = 0
324
- @stat['issues'] = ''
325
- @stat['urls'] = ''
326
- end
327
-
328
- def read_config file
329
-
330
- burp_config = {}
331
- bscan_config = {}
332
-
333
- begin
334
- open_in_path(file).each_line do |line|
335
- line.chomp!
336
- line.strip!
337
- next if (line =~ /^#/ or line.length < 1)
338
- data = line.split(/=/)
339
- val = nil
340
- val = data[1..-1].join('=') if data.size > 1
341
- if data[0] =~ /^bscan./
342
- add_multi(bscan_config,data[0],val)
343
- else
344
- burp_config[data[0]] = val
345
- end
346
- end
347
- rescue Exception => e
348
- $stderr.puts("BScan.read_config Error: can't read config file '#{file}', exception: #{e.message}")
349
- $stderr.puts(e.backtrace.join("\n"))
350
- Process.exit(3)
351
- end
352
- [burp_config, bscan_config]
353
- end
354
152