Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
beefproject
GitHub Repository: beefproject/beef
Path: blob/master/extensions/metasploit/rpcclient.rb
1154 views
1
#
2
# Copyright (c) 2006-2025 Wade Alcorn - [email protected]
3
# Browser Exploitation Framework (BeEF) - https://beefproject.com
4
# See the file 'doc/COPYING' for copying permission
5
#
6
module BeEF
7
module Extension
8
module Metasploit
9
class RpcClient < ::Msf::RPC::Client
10
include Singleton
11
12
def initialize
13
@config = BeEF::Core::Configuration.instance.get('beef.extension.metasploit')
14
15
unless @config.key?('host') || @config.key?('uri') || @config.key?('port') ||
16
@config.key?('user') || @config.key?('pass')
17
print_error 'There is not enough information to initalize Metasploit connectivity at this time'
18
print_error 'Please check your options in config.yaml to verify that all information is present'
19
BeEF::Core::Configuration.instance.set('beef.extension.metasploit.enabled', false)
20
BeEF::Core::Configuration.instance.set('beef.extension.metasploit.loaded', false)
21
return
22
end
23
24
@lock = false
25
@lastauth = nil
26
@unit_test = false
27
@msf_path = nil
28
29
opts = {
30
host: @config['host'] || '127.0.0.1',
31
port: @config['port'] || 55_552,
32
uri: @config['uri'] || '/api/',
33
ssl: @config['ssl'],
34
ssl_version: @config['ssl_version'],
35
context: {}
36
}
37
38
print_warning '[Metasploit] Warning: Connections to Metasploit RPC over SSLv3 are insecure. Use TLSv1 instead.' if opts[:ssl_version].match?(/SSLv3/i)
39
40
if @config['auto_msfrpcd']
41
@config['msf_path'].each do |path|
42
@msf_path = "#{path['path']}/msfrpcd" if File.exist? "#{path['path']}/msfrpcd"
43
end
44
45
if @msf_path.nil?
46
print_error '[Metasploit] Please add a custom path for msfrpcd to the config file.'
47
return
48
end
49
50
print_info "[Metasploit] Found msfrpcd: #{@msf_path}"
51
52
return unless launch_msfrpcd(opts)
53
end
54
55
super(opts)
56
end
57
58
#
59
# @note auto start msfrpcd
60
#
61
def launch_msfrpcd(opts)
62
if opts[:ssl]
63
argssl = '-S'
64
proto = 'http'
65
else
66
argssl = ''
67
proto = 'https'
68
end
69
70
msf_url = "#{proto}://#{opts[:host]}:#{opts[:port]}#{opts[:uri]}"
71
72
child = IO.popen([
73
@msf_path,
74
'-f',
75
argssl,
76
'-P', @config['pass'],
77
'-U', @config['user'],
78
'-u', opts[:uri],
79
'-a', opts[:host],
80
'-p', opts[:port].to_s
81
], 'r+')
82
83
print_info "[Metasploit] Attempt to start msfrpcd, this may take a while. PID: #{child.pid}"
84
85
# Give daemon time to launch
86
# poll and giveup after timeout
87
retries = @config['auto_msfrpcd_timeout']
88
uri = URI(msf_url)
89
http = Net::HTTP.new(uri.host, uri.port)
90
91
if opts[:ssl]
92
http.use_ssl = true
93
http.ssl_version = opts[:ssl_version]
94
end
95
96
http.verify_mode = OpenSSL::SSL::VERIFY_NONE unless @config['ssl_verify']
97
98
headers = { 'Content-Type' => 'binary/message-pack' }
99
path = uri.path.empty? ? '/' : uri.path
100
101
begin
102
sleep 1
103
code = http.head(path, headers).code.to_i
104
print_debug "[Metasploit] Success - HTTP response: #{code}"
105
rescue StandardError
106
retry if (retries -= 1).positive?
107
end
108
109
true
110
end
111
112
def get_lock
113
sleep 0.2 while @lock
114
@lock = true
115
end
116
117
def release_lock
118
@lock = false
119
end
120
121
def call(meth, *args)
122
super(meth, *args)
123
rescue StandardError => e
124
print_error "[Metasploit] RPC call to '#{meth}' failed: #{e}"
125
print_error e.backtrace
126
nil
127
end
128
129
def unit_test_init
130
@unit_test = true
131
end
132
133
# login to metasploit
134
def login
135
get_lock
136
137
res = super(@config['user'], @config['pass'])
138
139
unless res
140
print_error '[Metasploit] Could not authenticate to Metasploit RPC sevrice.'
141
return false
142
end
143
144
unless @lastauth
145
print_info '[Metasploit] Successful connection with Metasploit.' unless @unit_test
146
print_debug "[Metasploit] Received temporary token: #{token}"
147
148
# Generate permanent token
149
new_token = token_generate
150
if new_token.nil?
151
print_warning '[Metasploit] Could not retrieve permanent Metasploit token. Connection to Metasploit will time out in 5 minutes.'
152
else
153
self.token = new_token
154
print_debug "[Metasploit] Received permanent token: #{token}"
155
end
156
end
157
@lastauth = Time.now
158
159
true
160
ensure
161
release_lock
162
end
163
164
# generate a permanent auth token
165
def token_generate
166
res = call('auth.token_generate')
167
168
return unless res || res['token']
169
170
res['token']
171
end
172
173
def browser_exploits
174
get_lock
175
res = call('module.exploits')
176
177
return [] unless res || res['modules']
178
179
res['modules'].select { |m| m.include?('/browser/') }.sort
180
ensure
181
release_lock
182
end
183
184
def get_exploit_info(name)
185
get_lock
186
res = call('module.info', 'exploit', name)
187
res || {}
188
rescue StandardError => e
189
print_error "Call module.info for module #{name} failed: #{e.message}"
190
{}
191
ensure
192
release_lock
193
end
194
195
def get_payloads(name)
196
get_lock
197
res = call('module.compatible_payloads', name)
198
res || {}
199
rescue StandardError => e
200
print_error "Call module.compatible_payloads for module #{name} failed: #{e.message}"
201
{}
202
ensure
203
release_lock
204
end
205
206
def get_options(name)
207
get_lock
208
res = call('module.options', 'exploit', name)
209
res || {}
210
rescue StandardError => e
211
print_error "Call module.options for module #{name} failed: #{e.message}"
212
{}
213
ensure
214
release_lock
215
end
216
217
def payloads
218
get_lock
219
res = call('module.payloads')
220
return {} unless res || res['modules']
221
222
res['modules']
223
rescue StandardError => e
224
print_error "Call module.payloads failed: #{e.message}"
225
{}
226
ensure
227
release_lock
228
end
229
230
def payload_options(name)
231
get_lock
232
res = call('module.options', 'payload', name)
233
return {} unless res
234
235
res
236
rescue StandardError => e
237
print_error "Call module.options for payload #{name} failed: #{e.message}"
238
{}
239
ensure
240
release_lock
241
end
242
243
def launch_exploit(exploit, opts)
244
get_lock
245
res = call('module.execute', 'exploit', exploit, opts)
246
proto = opts['SSL'] ? 'https' : 'http'
247
res['uri'] = "#{proto}://#{@config['callback_host']}:#{opts['SRVPORT']}/#{opts['URIPATH']}"
248
res
249
rescue StandardError => e
250
print_error "Exploit failed for #{exploit}\n#{e.message}"
251
false
252
ensure
253
release_lock
254
end
255
256
def launch_autopwn
257
opts = {
258
'LHOST' => @config['callback_host'],
259
'URIPATH' => @apurl
260
}
261
get_lock
262
call('module.execute', 'auxiliary', 'server/browser_autopwn', opts)
263
rescue StandardError => e
264
print_error "Failed to launch browser_autopwn: #{e.message}"
265
false
266
ensure
267
release_lock
268
end
269
end
270
end
271
end
272
end
273
274