|
| 1 | +# Notepad++ Plugin Autoload Persistence & Execution |
| 2 | + |
| 3 | +{{#include ../../banners/hacktricks-training.md}} |
| 4 | + |
| 5 | +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. |
| 6 | + |
| 7 | +## Writable plugin locations |
| 8 | +- Standard install: `C:\Program Files\Notepad++\plugins\<PluginName>\<PluginName>.dll` (usually requires admin to write). |
| 9 | +- Writable options for low-privileged operators: |
| 10 | + - Use the **portable Notepad++ build** in a user-writable folder. |
| 11 | + - Copy `C:\Program Files\Notepad++` to a user-controlled path (e.g., `%LOCALAPPDATA%\npp\`) and run `notepad++.exe` from there. |
| 12 | +- Each plugin gets its own subfolder under `plugins` and is loaded automatically at startup; menu entries appear under **Plugins**. |
| 13 | + |
| 14 | +## Plugin load points (execution primitives) |
| 15 | +Notepad++ expects specific **exported functions**. These are all called during initialization, giving multiple execution surfaces: |
| 16 | +- **`DllMain`** — runs immediately on DLL load (first execution point). |
| 17 | +- **`setInfo(NppData)`** — called once on load to provide Notepad++ handles; typical place to register menu items. |
| 18 | +- **`getName()`** — returns the plugin name shown in the menu. |
| 19 | +- **`getFuncsArray(int *nbF)`** — returns menu commands; even if empty, it is called during startup. |
| 20 | +- **`beNotified(SCNotification*)`** — receives editor events (file open/change, UI events) for ongoing triggers. |
| 21 | +- **`messageProc(UINT, WPARAM, LPARAM)`** — message handler, useful for larger data exchanges. |
| 22 | +- **`isUnicode()`** — compatibility flag checked at load. |
| 23 | + |
| 24 | +Most exports can be implemented as **stubs**; execution can occur from `DllMain` or any callback above during autoload. |
| 25 | + |
| 26 | +## Minimal malicious plugin skeleton |
| 27 | +Compile a DLL with the expected exports and place it in `plugins\\MyNewPlugin\\MyNewPlugin.dll` under a writable Notepad++ folder: |
| 28 | + |
| 29 | +```c |
| 30 | +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; } |
| 31 | +extern "C" __declspec(dllexport) void setInfo(NppData) {} |
| 32 | +extern "C" __declspec(dllexport) const TCHAR *getName() { return TEXT("MyNewPlugin"); } |
| 33 | +extern "C" __declspec(dllexport) FuncItem *getFuncsArray(int *nbF) { *nbF = 0; return NULL; } |
| 34 | +extern "C" __declspec(dllexport) void beNotified(SCNotification *) {} |
| 35 | +extern "C" __declspec(dllexport) LRESULT messageProc(UINT, WPARAM, LPARAM) { return TRUE; } |
| 36 | +extern "C" __declspec(dllexport) BOOL isUnicode() { return TRUE; } |
| 37 | +``` |
| 38 | +
|
| 39 | +1. Build the DLL (Visual Studio/MinGW). |
| 40 | +2. Create the plugin subfolder under `plugins` and drop the DLL inside. |
| 41 | +3. Restart Notepad++; the DLL is loaded automatically, executing `DllMain` and subsequent callbacks. |
| 42 | +
|
| 43 | +## Reflective loader plugin pattern |
| 44 | +A weaponized plugin can turn Notepad++ into a **reflective DLL loader**: |
| 45 | +- Present a minimal UI/menu entry (e.g., "LoadDLL"). |
| 46 | +- Accept a **file path** or **URL** to fetch a payload DLL. |
| 47 | +- Reflectively map the DLL into the current process and invoke an exported entry point (e.g., a loader function inside the fetched DLL). |
| 48 | +- Benefit: reuse a benign-looking GUI process instead of spawning a new loader; payload inherits the integrity of `notepad++.exe` (including elevated contexts). |
| 49 | +- Trade-offs: dropping an **unsigned plugin DLL** to disk is noisy; consider piggybacking on existing trusted plugins if present. |
| 50 | +
|
| 51 | +## Detection and hardening notes |
| 52 | +- Block or monitor **writes to Notepad++ plugin directories** (including portable copies in user profiles); enable controlled folder access or application allowlisting. |
| 53 | +- Alert on **new unsigned DLLs** under `plugins` and unusual **child processes/network activity** from `notepad++.exe`. |
| 54 | +- Enforce plugin installation via **Plugins Admin** only, and restrict execution of portable copies from untrusted paths. |
| 55 | +
|
| 56 | +## References |
| 57 | +- [Notepad++ Plugins: Plug and Payload](https://trustedsec.com/blog/notepad-plugins-plug-and-payload) |
| 58 | +- [MyNewPlugin PoC snippet](https://gitlab.com/-/snippets/4930986) |
| 59 | +- [LoadDLL reflective loader plugin](https://gitlab.com/KevinJClark/ops-scripts/-/tree/main/notepad_plus_plus_plugin_LoadDLL) |
| 60 | +
|
| 61 | +{{#include ../../banners/hacktricks-training.md}} |
0 commit comments