JSON Structure for Defining .tool Files in LazyOwn: Complete Schema Guide
LazyOwn .tool files require a strict JSON object containing four mandatory fields—toolname, command, trigger, and active—where the command string supports dynamic placeholders like {ip}, {port}, and {outputdir} for runtime substitution.
LazyOwn treats every external utility—from Nmap scripts to web fuzzers—as a modular .tool file defined in JSON format. Understanding the exact JSON structure for defining .tool files in LazyOwn is essential for extending the framework with custom reconnaissance or exploitation utilities, as the pwntomate.py engine strictly enforces this schema during scan execution.
Core JSON Schema for LazyOwn .tool Files
Every .tool file must contain a single JSON object with exactly four required keys. The parser in main/pwntomate.py raises a KeyError if any field is missing, aborting execution immediately.
Required Fields
toolname(string): Human-readable identifier used to construct output filenames. The engine saves results to{outputdir}/{toolname}.txt.command(string): The shell command to execute. Must include placeholders for dynamic values like target IPs and ports.trigger(array of strings): Service names (as reported by Nmap) that activate this tool. Use["all"]to run against any service.active(boolean): Enable or disable the tool. Inactive tools (false) are ignored during scans.
Available Placeholders for Dynamic Command Construction
The command field supports string substitution using Python's str.replace method before execution. Valid placeholders include:
{ip}— Target IP address{port}— Target service port{domain}— Target domain name{outputdir}— Base results directory (args.basedir){toolname}— Value of thetoolnamefield{s}— Insertssfor HTTPS or empty string for HTTP{username}/{password}— Credentials fromsessions/credentials.txt{usrwordlist}/{dirworlist}— Wordlist paths frommain/payload.json{ext}/{nameserver}— Domain components for DNS tools
Real-World .tool File Examples from the Repository
Web Fuzzing with ffuf.tool
Located at main/tools/ffuf.tool:
{
"toolname": "ffuf_tool",
"command": "ffuf -u http{s}://{ip}:{port}/FUZZ -w /usr/share/wordlists/dirb/common.txt -mc 200,204,301,302,307,401 -o {outputdir}/{toolname}.txt",
"trigger": ["http", "https", "http-mgmt", "http-alt"],
"active": true
}
Kerberos Enumeration with kerbrute.tool
Located at main/tools/kerbrute.tool:
{
"toolname": "kerbrute_tool_user",
"command": "kerbrute userenum --dc {ip} -d {domain} -t 20 /usr/share/wordlists/SecLists-master/Usernames/xato-net-10-million-usernames.txt | tee {outputdir}/{toolname}.txt",
"trigger": ["kerberos-sec"],
"active": true
}
DNS Enumeration with dnsenum.tool
Located at main/tools/dnsenum.tool:
{
"toolname": "dns_enum_tool",
"command": "dnsenum --dnsserver {ip} --enum {domain} {dnswordlist} > {outputdir}/dnsenum.txt",
"trigger": ["domain"],
"active": true
}
Custom Exploit Wrapper (Inactive)
Located at main/tools/bigbang.tool:
{
"toolname": "bigbang",
"command": "cd /home/grisun0/src/scripts ; python3 exploit_bigbang.py | tee {outputdir}/{toolname}.txt",
"trigger": ["http", "https", "http-mgmt", "http-alt"],
"active": false
}
How LazyOwn Processes .tool Files
The execution logic resides in main/pwntomate.py. During a scan, the engine:
- Iterates through all
.toolfiles inmain/tools/ - Parses the JSON and validates the four required fields
- Checks if
activeistrueand if the detected service matches any value intrigger - Performs string substitution on
commandusing the placeholder mapping - Executes the final shell command and saves output to
{outputdir}/{toolname}.txt
Optional runtime variables like {usrwordlist} and {dirworlist} are loaded from main/payload.json, while credentials ({username}, {password}) are sourced from sessions/credentials.txt when available.
Step-by-Step Guide to Creating Custom .tool Files
Follow this checklist when adding new tools to LazyOwn:
- Create the JSON file in
main/tools/with a.toolextension. - Include all four mandatory fields:
toolname,command,trigger,active. - Use valid placeholders from the supported list only; unsupported variables will remain as literal text.
- Set
active: trueto enable automatic execution during scans. - Define accurate triggers using Nmap service names (e.g.,
http,ssh,microsoft-ds,kerberos-sec). - Test the command manually by replacing placeholders with real values before committing the file.
When the scanner runs, it will automatically pick up any new, active .tool file, inject the proper values, and execute the command only when the service matches a trigger.
Summary
- LazyOwn
.toolfiles use a strict four-field JSON schema:toolname,command,trigger, andactive. - The
commandfield supports dynamic placeholders like{ip},{port}, and{outputdir}for runtime substitution. - Tools execute only when their
triggerarray matches the detected Nmap service name andactiveis set totrue. - The parsing engine in
main/pwntomate.pyvalidates the schema and performs string replacement before shell execution. - Custom tools require testing with literal values before deployment to ensure placeholder alignment.
Frequently Asked Questions
What happens if a required field is missing from a .tool file?
The LazyOwn parser in main/pwntomate.py will raise a KeyError and abort execution. All four fields—toolname, command, trigger, and active—must be present for the tool to load correctly.
Can I use custom placeholders not listed in the documentation?
No. The engine only substitutes known placeholders like {ip}, {port}, and {domain}. Any custom variables will remain as literal text in the final command, likely causing execution errors or unexpected behavior.
How do I run a tool against every service regardless of the port?
Set the trigger array to ["all"]. This special value instructs the engine to execute the command for any detected service, bypassing the normal service-name matching logic in pwntomate.py.
Where does LazyOwn save the output from .tool executions?
Results are written to {outputdir}/{toolname}.txt, where {outputdir} maps to the base directory specified by args.basedir and {toolname} is the value defined in the tool's JSON configuration.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →