Note:
The ronin-exploits new
command can generate a skeleton exploit
file, complete with included modules and metadata, which can save some typing.
This guide explains how to convert a Metasploit exploit into a Ronin exploit.
check
vs. test methodsexploit
vs. validate
/build
/launch
/cleanup
methodscleanup
methodfail_with
vs. fail
methodsEvery Metasploit exploit class is named MetasploitModule
and inherits from
either Msf::Exploit::Remote
, Msf::Exploit::Local
, or Msf::Exploit
.
class MetasploitModule < Msf::Exploit::Remote
# ...
end
Ronin exploits classes must be:
Ronin::Exploits
namespace.CamelCase
name similar to the file name.register
with the same name as it’s file name.# exploits/my_exploit.rb
require 'ronin/exploits/exploit'
module Ronin
module Exploits
class MyExploit < Exploit
register 'my_exploit'
# ...
end
end
end
Both Metasploit exploits and Ronin exploit classes will include modules to add additional functionality.
class MetasploitModule < Msf::Exploit::Remote
include Msf::Exploit::Remote::Tcp
# ...
end
require 'ronin/exploits/exploit'
require 'ronin/exploits/mixins/remote_tcp'
module Ronin
module Exploits
class MyExploit < Exploit
include Mixins::RemoteTCP
# ...
end
end
end
Metasploit | Ronin |
---|---|
Msf::Exploit::Remote::Tcp |
Mixins::RemoteTCP |
Msf::Exploit::Remote::Udp |
Mixins::RemoteUDP |
Msf::Exploit::Remote::HttpClient |
Mixins::HTTP |
Msf::Exploit::Seh |
Mixins::SEH |
Msf::Exploit::FormatString |
Mixins::FormatString |
Metasploit exploits define their metadata in the initialize
method by
passing a large Hash of Strings:
class MetasploitModule < Msf::Exploit::Remote
def initialize(info = {})
super(update_info(info,
'Name' => 'DD-WRT HTTP Daemon Arbitrary Command Execution',
'Description' => %q{
This module abuses a metacharacter injection vulnerability in the
HTTP management server of wireless gateways running DD-WRT. This flaw
allows an unauthenticated attacker to execute arbitrary commands as
the root user account.
},
'Author' => [ 'gat3way', 'hdm' ],
'License' => MSF_LICENSE,
'References' =>
[
[ 'CVE', '2009-2765' ],
[ 'OSVDB', '55990' ],
[ 'BID', '35742' ],
[ 'EDB', '9209' ]
],
# ...
'DisclosureDate' => '2009-07-20'
))
end
end
Ronin exploits and payloads define their metadata in the class body by calling class methods:
require 'ronin/exploits/exploit'
module Ronin
module Exploits
class MyExploit < Exploit
register 'my_exploit'
summary 'A single sentence summary of the exploit'
description <<~EOS
A longer multi-line or multi-paragraph description of the exploit.
Bla bla bla bla.
EOS
author 'Author1'
author 'Author2', website: 'https://example.com',
email: 'author1@example2.com',
github: 'author2',
mastodon: 'https://example.com/@author2',
twitter: '@author2',
discord: '...'
disclosure_date 'YYY-MM-DD'
release_date 'YYYY-MM-DD'
advisory 'CVE-YYYY-NNNN'
advisory 'GHSA-XXXXXX'
software 'TestHTTP'
software_versions '1.0.0'..'1.5.4'
references [
'https://example.com/url1',
'https://example.com/url2',
# ...
]
# ...
end
end
end
Additional metadata modules can be included to define additional metadata, such as Metadata::Arch or Metadata::OS. If the exploit class inherits from the MemoryCorruption class, or one of it’s sub-class, then those modules are already included by default.
require 'ronin/exploits/stack_overflow'
module Ronin
module Exploits
class MyExploit < StackOverflow
# ...
arch :arm
os :linux
# ...
end
end
end
See the arch, os, and os_version method documentation for further details.
Metasploit | Ronin |
Name' => '...', |
summary '...' |
'Description' => %q{ ... }, |
description <<~DESC ... DESC |
'License' => MSF_LICENSE, |
N/A |
'Author' => [ 'John Doe', # discoverer ... ], |
author 'John Doe' ... |
'References' => [ [ 'CVE', 'YYYY-NNNN' ], [ 'GHSA', 'XXXXXX' ], [ 'URL', 'https://example.com/...' ], ], |
advisory 'CVE-YYYY-NNNN' advisory 'GHSA-XXXXXX' references [ 'https://example.com/...', # ... ] |
'Platform' => 'Linux', |
include Metadata::OS # ... os :linux |
Metasploit exploits define additional platform targeting information as an Array of Arrays in the metadata section.
class MetasploitModule < Msf::Exploit::Remote
# ...
def initialize(info = {})
super(update_info(info,
# ...
'Targets' =>
[
# npFoxitReaderPlugin.dll version 2.2.1.530
[ 'Automatic', {} ],
[ 'Windows 7 SP1 / Firefox 18 / Foxit Reader 5.4.4.11281',
{
'Offset' => 272,
'Ret' => 0x1000c57d, # pop # ret # from npFoxitReaderPlugin
'WritableAddress' => 0x10045c10, # from npFoxitReaderPlugin
:rop => :win7_rop_chain
}
]
],
'DefaultTarget' => 0,
# ...
))
# ...
end
end
Ronin exploits may define additional platform
targeting by including the
Mixins::HasTargets module.
The Mixins::HasTargets module adds a
target
class method for defining platform/software specific target
information.
require 'ronin/exploits/exploit'
require 'ronin/exploits/mixins/has_targets'
module Ronin
module Exploits
class MyExploit < Exploit
include Mixins::HasTargets
# ...
target os: :windows, os_version: '7 SP1', software: 'Foxit Reader', software_version: '5.4.4.11281' do |target|
target.offset = 272
target.ret = 0x1000c57d, # pop # ret # from npFoxitReaderPlugin
target.writable_address = 0x10045c10, # from npFoxitReaderPlugin
target.rop = :win7_rop_chain
end
# ...
end
end
end
Metasploit exploits defines options using the register_options
within the
initialize
method. The register_options
method accepts an Array of one or
more options. The options are initialized using OptString
, OptBool
, etc,
option classes. The first argument is the option name in all uppercase.
The second argument is the option description. The first argument is the
optional default value for the option.
class MetasploitModule < Msf::Exploit::Remote
def initialize(info = {})
# ...
register_options([
OptString.new('FILENAME', [ true, 'The file name.', 'msf.pdf' ])
])
end
end
Ronin exploits defines options using the param
method which can be called multiple times. The first argument is the
param name, in lowercase or snake_case
. The second argument is the
param type class. Additional keyword arguments
may define whether the param is required, it’s default value, and it’s
description.
require 'ronin/exploits/exploit'
module Ronin
module Exploits
class MyExploit < Exploit
# ...
param :filename, String, required: true,
default: 'msf.pdf',
desc: 'The file name'
# ...
end
end
end
Metasploit | Ronin |
---|---|
OptString.new('FOO', ...) |
param :foo, String, ... |
OptInt.new('FOO', ...) |
param :foo, Integer, ... |
OptBool.new('FOO', ...) |
param :foo, Boolean, ... |
OptEnum.new('FOO', [true, '...', ['value1', 'value2', ...]) |
param :foo, Enum[:value1, :value2, ...] |
Opt::RHOST() |
include Params::Host |
Opt::RPORT() |
include Params::Port |
Opt::RPORT(443) |
include Params::Port and default_port 443 |
Opt::LHOST() |
include Params::BindHost |
???? | include Params::BindPort |
OptString.new('TARGETURI', ...) |
include Params::BaseURL |
OptString.new('FILENAME', [true, '...', 'foo.pdf']) |
include Params::Filename and default_filename 'foo.pdf' |
check
vs. test
methodsA Metasploit exploit may define a check
method which tests whether the
remote host is vulnerable to the exploit. These check
methods will return
a Exploit::CheckCode::Safe
, Exploit::CheckCode::Vulnerable
, Exploit::CheckCode::Detected
, Exploit::CheckCode::Appears
, or Exploit::CheckCode::Unknown
value to
indicate the status of the remote host.
class MetasploitModule < Msf::Exploit::Remote
# ...
def check
uri = '/tws/getStatus'
res = send_request_cgi({
'method' => 'POST',
'uri' => uri,
'vars_post' => {
'transaction_id' => rand(0x100000000),
'oauth_token' => 'invalid'
}})
unless res && res.code == 200 && res.body.to_s =~ /"result_msg":"MD5 token is invalid"/
return Exploit::CheckCode::Safe
end
res = send_request_cgi({
'method' => 'POST',
'uri' => uri,
'vars_post' => {
'transaction_id' => rand(0x100000000),
'oauth_token' => "';echo '"
}})
unless res && res.code == 200 && res.body.to_s =~ /"result_msg":"Success","transaction_id":"/
return Exploit::CheckCode::Safe
end
Msf::Exploit::CheckCode::Vulnerable
end
# ...
end
A Ronin exploit may define a test
method which
tests whether the remote host is indeed vulnerable to the exploit. Unlike
Metasploit’s check
method, the test
method may only return
Vulnerable(‘message here’),
NotVulnerable(‘message here’), or
Unknown(‘message here’).
require 'ronin/exploits/exploit'
require 'ronin/exploits/mixins/http'
module Ronin
module Exploits
class MyExploit < Exploit
include Mixins::HTTP
# ...
def test
case http.get_body('/')
when /Powered by Foo 4\.19\./
Vulnerable('host is vulnerable')
when /Powered by Foo 4\.2[0-9]\./
NotVulnerable('host is patched')
else
Unknown('cannot determine whether the host is vulnerable or not')
end
end
# ...
end
end
end
Metasplioit | Ronin |
---|---|
Exploit::CheckCode::Safe |
NotVulnerable("host is not vulnerable") |
Exploit::CheckCode::Vulnerable |
Vulnerable("host is vulnerable") |
Exploit::CheckCode::Detected |
Unknown("the service is running but could not be validated") |
Exploit::CheckCode::Appears |
Unknown("the host appears to be vulnerable") |
Exploit::CheckCode::Unknown |
Unknown("...") |
exploit
vs. validate
/build
/launch
/cleanup
methodsMetasploit exploits define the exploit’s logic in one giant exploit
method:
class MetasploitModule < Msf::Exploit::Remote
def exploit
connect_udp
nops = make_nops(50)
lead = rand_text_alphanumeric(target['Offset'] - payload.encoded.length - nops.length)
near = "\xe9\x80\xfd\xff\xff" #jump back 640 bytes to the nop sled
nseh = "\xeb\xf9" + make_nops(2) #jump back 7 bytes to the long jump
evil = lead + nops + payload.encoded + near + nseh + [target.ret].pack('V')
mode = "netascii"
#Send the WRQ packet (header "\x00\x02")
sploit = "\x00\x02" + evil + "\0" + mode +"\0"
udp_sock.put(sploit)
handler
disconnect_udp
end
end
While the Ronin::Exploits::Exploit class do provide an exploit method as an entry-point method for running the exploit, Ronin exploits define their exploit logic in four main methods:
validate
- Perform any additional validations before building the exploit.build
- Builds any exploit buffers, files, or other data that will be used.launch
- Sends the exploit to the host or service.cleanup
- Perform any extra cleanup tasks after the user is done using the
exploit.require 'ronin/exploits/exploit'
require 'ronin/exploits/mixins/has_targets'
require 'ronin/exploits/mixins/has_payload'
require 'ronin/exploits/mixins/text'
require 'ronin/exploits/mixins/nops'
require 'ronin/exploits/mixins/remote_udp'
module Ronin
module Exploits
class MyExploit < Exploit
include Mixins::HasTargets
include Mixins::HasPayload
include Mixins::Text
include Mixins::NOPS
include Mixins::RemoteUDP
def build
nopsled = nops(50)
lead = random_alpha_numeric(target.offset - payload.length - nopsled.length)
near = "\xe9\x80\xfd\xff\xff" # jump back 640 bytes to the nop sled
nseh = "\xeb\xf9" + nops(2) # jump back 7 bytes to the long jump
evil = lead + nopsled + payload + near + nseh + target.ret.pack(:uint32_le)
# send the WRQ packet (header "\x00\x02")
mode = "netascii"
@buffer = "\x00\x02" + evil + "\0" + mode +"\0"
end
def launch
# connect to the remote service, send the data, return the open socket
@socket = udp_connect_and_send(@buffer)
end
def cleanup
# close the open socket
@socket.close
end
end
end
end
cleanup
methodBoth Metasploit and Ronin define a cleanup
method for additional logic to
cleanup after the exploit.
Metasploit provides a set of methods for printing status messages from an exploit:
print_status "Running the Javascript shell..."
# ...
print_warning("Unable to retrieve token")
# ...
print_error('Connection failed.')
# ...
Ronin also provides a similar set of methods for printing status messages from an exploit:
print_status
print_failure
/ print_bad
print_success
/ print_good
print_status "Sending request to /path ..."
response = http_get('/path')
if response.code == '200'
if response.body.include?('Success')
print_success "response indicates success! Proceeding ..."
else
print_failure "request failed! Trying again ..."
print_debug response.body
end
else
print_error "Did not receive a 200 response: #{response.code}"
end
Metasploit | Ronin |
print_status("Message here") vprint_status("Message here")
|
print_info "Message here" /print_status "Message here"
|
print_good("Message here") vprint_good("Message here")
|
print_good "Message here" /print_success "Message here" /print_positive "Message here"
|
print_bad("Message here") vprint_bad("Message here")
|
print_bad "Message here" /print_failure "Message here" /print_negative "Message here"
|
print_warning("Message here") vprint_warning("Message here")
|
print_warning "Message here"
|
print_error("Message here") print_bad("Message here") vprint_error("Message here") vprint_bad("Message here")
|
print_error "Message here"
|
Metasploit exploits provide a series of methods for generating random text,
such as rand_text_alpha
or rand_text_alphanumeric
.
class MetasploitModule < Msf::Exploit::Remote
def check
token = rand_text_alphanumeric(8..42)
# ...
end
end
Ronin exploits may include the Mixins::Text module, which adds various methods such as random_alpha or random_alpha_numeric.
require 'ronin/exploits/exploit'
require 'ronin/exploits/mixins/text'
module Ronin
module Exploits
class MyExploit < Exploit
include Mixins::Text
def test
token = random_alpha_numeric(8..42)
# ...
end
end
end
end
Metasploit | Ronin |
---|---|
rand_text_alpha |
random_alpha |
rand_text_alphanumeric |
random_alpha_numeric |
rand_text_alpha_lower |
random_lowercase_alpha / random_lower_alpha |
rand_text_alpha_upper |
random_uppercase_alpha / random_upper_alpha |
rand_text_numeric |
random_numeric / random_digits |
rand_text_hex |
random_hex |
rand_text_highascii |
random_signed_ascii |
rand_char |
random_ascii (without no arguments) |
Metasploit exploits use Ruby’s built-in Array#pack method, which packs the contents of an Array using a binary format String:
pop_r3_ret = [0x00013cd0].pack('V')
Ronin adds a it’s own pack
method to Array,
Integer, and Float
which can also accept a binary type Symbol name instead of a pack String:
pop_r3_ret = 0x00013cd0.pack(:uint32_le)
If the Ronin exploit includes Mixins::Binary, then a pack method will be added, which packs a single value based on the exploit’s defined arch and os.
require 'ronin/exploits/exploit'
require 'ronin/exploits/metadata/arch'
require 'ronin/exploits/metadata/os'
require 'ronin/exploits/mixins/binary'
module Ronin
module Exploits
class MyExploit < Exploit
include Metadata::Arch
include Metadata::OS
include Mixins::Binary
arch :x86_64
os :linux
def build
# ...
buf << pack(:uint32, 0x12345678)
# ...
end
end
end
end
The pack method can also be used with
the Mixins::HasTargets module and will
use the arch
and os
of the selected target:
require 'ronin/exploits/exploit'
require 'ronin/exploits/mixins/binary'
require 'ronin/exploits/mixins/has_targets'
module Ronin
module Exploits
class MyExploit < Exploit
include Mixins::Binary
include Mixins::HasTargets
target arch: :x86_64, os: :linux do |target|
target.ret = 0xffff1234
end
target arch: :arm_le, os: :linux do |target|
target.ret = 0xffff1234
end
target arch: :arm_be, os: :linux do |target|
target.ret = 0xffff1234
end
def build
# ...
buf << pack(:uint32, target.ret)
# ...
end
end
end
end
Metasploit | Ronin |
---|---|
[i].pack('C') |
i.pack(:uchar) |
[i].pack('S') |
i.pack(:uint16) |
[i].pack('L') |
i.pack(:uint32) |
[i].pack('Q') |
i.pack(:uint64) |
[i].pack('c') |
i.pack(:char) |
[i].pack('s') |
i.pack(:int16) |
[i].pack('l') |
i.pack(:int32) |
[i].pack('q') |
i.pack(:int64) |
[i].pack('S<') |
i.pack(:uint16_le) |
[i].pack('L<') |
i.pack(:uint32_le) |
[i].pack('Q<') |
i.pack(:uint64_le) |
[i].pack('s<') |
i.pack(:int16_le) |
[i].pack('l<') |
i.pack(:int32_le) |
[i].pack('q<') |
i.pack(:int64_le) |
[i].pack('S>') |
i.pack(:uint16_be) |
[i].pack('L>') |
i.pack(:uint32_be) |
[i].pack('Q>') |
i.pack(:uint64_be) |
[i].pack('s>') |
i.pack(:int16_be) |
[i].pack('l>') |
i.pack(:int32_be) |
[i].pack('q>') |
i.pack(:int64_be) |
[f].pack('F') / [f].pack('f') |
f.pack(:float) / f.pack(:float32) |
[f].pack('D') / [f].pack('d') |
f.pack(:double) / f.pack(:float64) |
[f].pack('e') |
f.pack(:float_le) / f.pack(:float32_le) |
[f].pack('E') |
f.pack(:double_le) / f.pack(:float64_le) |
[f].pack('g') |
f.pack(:float_be) / f.pack(:float32_be) |
[f].pack('G') |
f.pack(:double_be) / f.pack(:float64_be) |
[i].pack('n') |
i.pack(:uint16_le) |
[i].pack('N') |
i.pack(:uint32_le) |
[i].pack('v') |
i.pack(:uint16_be) |
[i].pack('V') |
i.pack(:uint32_be) |
[...].pack('VVV') |
[...].pack([:uint32_le, 3]) |
[...].pack('V*') |
[...].pack(:uint32_le..) |
[...].pack('VS<C') |
[...].pack(:uint32_le, :uint16_le, :uchar) |
A Metasploit exploit can connect to a remote TCP service, specified by the
RHOST
and
RPORT options. if it includes
Msf::Exploit::Remote::Tcp`.
class MetasploitModule < Msf::Exploit::Remote
include Msf::Exploit::Remote::Tcp
def exploit
begin
connect
packet = "..."
sock.put(packet)
disconnect
rescue ::Exception => e
fail_with(Failure::Unreachable, "Unable to connect")
end
end
end
A Ronin exploit can also connect to a remote TCP
service, specified by the host
and port
params, if it includes the
Ronin::Exploits::Mixins::RemoteTCP module. The module also adds TCP helper
methods for connecting, sending data, receiving data:
require 'ronin/exploits/exploit'
require 'ronin/exploits/mixins/remote_tcp'
module Ronin
module Exploits
class MyExploit < Exploit
include Mixins::RemoteTCP
def build
@buffer = "..."
end
def launch
# connect to the remote TCP service, send the data, return the socket
@socket = tcp_connect_and_send(@buffer)
end
def cleanup
# close the connection
@socket.close
end
end
end
end
Metasploit | Ronin |
---|---|
include Msf::Exploit::Remote::Tcp |
include Mixins::RemoteTCP |
rhost |
host |
rport |
port |
peer |
"#{host}:#{port}" |
connect |
@socket = tcp_connect / @socket = tcp_connect_and_send(@buffer) |
banner = sock.get_once |
tcp_banner / socket.gets |
disconnect |
socket.close |
A Metasploit exploit can connect to a remote UDP service, specified by the
RHOST
and
RPORT options. if it includes the
Msf::Exploit::Remote::Udp`
module.
class MetasploitModule < Msf::Exploit::Remote
include Msf::Exploit::Remote::Udp
def exploit
connect_udp
sploit = "..."
udp_sock.put(sploit)
handler
disconnect_udp
end
end
A Ronin exploit can also connect to a remote UDP
service, specified by the host
and port
params, if it includes the
Ronin::Exploits::Mixins::RemoteUDP module. The module also adds UDP helper
methods for connecting, sending data, and receiving data:
require 'ronin/exploits/exploit'
require 'ronin/exploits/mixins/remote_udp'
module Ronin
module Exploits
class MyExploit < Exploit
include Mixins::RemoteUDP
# ...
def build
@buffer = "..."
end
def launch
# connect to the remote UDP service, send the data, return the socket
@socket = udp_connect_and_send(@buffer)
end
def cleanup
# close the connection
@socket.close
end
end
end
end
Metasploit | Ronin |
---|---|
include Msf::Exploit::Remote::Udp |
include Mixins::RemoteUDP |
rhost |
host |
rport |
port |
connect_udp |
@socket = udp_connect / @socket = udp_connect_and_send(@buffer) |
banner = sock.get_once |
udp_banner / socket.gets |
disconnect_udp |
socket.close |
A Metasploit exploits may send HTTP requests using the send_request_cgi
method, if it includes the Msf::Exploits::Remote::HttpClient
module.
# perform a GET request
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path)
})
# ...
# perform a POST request
send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path),
'data' => soap
}, 1)
Ronin exploits can also send HTTP requests to a
remote web server, specified by the base_url
param, if it includes
the Mixins::HTTP module.
The Mixins::HTTP module will add many
http_
helper methods to the exploit:
require 'ronin/exploits/exploit'
require 'ronin/exploits/mixins/http'
module Ronin
module Exploits
class MyExploit < Exploit
include Mixins::HTTP
param :path, String, required: true,
desc: 'The target path to exploit'
def launch
# perform a GET request
response = http_get(params[:path])
# perform a GET request with query params
response = http_get(params[:path], query_params: {'foo' => 'bar'})
# perform a POST request
response = http_post(params[:path], body: data)
# perform a POST request with form params
response = http_post(params[:path], form_data: {'foo' => 'bar'})
end
end
end
end
Metasploit | Ronin |
---|---|
send_request_cgi({'method' => 'DELETE', ...}) |
http_delete(...) |
send_request_cgi({'method' => 'HEAD', ...}) |
http_head(...) |
send_request_cgi({'method' => 'GET', ...}) |
http_get(...) |
send_request_cgi({'method' => 'OPTIONS', ...}) |
http_options(...) |
send_request_cgi({'method' => 'POST', ...}) |
http_post(...) |
send_request_cgi({'method' => 'PUT', ...}) |
http_put(...) |
'uri' => '/index.php' |
'/index.php' |
'uri' => normalize_uri(target_uri.path), ...} |
path |
'headers' => {...} |
headers: {...} |
'authorization' => "..." |
authorization: "..." |
'authorization' => basic_auth(user,pass) |
user: user, password: pass |
'data' => ... |
body: ... |
'cookie' => ... |
cookie: ... |
'ctype' => ... |
content_type: ... |
'vars_get' => {...} |
query_params: {...} |
'vars_post' => {...} |
form_data: {...} |
A Metasploit exploit can store captured files or other data from a compromised
system using the store_loot
method:
loot_path = store_loot('gitlab.secrets', 'text/plain', datastore['RHOST'], secrets_yml, 'secrets.yml')
JSON, YAML, and CSV data can also be stored:
stored_path = store_loot('ad.exchange.mailboxes', 'text/csv', rhost, mailbox_table.to_csv)
Ronin exploits can store captured files or other data from a compromised system by including Mixins::Loot and calling the loot.add_file method:
require 'ronin/exploits/exploit'
require 'ronin/exploits/mixins/loot'
module Ronin
module Exploits
class MyExploit < Exploit
include Mixins::Loot
def launch
# ...
loot.add_file('foo.txt', captured_data1)
loot.add_file('dir/bar.txt', captured_data2)
end
end
end
end
JSON, YAML, and CSV data can also be automatically serialized and stored:
loot.add('foo.json', captured_data, format: :json)
loot.add('foo.yaml', captured_data, format: :yaml)
loot.add('foo.csv', captured_data, format: :csv)
Metasploit | Ronin |
---|---|
store_file('foo.bar', 'mime/type', rhost, data) |
loot.add('foo/bar.txt',data) |
fail_with
vs. fail
methodsWhen a Metasploit exploit encounters a serious error and needs to abort,
it can call the fail_with
method which raises an exception:
fail_with(Failure::Unreachable, "#{peer} - Could not connect to web service - no response") if res.nil?
When Ronin exploits need to raise an exception and abort from the validate
,
build
, launch
, or cleanup
methods, they can call the
fail method which raises an ExploitFailed
exception.
unless response
fail("could not connect to web service: #{base_url}")
end
Metasploit | Ronin |
---|---|
fail_with(Failure::Foo,"message here") |
fail("message here") |