bscan 2.0.1 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CONFIG.rdoc +6 -1
- data/README.rdoc +37 -36
- data/Rakefile +13 -1
- data/VERSION +1 -1
- data/bin/bscan +24 -6
- data/java/bin/bscan.jar +0 -0
- data/java/bin/burp/BurpExtender.class +0 -0
- data/java/build.sh +10 -0
- data/java/lib/jruby.jar +0 -0
- data/java/src/burp/BurpExtender.java +146 -0
- data/lib/bscan.jar +0 -0
- data/lib/bscan.rb +191 -48
- data/lib/bscan/modules/injector.rb +25 -9
- data/lib/bscan/modules/jboss_vulns.rb +10 -0
- data/lib/bscan/modules/kill_apache.rb +10 -0
- data/lib/bscan/modules/many_threads.rb +10 -0
- data/lib/bscan/modules/slowloris.rb +10 -0
- data/lib/bscan/utils/bscan_helper.rb +162 -10
- data/lib/bscan/utils/mailer.rb +11 -0
- data/lib/burp.jar +0 -0
- data/release_notes.txt +8 -0
- data/samples/config/burp.conf +13 -0
- data/test/bscan_test.rb +12 -0
- metadata +20 -32
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 7cd2c132cb1c5719f640c8820bcea3eb7b0fa121
|
4
|
+
data.tar.gz: db78ba320a6d30b6d587b23f38d5b69f2841b0b7
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1de53e763e7160627e70880ffeb82eee7991aab9cfcedc0ae42627ea200630fc708737910614ffc0cfb2e2e762832641d9a47f5f6e252252e9528154f8c64c0d
|
7
|
+
data.tar.gz: 1992b9fcac4775b3f5cdafb69c5b517b67b81bd9739daad4b40f9812d6c0abbde65ba4d1d80e5c387c2147afddc03e773ac4a5072a260cdfca79f75900062e1b
|
data/CONFIG.rdoc
CHANGED
@@ -32,12 +32,17 @@ see BscannerHelper#search_path for details
|
|
32
32
|
|
33
33
|
== BScan Parameters
|
34
34
|
* bscan.modules - see 'CONVENTIONS' for details
|
35
|
-
* bscan.inactivity_to - inactivity is sec that triggers exit
|
35
|
+
* bscan.inactivity_to - inactivity is sec that triggers exit and generating a report
|
36
|
+
* bscan.run_proxy - run Burp proxy and collect vulns in passive mode
|
37
|
+
Default: false
|
38
|
+
* bscan.report_url_prefix=<URL-prefix>|<path-to-report-file.xml> sort reports by URL
|
39
|
+
* bscan.report_def_name=<path-to-report-file.xml> default report file
|
36
40
|
* bscan.issues=issues - output directory for findings/issues
|
37
41
|
* scan.modules_only - if true, only modules with static requests
|
38
42
|
will run (no spider)
|
39
43
|
* bscan.url - URL to spider, multiple entries are OK. Have no effect
|
40
44
|
if scan.modules_only=true
|
45
|
+
* proxy.listener0=1.<port>.1.0..0.0.1.0..0..0..0. - this is a burp's param, used to change a proxy's port number
|
41
46
|
|
42
47
|
== BScan SMTP Parameters
|
43
48
|
If specified an email will be sent. If 'include_report' is set
|
data/README.rdoc
CHANGED
@@ -2,9 +2,12 @@
|
|
2
2
|
== DESCRIPTION:
|
3
3
|
BScan is a configurable and extendable command line application security scanner.
|
4
4
|
It's built on top of arguably the most popular commercial security testing tool
|
5
|
-
Burp Suite from PortSwigger
|
5
|
+
Burp Suite from PortSwigger
|
6
6
|
|
7
7
|
== USE CASES:
|
8
|
+
* Run Burp proxy from a command line and passively scan, e.g. QA regression traffic:
|
9
|
+
jruby -S bscan -c bscan.config -l bscan.log
|
10
|
+
|
8
11
|
* Run security scans offline from a command line headless (without UI).
|
9
12
|
|
10
13
|
* Change the type of scanning easily by changing configuration parameters.
|
@@ -22,13 +25,11 @@ Burp Suite from PortSwigger and Buby from Eric Monti and Timur Duehr
|
|
22
25
|
== DOCS, CODE, etc.:
|
23
26
|
* Documentation: http://gryb.info/bscan
|
24
27
|
* Git repo: git://git.code.sf.net/p/b-scan/trunk
|
25
|
-
* Sourceforge: http://sf.net/projects/b-scan/
|
26
28
|
* Gem package: http://gemcutter.org (see 'BUILD/INSTALL')
|
27
29
|
|
28
30
|
== REQUIREMENTS:
|
29
31
|
* JRuby - http://jruby.org
|
30
32
|
* Burp pro if you want to use default Burp's scanners
|
31
|
-
* Buby 1.3.1 (see http://emonti.github.com/buby/) (not neccessary for modules_only mode)
|
32
33
|
|
33
34
|
== BUILD/INSTALL:
|
34
35
|
|
@@ -37,14 +38,13 @@ Burp Suite from PortSwigger and Buby from Eric Monti and Timur Duehr
|
|
37
38
|
sudo jruby -S gem install buby -d --source=http://gemcutter.org (not necessary for modules_only)
|
38
39
|
sudo jruby -S gem install bscan --source=http://gemcutter.org
|
39
40
|
|
40
|
-
After Buby and BScan are installed, you'll need to link BScan to Burp's JAR (see below)
|
41
41
|
|
42
42
|
=== Building Manually from Git
|
43
43
|
|
44
44
|
git git://git.code.sf.net/p/b-scan/trunk <src_dir>
|
45
45
|
cd <src_dir>
|
46
|
-
jruby -S
|
47
|
-
jruby -S gem install
|
46
|
+
jruby -S rake build gemspec
|
47
|
+
sudo jruby -S gem install --local pkg/bscan-*.gem (sudo might not be necessary on some systems)
|
48
48
|
bscan --help
|
49
49
|
bscan --help config
|
50
50
|
|
@@ -52,22 +52,29 @@ Burp Suite from PortSwigger and Buby from Eric Monti and Timur Duehr
|
|
52
52
|
|
53
53
|
* This step is not neccessary for modules_only mode
|
54
54
|
|
55
|
-
|
56
|
-
you'll need to link them to a Burp's JAR.
|
55
|
+
Java code is used to register a Burp extension and to bind Burp's events to Ruby functions.
|
57
56
|
|
58
|
-
|
59
|
-
and then create a link from that directory to a Burp's jar:
|
57
|
+
You'll need to re-compile it in at least three following cases:
|
60
58
|
|
61
|
-
|
62
|
-
|
59
|
+
1. You want to link to your own license version of Burp's jar. The default BScan comes with a public Burp's version.
|
60
|
+
2. You want to update the Burp's jar when a new version is released (either public or licensed).
|
61
|
+
3. You want to change the Java code.
|
63
62
|
|
64
|
-
|
65
|
-
|
66
|
-
jruby -e 'puts $:'
|
63
|
+
Use the following commands to recompile Java and to put a generated jar to the right location
|
67
64
|
|
68
|
-
|
69
|
-
|
70
|
-
|
65
|
+
cd <src-dir>/java
|
66
|
+
./build.sh <path-to-burp-jar>
|
67
|
+
|
68
|
+
Verify that the Java build was successful by typing:
|
69
|
+
|
70
|
+
ls -l ../lib
|
71
|
+
|
72
|
+
You should look for two jar files in that directory:
|
73
|
+
|
74
|
+
bscan.jar
|
75
|
+
burp.jar
|
76
|
+
|
77
|
+
They will be deployed to JRuby locations when you install the gem
|
71
78
|
|
72
79
|
== TEST AND USAGE EXAMPLE:
|
73
80
|
|
@@ -84,9 +91,8 @@ You need to register you burp.jar before you can run it headless
|
|
84
91
|
|
85
92
|
* Not neccessary for modules_only mode
|
86
93
|
|
87
|
-
*
|
88
|
-
|
89
|
-
|
94
|
+
* Either run Burp with UI and upload the license there or run it headless and copy/paste the license when prompted.
|
95
|
+
* No license will be asked for a public version.
|
90
96
|
|
91
97
|
== DOCUMENTATION, SAMPLES, RUNNING HEADLESSLY
|
92
98
|
* Rdoc generated files: http://gryb.info/bscan/
|
@@ -103,8 +109,7 @@ You need to register you burp.jar before you can run it headless
|
|
103
109
|
Copyright 2012 PortSwigger Ltd. All rights reserved.
|
104
110
|
See http://portswigger.net for license terms.
|
105
111
|
|
106
|
-
* Buby
|
107
|
-
written by Eric Monti @ Matasano Security. Matasano Security claims no
|
112
|
+
* Buby BurpExtender.java has been initially implemented by Eric Monti @ Matasano Security and modified by Oleg Gryb. Matasano Security claims no
|
108
113
|
professional or legal affiliation with PortSwigger LTD.
|
109
114
|
|
110
115
|
* This BScan tools and library written by Oleg Gryb who claims no professional or
|
@@ -121,8 +126,7 @@ You need to register you burp.jar before you can run it headless
|
|
121
126
|
Copyright 2012 PortSwigger Ltd. All rights reserved.
|
122
127
|
See http://portswigger.net for license terms.
|
123
128
|
|
124
|
-
* The
|
125
|
-
both freely available under the terms of the MIT public license:
|
129
|
+
* The BurpExtender implementation is freely available under the terms of the MIT public and BSD 2-Clause license:
|
126
130
|
|
127
131
|
(The MIT License)
|
128
132
|
|
@@ -134,15 +138,12 @@ The above copyright notice and this permission notice shall be included in all c
|
|
134
138
|
|
135
139
|
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
136
140
|
|
137
|
-
* The BScan tools and library are freely available under the terms of the
|
138
|
-
|
139
|
-
(The MIT License)
|
140
|
-
|
141
|
-
Copyright (C) 2012 Oleg Gryb
|
142
|
-
|
143
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
144
|
-
|
145
|
-
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
146
|
-
|
147
|
-
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
141
|
+
* The BScan tools and library are freely available under the terms of the BSD 2-Clause license:
|
148
142
|
|
143
|
+
Copyright (C) 2015, Oleg Gryb
|
144
|
+
All rights reserved.
|
145
|
+
|
146
|
+
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
147
|
+
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
148
|
+
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
149
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/Rakefile
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
=begin
|
2
|
+
Copyright (c) 2015, Oleg Gryb
|
3
|
+
All rights reserved.
|
4
|
+
|
5
|
+
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
6
|
+
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
7
|
+
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
8
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
9
|
+
=end
|
10
|
+
|
1
11
|
require 'rubygems'
|
2
12
|
require 'rake'
|
3
13
|
require 'rake/clean'
|
@@ -5,8 +15,10 @@ require 'rake/clean'
|
|
5
15
|
begin
|
6
16
|
require 'jeweler'
|
7
17
|
Jeweler::Tasks.new do |gem|
|
8
|
-
|
18
|
+
# gem.add_dependency('buby', '>= 1.3.1')
|
19
|
+
# gem.add_dependency(nil)
|
9
20
|
gem.name = "bscan"
|
21
|
+
gem.license = "BSD 2-Clause"
|
10
22
|
gem.summary = %q{BScan is an extendable and configurable command line web application security scanner}
|
11
23
|
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
24
|
gem.email = "oleg@gryb.info"
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
3.0.0
|
data/bin/bscan
CHANGED
@@ -1,24 +1,37 @@
|
|
1
1
|
#!/usr/bin/env jruby
|
2
2
|
|
3
|
+
=begin
|
4
|
+
Copyright (c) 2015, Oleg Gryb
|
5
|
+
All rights reserved.
|
6
|
+
|
7
|
+
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
8
|
+
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
9
|
+
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
10
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
11
|
+
=end
|
12
|
+
|
3
13
|
#require File.expand_path(File.join(File.dirname(__FILE__), %w[.. lib bscan]))
|
4
14
|
$: << File.expand_path(File.join(File.dirname(__FILE__), %w[.. lib]))
|
5
15
|
|
16
|
+
require 'java'
|
6
17
|
require 'getoptlong'
|
7
18
|
require 'bscan/utils/bscan_helper'
|
8
19
|
require 'json'
|
9
20
|
|
21
|
+
|
10
22
|
include BscanHelper
|
11
23
|
|
12
24
|
def usage
|
13
25
|
|
14
26
|
puts %q{
|
15
27
|
USAGE: jruby [-J-Xmx<nnn>M] [-J-Djava.awt.headless=true] -S bscan --config path_to_file \
|
16
|
-
[--help [config]] [--loglevel n] [--logfile file] [--version]
|
28
|
+
[--configonly] [--help [config]] [--loglevel n] [--logfile file] [--version]
|
17
29
|
|
18
30
|
-J-Xmx<nnn>M tells JVM to set maximum heap size to <nnn> MB
|
19
31
|
-J-Djava.awt.headless=true tells JVM to run it headless (no UI)
|
20
32
|
-S tells jruby to search for bscan in a PATH
|
21
33
|
--config -c path_to_file path to config (see 'CONFIG' section in rdoc)
|
34
|
+
--configonly -O configure burp and exit
|
22
35
|
--help -h this help
|
23
36
|
--help config config help
|
24
37
|
--loglevel -L 0 errors, 1 - warning, 2 - info, 3 - debug
|
@@ -64,6 +77,7 @@ def get_cmd_params
|
|
64
77
|
[ '--help', '-h', GetoptLong::OPTIONAL_ARGUMENT ],
|
65
78
|
[ '--version', '-v', GetoptLong::NO_ARGUMENT ],
|
66
79
|
[ '--config', '-c', GetoptLong::REQUIRED_ARGUMENT ],
|
80
|
+
[ '--configonly', '-O', GetoptLong::NO_ARGUMENT ],
|
67
81
|
[ '--loglevel', '-L', GetoptLong::REQUIRED_ARGUMENT ],
|
68
82
|
[ '--logfile', '-l', GetoptLong::REQUIRED_ARGUMENT ]
|
69
83
|
)
|
@@ -82,6 +96,8 @@ def get_cmd_params
|
|
82
96
|
exit(1)
|
83
97
|
when '--config'
|
84
98
|
params['burp_config'], params['bscan_config'] = read_config(arg)
|
99
|
+
when '--configonly'
|
100
|
+
params['burp_config_only'] = true
|
85
101
|
when '--loglevel'
|
86
102
|
params['loglevel'] = arg
|
87
103
|
when '--logfile'
|
@@ -108,10 +124,12 @@ init_internals params
|
|
108
124
|
run_modules self
|
109
125
|
exit 0 if @modules_only
|
110
126
|
|
111
|
-
require 'buby'
|
112
|
-
require 'burp'
|
127
|
+
#require 'buby'
|
128
|
+
#require 'burp'
|
113
129
|
require 'bscan'
|
130
|
+
include BScan
|
131
|
+
|
132
|
+
#$burp = Buby.new()
|
133
|
+
#$burp.extend(BScan)
|
114
134
|
|
115
|
-
|
116
|
-
$burp.extend(BScan)
|
117
|
-
$burp.start_burp([params.to_json])
|
135
|
+
start_burp([params.to_json], ARGV)
|
data/java/bin/bscan.jar
ADDED
Binary file
|
Binary file
|
data/java/build.sh
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
|
3
|
+
[ -f "$1" ] || (echo Usage: ./build.sh path_to_burp_jar && exit 1)
|
4
|
+
|
5
|
+
cp "$1" lib/.
|
6
|
+
rm -rf bin/burp bin/bscan*
|
7
|
+
javac -cp 'lib/*' -d bin src/burp/BurpExtender.java
|
8
|
+
jar -cf bin/bscan.jar -C bin burp/BurpExtender.class
|
9
|
+
cp bin/bscan.jar ../lib/.
|
10
|
+
cp lib/burp*.jar ../lib/burp.jar
|
data/java/lib/jruby.jar
ADDED
Binary file
|
@@ -0,0 +1,146 @@
|
|
1
|
+
package burp;
|
2
|
+
|
3
|
+
import burp.*;
|
4
|
+
|
5
|
+
import org.jruby.*;
|
6
|
+
import org.jruby.javasupport.JavaUtil;
|
7
|
+
import org.jruby.runtime.ThreadContext;
|
8
|
+
import org.jruby.runtime.builtin.IRubyObject;
|
9
|
+
import org.jruby.RubyBoolean;
|
10
|
+
|
11
|
+
import java.io.File;
|
12
|
+
import java.util.HashMap;
|
13
|
+
import java.util.List;
|
14
|
+
import java.util.Map;
|
15
|
+
|
16
|
+
import javax.swing.JMenuItem;
|
17
|
+
|
18
|
+
public class BurpExtender implements IBurpExtender, IHttpListener, IScannerListener, ISessionHandlingAction {
|
19
|
+
|
20
|
+
// Internal reference to hold the ruby Burp handler
|
21
|
+
private static IRubyObject r_obj = null;
|
22
|
+
private IBurpExtenderCallbacks burp_cb = null;
|
23
|
+
public static void setHandler(IRubyObject hnd) { r_obj = hnd; }
|
24
|
+
public static IRubyObject getHandler() { return r_obj; }
|
25
|
+
|
26
|
+
public BurpExtender() {
|
27
|
+
if (r_obj !=null)
|
28
|
+
r_obj.callMethod(ctx(r_obj), "evt_extender_init", to_ruby(rt(r_obj), this));
|
29
|
+
}
|
30
|
+
|
31
|
+
public void setCommandLineArgs(String[] args) {
|
32
|
+
if(r_obj != null)
|
33
|
+
r_obj.callMethod(ctx(r_obj), "evt_commandline_args", to_ruby(rt(r_obj), args));
|
34
|
+
}
|
35
|
+
|
36
|
+
@Override
|
37
|
+
public void registerExtenderCallbacks(IBurpExtenderCallbacks cb) {
|
38
|
+
this.burp_cb = cb;
|
39
|
+
cb.setExtensionName("BScan");
|
40
|
+
cb.issueAlert("registering JRuby handler callbacks for BScan");
|
41
|
+
cb.registerHttpListener(this);
|
42
|
+
cb.registerScannerListener(this);
|
43
|
+
cb.registerSessionHandlingAction(this);
|
44
|
+
// this.burp_cb.issueAlert("Listeners: " + cb.getHttpListeners().get(0).toString());
|
45
|
+
if(r_obj != null) {
|
46
|
+
IRubyObject args[] = {to_ruby(rt(r_obj), cb), RubyBoolean.newBoolean(rt(r_obj), false)};
|
47
|
+
r_obj.callMethod(ctx(r_obj), "evt_register_callbacks", args[0]);
|
48
|
+
}
|
49
|
+
}
|
50
|
+
/*
|
51
|
+
public void processHttpMessage(
|
52
|
+
String toolName,
|
53
|
+
boolean messageIsRequest,
|
54
|
+
IHttpRequestResponse messageInfo )
|
55
|
+
{
|
56
|
+
this.burp_cb.issueAlert("HttpMessage from: " + toolName + " " + messageIsRequest);
|
57
|
+
if (r_obj != null && r_obj.respondsTo("evt_http_message")) {
|
58
|
+
Ruby rt = rt(r_obj);
|
59
|
+
IRubyObject http_msg[] = {
|
60
|
+
to_ruby(rt, toolName),
|
61
|
+
to_ruby(rt, messageIsRequest),
|
62
|
+
to_ruby(rt, messageInfo)
|
63
|
+
};
|
64
|
+
|
65
|
+
r_obj.callMethod(ctx(r_obj), "evt_http_message", http_msg);
|
66
|
+
}
|
67
|
+
}
|
68
|
+
*/
|
69
|
+
|
70
|
+
@Override
|
71
|
+
public void processHttpMessage(int toolFlag, boolean messageIsRequest, IHttpRequestResponse messageInfo)
|
72
|
+
{
|
73
|
+
// this.burp_cb.issueAlert("HttpMessage from: " + toolFlag + " " + messageIsRequest);
|
74
|
+
if (r_obj != null) {
|
75
|
+
Ruby rt = rt(r_obj);
|
76
|
+
IRubyObject http_msg[] = {
|
77
|
+
to_ruby(rt, toolFlag),
|
78
|
+
to_ruby(rt, messageIsRequest),
|
79
|
+
to_ruby(rt, messageInfo)
|
80
|
+
};
|
81
|
+
|
82
|
+
// this.burp_cb.issueAlert("HttpMessage from: " + toolFlag);
|
83
|
+
r_obj.callMethod(ctx(r_obj), "evt_http_message", http_msg);
|
84
|
+
}
|
85
|
+
}
|
86
|
+
|
87
|
+
@Override
|
88
|
+
public void newScanIssue(IScanIssue issue) {
|
89
|
+
|
90
|
+
// this.burp_cb.issueAlert("newScanIssue: " + issue.getIssueDetail());
|
91
|
+
if (r_obj != null)
|
92
|
+
r_obj.callMethod(ctx(r_obj), "evt_scan_issue", to_ruby(rt(r_obj), issue));
|
93
|
+
}
|
94
|
+
|
95
|
+
|
96
|
+
public void applicationClosing() {
|
97
|
+
if (r_obj != null)
|
98
|
+
r_obj.callMethod(ctx(r_obj), "evt_application_closing");
|
99
|
+
}
|
100
|
+
|
101
|
+
private ThreadContext ctx(IRubyObject obj) {
|
102
|
+
return rt(obj).getThreadService().getCurrentContext();
|
103
|
+
}
|
104
|
+
|
105
|
+
private Ruby rt(IRubyObject obj) {
|
106
|
+
return obj.getRuntime();
|
107
|
+
}
|
108
|
+
|
109
|
+
public IRubyObject to_ruby(Ruby rt, Object obj) {
|
110
|
+
return JavaUtil.convertJavaToUsableRubyObject(rt, obj);
|
111
|
+
}
|
112
|
+
@Override
|
113
|
+
public String getActionName() {
|
114
|
+
String ret = "";
|
115
|
+
// this.burp_cb.issueAlert("getActionName");
|
116
|
+
if (r_obj != null)
|
117
|
+
ret = r_obj.callMethod(ctx(r_obj), "evt_get_action_name").asJavaString();
|
118
|
+
// this.burp_cb.issueAlert("getActionName " + ret);
|
119
|
+
return ret;
|
120
|
+
}
|
121
|
+
@Override
|
122
|
+
public void performAction(IHttpRequestResponse req,
|
123
|
+
IHttpRequestResponse[] macros) {
|
124
|
+
// this.burp_cb.issueAlert("perfromAction");
|
125
|
+
|
126
|
+
if (r_obj != null)
|
127
|
+
r_obj.callMethod(ctx(r_obj), "evt_perfrom_action", to_ruby(rt(r_obj), req));
|
128
|
+
}
|
129
|
+
|
130
|
+
public void loadConfig (RubyHash rh, String defConfigFile) {
|
131
|
+
|
132
|
+
if (defConfigFile != null) {
|
133
|
+
this.burp_cb.restoreState(new File(defConfigFile));
|
134
|
+
}
|
135
|
+
|
136
|
+
Map<String,String> map = new HashMap<String,String>();
|
137
|
+
for (Object k : rh.keys()) {
|
138
|
+
map.put((String) k, (String) rh.get(k));
|
139
|
+
}
|
140
|
+
this.burp_cb.loadConfig(map); // this will set custom config
|
141
|
+
// this.burp_cb.issueAlert("Config loaded");
|
142
|
+
// this.burp_cb.issueAlert("Listeners after load: " + this.burp_cb.getHttpListeners().get(0).toString());
|
143
|
+
}
|
144
|
+
|
145
|
+
}
|
146
|
+
|
data/lib/bscan.jar
ADDED
Binary file
|
data/lib/bscan.rb
CHANGED
@@ -1,54 +1,173 @@
|
|
1
1
|
#!/usr/bin/env jruby
|
2
2
|
|
3
|
-
|
3
|
+
|
4
|
+
=begin
|
5
|
+
Copyright (c) 2015, Oleg Gryb
|
6
|
+
All rights reserved.
|
7
|
+
|
8
|
+
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
9
|
+
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
10
|
+
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
11
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
12
|
+
=end
|
13
|
+
|
4
14
|
require 'getoptlong'
|
5
15
|
require 'bscan/utils/bscan_helper'
|
6
16
|
require 'bscan/utils/mailer'
|
7
17
|
require 'java'
|
8
18
|
require 'json'
|
19
|
+
require 'bscan.jar'
|
20
|
+
require 'burp.jar'
|
9
21
|
|
10
22
|
module BScan
|
11
23
|
|
12
24
|
include BscanHelper
|
13
25
|
include Mailer
|
14
26
|
|
27
|
+
def start_burp args, arg_strs
|
28
|
+
Java.burp.BurpExtender.handler = self
|
29
|
+
init_internals JSON.parse(args[0])
|
30
|
+
Java.burp.StartBurp.main(arg_strs.to_java(:string))
|
31
|
+
|
32
|
+
end
|
15
33
|
|
34
|
+
def evt_extender_init ext
|
35
|
+
@burp_extender = ext
|
36
|
+
Log 2, "#"*70, "# BScan.evt_extender_init EXT: #{ext.toString}", "#"*70
|
37
|
+
end
|
38
|
+
|
16
39
|
def evt_commandline_args args
|
17
40
|
init_internals JSON.parse(args[0])
|
18
41
|
end
|
19
42
|
|
43
|
+
def get_filtered_issues issues
|
44
|
+
|
45
|
+
info = get_bool_prop('bscan.ignore_info')
|
46
|
+
low = get_bool_prop('bscan.ignore_low')
|
47
|
+
medium = get_bool_prop('bscan.ignore_medium')
|
48
|
+
high = get_bool_prop('bscan.ignore_high')
|
49
|
+
|
50
|
+
return issues if (not (info or low or medium or high))
|
51
|
+
|
52
|
+
filtered = []
|
53
|
+
issues.each do |i|
|
54
|
+
# puts "=============ISSUE==================="
|
55
|
+
# puts i
|
56
|
+
# puts i.getSeverity()
|
57
|
+
# i.getClass().methods.each do |m|
|
58
|
+
# p m.getName()
|
59
|
+
# end
|
60
|
+
# puts
|
61
|
+
case i.getSeverity()
|
62
|
+
when 'Information'
|
63
|
+
filtered.push(i) if not info
|
64
|
+
when 'Low'
|
65
|
+
filtered.push(i) if not low
|
66
|
+
when 'Medium'
|
67
|
+
filtered.push(i) if not medium
|
68
|
+
when 'High'
|
69
|
+
filtered.push(i) if not high
|
70
|
+
end
|
71
|
+
end
|
72
|
+
return filtered
|
73
|
+
end
|
20
74
|
|
75
|
+
def gen_report
|
76
|
+
issues = nil
|
77
|
+
if not @url_prefs
|
78
|
+
issues = @burp_cb.getScanIssues(nil)
|
79
|
+
file = "report.xml"
|
80
|
+
file = @bscan_config['bscan.report_def_name'] if @bscan_config['bscan.report_def_name']
|
81
|
+
file = File.expand_path(File.join(@issues, [file])) if @issues
|
82
|
+
gen_report_params(issues,file)
|
83
|
+
else
|
84
|
+
i=1
|
85
|
+
@url_prefs.each do |url_name|
|
86
|
+
u, n = url_name.split('|')
|
87
|
+
n = 'pref' + i.to_s if not n
|
88
|
+
i += 1
|
89
|
+
issues = @burp_cb.getScanIssues(u)
|
90
|
+
n = File.expand_path(File.join(@issues, [n])) if @issues
|
91
|
+
gen_report_params(issues,n)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
def gen_report_params issues, file
|
96
|
+
io = Java.java.io.File.new(file.to_java(:string))
|
97
|
+
filtered = get_filtered_issues(issues)
|
98
|
+
@burp_cb.generateScanReport("XML".to_java(:string), filtered, io)
|
99
|
+
Log 2, "#"*70, "# BScan.gen_report: #{file} #{io.to_s} #{filtered.to_s}", "#"*70
|
100
|
+
end
|
21
101
|
|
22
|
-
def
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
102
|
+
def evt_get_action_name
|
103
|
+
Log 2, "# BScan.evt_get_action_name"
|
104
|
+
ret = ''
|
105
|
+
acts = get_action
|
106
|
+
Log 2, "# BScan.evt_get_action_name"
|
107
|
+
ret = acts.join('+') if acts.size > 0
|
108
|
+
ret
|
109
|
+
end
|
110
|
+
|
111
|
+
def evt_perfrom_action req
|
112
|
+
acts = get_action
|
113
|
+
pars = get_action_params
|
114
|
+
Log 3, "BScan.evt_perform_action #{acts[0]} #{pars[0]}"
|
115
|
+
msg_info = @burp_cb.getHelpers().analyzeRequest(req)
|
116
|
+
msg_body = req.getRequest()[msg_info.getBodyOffset()..-1]
|
117
|
+
i = 0
|
118
|
+
acts.each do |a|
|
119
|
+
par = pars[i]
|
120
|
+
i++
|
121
|
+
case a
|
122
|
+
when 'add_header'
|
123
|
+
Log 3, "BScan.evt_perform_action #{msg_info.getRequest().to_s} #{a} #{par}"
|
124
|
+
hdrs = msg_info.getHeaders()
|
125
|
+
hdrs.add(par.to_java(:string))
|
126
|
+
msg = @burp_cb.getHelpers().buildHttpMessage(hdrs, msg_body)
|
127
|
+
@burp_cb.issueAlert(@burp_cb.getHelpers().bytesToString(msg))
|
128
|
+
req.setRequest(msg)
|
31
129
|
end
|
32
130
|
end
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
131
|
+
end
|
132
|
+
|
133
|
+
def evt_http_message(tool_name, is_request, message_info)
|
134
|
+
# super(tool_name, is_request, message_info)
|
135
|
+
begin
|
136
|
+
Log 3, "BScan.evt_http_message #{tool_name} #{Java.burp.IBurpExtenderCallbacks.TOOL_SPIDER} #{is_request} #{message_info.to_s}"
|
137
|
+
if tool_name == Java.burp.IBurpExtenderCallbacks.TOOL_SCANNER or tool_name == 'scanner'
|
138
|
+
if is_request
|
139
|
+
Log 2, "#"*70, "# BScan.evt_http_message REQUEST: #{message_info.url.toString}, tool: #{tool_name}", "#"*70
|
140
|
+
Log 3, "BScan.evt_http_message #{message_info.getRequest()}", ""
|
141
|
+
else
|
142
|
+
Log 2, "# BScan.evt_http_message RESPONSE CODE: #{message_info.statusCode}", ""
|
143
|
+
Log 3, "BScan.evt_http_message #{message_info.getResponse()}", ""
|
44
144
|
end
|
45
|
-
|
46
|
-
|
145
|
+
end
|
146
|
+
if tool_name == Java.burp.IBurpExtenderCallbacks.TOOL_SPIDER or tool_name == 'spider'\
|
147
|
+
or tool_name == Java.burp.IBurpExtenderCallbacks.TOOL_PROXY or tool_name == 'proxy'
|
148
|
+
if not is_request
|
149
|
+
@activity[0] = true
|
150
|
+
https = message_info.getProtocol() == "https" ? true : false
|
151
|
+
Log 2, "BScan.evt_http_message Passively scanning: #{message_info.url.to_string}"
|
152
|
+
do_passive_scan(message_info.getHost(), message_info.getPort(), https, message_info.getRequest(), message_info.getResponse())
|
153
|
+
if (is_in_scope(message_info.url) and not excluded? message_info.url)
|
154
|
+
Log 2, "BScan.evt_http_message Actively scanning: #{message_info.url.to_string}"
|
155
|
+
# isqi = do_active_scan(message_info.getHost(), message_info.getPort(), https, message_info.getRequest(), [])
|
156
|
+
isqi = do_active_scan(message_info.getHost(), message_info.getPort(), https, message_info.getRequest())
|
157
|
+
@queue.push(isqi)
|
158
|
+
run_modules self, message_info
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
rescue Exception => e
|
163
|
+
Log 0, "BScan.evt_http_message Exception: #{e.message}"
|
164
|
+
Log 0, e.backtrace.join("\n")
|
165
|
+
end
|
47
166
|
end
|
48
167
|
|
49
168
|
|
50
169
|
def evt_scan_issue issue
|
51
|
-
super(issue)
|
170
|
+
# super(issue)
|
52
171
|
# Buby::HttpRequestResponseHelper.implant(issue.http_messages)
|
53
172
|
write_issue_state issue
|
54
173
|
end
|
@@ -64,10 +183,14 @@ module BScan
|
|
64
183
|
def evt_application_closing
|
65
184
|
begin
|
66
185
|
Log 2,"BScan.evt_application_closing #{@bscan_config['bscan.smtp.server']} #{@bscan_config['bscan.smtp.to']}"
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
186
|
+
if not @load_config_flag
|
187
|
+
@istream.close if @istream
|
188
|
+
@stat['end_time'] = Time.now.strftime("%Y-%m-%d %H:%M:%S")
|
189
|
+
send_email if @bscan_config['bscan.smtp.server'] and @bscan_config['bscan.smtp.to']
|
190
|
+
@log.close if @log
|
191
|
+
# exit_suite false
|
192
|
+
end
|
193
|
+
@load_config_flag = false
|
71
194
|
rescue Exception => e
|
72
195
|
Log 0, "BScan.evt_application_closing Exception: #{e.message}"
|
73
196
|
Log 0, e.backtrace.join("\n")
|
@@ -75,7 +198,8 @@ module BScan
|
|
75
198
|
end
|
76
199
|
|
77
200
|
def evt_register_callbacks cb
|
78
|
-
super(cb)
|
201
|
+
# super(cb)
|
202
|
+
@burp_cb = cb
|
79
203
|
@burp ||= self
|
80
204
|
begin
|
81
205
|
Log 2, "="*30, "BScan.evt_register_callbacks registring, log = #{@cmd_params['logfile']} ", "="*30
|
@@ -84,14 +208,18 @@ module BScan
|
|
84
208
|
@queue ||= []
|
85
209
|
@inactivity_to = @bscan_config['bscan.inactivity_to']
|
86
210
|
@inactivity_to ||= '30'
|
211
|
+
@max_proxy_time ||= '30'
|
87
212
|
@inactivity_to = @inactivity_to.to_i
|
213
|
+
@max_proxy_time = @max_proxy_time.to_i
|
88
214
|
# Will exit if @activity = 0 and @queue is empty two times
|
89
215
|
if @monitor == nil
|
90
216
|
Log 2, "="*30, "BScan.evt_register_callbacks Starting Monitor", "="*30
|
91
217
|
@monitor = Thread.new(@queue, @activity) {|q,a|
|
92
218
|
cnt=0;
|
93
219
|
while (true)
|
94
|
-
sleep(@inactivity_to/2)
|
220
|
+
sleep(@inactivity_to/2)
|
221
|
+
@max_proxy_time -= @inactivity_to/2
|
222
|
+
|
95
223
|
q.delete_if {|e| e.getPercentageComplete() == 100}
|
96
224
|
if q.length == 0 and not a[0]
|
97
225
|
cnt += 1
|
@@ -99,11 +227,15 @@ module BScan
|
|
99
227
|
cnt = 0
|
100
228
|
# Log 2, "BScan.evt_register_callbacks QUEUE: #{q.length}, Activity: #{a[0]}"
|
101
229
|
end
|
102
|
-
if cnt > 1
|
103
|
-
|
104
|
-
|
230
|
+
if cnt > 1
|
231
|
+
Log 2, "BScan.evt_register_callbacks Scanning complete"
|
232
|
+
if @run_proxy
|
233
|
+
gen_report
|
234
|
+
end
|
235
|
+
exit_suite false
|
105
236
|
break
|
106
237
|
end
|
238
|
+
Log 2, "BScan.evt_register_callbacks monitor #{@run_proxy} #{@max_proxy_time}"
|
107
239
|
a[0] = false
|
108
240
|
end
|
109
241
|
}
|
@@ -111,11 +243,19 @@ module BScan
|
|
111
243
|
|
112
244
|
Log 2, '='*30, 'BScan.evt_register_callbacks Params', '='*30
|
113
245
|
params = save_config
|
246
|
+
# params.each_pair {|k,v| Log 2,"#{k}:#{v}:#{v.class}"} # if k =~ /^(scanner|spider)/}
|
114
247
|
params['target.scopeinclude0']='**empty**' # burp can store the previous scope somehow, thus need to clean
|
115
248
|
@burp_config.each_pair do |k,v|
|
116
|
-
params[k] = v
|
117
|
-
end
|
118
|
-
|
249
|
+
params[k] = v if params[k]
|
250
|
+
end
|
251
|
+
add_spider_headers(params)
|
252
|
+
if @cmd_params['burp_config_only']
|
253
|
+
load_config params, @bscan_config['bscan.burp_defaults']
|
254
|
+
exit_suite false
|
255
|
+
else
|
256
|
+
load_config @burp_config
|
257
|
+
end
|
258
|
+
|
119
259
|
params.each_pair {|k,v| Log 2,"#{k}:#{v}"} # if k =~ /^(scanner|spider)/}
|
120
260
|
|
121
261
|
# run_modules
|
@@ -123,24 +263,27 @@ module BScan
|
|
123
263
|
|
124
264
|
urls = @bscan_config['bscan.url']
|
125
265
|
Log 2, "BScan.evt_register_callbacks urls: #{@modules_only} #{urls}"
|
126
|
-
|
127
|
-
|
266
|
+
|
267
|
+
|
268
|
+
if not urls and not @run_proxy
|
128
269
|
Log 0, "BScan.evt_register_callbacks No URL's provided in config. Use bscan.url param. Multiple entries are OK"
|
129
|
-
exit_suite
|
270
|
+
exit_suite false
|
130
271
|
end
|
131
272
|
|
132
|
-
urls = [urls] if not urls.kind_of?(Array)
|
273
|
+
urls = [urls] if urls and not urls.kind_of?(Array)
|
133
274
|
|
134
|
-
urls
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
275
|
+
if urls
|
276
|
+
urls.each do |u|
|
277
|
+
Log 2, "BScan.evt_register_callbacks checking url: #{u}"
|
278
|
+
if not is_in_scope(u)
|
279
|
+
Log 2, "BScan.evt_register_callbacks including url: #{u}"
|
280
|
+
include_in_scope(u)
|
281
|
+
end
|
282
|
+
Log 2, "BScan.evt_register_callbacks Sending to spider: #{u}"
|
283
|
+
send_to_spider(u)
|
139
284
|
end
|
140
|
-
Log 2, "BScan.evt_register_callbacks Sending to spider: #{u}"
|
141
|
-
send_to_spider(u)
|
142
285
|
end
|
143
|
-
|
286
|
+
end
|
144
287
|
rescue Exception => e
|
145
288
|
Log 0, "BScan.evt_register_callbacks Exception: #{e.message}"
|
146
289
|
Log 0, e.backtrace.join("\n")
|