bscan 1.4.4 → 1.4.5

Sign up to get free protection for your applications and to get access to all the features.
data/CONFIG.rdoc CHANGED
@@ -30,7 +30,7 @@ path that configs refers to:
30
30
 
31
31
  see BscannerHelper#search_path for details
32
32
 
33
- == BScan Specific Parameters
33
+ == BScan Parameters
34
34
  * bscan.modules - see 'CONVENTIONS' for details
35
35
  * bscan.inactivity_to - inactivity is sec that triggers exit
36
36
  * bscan.issues=issues - output directory for findings/issues
@@ -39,6 +39,22 @@ see BscannerHelper#search_path for details
39
39
  * bscan.url - URL to spider, multiple entries are OK. Have no effect
40
40
  if scan.modules_only=true
41
41
 
42
+ == BScan SMTP Parameters
43
+ If specified an email will be sent. If 'include_report' is set
44
+ to 'true', the detailed zipped report will be attached. You'll ned
45
+ 'zip' gem to make attachments working.
46
+ * bscan.smtp.server=<server> SMTP server
47
+ * bscan.smtp.port=n SMTP port
48
+ Default: 25 for plain, 465 for SSL
49
+ * bscan.smtp.ssl=<true|false> Use SSL
50
+ Default - false
51
+ * bscan.smtp.to=<to_emails_coma_separated>
52
+ * bscan.smtp.from=<from_email>
53
+ * bscan.smtp.domain=<from_domain>
54
+ Deafult: from_email's domain
55
+ * bscan.smtp.include_report=<true|false> attach report as zip
56
+ Default: false
57
+
42
58
  == Modules Included to the Package
43
59
  * injector.rb - injects malicious patterns provided in a file (e.g. Google's
44
60
  fuzzdb) to URL or body parameters. It can also inject to pattern marked
data/README.rdoc CHANGED
@@ -78,6 +78,13 @@ To get help for config layout run:
78
78
 
79
79
  bscan --help config
80
80
 
81
+ == RUNNING, REGISTERING Burp Pro:
82
+ You need to register you burp.jar before you can run it headless
83
+
84
+ * Run your Burp as usual with GUI and provide you license.
85
+ After this is done, you can run it headless using 'bscan'
86
+
87
+
81
88
  == DOCUMENTATION, SAMPLES, RUNNING HEADLESSLY
82
89
  * Rdoc generated files: http://gryb.info/bscan/
83
90
  * After installing BScan's gem find the location of 'samples' dir:
@@ -88,8 +95,6 @@ To get help for config layout run:
88
95
  #!/bin/sh
89
96
  jruby -J-Xmx1024M -J-Djava.awt.headless=true -S bscan -c ../config/conf -L 2 -l bscan.log
90
97
 
91
-
92
-
93
98
  == CREDITS:
94
99
  * Burp and Burp Suite are trademarks of PortSwigger(ltd)
95
100
  Copyright 2012 PortSwigger Ltd. All rights reserved.
data/Rakefile CHANGED
@@ -10,7 +10,7 @@ begin
10
10
  gem.summary = %q{BScan is an extendable and configurable command line web application security scanner}
11
11
  gem.description = %q{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}
12
12
  gem.email = "oleg@gryb.info"
13
- gem.homepage = "http://sf.net/projects/b-scan/"
13
+ gem.homepage = "http://gryb.info/bscan"
14
14
  gem.authors = ["Oleg Gryb (ogryb)"]
15
15
  #gem.platform = "java"
16
16
  gem.test_files = ["test/bscan_test.rb"]
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.4.4
1
+ 1.4.5
data/bscan.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "bscan"
8
- s.version = "1.4.4"
8
+ s.version = "1.4.5"
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-13"
12
+ s.date = "2012-08-15"
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"]
@@ -32,16 +32,18 @@ Gem::Specification.new do |s|
32
32
  "lib/bscan/modules/many_threads.rb",
33
33
  "lib/bscan/modules/slowloris.rb",
34
34
  "lib/bscan/utils/bscan_helper.rb",
35
+ "lib/bscan/utils/mailer.rb",
35
36
  "release_notes.txt",
36
37
  "samples/config/big_request.txt",
37
38
  "samples/config/conf",
38
39
  "samples/config/injector.txt",
39
40
  "samples/config/request.txt",
41
+ "samples/config/xss.txt",
40
42
  "samples/headless-bscan.sh",
41
43
  "test.sh",
42
44
  "test/bscan_test.rb"
43
45
  ]
44
- s.homepage = "http://sf.net/projects/b-scan/"
46
+ s.homepage = "http://gryb.info/bscan"
45
47
  s.rdoc_options = ["--main", "README.rdoc"]
46
48
  s.require_paths = ["lib"]
47
49
  s.rubygems_version = "1.8.24"
data/lib/bscan.rb CHANGED
@@ -5,6 +5,7 @@ require 'buby'
5
5
  require 'getoptlong'
6
6
  require 'json'
7
7
  require 'bscan/utils/bscan_helper'
8
+ require 'bscan/utils/mailer'
8
9
  require 'java'
9
10
 
10
11
  class String
@@ -19,10 +20,12 @@ end
19
20
  module BScan
20
21
 
21
22
  include BscanHelper
23
+ include Mailer
22
24
 
23
25
  attr_accessor :activity
24
26
  attr_reader :modules_only
25
27
  attr_reader :bscan_config
28
+ attr_accessor :stat
26
29
 
27
30
  def Log (mtype, *msgs)
28
31
  pr = "Unknown:"
@@ -46,6 +49,7 @@ module BScan
46
49
  end
47
50
 
48
51
  def evt_commandline_args args
52
+ init_stat
49
53
  @cmd_params ||= JSON.parse args[0]
50
54
  @ll = @cmd_params['loglevel'].to_i
51
55
 
@@ -151,16 +155,22 @@ module BScan
151
155
  def write_issue_state issue
152
156
  # Log 2,"INSPECT: #{issue.http_messages[0].methods} #{issue.http_messages[0].inspect} #{issue.http_messages[0].to_s} "
153
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
+
154
163
  Log 2,"BScan.write_issue_state #{not @istream} #{issue.http_messages[0].methods} #{issue.http_messages[0].to_s} "
155
164
  @istream or return
156
165
  begin
157
- @istream.puts '#'*70,"#{issue.issue_name} : #{issue.url}",
158
- "Severity: #{issue.severity}(#{issue.confidence})",
159
- "Background: #{issue.issue_background}",
160
- "Details: #{issue.issue_detail}",
161
- "Remediation: #{issue.remediation_background}",
162
- "Request: #{issue.http_messages[0].req_str}",
163
- "Response: #{issue.http_messages[0].rsp_str}"
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}"
164
174
  # sync_save_state issue throws exceptions
165
175
  @istream.flush
166
176
  rescue Exception => e
@@ -169,9 +179,16 @@ module BScan
169
179
  end
170
180
  end
171
181
  def evt_application_closing
172
- Log 2,"BScan.evt_application_closing"
173
- @istream.close if @istream
174
- @log.close if @log
182
+ begin
183
+ Log 2,"BScan.evt_application_closing #{@bscan_config['bscan.smtp.server']} #{@bscan_config['bscan.smtp.to']}"
184
+ @istream.close if @istream
185
+ @stat['end_time'] = Time.now.strftime("%Y-%m-%d %H:%M:%S")
186
+ send_email if @bscan_config['bscan.smtp.server'] and @bscan_config['bscan.smtp.to']
187
+ @log.close if @log
188
+ rescue Exception => e
189
+ Log 0, "BScan.evt_application_closing Exception: #{e.message}"
190
+ Log 0, e.backtrace.join("\n")
191
+ end
175
192
  end
176
193
 
177
194
  def evt_register_callbacks cb
@@ -190,11 +207,12 @@ module BScan
190
207
  dt = Time.now.strftime("%y%m%d_%H%M%S")
191
208
  File.directory? @issues or %x{mkdir -p "#{@issues}"}
192
209
  @sstream = "#{@issues}/session.#{dt}.zip"
193
- @istream = File.open("#{@issues}/issues.#{dt}.txt","w")
210
+ ifile = "#{@issues}/issues.#{dt}.txt"
211
+ @istream = java.io.PrintStream.new(ifile)
212
+ @stat['issues'] = ifile
194
213
  rescue Exception => e
195
214
  Log 0, "BScan.evt_register_callbacks Can't create issues or session files, Exception: #{e.message}"
196
215
  Log 0, e.backtrace.join("\n")
197
-
198
216
  exit_suite
199
217
  end
200
218
  end
@@ -238,6 +256,7 @@ module BScan
238
256
  params.each_pair {|k,v| Log 2,"#{k}:#{v}"} # if k =~ /^(scanner|spider)/}
239
257
 
240
258
  @modules ||= @bscan_config['bscan.modules']
259
+ @modules ||= [] if not @modules
241
260
  @modules = [@modules] if not @modules.kind_of?(Array)
242
261
 
243
262
  mods = []
@@ -247,8 +266,8 @@ module BScan
247
266
 
248
267
  @modules = mods.flatten
249
268
 
250
- urls = @bscan_config['bscan.url']
251
- Log 2, "BScan.evt_register_callbacks urls: #{@modules_only} #{urls.join('|')}"
269
+ urls = @bscan_config['bscan.url']
270
+ Log 2, "BScan.evt_register_callbacks urls: #{@modules_only} #{urls}"
252
271
 
253
272
  run_modules # run_modules without 'msg' will do static reqs only
254
273
  return if @modules_only
@@ -295,6 +314,17 @@ def add_multi map,k,v
295
314
  end
296
315
  end
297
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
+
298
328
  def read_config file
299
329
 
300
330
  burp_config = {}
@@ -7,7 +7,7 @@ module Injector
7
7
  def run *args
8
8
 
9
9
  @bscan = args[0]
10
- @config ||= @bscan.instance_variable_get("@bscan_config")
10
+ @config ||= @bscan.bscan_config
11
11
  @bscan.activity[0]=true
12
12
 
13
13
  @prop_pref = 'bscan.injector.'
@@ -37,12 +37,15 @@ module BscanHelper
37
37
  Pathname.new(file).absolute? ? [file] : search_path.map! {|p| File.join(p,file)}
38
38
  end
39
39
 
40
- def open_in_path file
40
+ def open_in_path file,pathonly=false
41
41
  io = nil
42
42
  files = search_path_file(file)
43
43
  files.each do |p|
44
- io = File.open(p,"r") if File.file?(p)
45
- return io if io
44
+ if File.file?(p)
45
+ return p if pathonly
46
+ io = File.open(p,"r")
47
+ return io if io
48
+ end
46
49
  end
47
50
  raise "Can't find file in: #{files.join(':')}"
48
51
  end
@@ -0,0 +1,150 @@
1
+ require 'net/smtp'
2
+ require 'socket'
3
+
4
+
5
+ module Mailer
6
+
7
+ MARKER = "ABCDEFFEDCBA"
8
+
9
+ HEADERS =
10
+ %q{From: BScan-<ver> <from>
11
+ To: <to>
12
+ Subject: <subject>
13
+ Content-Type: multipart/mixed; boundary="<MARKER>"
14
+ MIME-Version: 1.0
15
+
16
+ --<MARKER>
17
+ }
18
+
19
+ SIMPLE =
20
+ %q{From: BScan-<ver> <from>
21
+ To: <to>
22
+ Subject: <subject>
23
+ Content-Type: text/plain; charset="UTF-8";
24
+
25
+ <BODY>}
26
+
27
+ BODY =
28
+ %q{
29
+ Start Time: <start_time>
30
+ End Time: <end_time>
31
+ High #: <high>
32
+ Med #: <med>
33
+ Low #: <low>
34
+ Issues: <issues>
35
+ URL's :
36
+ <urls>
37
+ }
38
+
39
+ MESSAGE =
40
+ %q{Content-Type: text/plain
41
+ Content-Transfer-Encoding:8bit
42
+
43
+ <BODY>
44
+ --<MARKER>
45
+ }
46
+
47
+ ATTACHMENT =
48
+ %q{Content-Type: application/zip; name="<filename>"
49
+ Content-Transfer-Encoding:base64
50
+ Content-Disposition: attachment; filename="<filename>"
51
+
52
+ <encoded>
53
+ --<MARKER>--
54
+ }
55
+
56
+ def pv par,defv=nil
57
+ val = bscan_config[@m_pref + par]
58
+ val ? val : defv
59
+ end
60
+
61
+ def sv par,defv=nil
62
+ val = @stat[ par]
63
+ val ? val : defv
64
+ end
65
+ def ver
66
+ file=::File.expand_path(File.join(::File.dirname(__FILE__), "../../../VERSION"))
67
+ ::File.file?(file) ? File.read(file).chomp : ''
68
+ end
69
+
70
+ def send_email
71
+ begin
72
+
73
+ @m_pref = 'bscan.smtp.'
74
+ srv = pv 'server',nil
75
+ ssl = pv 'ssl',false
76
+ defport = ssl ? 465 : 25
77
+ port = pv 'port',defport
78
+ from = pv 'from',nil
79
+ dfrom = $1 if from =~ /@(.+)/
80
+ domain = pv 'domain',dfrom
81
+ user = pv 'user',nil
82
+ pwd = pv 'pwd',nil
83
+ attach = pv 'include_report','false'
84
+ attach = attach=='true' ? true:false
85
+ to = pv 'to', nil
86
+ file = @stat['issues']
87
+ file ||= ''
88
+ raise "Can't send '#{file}' that doesn't exist" if attach && !File.file?(file)
89
+ file = File.absolute_path(file)
90
+
91
+ @stat['subject'] = sv 'subject', "BScan @ #{Socket.gethostname}"
92
+
93
+ Log 2,"Mailer.send_mail #{@stat} #{pv 'server'} #{pv 'from'} #{pv 'to'} #{pv 'ssl'} #{pv 'port'} #{pv 'domwin'} #{pv 'user'} "
94
+
95
+ raise "Params 'server', 'from', 'to', 'domain' are mandatory" if !srv or !from or !to or !domain
96
+
97
+ if (attach)
98
+ msg = HEADERS + MESSAGE + ATTACHMENT
99
+ msg.gsub!( /<MARKER>/ , MARKER)
100
+ msg.gsub!( /<filename>/ , File.basename(sv('issues'),'.*') + '.zip')
101
+ msg.sub!(/<encoded>/,zip_encode(file))
102
+ else
103
+ msg = SIMPLE
104
+ end
105
+
106
+ msg.sub!( /<BODY>/ , BODY)
107
+
108
+ @stat.each_key do |k|
109
+ Log 2,"Mailer.send_mail replacing <#{k}>"
110
+ msg.gsub!( /<#{k}>/ , k=='issues'?file:sv(k,'').to_s)
111
+ end
112
+
113
+ msg.sub!( /<from>/, "<#{from}>")
114
+ msg.sub!( /<to>/ , "<#{to}>")
115
+ msg.sub!( /<ver>/ , ver)
116
+
117
+ msg.gsub!(/\r?\n/,"\r\n")
118
+
119
+ to = to.split(',')
120
+
121
+ smtp = Net::SMTP.new srv,port
122
+ smtp.enable_ssl if ssl
123
+ if (user)
124
+ smtp.start(domain,user,pwd)
125
+ else
126
+ smtp.start(domain)
127
+ end
128
+ Log 2,"Mailer.send_mail send_message #{from} #{to}\n#{msg}"
129
+ smtp.send_message msg, from, to
130
+ smtp.finish
131
+ rescue Exception => e
132
+ Log 0, "Mailer.send Exception: #{e.message}"
133
+ Log 0, e.backtrace.join("\n")
134
+ end
135
+ end
136
+
137
+ def zip_encode f
138
+ require 'zip/zip'
139
+ fb = File.basename(f, '.*')
140
+ fbe = File.basename(f)
141
+ zipf = fb + '.zip'
142
+ zipp = File.join(File.dirname(f), zipf)
143
+ zip = Zip::ZipFile.open(zipp, Zip::ZipFile::CREATE)
144
+ zip.find_entry(fbe)?zip.replace(fbe,f):zip.add(fbe,f)
145
+ zip.close
146
+ content = File.read(zipp)
147
+ [content].pack("m")
148
+ end
149
+
150
+ end
data/release_notes.txt CHANGED
@@ -1,3 +1,8 @@
1
+ == 1.4.5
2
+ * Mailer added to send scan status and detailed reports over SMTP
3
+ * Issues are logged with Java's PrintStream
4
+ * Some bugs have been fixed
5
+
1
6
  == 1.4.4
2
7
  * Added a module for apache killer (apache_killer.rb)
3
8
  * Changed logging to use Java IO (Ruby's IO caused Java exceptions)
@@ -0,0 +1,2 @@
1
+ # An example of simple file for injector to find XSS vulns
2
+ <xss_check>
metadata CHANGED
@@ -2,14 +2,14 @@
2
2
  name: bscan
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 1.4.4
5
+ version: 1.4.5
6
6
  platform: ruby
7
7
  authors:
8
8
  - Oleg Gryb (ogryb)
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-08-13 00:00:00.000000000 Z
12
+ date: 2012-08-15 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: buby
@@ -50,15 +50,17 @@ files:
50
50
  - lib/bscan/modules/many_threads.rb
51
51
  - lib/bscan/modules/slowloris.rb
52
52
  - lib/bscan/utils/bscan_helper.rb
53
+ - lib/bscan/utils/mailer.rb
53
54
  - release_notes.txt
54
55
  - samples/config/big_request.txt
55
56
  - samples/config/conf
56
57
  - samples/config/injector.txt
57
58
  - samples/config/request.txt
59
+ - samples/config/xss.txt
58
60
  - samples/headless-bscan.sh
59
61
  - test.sh
60
62
  - test/bscan_test.rb
61
- homepage: http://sf.net/projects/b-scan/
63
+ homepage: http://gryb.info/bscan
62
64
  licenses: []
63
65
  post_install_message:
64
66
  rdoc_options: