metasploit-runner 0.0.1

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.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ Yjk2ODJjODk3YmE1YTU3OWJjMDE0MDg1NTQ0ZjAyNTkyNTBiYzVlNQ==
5
+ data.tar.gz: !binary |-
6
+ YWViNThkOGU2MThjYjk4OGM4NTI2NDJjM2MxODBiY2QzODU0ZDFlYg==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ NjYxZTFjNzNjODE3MmZiYzkxNmJlNTFmMDlhYjhmMzAzM2ZhZmYwYzIzNzRj
10
+ ZjIzOTJmMGYwZGIwNGNhZTM5OTkwYzBhNjg1NzZiODNjYTA2NTk1MDA2YTJl
11
+ NDY2NjJiODlhYTExOGQyNWUyMGZmMTY3NzhiZWUzZGE5NGM2ZGI=
12
+ data.tar.gz: !binary |-
13
+ YTViYjk1ODJiMzExOGNhOThiMjc0ZTBhNjJmMTJkYWQyNjg0ZDEyNzdiMGVk
14
+ NzEzMzQ4M2Q4MTI0ZTViNGFhYzdmNjI4NzJmYWRkOWY0ZjI3OGI1MWRjNDYw
15
+ YjExZDUyYjc3OTRhNGVjYjc1Yjg0NjAxMjBmZjJkY2FmOTJmNTU=
data/.gitignore ADDED
@@ -0,0 +1,23 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
23
+ .idea/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format documentation
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in MetasploitPenTestScript.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 James Armstead
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'MetasploitPenTestScript/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'metasploit-runner'
8
+ spec.version = MetasploitPenTestScript::VERSION
9
+ spec.authors = ['Nathan Gibson']
10
+ spec.email = ['amngibson@gmail.com']
11
+ spec.summary = 'Script to run automated Metaspolit Penetration Tests.'
12
+ spec.description = ''
13
+ spec.homepage = ''
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = %w(exploit)
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.add_dependency 'msfrpc-client', '1.0.2'
22
+
23
+ spec.add_development_dependency 'bundler', '~> 1.6'
24
+ spec.add_development_dependency 'rake'
25
+ spec.add_development_dependency 'rspec', '3.0.0'
26
+ end
data/README.md ADDED
@@ -0,0 +1,51 @@
1
+ # MetasploitPenTestScript
2
+
3
+ This is a ruby gem that basically wraps the msfrpc-client gem.
4
+
5
+ It was primarily created to automate workspace creation and automatic import of nexpose scan data from use in
6
+ a Jenkins automated CI/CD environment.
7
+
8
+ Basically this allows you to attach metasploit to your Continuous Delivery/Continuous integration pipeline.
9
+ Though it can be used for other purposes.
10
+
11
+ ## Installation
12
+
13
+ Add this line to your application's Gemfile:
14
+
15
+ gem 'metasploit-runner'
16
+
17
+ And then execute:
18
+
19
+ $ bundle
20
+
21
+ Or install it yourself as:
22
+
23
+ $ gem install metasploit-runner
24
+
25
+ ## Usage
26
+
27
+ This gem allows you to specify the Metasploit Connection URL, Metasploit Connection Port, Metasploit URI, SSL TRUE/False, Token, Workspace Name, Nexpose Console Name, Device/Target IP.
28
+
29
+ $ exploit "connection_url" "port" "uri" "use_ssl" "token" "workspace_name" "nexpose_console_name" "device_ip_to_scan"
30
+
31
+ Example:
32
+
33
+ $ exploit "sploit.mydomain.com" "3790" "/api/1.0" "true" "asdlkjhsdfuw1228340asdasf8" "mycoolsoftware-build-28" "nexpose-console-1" "10.0.0.1"
34
+
35
+ The if you do not pass the following options they will default to the respective values:
36
+
37
+ port -> 3790
38
+ uri -> /api/1.0
39
+ use_ssl -> true
40
+
41
+ Example using the defaults:
42
+
43
+ $ exploit "sploit.mydomain.com" "" "" "" "asdlkjhsdfuw1228340asdasf8" "mycoolsoftware-build-28" "nexpose-console-1" "10.0.0.1"
44
+
45
+ ## Contributing
46
+
47
+ 1. Fork it ( https://github.com/[my-github-username]/MetasploitPenTestScript/fork )
48
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
49
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
50
+ 4. Push to the branch (`git push origin my-new-feature`)
51
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/exploit ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'metasploit/exploit'
4
+
5
+ $stdout.sync = true
6
+ Metasploit::Exploit.start ARGV[0], ARGV[1], ARGV[2], ARGV[3], ARGV[4], ARGV[5], ARGV[6], ARGV[7]
@@ -0,0 +1,3 @@
1
+ module MetasploitPenTestScript
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,5 @@
1
+ require "MetasploitPenTestScript/version"
2
+
3
+ module MetasploitPenTestScript
4
+ # Your code goes here...
5
+ end
@@ -0,0 +1,17 @@
1
+ module CONSTANTS
2
+ DEFAULT_PORT = '3790'
3
+ DEFAULT_URI = '/api/1.0'
4
+ DEFAULT_SSL= true
5
+ RUNNING_IMPORT_STATUS = 'running'
6
+ REQUIRED_TOKEN_MESSAGE = 'PWNED! Token is required'
7
+ REQUIRED_CONNECTION_URL_MESSAGE = 'PWNED! Connection URL is required'
8
+ REQUIRED_DEVICE_IP_TO_SCAN_MESSAGE = 'PWNED! Device IP to scan is required'
9
+ USING_DEFAULT_PORT_MESSAGE = '[*] No port specified in call, using 3790 as default'
10
+ USING_DEFAULT_URI_MESSAGE = '[*] No URI specified in call, using /api/1.0 as default'
11
+ SUCCESSFUL_CONNECTION_MESSAGE = '[*] Sucessfully authenticated to the Metasploit server'
12
+ USING_DEFAULT_SSL_MESSAGE = '[*] Using SSL=TRUE'
13
+ IMPORTING_DATA_MESSAGE = '[*] Importing...'
14
+ SCANNING_MESSAGE = '[*] Scanning all your things...'
15
+ REQUIRED_WORKSPACE_MESSAGE= 'PWNED! Workspace Name is required'
16
+
17
+ end
@@ -0,0 +1,86 @@
1
+ require 'msfrpc-client'
2
+ require 'metasploit/constants'
3
+
4
+ module Metasploit
5
+ module Exploit
6
+ def Exploit.start(connection_url, port, uri, use_ssl, token, workspace_name, nexpose_console_name, device_ip_to_scan)
7
+ are_parameters_valid(connection_url, token, workspace_name, device_ip_to_scan)
8
+
9
+ rpc_client = get_new_metasploit_rpc_connection(connection_url, port, uri, use_ssl, token)
10
+
11
+ create_workspace(rpc_client, workspace_name)
12
+
13
+ do_nexpose_import(nexpose_console_name, rpc_client, workspace_name)
14
+
15
+ do_metasploit_scan(device_ip_to_scan, rpc_client, workspace_name)
16
+ end
17
+
18
+ private
19
+ def self.are_parameters_valid(connection_url, token, workspace_name, device_ip_to_scan)
20
+ raise StandardError, CONSTANTS::REQUIRED_WORKSPACE_MESSAGE if workspace_name.nil? || workspace_name.empty?
21
+ raise StandardError, CONSTANTS::REQUIRED_TOKEN_MESSAGE if token.nil? || token.empty?
22
+ raise StandardError, CONSTANTS::REQUIRED_CONNECTION_URL_MESSAGE if connection_url.nil? || connection_url.empty?
23
+ raise StandardError, CONSTANTS::REQUIRED_DEVICE_IP_TO_SCAN_MESSAGE if device_ip_to_scan.nil? || device_ip_to_scan.empty?
24
+ end
25
+
26
+ def self.get_metasploit_options(connection_url, port, uri, use_ssl, token)
27
+ if port.nil? || port.empty?
28
+ puts CONSTANTS::USING_DEFAULT_PORT_MESSAGE
29
+ port = CONSTANTS::DEFAULT_PORT
30
+ end
31
+
32
+ if uri.nil? || uri.empty?
33
+ puts CONSTANTS::USING_DEFAULT_URI_MESSAGE
34
+ uri = CONSTANTS::DEFAULT_URI
35
+ end
36
+
37
+ if use_ssl != false
38
+ puts CONSTANTS::USING_DEFAULT_SSL_MESSAGE
39
+ use_ssl = CONSTANTS::DEFAULT_SSL
40
+ end
41
+
42
+ {:host => connection_url, :port => port, :token => token, :uri => uri, :ssl => use_ssl}
43
+ end
44
+
45
+ def self.get_new_metasploit_rpc_connection(connection_url, port, uri, use_ssl, token)
46
+ client = Msf::RPC::Client.new(get_metasploit_options(connection_url, port, uri, use_ssl, token))
47
+ puts CONSTANTS::SUCCESSFUL_CONNECTION_MESSAGE
48
+
49
+ client
50
+ end
51
+
52
+ def self.do_nexpose_import(nexpose_console_name, rpc_client, workspace_name)
53
+ import = rpc_client.call('pro.start_import', {'workspace' => workspace_name, 'DS_NEXPOSE_CONSOLE' => nexpose_console_name, 'DS_NEXPOSE_SITE' => workspace_name})
54
+
55
+ wait_for_task_to_stop_running(rpc_client, CONSTANTS::IMPORTING_DATA_MESSAGE, import['task_id'])
56
+ end
57
+
58
+ def self.create_workspace(rpc_client, workspace_name)
59
+ rpc_client.call('pro.workspace_add', {'name' => workspace_name})
60
+ end
61
+
62
+ def self.do_metasploit_scan(device_ip_to_scan, rpc_client, workspace_name)
63
+ scan = rpc_client.call('pro.start_webscan', {'workspace' => workspace_name, 'DS_URLS' => "http://#{device_ip_to_scan}"})
64
+
65
+ wait_for_task_to_stop_running(rpc_client, CONSTANTS::SCANNING_MESSAGE, scan['task_id'])
66
+ end
67
+
68
+ def self.create_workspace(rpc_client, workspace_name)
69
+ rpc_client.call('pro.workspace_add', {'name' => workspace_name})
70
+ end
71
+
72
+ def self.do_metasploit_scan(device_ip_to_scan, rpc_client, workspace_name)
73
+ scan = rpc_client.call('pro.start_webscan', {'workspace' => workspace_name, 'DS_URLS' => "http://#{device_ip_to_scan}"})
74
+
75
+ wait_for_task_to_stop_running(rpc_client, CONSTANTS::SCANNING_MESSAGE, scan['task_id'])
76
+ end
77
+
78
+ def self.wait_for_task_to_stop_running(rpc_client, status_message, task_id)
79
+ sleep(3)
80
+ status = rpc_client.call('pro.task_status', task_id)
81
+ puts status_message
82
+
83
+ wait_for_task_to_stop_running(rpc_client, status_message, task_id) if status['status'] == CONSTANTS::RUNNING_IMPORT_STATUS
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,283 @@
1
+ require 'metasploit/exploit'
2
+
3
+ describe 'exploit' do
4
+ before(:each) do
5
+ allow(Metasploit::Exploit).to receive(:sleep)
6
+ end
7
+
8
+ describe 'start' do
9
+ before(:each) do
10
+ @expected_connection = 'http://test.connection'
11
+ @expected_token = 'testtoken'
12
+ @expected_port = '3791'
13
+ @expected_uri = '/api/1.1'
14
+ @expected_ssl = false
15
+ @expected_workspace_name = 'workspacename'
16
+ @expected_nexpose_console_name = 'nexpose_console_name'
17
+ @expected_webscan_task_id = '12'
18
+ @expected_import_task_id = '1'
19
+ @mock_rpc_client = get_mock_rpc_client
20
+ @mock_device_ip_to_scan = '127.0.0.1'
21
+ @mock_device_url_to_scan = "http://#{@mock_device_ip_to_scan}"
22
+ end
23
+
24
+ describe 'get connection' do
25
+ it 'should create a session with the metasploit server' do
26
+ expected_options = get_default_options_and_override({})
27
+
28
+ expect(Msf::RPC::Client).to receive(:new)
29
+ .with(expected_options)
30
+ .and_return(@mock_rpc_client)
31
+
32
+ Metasploit::Exploit.start(@expected_connection, @expected_port, @expected_uri, @expected_ssl, @expected_token, @expected_workspace_name, '', @mock_device_ip_to_scan)
33
+ end
34
+
35
+ it 'should throw an error if no token is passed' do
36
+ expect { Metasploit::Exploit.start(@expected_connection, @expected_port, @expected_uri, @expected_ssl, '', @expected_workspace_name, '', @mock_device_ip_to_scan) }.to raise_error(StandardError, 'PWNED! Token is required')
37
+ expect { Metasploit::Exploit.start(@expected_connection, @expected_port, @expected_uri, @expected_ssl, nil, @expected_workspace_name, '', @mock_device_ip_to_scan) }.to raise_error(StandardError, 'PWNED! Token is required')
38
+ end
39
+
40
+ it 'should throw an error if no connection url is passed' do
41
+ expect { Metasploit::Exploit.start('', @expected_port, @expected_uri, @expected_ssl, @expected_token, @expected_workspace_name, '', @mock_device_ip_to_scan) }.to raise_error(StandardError, 'PWNED! Connection URL is required')
42
+ expect { Metasploit::Exploit.start(nil, @expected_port, @expected_uri, @expected_ssl, @expected_token, @expected_workspace_name, '', @mock_device_ip_to_scan) }.to raise_error(StandardError, 'PWNED! Connection URL is required')
43
+ end
44
+
45
+ it 'should throw an error if no ip address is passed' do
46
+ expect { Metasploit::Exploit.start(@expected_connection, @expected_port, @expected_uri, @expected_ssl, @expected_token, @expected_workspace_name, '', '') }.to raise_error(StandardError, 'PWNED! Device IP to scan is required')
47
+ expect { Metasploit::Exploit.start(@expected_connection, @expected_port, @expected_uri, @expected_ssl, @expected_token, @expected_workspace_name, '', nil) }.to raise_error(StandardError, 'PWNED! Device IP to scan is required')
48
+ end
49
+
50
+ it 'should use 3790 as default if port is empty string' do
51
+ expected_options = get_default_options_and_override({:port => '3790'})
52
+
53
+ expect(Msf::RPC::Client).to receive(:new)
54
+ .with(expected_options)
55
+ .and_return(@mock_rpc_client)
56
+
57
+ Metasploit::Exploit.start(@expected_connection, '', @expected_uri, @expected_ssl, @expected_token, @expected_workspace_name, '', @mock_device_ip_to_scan)
58
+ end
59
+
60
+ it 'should use 3790 as default if port is nil' do
61
+ expected_options = get_default_options_and_override({:port => '3790'})
62
+
63
+ expect(Msf::RPC::Client).to receive(:new)
64
+ .with(expected_options)
65
+ .and_return(@mock_rpc_client)
66
+
67
+ Metasploit::Exploit.start(@expected_connection, nil, @expected_uri, @expected_ssl, @expected_token, @expected_workspace_name, '', @mock_device_ip_to_scan)
68
+ end
69
+
70
+ it 'should use /api/1.0 as default if no uri is passed' do
71
+ expected_options = get_default_options_and_override({:uri => '/api/1.0'})
72
+
73
+ expect(Msf::RPC::Client).to receive(:new)
74
+ .with(expected_options)
75
+ .and_return(@mock_rpc_client)
76
+
77
+ Metasploit::Exploit.start(@expected_connection, @expected_port, '', @expected_ssl, @expected_token, @expected_workspace_name, '', @mock_device_ip_to_scan)
78
+ end
79
+
80
+ it 'should use /api/1.0 as default if no uri is passed' do
81
+ expected_options = get_default_options_and_override({:uri => '/api/1.0'})
82
+
83
+ expect(Msf::RPC::Client).to receive(:new)
84
+ .with(expected_options)
85
+ .and_return(@mock_rpc_client)
86
+
87
+ Metasploit::Exploit.start(@expected_connection, @expected_port, nil, @expected_ssl, @expected_token, @expected_workspace_name, '', @mock_device_ip_to_scan)
88
+ end
89
+
90
+ it 'should use ssl true as default if empty string is passed' do
91
+ expected_options = get_default_options_and_override({:ssl => true})
92
+
93
+ expect(Msf::RPC::Client).to receive(:new)
94
+ .with(expected_options)
95
+ .and_return(@mock_rpc_client)
96
+
97
+ Metasploit::Exploit.start(@expected_connection, @expected_port, @expected_uri, '', @expected_token, @expected_workspace_name, '', @mock_device_ip_to_scan)
98
+ end
99
+
100
+ it 'should use ssl true as default if random string is passed' do
101
+ expected_options = get_default_options_and_override({:ssl => true})
102
+
103
+ expect(Msf::RPC::Client).to receive(:new)
104
+ .with(expected_options)
105
+ .and_return(@mock_rpc_client)
106
+
107
+ Metasploit::Exploit.start(@expected_connection, @expected_port, @expected_uri, 'sadf', @expected_token, @expected_workspace_name, '', @mock_device_ip_to_scan)
108
+ end
109
+
110
+ it 'should use ssl true as default if nil is passed' do
111
+ expected_options = get_default_options_and_override({:ssl => true})
112
+
113
+ expect(Msf::RPC::Client).to receive(:new)
114
+ .with(expected_options)
115
+ .and_return(@mock_rpc_client)
116
+
117
+ Metasploit::Exploit.start(@expected_connection, @expected_port, @expected_uri, nil, @expected_token, @expected_workspace_name, '', @mock_device_ip_to_scan)
118
+ end
119
+
120
+ it 'should use ssl true as default if true is passed' do
121
+ expected_options = get_default_options_and_override({:ssl => true})
122
+
123
+ expect(Msf::RPC::Client).to receive(:new)
124
+ .with(expected_options)
125
+ .and_return(@mock_rpc_client)
126
+
127
+ Metasploit::Exploit.start(@expected_connection, @expected_port, @expected_uri, true, @expected_token, @expected_workspace_name, '', @mock_device_ip_to_scan)
128
+ end
129
+ end
130
+
131
+ describe 'create workspace' do
132
+ it 'should create a workspace based on workspace name' do
133
+ expect(@mock_rpc_client).to receive(:call)
134
+ .with('pro.workspace_add', {'name' => @expected_workspace_name})
135
+
136
+ Metasploit::Exploit.start(@expected_connection, @expected_port, @expected_uri, @expected_ssl, @expected_token, @expected_workspace_name, '', @mock_device_ip_to_scan)
137
+ end
138
+
139
+ it 'should throw an error if workspace name is invalid' do
140
+ expect { Metasploit::Exploit.start(@expected_connection, @expected_port, @expected_uri, @expected_ssl, @expected_token, '', '', @mock_device_ip_to_scan) }.to raise_error(StandardError, 'PWNED! Workspace Name is required')
141
+ expect { Metasploit::Exploit.start(@expected_connection, @expected_port, @expected_uri, @expected_ssl, @expected_token, nil, '', @mock_device_ip_to_scan) }.to raise_error(StandardError, 'PWNED! Workspace Name is required')
142
+ end
143
+ end
144
+
145
+ describe 'start import from nexpose' do
146
+ it 'should start a import' do
147
+ expect(@mock_rpc_client).to receive(:call)
148
+ .with('pro.start_import', {'workspace' => @expected_workspace_name,
149
+ 'DS_NEXPOSE_CONSOLE' => @expected_nexpose_console_name,
150
+ 'DS_NEXPOSE_SITE' => @expected_workspace_name})
151
+
152
+ Metasploit::Exploit.start(@expected_connection, @expected_port, @expected_uri, @expected_ssl, @expected_token, @expected_workspace_name, @expected_nexpose_console_name, @mock_device_ip_to_scan)
153
+ end
154
+
155
+ describe 'wait to be over' do
156
+ before(:each) do
157
+ expect(@mock_rpc_client).to receive(:call)
158
+ .with('pro.start_import', {'workspace' => @expected_workspace_name,
159
+ 'DS_NEXPOSE_CONSOLE' => @expected_nexpose_console_name,
160
+ 'DS_NEXPOSE_SITE' => @expected_workspace_name})
161
+ .and_return({'task_id' => @expected_import_task_id})
162
+ end
163
+
164
+ it 'should call to check the status of an import' do
165
+ expect(@mock_rpc_client).to receive(:call).with('pro.task_status', @expected_import_task_id)
166
+
167
+ Metasploit::Exploit.start(@expected_connection, @expected_port, @expected_uri, @expected_ssl, @expected_token, @expected_workspace_name, @expected_nexpose_console_name, @mock_device_ip_to_scan)
168
+ end
169
+
170
+ it 'should call to check the status until it is not running' do
171
+ expect(@mock_rpc_client).to receive(:call)
172
+ .with('pro.task_status', @expected_import_task_id)
173
+ .and_return({'status' => 'running'})
174
+ .exactly(3).times
175
+ .ordered
176
+
177
+ expect(@mock_rpc_client).to receive(:call)
178
+ .with('pro.task_status', @expected_import_task_id)
179
+ .and_return({'status' => 'not running'})
180
+ .once
181
+ .ordered
182
+
183
+ Metasploit::Exploit.start(@expected_connection, @expected_port, @expected_uri, @expected_ssl, @expected_token, @expected_workspace_name, @expected_nexpose_console_name, @mock_device_ip_to_scan)
184
+ end
185
+
186
+ it 'should sleep for 3 seconds if the status is still running' do
187
+ expect(@mock_rpc_client).to receive(:call)
188
+ .with('pro.task_status', @expected_import_task_id)
189
+ .and_return({'status' => 'running'})
190
+ .exactly(3).times
191
+ .ordered
192
+
193
+ expect(@mock_rpc_client).to receive(:call)
194
+ .with('pro.task_status', @expected_import_task_id)
195
+ .and_return({'status' => 'not running'})
196
+ .once
197
+ .ordered
198
+
199
+ #Expecting 5 because we are mocking 4 above and the global :call mock in get_mock_rpc_client
200
+ expect(Metasploit::Exploit).to receive(:sleep).with(3).exactly(5).times
201
+
202
+ Metasploit::Exploit.start(@expected_connection, @expected_port, @expected_uri, @expected_ssl, @expected_token, @expected_workspace_name, @expected_nexpose_console_name, @mock_device_ip_to_scan)
203
+ end
204
+ end
205
+ end
206
+
207
+ describe 'start metasploit scan' do
208
+ it 'should kick off a scan' do
209
+ expect(@mock_rpc_client).to receive(:call)
210
+ .with('pro.start_webscan', {'workspace' => @expected_workspace_name,
211
+ 'DS_URLS' => @mock_device_url_to_scan})
212
+
213
+ Metasploit::Exploit.start(@expected_connection, @expected_port, @expected_uri, @expected_ssl, @expected_token, @expected_workspace_name, @expected_nexpose_console_name, @mock_device_ip_to_scan)
214
+ end
215
+
216
+ describe 'wait to be over' do
217
+ before(:each) do
218
+ expect(@mock_rpc_client).to receive(:call)
219
+ .with('pro.start_webscan', {'workspace' => @expected_workspace_name,
220
+ 'DS_URLS' => @mock_device_url_to_scan})
221
+ .and_return({'task_id' => @expected_webscan_task_id})
222
+ end
223
+
224
+ it 'should call to check the status of the scan' do
225
+ expect(@mock_rpc_client).to receive(:call).with('pro.task_status', @expected_webscan_task_id)
226
+
227
+ Metasploit::Exploit.start(@expected_connection, @expected_port, @expected_uri, @expected_ssl, @expected_token, @expected_workspace_name, @expected_nexpose_console_name, @mock_device_ip_to_scan)
228
+ end
229
+
230
+ it 'should call to check the status until it is not running' do
231
+ expect(@mock_rpc_client).to receive(:call)
232
+ .with('pro.task_status', @expected_webscan_task_id)
233
+ .and_return({'status' => 'running'})
234
+ .exactly(3).times
235
+ .ordered
236
+
237
+ expect(@mock_rpc_client).to receive(:call)
238
+ .with('pro.task_status', @expected_webscan_task_id)
239
+ .and_return({'status' => 'not running'})
240
+ .once
241
+ .ordered
242
+
243
+ Metasploit::Exploit.start(@expected_connection, @expected_port, @expected_uri, @expected_ssl, @expected_token, @expected_workspace_name, @expected_nexpose_console_name, @mock_device_ip_to_scan)
244
+ end
245
+
246
+ it 'should sleep for 3 seconds if the status is still running' do
247
+ expect(@mock_rpc_client).to receive(:call)
248
+ .with('pro.task_status', @expected_webscan_task_id)
249
+ .and_return({'status' => 'running'})
250
+ .exactly(3).times
251
+ .ordered
252
+
253
+ expect(@mock_rpc_client).to receive(:call)
254
+ .with('pro.task_status', @expected_webscan_task_id)
255
+ .and_return({'status' => 'not running'})
256
+ .once
257
+ .ordered
258
+
259
+ #Expecting 5 because we are mocking 4 above and the global :call mock in get_mock_rpc_client
260
+ expect(Metasploit::Exploit).to receive(:sleep).with(3).exactly(5).times
261
+
262
+ Metasploit::Exploit.start(@expected_connection, @expected_port, @expected_uri, @expected_ssl, @expected_token, @expected_workspace_name, @expected_nexpose_console_name, @mock_device_ip_to_scan)
263
+ end
264
+ end
265
+ end
266
+
267
+ end
268
+ end
269
+
270
+ def get_default_options_and_override(override)
271
+ {:host => @expected_connection, :port => @expected_port, :token => @expected_token, :uri => @expected_uri, :ssl => @expected_ssl}.merge(override)
272
+ end
273
+
274
+ def get_mock_rpc_client
275
+ mock_rpc_client = double(Msf::RPC::Client)
276
+
277
+ allow(mock_rpc_client).to receive(:call).with(any_args).and_return({})
278
+
279
+ allow(Msf::RPC::Client).to receive(:new)
280
+ .and_return(mock_rpc_client)
281
+
282
+ mock_rpc_client
283
+ end
@@ -0,0 +1,9 @@
1
+ RSpec.configure do |config|
2
+
3
+ config.mock_with :rspec do |mocks|
4
+ mocks.verify_partial_doubles = true
5
+ end
6
+
7
+ Dir["./spec/support/**/*.rb"].sort.each { |f| require f }
8
+
9
+ end
metadata ADDED
@@ -0,0 +1,117 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: metasploit-runner
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Nathan Gibson
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-08-22 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: msfrpc-client
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '='
18
+ - !ruby/object:Gem::Version
19
+ version: 1.0.2
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '='
25
+ - !ruby/object:Gem::Version
26
+ version: 1.0.2
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '1.6'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '1.6'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ! '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '='
60
+ - !ruby/object:Gem::Version
61
+ version: 3.0.0
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '='
67
+ - !ruby/object:Gem::Version
68
+ version: 3.0.0
69
+ description: ''
70
+ email:
71
+ - amngibson@gmail.com
72
+ executables:
73
+ - exploit
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - .gitignore
78
+ - .rspec
79
+ - Gemfile
80
+ - LICENSE.txt
81
+ - MetasploitPenTestScript.gemspec
82
+ - README.md
83
+ - Rakefile
84
+ - bin/exploit
85
+ - lib/MetasploitPenTestScript.rb
86
+ - lib/MetasploitPenTestScript/version.rb
87
+ - lib/metasploit/constants.rb
88
+ - lib/metasploit/exploit.rb
89
+ - spec/exploit_spec.rb
90
+ - spec/spec_helper.rb
91
+ homepage: ''
92
+ licenses:
93
+ - MIT
94
+ metadata: {}
95
+ post_install_message:
96
+ rdoc_options: []
97
+ require_paths:
98
+ - lib
99
+ required_ruby_version: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ! '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ required_rubygems_version: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - ! '>='
107
+ - !ruby/object:Gem::Version
108
+ version: '0'
109
+ requirements: []
110
+ rubyforge_project:
111
+ rubygems_version: 2.2.2
112
+ signing_key:
113
+ specification_version: 4
114
+ summary: Script to run automated Metaspolit Penetration Tests.
115
+ test_files:
116
+ - spec/exploit_spec.rb
117
+ - spec/spec_helper.rb