A few days ago, I published Alien v5.0.0. After that, I took some time to get some rest (well… I had been dealing with too many things, including sleep problems).
In this article, I will introduce the plugin framework of Alien and demonstrate how to develop a custom plugin.
Why Plugins?
A plugin architecture is one of the most essential components of a modern offensive security tool because it improves extensibility and extends the lifespan of the framework.
Many well-known offensive security tools, including Cobalt Strike, Ghidra, IDA Pro, and DanderSpritz, provide plugin architectures. Plugins can be used to target different servers, web applications, databases, and content management systems (CMS), including Apache, Nginx, IIS, phpMyAdmin, MySQL, and WordPress.
How Alien Plugins Work
The core of the plugin system is an embedded WebView. The WebView in Control Panel loads the UI (mainly written in HTML) of a plugin. The UI logic is implemented in JavaScript. In other words, all plugins run in an embedded web browser.
Alien exposes a set of APIs that bridge the embedded browser and the native application. Therefore, plugins can read additional payload files (such as DLLs or class files) through the provided APIs.
The payload executed by a plugin is essentially an advanced form of eval(). Languages such as PHP and Classic ASP execute payloads through eval(), while Java and .NET rely on reflective loading.
Executes the specified payload on the remote server.
Parameters:
szJson — JSON configuration passed to the payload.
szPayload — Payload source code or binary.
szEnvironment — Environment string of the current webshell.
Returns:
The raw output returned by the payload.
Developing a Plugin
In this section, I am going to show how to write a plugin to detect any anti-virus software on the remote server. The core idea is to obtain all running processes from the remote server and compare them against a database of known anti-virus software.
First, create a new directory Anti-Virus, then we need a manifest.json to configure the information of a plugin:
All fields shown above are required. Among these fields, environment is the most important. The environment string serves two purposes:
It determines whether the plugin is compatible with the current webshell.
It determines where the corresponding payload is located.
For instance, if the environment of the current webshell is PHP/v8.X/OneShell, the payload can be loaded in JavaScript as follows:
1 2 3 4 5 6 7 8 9 10 11
// PHP/v8.X/OneShell let currentShellType = await bridge.fnGetShellType();
// Object for bridging WebView and C# application const bridge = window.chrome.webview.hostObjects.nativeBridge;
// Current directory of the HTML (Value of browser URL) const currentDir = window.location.pathname.substring(1, window.location.pathname.lastIndexOf('/') + 1);
// Payload code. If environment (ShellType) is NebulaPulsar, it returns a Base64-encoded bytes const payloadCode = await bridge.fnGetPayload(currentDir, currentShellType, "payload");
Alien recursively scans the ./Plugins/ directory during startup. Whenever a manifest.json file is found, the directory is treated as a plugin. The recursion stops once a directory containing manifest.json is found.
Regardless of whether manifest.json exists, the WebView always loads index.html. Therefore, index.html can either serve as the user interface of a plugin or simply as an easter egg inside directory!
In addition, each plugin performs an additional validation in JavaScript:
if (isset($data[0])) { $processes[] = trim($data[0]); } }
echojson_encode($processes);
?>
In this case, we don’t have any input parameter. However, if we do, then the JSON configuration must be received through an HTTP POST parameter and CANNOT be z0:
Once everything is in place, we can handle the returned data of payload execution. Therefore, the execution method in JavaScript can be implemented as follows:
if (!jsonContentRaw) { appendLog("[!] WARNING: LOCAL SIGNATURE FILE IS EMPTY OR NOT FOUND. UNABLE TO PERFORM MATCHING."); appendLog("--- RAW TASKLIST OUTPUT ---"); appendLog(tasklistResultRaw); return; }
if (matchCount === 0) { appendLog("[+] ANALYSIS COMPLETE: NO KNOWN ANTI-VIRUS PROCESSES DETECTED."); } else { appendLog(`[+] ANALYSIS COMPLETE: DETECTED ${matchCount} CONFLICTING SYSTEM DEFENDERS.`); }
} catch (jsonErr) { appendLog("[-] MATRIX PARSE ERROR: FAILED TO PARSE LOCAL JSON CONTENT. " + jsonErr.message.toUpperCase()); appendLog("--- RAW TASKLIST OUTPUT ---"); appendLog(tasklistResultRaw); } }
If you are not familiar with HTML or JavaScript development, don’t worry! You can simply copy one of the existing plugins and modify only the functionality you need.
Another detail worth mentioning is NebulaPulsar. The main logic has to be implemented in Execute():
publicstringExecute(object param) { List<string> processes = new List<string>();
Process[] processList = Process.GetProcesses(); foreach (Process p in processList) { try { string processName = p.ProcessName + ".exe"; processes.Add(processName); } catch { // do something. } }
return fnBuildJsonArray(processes); }
Conclusion
This concludes the introduction to developing plugins for Alien.
I hope this article provides enough information for you to start building your own plugins. Whether they target web applications, databases, or entirely different services, the plugin architecture is designed to remain flexible and extensible.
If you are interested in extending Alien, I encourage you to experiment with the plugin framework and build your own modules. I also plan to develop more official plugins and publish them on GitHub!
In the next article, I will introduce the MemoryShell feature provided by Alien.