daemon-sec-cheatsheet

The cheatsheet vault for operators: AD, enumeration, exploitation, priv-esc, web, DFIR
git clone https://git.daemon-sec.xyz/daemon-sec-cheatsheet.git
Log | Files | Refs | README | LICENSE

notepad-plus-plus-plugin-autoload-persistence.md (7837B)


      1 ---
      2 title: "Notepad++ Plugin Autoload Persistence & Execution"
      3 section: "Windows"
      4 sectionSlug: "windows-hardening"
      5 sourcePath: "src/windows-hardening/windows-local-privilege-escalation/notepad-plus-plus-plugin-autoload-persistence.md"
      6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/windows-hardening/windows-local-privilege-escalation/notepad-plus-plus-plugin-autoload-persistence.md"
      7 sha: "188de82beb54e70956b2952367a0af91d26758b8"
      8 isIndex: false
      9 modified: true
     10 license: "CC-BY-NC-4.0"
     11 ---
     12 
     13 # Notepad++ Plugin Autoload Persistence & Execution
     14 
     15 Notepad++ will **autoload every plugin DLL found under its `plugins` subfolders** on launch. Dropping a malicious plugin into any **writable Notepad++ installation** gives code execution inside `notepad++.exe` every time the editor starts, which can be abused for **persistence**, stealthy **initial execution**, or as an **in-process loader** if the editor is launched elevated.<sup>[[1]](#references)</sup>
     16 
     17 Since **Notepad++ 7.6+** the expected manual-install layout is **one subfolder per plugin** (`plugins\<PluginName>\<PluginName>.dll`). In **portable mode** (presence of `doLocalConf.xml` next to `notepad++.exe`), the whole application tree stays local to that directory, which often turns copied/admin tool bundles into an easy user-writable execution surface.<sup>[[2]](#references)</sup>
     18 
     19 ## Writable plugin locations
     20 
     21 - Standard install: `C:\Program Files\Notepad++\plugins\<PluginName>\<PluginName>.dll` (usually requires admin to write).<sup>[[1]](#references)</sup>
     22 - Writable options for low-privileged operators:<sup>[[1]](#references)</sup>
     23   - Use the **portable Notepad++ build** in a user-writable folder.
     24   - Copy `C:\Program Files\Notepad++` to a user-controlled path (e.g. `%LOCALAPPDATA%\npp\`) and run `notepad++.exe` from there.
     25   - Hunt for **admin tool bundles**, extracted zip copies, or help-desk toolkits that already contain `doLocalConf.xml` and live outside `Program Files`.
     26 - Each plugin gets its own subfolder under `plugins` and is loaded automatically at startup; menu entries appear under **Plugins**.<sup>[[2]](#references)</sup>
     27 
     28 Quick triage:
     29 
     30 ```batch
     31 where /r C:\ notepad++.exe 2>nul
     32 for /d %D in ("%ProgramFiles%\Notepad++" "%ProgramFiles(x86)%\Notepad++" "%LOCALAPPDATA%\*notepad*" "%USERPROFILE%\Desktop\*notepad*") do @if exist "%~fD\plugins" echo [*] %~fD
     33 icacls "C:\Program Files\Notepad++\plugins" 2>nul
     34 ```
     35 
     36 ## Plugin load points (execution primitives)
     37 Notepad++ expects specific **exported functions**. These are all called during initialization, giving multiple execution surfaces:<sup>[[1]](#references)</sup>
     38 - **`DllMain`** — runs immediately on DLL load (first execution point).
     39 - **`setInfo(NppData)`** — called once on load to provide Notepad++ handles; typical place to register menu items.
     40 - **`getName()`** — returns the plugin name shown in the menu.
     41 - **`getFuncsArray(int *nbF)`** — returns menu commands; even if empty, it is called during startup.
     42 - **`beNotified(SCNotification*)`** — receives Notepad++ / Scintilla events (useful to defer payloads until a user action or editor event).
     43 - **`messageProc(UINT, WPARAM, LPARAM)`** — message handler, useful for larger data exchanges.
     44 - **`isUnicode()`** — compatibility flag checked at load.
     45 
     46 Most exports can be implemented as **stubs**; execution can occur from `DllMain` or any callback above during autoload.
     47 
     48 ## Minimal malicious plugin skeleton
     49 Compile a DLL with the expected exports and place it in `plugins\\MyNewPlugin\\MyNewPlugin.dll` under a writable Notepad++ folder:<sup>[[1]](#references)</sup>
     50 
     51 ```c
     52 BOOL APIENTRY DllMain(HMODULE h, DWORD r, LPVOID) { if (r == DLL_PROCESS_ATTACH) MessageBox(NULL, TEXT("Hello from Notepad++"), TEXT("MyNewPlugin"), MB_OK); return TRUE; }
     53 extern "C" __declspec(dllexport) void setInfo(NppData) {}
     54 extern "C" __declspec(dllexport) const TCHAR *getName() { return TEXT("MyNewPlugin"); }
     55 extern "C" __declspec(dllexport) FuncItem *getFuncsArray(int *nbF) { *nbF = 0; return NULL; }
     56 extern "C" __declspec(dllexport) void beNotified(SCNotification *) {}
     57 extern "C" __declspec(dllexport) LRESULT messageProc(UINT, WPARAM, LPARAM) { return TRUE; }
     58 extern "C" __declspec(dllexport) BOOL isUnicode() { return TRUE; }
     59 ```
     60 
     61 1. Build the DLL (Visual Studio/MinGW).
     62 2. Create the plugin subfolder under `plugins` and drop the DLL inside.
     63 3. Restart Notepad++; the DLL is loaded automatically, executing `DllMain` and subsequent callbacks.
     64 
     65 ## Low-noise trigger pattern via `beNotified`
     66 For OPSEC, many payloads should **not** fire from `DllMain`. A quieter pattern is to let the plugin load cleanly, then execute only after a realistic editor event such as **startup complete**, **buffer activation**, or the **first typed character**.
     67 
     68 ```c
     69 static bool fired = false;
     70 extern "C" __declspec(dllexport) void beNotified(SCNotification *n) {
     71   if (fired) return;
     72   if (n->nmhdr.code == NPPN_READY ||
     73       n->nmhdr.code == NPPN_BUFFERACTIVATED ||
     74       n->nmhdr.code == SCN_CHARADDED) {
     75     fired = true;
     76     WinExec("powershell -w hidden -nop -c <payload>", SW_HIDE);
     77   }
     78 }
     79 ```
     80 
     81 This matches public offensive research better than a noisy `DllMain` beacon: the DLL is still autoloaded at startup, but the malicious action is delayed until Notepad++ looks genuinely in use.
     82 
     83 ## Using the plugin config directory as secondary storage
     84 Notepad++ exposes `NPPM_GETPLUGINSCONFIGDIR`, which returns the **current user's plugin configuration directory**.<sup>[[3]](#references)</sup> A malicious plugin can use this to keep the on-disk DLL minimal while storing encrypted config, staged payloads, or tasking files in a path that blends in with normal plugin state.
     85 
     86 ```c
     87 wchar_t cfg[MAX_PATH] = {0};
     88 SendMessage(nppData._nppHandle, NPPM_GETPLUGINSCONFIGDIR, MAX_PATH, (LPARAM)cfg);
     89 // Example result: %AppData%\Notepad++\plugins\config
     90 ```
     91 
     92 Operationally this is useful when you want:
     93 - a tiny autoloaded bootstrap DLL;
     94 - per-user tasking without touching the main plugin binary again;
     95 - to separate the **autoload trigger** from the heavier second stage.
     96 
     97 ## Reflective loader plugin pattern
     98 A weaponized plugin can turn Notepad++ into a **reflective DLL loader**:<sup>[[1]](#references)</sup>
     99 - Present a minimal UI/menu entry (e.g., "LoadDLL").
    100 - Accept a **file path** or **URL** to fetch a payload DLL.
    101 - Reflectively map the DLL into the current process and invoke an exported entry point (e.g., a loader function inside the fetched DLL).
    102 - Benefit: reuse a benign-looking GUI process instead of spawning a new loader; payload inherits the integrity of `notepad++.exe` (including elevated contexts).
    103 - Trade-offs: dropping an **unsigned plugin DLL** to disk is noisy; a practical variation is to use the autoloaded plugin only as a stub and keep the real implant encrypted/staged elsewhere.
    104 
    105 ## Detection and hardening notes
    106 - Block or monitor **writes to Notepad++ plugin directories** (including portable copies in user profiles); enable controlled folder access or application allowlisting.
    107 - Alert on **new unsigned DLLs** under `plugins`, changes to portable Notepad++ trees, and unusual **child processes/network activity** from `notepad++.exe`.
    108 - Baseline legitimate plugins and investigate any new DLL that exports the normal Notepad++ plugin interface but also spawns shells, PowerShell, or network beacons.
    109 - Enforce plugin installation via **Plugins Admin** only, and restrict execution of portable copies from untrusted paths.
    110 
    111 ## References
    112 
    113 - [1] [TrustedSec - Notepad++ Plugins: Plug and Payload](https://trustedsec.com/blog/notepad-plugins-plug-and-payload)
    114 - [2] [Notepad++ User Manual - Plugins](https://npp-user-manual.org/docs/plugins/)
    115 - [3] [Notepad++ User Manual - Plugin Communication](https://npp-user-manual.org/docs/plugin-communication/)