msfrpc-client 1.0.0

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.
@@ -0,0 +1,9 @@
1
+ # Metasploit Pro RPC Client
2
+
3
+ This is the official Ruby client for the Metasploit Pro RPC service. Metasploit
4
+ Pro is a commercial penetration testing product provided by Rapid7. For more
5
+ information on Metasploit Pro, please visit the http://www.metasploit.com/ site.
6
+
7
+ # Credits
8
+ Rapid7 LLC
9
+
@@ -0,0 +1,18 @@
1
+ # encoding: utf-8
2
+
3
+ task :build => :update do
4
+ Rake::Task['clean'].execute
5
+ puts "[*] Building msfrpc-client.gemspec"
6
+ system "gem build msfrpc-client.gemspec &> /dev/null"
7
+ end
8
+
9
+ task :release => :build do
10
+ puts "[*] Pushing msfrpc-client to rubygems.org"
11
+ system "gem push msfrpc-client-*.gem &> /dev/null"
12
+ Rake::Task['clean'].execute
13
+ end
14
+
15
+ task :clean do
16
+ system "rm *.gem &> /dev/null"
17
+ end
18
+
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'optparse'
5
+ require 'msfrpc-client'
6
+ require 'rex/ui'
7
+
8
+
9
+ # Use the RPC option parser to handle standard flags
10
+ opts = {}
11
+ parser = Msf::RPC::Client.option_parser(opts)
12
+ parser.parse!(ARGV)
13
+
14
+ # Parse additional options, environment variables, etc
15
+ opts = Msf::RPC::Client.option_handler(opts)
16
+
17
+ # Create the RPC client with our parsed options
18
+ rpc = Msf::RPC::Client.new(opts)
19
+
20
+ $stdout.puts "[*] The RPC client is available in variable 'rpc'"
21
+ if rpc.token
22
+ $stdout.puts "[*] Sucessfully authenticated to the server"
23
+ end
24
+
25
+ $stdout.puts "[*] Starting IRB shell..."
26
+ Rex::Ui::Text::IrbShell.new(binding).run
27
+
@@ -0,0 +1,126 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'optparse'
5
+ require 'msfrpc-client'
6
+ require 'rex/ui'
7
+
8
+ def usage(ropts)
9
+ $stderr.puts ropts
10
+
11
+ if @rpc and @rpc.token
12
+ wspaces = @rpc.call("pro.workspaces") rescue {}
13
+ if wspaces.keys.length > 0
14
+ $stderr.puts "Active Projects:"
15
+ wspaces.each_pair do |k,v|
16
+ $stderr.puts "\t#{k}"
17
+ end
18
+ end
19
+ end
20
+ $stderr.puts ""
21
+ exit(1)
22
+ end
23
+
24
+ opts = {
25
+ :format => 'PDF'
26
+ }
27
+
28
+ parser = Msf::RPC::Client.option_parser(opts)
29
+
30
+ parser.separator('Report Options:')
31
+ parser.on("--format FORMAT") do |v|
32
+ opts[:format] = v.upcase
33
+ end
34
+
35
+ parser.on("--project PROJECT") do |v|
36
+ opts[:project] = v
37
+ end
38
+
39
+ parser.on("--output OUTFILE") do |v|
40
+ opts[:output] = v
41
+ end
42
+
43
+ parser.on("--help") do
44
+ $stderr.puts ropts
45
+ exit(1)
46
+ end
47
+ parser.separator('')
48
+
49
+ parser.parse!(ARGV)
50
+ @rpc = Msf::RPC::Client.new(opts)
51
+
52
+ if not @rpc.token
53
+ $stderr.puts "Error: Invalid RPC server options specified"
54
+ $stderr.puts parser
55
+ exit(1)
56
+ end
57
+
58
+ wspace = opts[:project] || usage(parser)
59
+ fname = opts[:output] || usage(parser)
60
+ rtype = opts[:format]
61
+ user = @rpc.call("pro.default_admin_user")['username']
62
+
63
+ task = @rpc.call("pro.start_report", {
64
+ 'DS_WHITELIST_HOSTS' => "",
65
+ 'DS_BLACKLIST_HOSTS' => "",
66
+ 'workspace' => wspace,
67
+ 'username' => user,
68
+ 'DS_MaskPasswords' => false,
69
+ 'DS_IncludeTaskLog' => false,
70
+ 'DS_JasperDisplaySession' => true,
71
+ 'DS_JasperDisplayCharts' => true,
72
+ 'DS_LootExcludeScreenshots' => false,
73
+ 'DS_LootExcludePasswords' => false,
74
+ 'DS_JasperTemplate' => "msfxv3.jrxml",
75
+ 'DS_REPORT_TYPE' => rtype.upcase,
76
+ 'DS_UseJasper' => true,
77
+ 'DS_UseCustomReporting' => true,
78
+ 'DS_JasperProductName' => "Metasploit Pro",
79
+ 'DS_JasperDbEnv' => "production",
80
+ 'DS_JasperLogo' => '',
81
+ 'DS_JasperDisplaySections' => "1,2,3,4,5,6,7,8",
82
+ 'DS_EnablePCIReport' => true,
83
+ 'DS_EnableFISMAReport' => true,
84
+ 'DS_JasperDisplayWeb' => true,
85
+ })
86
+
87
+
88
+ if not task['task_id']
89
+ $stderr.puts "[-] Error generating the report: #{task.inspect}"
90
+ exit(0)
91
+ end
92
+
93
+ puts "[*] Report is generating with Task ID #{task['task_id']}..."
94
+ while true
95
+ select(nil, nil, nil, 0.50)
96
+ stat = @rpc.call("pro.task_status", task['task_id'])
97
+ if stat['status'] == 'invalid'
98
+ $stderr.puts "[-] Error checking task status"
99
+ exit(0)
100
+ end
101
+
102
+ info = stat[ task['task_id'] ]
103
+
104
+ if not info
105
+ $stderr.puts "[-] Error finding the task"
106
+ exit(0)
107
+ end
108
+
109
+ if info['status'] == "error"
110
+ $stderr.puts "[-] Error generating report: #{info['error']}"
111
+ exit(0)
112
+ end
113
+
114
+ break if info['progress'] == 100
115
+ end
116
+
117
+ report = @rpc.call('pro.report_download_by_task', task['task_id'])
118
+ if report and report['data']
119
+ ::File.open(fname, "wb") do |fd|
120
+ fd.write(report['data'])
121
+ end
122
+ $stderr.puts "[-] Report saved to #{::File.expand_path(fname)}"
123
+ else
124
+ $stderr.puts "[-] Error downloading report: #{report.inspect}"
125
+ end
126
+
@@ -0,0 +1,2 @@
1
+ require 'msfrpc-client/client'
2
+
@@ -0,0 +1,214 @@
1
+ # MessagePack for data encoding (http://www.msgpack.org/)
2
+ require 'msgpack'
3
+
4
+ # Standardize option parsing
5
+ require "optparse"
6
+
7
+ # Parse configuration file
8
+ require 'yaml'
9
+
10
+ # Rex library from the Metasploit Framework
11
+ require 'rex'
12
+ require 'rex/proto/http'
13
+
14
+ # Constants used by this client
15
+ require 'msfrpc-client/constants'
16
+
17
+ module Msf
18
+ module RPC
19
+
20
+ class Client
21
+
22
+ attr_accessor :token, :info
23
+
24
+ #
25
+ # Create a new RPC Client instance
26
+ #
27
+ def initialize(info={})
28
+ self.info = {
29
+ :host => '127.0.0.1',
30
+ :port => 3790,
31
+ :uri => '/api',
32
+ :ssl => true,
33
+ :ssl_version => 'SSLv3',
34
+ :context => {}
35
+ }.merge(info)
36
+
37
+ info[:port] = info[:port].to_i
38
+
39
+ self.token = self.info[:token]
40
+
41
+ if not self.token and (info[:user] and info[:pass])
42
+ login(info[:user], info[:pass])
43
+ end
44
+ end
45
+
46
+ #
47
+ # Authenticate using a username and password
48
+ #
49
+ def login(user,pass)
50
+ res = self.call("auth.login", user, pass)
51
+ if(not (res and res['result'] == "success"))
52
+ raise RuntimeError, "authentication failed"
53
+ end
54
+ self.token = res['token']
55
+ true
56
+ end
57
+
58
+ #
59
+ # Prepend the authentication token as the first parameter
60
+ # of every call except auth.login. This simplifies the
61
+ # calling API.
62
+ #
63
+ def call(meth, *args)
64
+ if(meth != "auth.login")
65
+ if(not self.token)
66
+ raise RuntimeError, "client not authenticated"
67
+ end
68
+ args.unshift(self.token)
69
+ end
70
+
71
+ args.unshift(meth)
72
+
73
+ if not @cli
74
+ @cli = Rex::Proto::Http::Client.new(info[:host], info[:port], info[:context], info[:ssl], info[:ssl_version])
75
+ @cli.set_config(
76
+ :vhost => info[:host],
77
+ :agent => "Metasploit Pro RPC Client/#{API_VERSION}",
78
+ :read_max_data => (1024*1024*512)
79
+ )
80
+ end
81
+
82
+ req = @cli.request_cgi(
83
+ 'method' => 'POST',
84
+ 'uri' => self.info[:uri],
85
+ 'ctype' => 'binary/message-pack',
86
+ 'data' => args.to_msgpack
87
+ )
88
+
89
+ res = @cli.send_recv(req)
90
+
91
+ if res and [200, 401, 403, 500].include?(res.code)
92
+ resp = MessagePack.unpack(res.body)
93
+
94
+ if resp and resp.kind_of?(::Hash) and resp['error'] == true
95
+ raise Msf::RPC::ServerException.new(res.code, resp['error_message'] || resp['error_string'], resp['error_class'], resp['error_backtrace'])
96
+ end
97
+
98
+ return resp
99
+ else
100
+ raise RuntimeError, res.inspect
101
+ end
102
+ end
103
+
104
+
105
+ #
106
+ # Class methods
107
+ #
108
+
109
+
110
+ #
111
+ # Provides a parser object that understands the
112
+ # RPC specific options
113
+ #
114
+ def self.option_parser(options)
115
+ parser = OptionParser.new
116
+
117
+ parser.banner = "Usage: #{$0} [options]"
118
+ parser.separator('')
119
+ parser.separator('RPC Options:')
120
+
121
+ parser.on("--rpc-host HOST") do |v|
122
+ options[:host] = v
123
+ end
124
+
125
+ parser.on("--rpc-port PORT") do |v|
126
+ options[:port] = v.to_i
127
+ end
128
+
129
+ parser.on("--rpc-ssl <true|false>") do |v|
130
+ options[:ssl] = v
131
+ end
132
+
133
+ parser.on("--rpc-uri URI") do |v|
134
+ options[:uri] = v
135
+ end
136
+
137
+ parser.on("--rpc-user USERNAME") do |v|
138
+ options[:user] = v
139
+ end
140
+
141
+ parser.on("--rpc-pass PASSWORD") do |v|
142
+ options[:pass] = v
143
+ end
144
+
145
+ parser.on("--rpc-token TOKEN") do |v|
146
+ options[:token] = v
147
+ end
148
+
149
+ parser.on("--rpc-config CONFIG-FILE") do |v|
150
+ options[:config] = v
151
+ end
152
+
153
+ parser.on("--rpc-help") do
154
+ $stderr.puts parser
155
+ exit(1)
156
+ end
157
+
158
+ parser.separator('')
159
+
160
+ parser
161
+ end
162
+
163
+ #
164
+ # Load options from the command-line, environment.
165
+ # and any configuration files specified
166
+ #
167
+ def self.option_handler(options={})
168
+ options[:host] ||= ENV['MSFRPC_HOST']
169
+ options[:port] ||= ENV['MSFRPC_PORT']
170
+ options[:uri] ||= ENV['MSFRPC_URI']
171
+ options[:user] ||= ENV['MSFRPC_USER']
172
+ options[:pass] ||= ENV['MSFRPC_PASS']
173
+ options[:ssl] ||= ENV['MSFRPC_SSL']
174
+ options[:token] ||= ENV['MSFRPC_TOKEN']
175
+ options[:config] ||= ENV['MSFRPC_CONFIG']
176
+
177
+ empty_keys = options.keys.select{|k| options[k].nil? }
178
+ empty_keys.each { |k| options.delete(k) }
179
+
180
+ config_file = options.delete(:config)
181
+
182
+ if config_file
183
+ yaml_data = ::File.read(config_file) rescue nil
184
+ if yaml_data
185
+ yaml = ::YAML.load(yaml_data) rescue nil
186
+ if yaml and yaml.kind_of?(::Hash) and yaml['options']
187
+ yaml['options'].each_pair do |k,v|
188
+ options[k.intern] = v
189
+ end
190
+ else
191
+ $stderr.puts "[-] Could not parse configuration file: #{config_file}"
192
+ exit(1)
193
+ end
194
+ else
195
+ $stderr.puts "[-] Could not read configuration file: #{config_file}"
196
+ exit(1)
197
+ end
198
+ end
199
+
200
+ if options[:port]
201
+ options[:port] = options[:port].to_i
202
+ end
203
+
204
+ if options[:ssl]
205
+ options[:ssl] = (options[:ssl] =~ /(1|Y|T)/i ? true : false )
206
+ end
207
+
208
+ options
209
+ end
210
+
211
+ end
212
+ end
213
+ end
214
+
@@ -0,0 +1,34 @@
1
+ module Msf
2
+ module RPC
3
+
4
+ API_VERSION = "1.0"
5
+
6
+
7
+ class Exception < RuntimeError
8
+ attr_accessor :code, :message
9
+
10
+ def initialize(code, message)
11
+ self.code = code
12
+ self.message = message
13
+ end
14
+ end
15
+
16
+
17
+ class ServerException < RuntimeError
18
+ attr_accessor :code, :error_message, :error_class, :error_backtrace
19
+
20
+ def initialize(code, error_message, error_class, error_backtrace)
21
+ self.code = code
22
+ self.error_message = error_message
23
+ self.error_class = error_class
24
+ self.error_backtrace = error_backtrace
25
+ end
26
+
27
+ def to_s
28
+ "#{self.error_class} #{self.error_message} #{self.error_backtrace}"
29
+ end
30
+ end
31
+
32
+ end
33
+ end
34
+
metadata ADDED
@@ -0,0 +1,107 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: msfrpc-client
3
+ version: !ruby/object:Gem::Version
4
+ hash: 23
5
+ prerelease:
6
+ segments:
7
+ - 1
8
+ - 0
9
+ - 0
10
+ version: 1.0.0
11
+ platform: ruby
12
+ authors:
13
+ - HD Moore
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-07-23 00:00:00 -05:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: msgpack
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 5
30
+ segments:
31
+ - 0
32
+ - 4
33
+ - 5
34
+ version: 0.4.5
35
+ type: :runtime
36
+ version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: librex
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ hash: 95
46
+ segments:
47
+ - 0
48
+ - 0
49
+ - 32
50
+ version: 0.0.32
51
+ type: :runtime
52
+ version_requirements: *id002
53
+ description: This gem provides a Ruby client API to access the Rapid7 Metasploit Pro RPC service.
54
+ email:
55
+ - hdm@metasploit.com
56
+ executables: []
57
+
58
+ extensions: []
59
+
60
+ extra_rdoc_files:
61
+ - README.markdown
62
+ files:
63
+ - Rakefile
64
+ - README.markdown
65
+ - lib/msfrpc-client/client.rb
66
+ - lib/msfrpc-client/constants.rb
67
+ - lib/msfrpc-client.rb
68
+ - examples/msfrpc_irb.rb
69
+ - examples/msfrpc_pro_report.rb
70
+ has_rdoc: true
71
+ homepage: http://www.metasploit.com/
72
+ licenses:
73
+ - BSD
74
+ post_install_message:
75
+ rdoc_options: []
76
+
77
+ require_paths:
78
+ - lib
79
+ required_ruby_version: !ruby/object:Gem::Requirement
80
+ none: false
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ hash: 57
85
+ segments:
86
+ - 1
87
+ - 8
88
+ - 7
89
+ version: 1.8.7
90
+ required_rubygems_version: !ruby/object:Gem::Requirement
91
+ none: false
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ hash: 3
96
+ segments:
97
+ - 0
98
+ version: "0"
99
+ requirements: []
100
+
101
+ rubyforge_project:
102
+ rubygems_version: 1.4.2
103
+ signing_key:
104
+ specification_version: 3
105
+ summary: Ruby API for the Rapid7 Metasploit Pro RPC service
106
+ test_files: []
107
+