msfrpc-simple 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.
- data/Gemfile +10 -0
- data/Gemfile.lock +33 -0
- data/LICENSE +31 -0
- data/README.md +1 -0
- data/Rakefile +5 -0
- data/lib/.DS_Store +0 -0
- data/lib/msfrpc-simple/.DS_Store +0 -0
- data/lib/msfrpc-simple/client.rb +58 -0
- data/lib/msfrpc-simple/features/.DS_Store +0 -0
- data/lib/msfrpc-simple/features/framework.rb +163 -0
- data/lib/msfrpc-simple/features/pro.rb +56 -0
- data/lib/msfrpc-simple/logger.rb +21 -0
- data/lib/msfrpc-simple/module_mapper.rb +149 -0
- data/lib/msfrpc-simple/version.rb +7 -0
- data/lib/msfrpc-simple.rb +7 -0
- data/msfrpc-simple.gemspec +17 -0
- data/spec/client_spec.rb +58 -0
- data/spec/logger_spec.rb +19 -0
- data/spec/module_mapper_spec.rb +57 -0
- data/spec/spec_helper.rb +3 -0
- metadata +69 -0
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
coderay (1.0.7)
|
5
|
+
diff-lcs (1.1.3)
|
6
|
+
librex (0.0.65)
|
7
|
+
method_source (0.8)
|
8
|
+
msfrpc-client (1.0.1)
|
9
|
+
librex (>= 0.0.32)
|
10
|
+
msgpack (>= 0.4.5)
|
11
|
+
msgpack (0.4.6)
|
12
|
+
pry (0.9.10)
|
13
|
+
coderay (~> 1.0.5)
|
14
|
+
method_source (~> 0.8)
|
15
|
+
slop (~> 3.3.1)
|
16
|
+
rspec (2.11.0)
|
17
|
+
rspec-core (~> 2.11.0)
|
18
|
+
rspec-expectations (~> 2.11.0)
|
19
|
+
rspec-mocks (~> 2.11.0)
|
20
|
+
rspec-core (2.11.1)
|
21
|
+
rspec-expectations (2.11.1)
|
22
|
+
diff-lcs (~> 1.1.3)
|
23
|
+
rspec-mocks (2.11.1)
|
24
|
+
slop (3.3.2)
|
25
|
+
|
26
|
+
PLATFORMS
|
27
|
+
ruby
|
28
|
+
|
29
|
+
DEPENDENCIES
|
30
|
+
librex
|
31
|
+
msfrpc-client
|
32
|
+
pry
|
33
|
+
rspec
|
data/LICENSE
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
Copyright (C) 2012, Pentestify LLC
|
2
|
+
All rights reserved.
|
3
|
+
|
4
|
+
Redistribution and use in source and binary forms, with or without modification,
|
5
|
+
are permitted provided that the following conditions are met:
|
6
|
+
|
7
|
+
* Redistributions of source code must retain the above copyright notice,
|
8
|
+
this list of conditions and the following disclaimer.
|
9
|
+
|
10
|
+
* Redistributions in binary form must reproduce the above copyright notice,
|
11
|
+
this list of conditions and the following disclaimer in the documentation
|
12
|
+
and/or other materials provided with the distribution.
|
13
|
+
|
14
|
+
* Neither the name of Pentestify LLC nor the names of its contributors
|
15
|
+
may be used to endorse or promote products derived from this software
|
16
|
+
without specific prior written permission.
|
17
|
+
|
18
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
19
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
20
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
21
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
22
|
+
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
23
|
+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
24
|
+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
25
|
+
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
26
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
27
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
28
|
+
|
29
|
+
================================================================================
|
30
|
+
|
31
|
+
The msfrpc-simple library is provided under the 3-clause BSD license above.
|
data/README.md
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
This library provides a simple-to-use wrapper for the Rapid7 Metasploit RPC API.
|
data/Rakefile
ADDED
data/lib/.DS_Store
ADDED
Binary file
|
Binary file
|
@@ -0,0 +1,58 @@
|
|
1
|
+
$:.unshift(File.expand_path(File.dirname(__FILE__)))
|
2
|
+
require 'msfrpc-client'
|
3
|
+
require 'features/framework'
|
4
|
+
require 'features/pro'
|
5
|
+
require 'module_mapper'
|
6
|
+
require 'logger'
|
7
|
+
require 'pry'
|
8
|
+
|
9
|
+
module Msf
|
10
|
+
module RPC
|
11
|
+
module Simple
|
12
|
+
class Client
|
13
|
+
|
14
|
+
include Msf::RPC::Simple::Features::Framework
|
15
|
+
include Msf::RPC::Simple::Features::Pro
|
16
|
+
|
17
|
+
# Public: Create a simple client object.
|
18
|
+
#
|
19
|
+
# opts - hash of options to include in our initial connection.
|
20
|
+
# project - project name we want to use for this connection.
|
21
|
+
#
|
22
|
+
# Returns nothing.
|
23
|
+
def initialize(project="default", username, password, user_opts)
|
24
|
+
|
25
|
+
#
|
26
|
+
# Merge our project in, and set this as the project we'll
|
27
|
+
# use going forward.
|
28
|
+
#
|
29
|
+
conn_params = {
|
30
|
+
:project => project,
|
31
|
+
:port => 55553,
|
32
|
+
:user => username,
|
33
|
+
:pass => password
|
34
|
+
}
|
35
|
+
|
36
|
+
user_opts.merge!(conn_params)
|
37
|
+
|
38
|
+
#
|
39
|
+
# Connect to the RPC daemon using the default r7 client
|
40
|
+
#
|
41
|
+
@client = Msf::RPC::Client.new(user_opts)
|
42
|
+
|
43
|
+
#
|
44
|
+
# Create a logger
|
45
|
+
#
|
46
|
+
@logger = Msf::RPC::Simple::Logger.new
|
47
|
+
end
|
48
|
+
|
49
|
+
#
|
50
|
+
#
|
51
|
+
#
|
52
|
+
def connected?
|
53
|
+
return true if @client.call("core.version")
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
Binary file
|
@@ -0,0 +1,163 @@
|
|
1
|
+
module Msf
|
2
|
+
module RPC
|
3
|
+
module Simple
|
4
|
+
module Features
|
5
|
+
module Framework
|
6
|
+
|
7
|
+
#
|
8
|
+
# This module simply runs a module
|
9
|
+
#
|
10
|
+
def execute_module_and_return_output(options)
|
11
|
+
|
12
|
+
module_name = options[:module_name]
|
13
|
+
#module_options = options[:module_options]
|
14
|
+
module_option_string = options[:module_option_string]
|
15
|
+
|
16
|
+
# split up the module name into type / name
|
17
|
+
module_type = module_name.split("/").first
|
18
|
+
raise "Error, bad module name" unless ["exploit", "auxiliary", "post", "encoder", "nop"].include? module_type
|
19
|
+
|
20
|
+
#module_options["TARGET"] = 0 unless module_options["TARGET"]
|
21
|
+
|
22
|
+
#info = @client.call("module.execute", module_type, module_name, module_options)
|
23
|
+
#@client.call("job.info", info["job_id"])
|
24
|
+
|
25
|
+
# The module output will be not available when run this way; to
|
26
|
+
# capture the result of the print_* commands, you have to set the
|
27
|
+
# output driver of the module to something you can read from (Buffer,
|
28
|
+
# File, etc). For your use case, the best bet is to run the module
|
29
|
+
# via the Console API instead of module.execute, and use that to read
|
30
|
+
# the output from the console itself, which provides buffer output for you.
|
31
|
+
|
32
|
+
# Create the console and get its id
|
33
|
+
console = @client.call("console.create")
|
34
|
+
console_id = console["id"]
|
35
|
+
|
36
|
+
# Do an initial read / discard to pull out the banner
|
37
|
+
@client.call("console.read", console_id)
|
38
|
+
|
39
|
+
# Move to the context of our module
|
40
|
+
@client.call("console.write", console_id, "use #{module_name}\n")
|
41
|
+
|
42
|
+
# Set up the module's datastore
|
43
|
+
module_option_string.split(",").each do |module_option|
|
44
|
+
@client.call "console.write", console_id, "set #{module_option}\n"
|
45
|
+
end
|
46
|
+
|
47
|
+
# Do an another read / discard to pull out the option confirmation
|
48
|
+
@client.call("console.read", console_id)
|
49
|
+
|
50
|
+
# Depending on the module_type, kick off the module
|
51
|
+
if module_type == "auxiliary"
|
52
|
+
@client.call "console.write", console_id, "run\n"
|
53
|
+
elsif module_type == "exploit"
|
54
|
+
@client.call "console.write", console_id, "exploit\n"
|
55
|
+
else
|
56
|
+
return "Unsupported"
|
57
|
+
end
|
58
|
+
|
59
|
+
# do an initial read of the module's output
|
60
|
+
module_output = @client.call("console.read", console_id)
|
61
|
+
module_output_data_string = "#{module_output['data']}"
|
62
|
+
|
63
|
+
return "Module Error" if module_output["result"] == "failure"
|
64
|
+
|
65
|
+
until (module_output["busy"] == false) do
|
66
|
+
module_output = @client.call("console.read", console_id)
|
67
|
+
module_output_data_string += "#{module_output['data']}"
|
68
|
+
return "Module Error" if module_output["result"] == "failure"
|
69
|
+
end
|
70
|
+
|
71
|
+
# Clean up
|
72
|
+
@client.call("console.destroy", console_id)
|
73
|
+
|
74
|
+
module_output_data_string
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
#
|
79
|
+
# This module runs a number of discovery modules
|
80
|
+
#
|
81
|
+
def discover_host(host)
|
82
|
+
|
83
|
+
# http version
|
84
|
+
modules_and_options = [
|
85
|
+
{:module_name => "auxiliary/scanner/http/http_version",
|
86
|
+
:module_option_string => "RHOSTS #{host}" },
|
87
|
+
{:module_name => "auxiliary/scanner/http/cert",
|
88
|
+
:module_option_string => "RHOSTS #{host}" }
|
89
|
+
]
|
90
|
+
|
91
|
+
# This is a naive and horrible way of doing it, but let's just knock
|
92
|
+
# out the basic thing first. For each module in our list...
|
93
|
+
module_output_data_string = ""
|
94
|
+
modules_and_options.each do |module_and_options|
|
95
|
+
|
96
|
+
module_name = module_and_options[:module_name]
|
97
|
+
module_option_string = module_and_options[:module_option_string]
|
98
|
+
|
99
|
+
# store this module's name in the output
|
100
|
+
module_output_data_string += "=== #{module_name} #{module_option_string} ===\n"
|
101
|
+
|
102
|
+
# split up the module name into type / name
|
103
|
+
module_type = module_name.split("/").first
|
104
|
+
raise "Error, bad module name" unless ["exploit", "auxiliary", "post", "encoder", "nop"].include? module_type
|
105
|
+
|
106
|
+
# Create the console and get its id
|
107
|
+
console = @client.call("console.create")
|
108
|
+
console_id = console["id"]
|
109
|
+
|
110
|
+
# Do an initial read / discard to pull out the banner
|
111
|
+
@client.call("console.read", console_id)
|
112
|
+
|
113
|
+
# Move to the context of our module
|
114
|
+
@client.call("console.write", console_id, "use #{module_name}\n")
|
115
|
+
|
116
|
+
# Set up the module's datastore
|
117
|
+
module_option_string.split(",").each do |module_option|
|
118
|
+
@client.call "console.write", console_id, "set #{module_option}\n"
|
119
|
+
end
|
120
|
+
|
121
|
+
# Do an another read / discard to pull out the option confirmation
|
122
|
+
@client.call("console.read", console_id)
|
123
|
+
|
124
|
+
# Depending on the module_type, kick off the module
|
125
|
+
if module_type == "auxiliary"
|
126
|
+
@client.call "console.write", console_id, "run\n"
|
127
|
+
elsif module_type == "exploit"
|
128
|
+
@client.call "console.write", console_id, "exploit\n"
|
129
|
+
else
|
130
|
+
return "Unsupported"
|
131
|
+
end
|
132
|
+
|
133
|
+
# do an initial read of the module's output
|
134
|
+
module_output = @client.call("console.read", console_id)
|
135
|
+
|
136
|
+
return "Module Error" if module_output["result"] == "failure"
|
137
|
+
|
138
|
+
until (module_output["busy"] == false) do
|
139
|
+
module_output = @client.call("console.read", console_id)
|
140
|
+
module_output_data_string += "#{module_output['data']}"
|
141
|
+
return "Module Error" if module_output["result"] == "failure"
|
142
|
+
end
|
143
|
+
|
144
|
+
# Clean up
|
145
|
+
@client.call("console.destroy", console_id)
|
146
|
+
end
|
147
|
+
|
148
|
+
module_output_data_string
|
149
|
+
end
|
150
|
+
|
151
|
+
|
152
|
+
#
|
153
|
+
# This module runs a number of _login modules
|
154
|
+
#
|
155
|
+
def fw_bruteforce(options)
|
156
|
+
return "Not Implemented"
|
157
|
+
end
|
158
|
+
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Msf
|
2
|
+
module RPC
|
3
|
+
module Simple
|
4
|
+
module Features
|
5
|
+
module Pro
|
6
|
+
|
7
|
+
def start_report(options)
|
8
|
+
raise "Not Implemented"
|
9
|
+
=begin
|
10
|
+
task = @rpc.call("pro.start_report", {
|
11
|
+
'DS_REPORT_TYPE' => options[:report_type],
|
12
|
+
'DS_WHITELIST_HOSTS' => options[:whitelist],
|
13
|
+
'DS_BLACKLIST_HOSTS' => options[:blacklist],
|
14
|
+
'workspace' => options[:workspace],
|
15
|
+
'username' => options[:username],
|
16
|
+
'DS_MaskPasswords' => options[:ds_mask_passwords] || true,
|
17
|
+
'DS_IncludeTaskLog' => options[:include_task_log] || true,
|
18
|
+
'DS_JasperDisplaySession' => options[:ds_jasper_display_session] || false,
|
19
|
+
'DS_JasperDisplayCharts' => options[:ds_mask_passwords] || true,
|
20
|
+
'DS_LootExcludeScreenshots' => options[:ds_loot_exclude_screenshots] || false,
|
21
|
+
'DS_LootExcludePasswords' => options[:ds_loot_exclude_passwords] || false,
|
22
|
+
'DS_JasperTemplate' => options[:ds_jasper_template] || "msfxv3.jrxml",
|
23
|
+
'DS_UseJasper' => options[:ds_use_jasper]] ||true,
|
24
|
+
'DS_UseCustomReporting' => options[:ds_use_custom_reporting] || false,
|
25
|
+
'DS_JasperProductName' => options[:ds_jasper_product_name] || "Metasploit Pro",
|
26
|
+
'DS_JasperDbEnv' => options[:ds_jasper_db_env] || "production",
|
27
|
+
'DS_JasperLogo' => options[:ds_jasper_logo] || "",
|
28
|
+
'DS_JasperDisplaySections' => options[:ds_jasper_display_sections] || "1,2,3,4,5,6,7,8",
|
29
|
+
'DS_EnablePCIReport' => options[:ds_enable_pci_report] || true,
|
30
|
+
'DS_EnableFISMAReport' => options[:ds_enable_fisma_report] || true,
|
31
|
+
'DS_JasperDisplayWeb' => options[:ds_enable_jasper_display_web] || true,
|
32
|
+
})
|
33
|
+
=end
|
34
|
+
end
|
35
|
+
|
36
|
+
def start_discover(options)
|
37
|
+
raise "Not Implemented"
|
38
|
+
|
39
|
+
#task = @rpc.call("pro.start_discover", {
|
40
|
+
# 'DS_WHITELIST_HOSTS' => options[:whitelist],
|
41
|
+
# 'DS_BLACKLIST_HOSTS' => options[:blacklist],
|
42
|
+
# 'workspace' => options[:workspace],
|
43
|
+
# 'username' => options[:username]
|
44
|
+
#})
|
45
|
+
end
|
46
|
+
|
47
|
+
def start_bruteforce(options)
|
48
|
+
raise "Not Implemented"
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Msf
|
2
|
+
module RPC
|
3
|
+
module Simple
|
4
|
+
class Logger
|
5
|
+
|
6
|
+
def initialize(filename="msfrpc-simple.log")
|
7
|
+
@log = File.open(filename, "w+")
|
8
|
+
end
|
9
|
+
|
10
|
+
def log(text)
|
11
|
+
@log.puts text
|
12
|
+
end
|
13
|
+
|
14
|
+
def close
|
15
|
+
@log.close
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,149 @@
|
|
1
|
+
module Msf
|
2
|
+
module RPC
|
3
|
+
module Simple
|
4
|
+
module ModuleMapper
|
5
|
+
|
6
|
+
# Public: Get all discovery modules, given a host endpoint
|
7
|
+
#
|
8
|
+
# This method may seem poorly abstracted but you must pass in an IP address
|
9
|
+
# in order to compensate for the different ways that modules accept an
|
10
|
+
# endpoint. For example, scanners need an RHOSTS option, while most other
|
11
|
+
# modules will accept a RHOST option.
|
12
|
+
#
|
13
|
+
# Returns a list of hashes, each one containing:
|
14
|
+
# [
|
15
|
+
# { :ip_address,
|
16
|
+
# :port_num,
|
17
|
+
# :protocol,
|
18
|
+
# :transport,
|
19
|
+
# :modules_and_options => [ { :module_name, :module_option_string }, ...],
|
20
|
+
# }, ...
|
21
|
+
# ]
|
22
|
+
def self.get_discovery_modules_for_endpoints(endpoints)
|
23
|
+
#
|
24
|
+
# Iterate through the endpoints, assigning modules
|
25
|
+
#
|
26
|
+
endpoints_with_modules = []
|
27
|
+
endpoints.each do |endpoint|
|
28
|
+
endpoints_with_modules << get_discovery_modules_for_endpoint(endpoint)
|
29
|
+
end
|
30
|
+
|
31
|
+
endpoints_with_modules
|
32
|
+
end
|
33
|
+
|
34
|
+
# Public: Returns all discovery modules for a singular endpoint
|
35
|
+
#
|
36
|
+
# An endpoint looks like:
|
37
|
+
#
|
38
|
+
# { :ip_address,
|
39
|
+
# :port_num,
|
40
|
+
# :protocol,
|
41
|
+
# :transport,
|
42
|
+
# :modules_and_options => [ { :module_name, :module_option_string }, ...],
|
43
|
+
# }
|
44
|
+
#
|
45
|
+
# Returns the endpoint object
|
46
|
+
def self.get_discovery_modules_for_endpoint(endpoint)
|
47
|
+
|
48
|
+
# If we have an unknown protocol, fall back to guessing by port
|
49
|
+
endpoint[:protocol] = get_protocol_by_port_num(endpoint) unless endpoint[:protocol]
|
50
|
+
|
51
|
+
# Start out with an empty modules_and_options array
|
52
|
+
endpoint[:modules_and_options] = []
|
53
|
+
|
54
|
+
# Now iterate through our protocols, assigning modules & optionss
|
55
|
+
#
|
56
|
+
# FTP
|
57
|
+
#
|
58
|
+
if endpoint[:protocol] == "FTP"
|
59
|
+
endpoint[:modules_and_options] << {
|
60
|
+
:module_name => "auxiliary/scanner/ftp/ftp_version",
|
61
|
+
:module_option_string => "RHOSTS #{endpoint[:ip_address]}, RPORT #{endpoint[:port_num]}" }
|
62
|
+
#
|
63
|
+
# TELNET
|
64
|
+
#
|
65
|
+
elsif endpoint[:protocol] == "TELNET"
|
66
|
+
endpoint[:modules_and_options] << {
|
67
|
+
:module_name => "auxiliary/scanner/telnet/telnet_version",
|
68
|
+
:module_option_string => "RHOSTS #{endpoint[:ip_address]}, RPORT #{endpoint[:port_num]}" }
|
69
|
+
#
|
70
|
+
# HTTP
|
71
|
+
#
|
72
|
+
elsif endpoint[:protocol] == "HTTP"
|
73
|
+
endpoint[:modules_and_options] << {
|
74
|
+
:module_name => "auxiliary/scanner/http/http_version",
|
75
|
+
:module_option_string => "RHOSTS #{endpoint[:ip_address]}, RPORT #{endpoint[:port_num]}" }
|
76
|
+
#
|
77
|
+
# SNMP
|
78
|
+
#
|
79
|
+
elsif endpoint[:protocol] == "SNMP"
|
80
|
+
endpoint[:modules_and_options] << {
|
81
|
+
:module_name => "auxiliary/scanner/snmp/snmp_enum",
|
82
|
+
:module_option_string => "RHOSTS #{endpoint[:ip_address]}, RPORT #{endpoint[:port_num]}" }
|
83
|
+
|
84
|
+
endpoint[:modules_and_options] << {
|
85
|
+
:module_name => "auxiliary/scanner/snmp/snmp_enumshares",
|
86
|
+
:module_option_string => "RHOSTS #{endpoint[:ip_address]}, RPORT #{endpoint[:port_num]}" }
|
87
|
+
|
88
|
+
endpoint[:modules_and_options] << {
|
89
|
+
:module_name => "auxiliary/scanner/snmp/snmp_enumusers",
|
90
|
+
:module_option_string => "RHOSTS #{endpoint[:ip_address]}, RPORT #{endpoint[:port_num]}" }
|
91
|
+
|
92
|
+
#
|
93
|
+
# HTTPS
|
94
|
+
#
|
95
|
+
elsif endpoint[:protocol] == "HTTPS"
|
96
|
+
endpoint[:modules_and_options] << {
|
97
|
+
:module_name => "auxiliary/scanner/http/http_version",
|
98
|
+
:module_option_string => "RHOSTS #{endpoint[:ip_address]}, RPORT #{endpoint[:port_num]}" }
|
99
|
+
|
100
|
+
endpoint[:modules_and_options] << {
|
101
|
+
:module_name => "auxiliary/scanner/http/cert",
|
102
|
+
:module_option_string => "RHOSTS #{endpoint[:ip_address]}, RPORT #{endpoint[:port_num]}" }
|
103
|
+
#
|
104
|
+
# Unknown protocol
|
105
|
+
#
|
106
|
+
else
|
107
|
+
|
108
|
+
end
|
109
|
+
|
110
|
+
# Return the modified endpoint
|
111
|
+
endpoint
|
112
|
+
end
|
113
|
+
|
114
|
+
|
115
|
+
# Public: Returns a guessed protocol based on transport and port num
|
116
|
+
#
|
117
|
+
# Returns a protocol (string)
|
118
|
+
def self.get_protocol_by_port_num(endpoint)
|
119
|
+
#return endpoint[:protocol] unless endpoint[:protocol] == nil
|
120
|
+
|
121
|
+
protocol = nil
|
122
|
+
if endpoint[:transport] == "TCP"
|
123
|
+
if endpoint[:port_num] == 21
|
124
|
+
protocol = "FTP"
|
125
|
+
elsif endpoint[:port_num] == 23
|
126
|
+
protocol = "TELNET"
|
127
|
+
elsif endpoint[:port_num] == 80
|
128
|
+
protocol = "HTTP"
|
129
|
+
elsif endpoint[:port_num] == 443
|
130
|
+
protocol = "HTTPS"
|
131
|
+
elsif endpoint[:port_num] == 8080
|
132
|
+
protocol = "HTTP"
|
133
|
+
end
|
134
|
+
elsif endpoint[:transport] == "UDP"
|
135
|
+
if endpoint[:port_num] == 161
|
136
|
+
protocol = "SNMP"
|
137
|
+
end
|
138
|
+
else
|
139
|
+
raise "Unknown Transport"
|
140
|
+
end
|
141
|
+
|
142
|
+
protocol
|
143
|
+
end
|
144
|
+
|
145
|
+
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/msfrpc-simple/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["jcran"]
|
6
|
+
gem.email = ["jcran@pentestify.com"]
|
7
|
+
gem.description = %q{Simple interface to Metasploit RPC}
|
8
|
+
gem.summary = %q{Simple interface to Metasploit RPC}
|
9
|
+
gem.homepage = "http://www.github.com/jcran/msfrpc-simple"
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.name = "msfrpc-simple"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = Msf::RPC::Simple::VERSION
|
17
|
+
end
|
data/spec/client_spec.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
describe "Msf" do
|
3
|
+
describe "RPC" do
|
4
|
+
describe "Simple" do
|
5
|
+
describe "Client" do
|
6
|
+
|
7
|
+
before :each do
|
8
|
+
|
9
|
+
@client = Msf::RPC::Simple::Client.new("default", "test", "test", {
|
10
|
+
# :host => "127.0.0.1",
|
11
|
+
# :port => 55553,
|
12
|
+
# :uri => '/api/'
|
13
|
+
# :ssl => true,
|
14
|
+
# :password => 'test'
|
15
|
+
})
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
it "connects to local default msfrpcd" do
|
21
|
+
|
22
|
+
# This spec requrires the msfrpcd to be runnning...
|
23
|
+
#
|
24
|
+
# ./msfrpcd -P test -U test
|
25
|
+
#
|
26
|
+
|
27
|
+
#
|
28
|
+
# notice how this client isn't @client, allowing us to modify @client
|
29
|
+
# as necessary
|
30
|
+
#
|
31
|
+
client = Msf::RPC::Simple::Client.new("default", "test", "test", {
|
32
|
+
# :host => "127.0.0.1",
|
33
|
+
# :port => 55553,
|
34
|
+
# :uri => '/api/'
|
35
|
+
# :ssl => true,
|
36
|
+
# :password => 'test'
|
37
|
+
})
|
38
|
+
|
39
|
+
client.connected?.should be_true
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
it "runs a module and gives the output" do
|
44
|
+
output = @client.execute_module_and_return_output({
|
45
|
+
:module_name => "auxiliary/scanner/http/http_version",
|
46
|
+
:module_option_string => "RHOSTS www.google.com,THREADS 10"
|
47
|
+
})
|
48
|
+
output.should include "Auxiliary module execution completed"
|
49
|
+
end
|
50
|
+
|
51
|
+
it "runs a basic discover with framework modules" do
|
52
|
+
output = @client.discover_host("www.google.com")
|
53
|
+
output.should include "Auxiliary module execution completed"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
data/spec/logger_spec.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
describe "Msf" do
|
3
|
+
describe "RPC" do
|
4
|
+
describe "Simple" do
|
5
|
+
describe "Logger" do
|
6
|
+
|
7
|
+
it "writes to a logfile" do
|
8
|
+
|
9
|
+
@logger = Msf::RPC::Simple::Logger.new
|
10
|
+
@logger.log "test"
|
11
|
+
@logger.close
|
12
|
+
|
13
|
+
File.open("msfrpc-simple.log").read.should == "test\n"
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
describe "Msf" do
|
3
|
+
describe "RPC" do
|
4
|
+
describe "Simple" do
|
5
|
+
describe "ModuleMapper" do
|
6
|
+
|
7
|
+
before :each do
|
8
|
+
end
|
9
|
+
|
10
|
+
it "maps modules for a standard HTTP endpoint" do
|
11
|
+
|
12
|
+
endpoint = {
|
13
|
+
:ip_address => "1.1.1.1",
|
14
|
+
:port_num => 80,
|
15
|
+
:transport => "TCP",
|
16
|
+
:protocol => "HTTP"
|
17
|
+
}
|
18
|
+
|
19
|
+
endpoint_and_modules = Msf::RPC::Simple::ModuleMapper.get_discovery_modules_for_endpoint endpoint
|
20
|
+
|
21
|
+
endpoint_and_modules[:ip_address].should == "1.1.1.1"
|
22
|
+
endpoint_and_modules[:port_num].should == 80
|
23
|
+
endpoint_and_modules[:transport].should == "TCP"
|
24
|
+
endpoint_and_modules[:protocol].should == "HTTP"
|
25
|
+
endpoint_and_modules[:modules_and_options].should include({
|
26
|
+
:module_name => "auxiliary/scanner/http/http_version",
|
27
|
+
:module_option_string => "RHOSTS 1.1.1.1, RPORT 80"
|
28
|
+
})
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
it "maps modules for a non-standard HTTP endpoint" do
|
33
|
+
|
34
|
+
endpoint = {
|
35
|
+
:ip_address => "1.1.1.1",
|
36
|
+
:port_num => 8080,
|
37
|
+
:transport => "TCP",
|
38
|
+
}
|
39
|
+
|
40
|
+
endpoint_and_modules = Msf::RPC::Simple::ModuleMapper.get_discovery_modules_for_endpoint endpoint
|
41
|
+
|
42
|
+
endpoint_and_modules[:ip_address].should == "1.1.1.1"
|
43
|
+
endpoint_and_modules[:port_num].should == 8080
|
44
|
+
endpoint_and_modules[:transport].should == "TCP"
|
45
|
+
endpoint_and_modules[:protocol].should == "HTTP"
|
46
|
+
endpoint_and_modules[:modules_and_options].should include({
|
47
|
+
:module_name => "auxiliary/scanner/http/http_version",
|
48
|
+
:module_option_string => "RHOSTS 1.1.1.1, RPORT 8080"
|
49
|
+
})
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: msfrpc-simple
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- jcran
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-08-16 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: Simple interface to Metasploit RPC
|
15
|
+
email:
|
16
|
+
- jcran@pentestify.com
|
17
|
+
executables: []
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- Gemfile
|
22
|
+
- Gemfile.lock
|
23
|
+
- LICENSE
|
24
|
+
- README.md
|
25
|
+
- Rakefile
|
26
|
+
- lib/.DS_Store
|
27
|
+
- lib/msfrpc-simple.rb
|
28
|
+
- lib/msfrpc-simple/.DS_Store
|
29
|
+
- lib/msfrpc-simple/client.rb
|
30
|
+
- lib/msfrpc-simple/features/.DS_Store
|
31
|
+
- lib/msfrpc-simple/features/framework.rb
|
32
|
+
- lib/msfrpc-simple/features/pro.rb
|
33
|
+
- lib/msfrpc-simple/logger.rb
|
34
|
+
- lib/msfrpc-simple/module_mapper.rb
|
35
|
+
- lib/msfrpc-simple/version.rb
|
36
|
+
- msfrpc-simple.gemspec
|
37
|
+
- spec/client_spec.rb
|
38
|
+
- spec/logger_spec.rb
|
39
|
+
- spec/module_mapper_spec.rb
|
40
|
+
- spec/spec_helper.rb
|
41
|
+
homepage: http://www.github.com/jcran/msfrpc-simple
|
42
|
+
licenses: []
|
43
|
+
post_install_message:
|
44
|
+
rdoc_options: []
|
45
|
+
require_paths:
|
46
|
+
- lib
|
47
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
48
|
+
none: false
|
49
|
+
requirements:
|
50
|
+
- - ! '>='
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: '0'
|
53
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
54
|
+
none: false
|
55
|
+
requirements:
|
56
|
+
- - ! '>='
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
version: '0'
|
59
|
+
requirements: []
|
60
|
+
rubyforge_project:
|
61
|
+
rubygems_version: 1.8.24
|
62
|
+
signing_key:
|
63
|
+
specification_version: 3
|
64
|
+
summary: Simple interface to Metasploit RPC
|
65
|
+
test_files:
|
66
|
+
- spec/client_spec.rb
|
67
|
+
- spec/logger_spec.rb
|
68
|
+
- spec/module_mapper_spec.rb
|
69
|
+
- spec/spec_helper.rb
|