Skip to main content

Minimal CLI helpers for authorized penetration-testing lab organization and reporting.

Project description

reconlab

Minimal Python CLI helpers for authorized penetration-testing lab work. The project focuses on lab organization, scan parsing, and reporting workflows. It does not include exploit automation and is not intended for use against real third-party systems.

Install

From PyPI (recommended)

pipx install reconlab        # isolated install, recommended for CLI tools
# or:
pip install reconlab         # if you already manage your own Python env

From source (for development)

git clone https://github.com/0xsl0th/reconlab.git
cd reconlab
python -m venv .venv
source .venv/bin/activate
python -m pip install -e ".[dev]"

Commands at a glance

Command What it does
workspace init Scaffold a target folder, metadata file, and a richer report scaffold.
workspace suggest Generate methodology from scans/ — merges every scan file by default.
workspace status Summarize a workspace — scans, methodology freshness, findings, and the next step.
workspace check Lint report.md for wrap-up readiness — unfilled findings and sections. Exits non-zero on issues.
finding add / finding list Capture findings into report.md; print the current findings table.
workflow show / workflow list Print one workflow as Markdown / list the workflow registry — no scan or workspace needed.
make-hosts Print an /etc/hosts entry plus a copy-paste shell command. Read-only.
parse-nmap Tabular summary of open services from an nmap XML scan.
parse-web Tabular summary of feroxbuster / gobuster output (text or JSON).
suggest-next Methodology generator over an explicit scan file (underlies workspace suggest).
report-init / obsidian-note Deprecated — superseded by workspace init / workspace suggest; slated for removal.

Run reconlab --help (or reconlab <command> --help) for full option lists, or reconlab --version to print the installed version.

Lab session walkthrough

End-to-end flow for a typical lab target. Replace placeholders with the real values your lab gives you.

# 1. Scaffold a workspace with metadata baked in.
reconlab workspace init target \
  --ip 10.10.10.5 \
  --host app.corp.local \
  --domain corp.local \
  --platform lab

cd target

# 2. (Optional) Print the /etc/hosts entry and a copy-paste shell command.
#    Does NOT modify /etc/hosts — you run the printed command yourself.
reconlab make-hosts 10.10.10.5 app.corp.local

# 3. Run nmap into the workspace's scans/ folder.
sudo nmap -sV -sC -p- -oA scans/initial 10.10.10.5

# 4. Generate prioritized, service-by-service methodology as an Obsidian vault.
#    Metadata from the workspace (target IP / host / domain) is filled in
#    automatically — no need to repeat the flags.
reconlab workspace suggest

# 5. Open notes/methodology/index.md in Obsidian (or any Markdown editor).
#    Work through the per-service checklists; capture screenshots into
#    screenshots/, recovered files into loot/, credentials into creds/.

# 6. Record findings into report.md as you go. The first call replaces the
#    placeholder finding; later calls auto-increment the finding number.
reconlab finding add \
  --title "SMB null session enabled" \
  --severity high \
  --service smb \
  --port 445 \
  --evidence screenshots/01-null-session.png

reconlab finding list   # quick check of what is in the report so far

Layout produced by workspace init:

target/
├── .reconlab.json    # target metadata (ip, host, domain, platform)
├── report.md           # engagement report scaffold with frontmatter
├── scans/              # raw nmap output (xml/nmap/gnmap)
├── screenshots/        # one set per finding
├── loot/               # recovered files (sanitized before report)
├── notes/              # working notes + generated methodology vault
├── exploits/           # adapted exploit code with attribution
└── creds/              # recovered credentials — gitignored

After workspace suggest, notes/methodology/ contains an Obsidian-friendly vault with one MOC (index.md) and one note per detected service.

Usage

Parse nmap XML

reconlab parse-nmap scans/target.xml

Example output:

Host        Names           Port  Proto  Service  Product  Version
----------  --------------  ----  -----  -------  -------  -------
10.10.10.5  app.corp.local  80    tcp    http     nginx    1.18.0

Parse feroxbuster / gobuster output

parse-web ingests web content-discovery output and prints a clean Status/Method/Size/URL table. It auto-detects feroxbuster text, feroxbuster --json, and gobuster text formats, strips ANSI colours, and inlines redirect targets into the URL column.

# Auto-detect the format
cpts-tools parse-web outputs/feroxbuster.txt
cpts-tools parse-web outputs/feroxbuster.json
cpts-tools parse-web outputs/gobuster.txt

# Filter to specific status codes
cpts-tools parse-web outputs/feroxbuster.txt --status 200,301,403

# Force a specific parser
cpts-tools parse-web outputs/scan.txt --input-format feroxbuster

Example output:

Status  Method  Size  Words  Lines  URL
------  ------  ----  -----  -----  ----------------------------------
200     GET     1234  46     4      http://10.10.10.5/admin
301     GET     0     0      0      http://10.10.10.5/login -> /login/
403     GET     287   12     2      http://10.10.10.5/.git
200     GET     4567  62     8      http://10.10.10.5/api/users

gobuster doesn't track word/line counts, so those columns show - for gobuster input. Feroxbuster's --json format is parsed as newline-delimited JSON, with non-response entries (scan-config, report) filtered out.

Make an /etc/hosts entry

make-hosts is a read-only helper. It prints the line you should add to /etc/hosts plus a ready-to-paste shell command. It never modifies any file.

Positional form:

reconlab make-hosts 10.10.10.5 app.corp.local dev.corp.local Dev.corp.local DEV.corp.local

Output:

# Add this to /etc/hosts:
10.10.10.5 app.corp.local dev.corp.local Dev.corp.local DEV.corp.local

# Or run:
echo "10.10.10.5 app.corp.local dev.corp.local Dev.corp.local DEV.corp.local" | sudo tee -a /etc/hosts

Flag form (equivalent output):

reconlab make-hosts \
  --ip 10.10.10.5 \
  --host app.corp.local \
  --aliases dev.corp.local Dev.corp.local DEV.corp.local

In the flag form, the first value after --aliases is consumed by the flag and any further positional arguments are appended as additional aliases — so the shell-natural --aliases a b c syntax works. Repeating the flag (--aliases a --aliases b) is also supported. Hostname casing is preserved exactly as typed.

Manage a lab workspace

workspace init scaffolds a target folder with a richer report template and persists target metadata so downstream commands inherit it.

reconlab workspace init target \
  --ip 10.10.10.5 \
  --host app.corp.local \
  --domain corp.local \
  --platform lab \
  -o ~/labs

workspace suggest merges every scan file in scans/ (oldest → newest) and generates methodology into notes/methodology/ (Obsidian vault by default), notes/methodology.md (--output-format md), or notes/methodology.json (--output-format json):

# From inside the workspace, no flags needed.
reconlab workspace suggest

# Or explicitly point at a workspace.
reconlab workspace suggest ~/labs/target --output-format md --force

Multi-scan behavior:

  • A typical engagement runs a TCP full scan, a UDP top-N scan, and a targeted -sV -sC rescan. Drop all three into scans/; methodology generation will union open ports across them and merge service metadata.
  • Records are keyed by (host, port, proto). When the same port appears in more than one scan, the most recent non-placeholder value wins for service name, product, and version — so a later -sV overrides an earlier banner-only scan, but an unscanned re-discovery cannot erase real data captured earlier.
  • Pass --latest to revert to single-scan mode (most-recently-modified file only). Useful if older scans in scans/ are stale or experimental.

Re-running refuses to overwrite the previous methodology unless --force is passed; unrelated files in the workspace are never touched.

Check workspace status

workspace status prints a one-screen summary of where a workspace stands — scan count, whether methodology has been generated (and whether it is stale relative to scans/), recorded findings by severity, and a single suggested next step.

# From inside the workspace, or point at one explicitly.
reconlab workspace status
reconlab workspace status ~/labs/target
Workspace: target
Path:      /home/op/labs/target

  Target       10.10.10.5 · app.corp.local · corp.local
  Platform     lab
  Scans        1 file (latest: initial.xml)
  Methodology  notes/methodology/  — STALE (newer scans present)
  Findings     1 recorded — 1 High

Next: scans/ changed since the methodology was generated — re-run `reconlab workspace suggest --force`.

The Next line is state-driven: it points at workspace suggest when no methodology exists yet, flags a stale methodology once newer scans land, and nudges toward finding add after methodology is in place. It never modifies the workspace — workspace status is read-only.

Check report readiness

workspace check lints the workspace's report.md and flags the scaffold placeholders still left unfilled — per-finding fields (Severity, Description, Evidence, Impact, Remediation) and the Executive Summary. It exits non-zero when issues remain, so it works as a pre-handover gate or a CI step.

# From inside the workspace, or point at one explicitly.
reconlab workspace check
reconlab workspace check ~/labs/target
Report check: /home/op/labs/target/report.md

Report:
  - Executive Summary is still the scaffold placeholder.

Findings:
  Finding 1 — SMB null session enabled
    - **Impact** is still a scaffold placeholder
    - **Remediation** is still a scaffold placeholder

3 issues found — fill these in before handing the report over.

finding add fills in Severity, Affected, and (with --service) Description, but Impact and Remediation are always left for you — workspace check is the reminder that they, and the Executive Summary, still need attention. Like workspace status, it is read-only.

Record findings into the report

finding add appends a structured finding block to report.md inside the workspace. The first call replaces the placeholder ### Finding 1 — _Title_ left there by workspace init; subsequent calls auto-increment the finding number after the highest existing one.

reconlab finding add \
  --title "SMB null session enabled" \
  --severity high \
  --service smb \
  --port 445 \
  --evidence screenshots/01-shares.png \
  --evidence loot/null-session-listing.txt

What finding add does:

  • Reads .reconlab.json and pre-fills Affected: with the workspace's target IP and hostname.
  • If --service matches a known workflow (smb, http, ...), seeds the Description: from the workflow's report-note (with [TARGET_IP] / [TARGET_HOST] / [DOMAIN] substituted) and adds a **Methodology:** see [[notes/methodology/services/<service>]] cross-link.
  • --description overrides the workflow seed when you want custom text.
  • Each --evidence PATH adds a bullet under Evidence:. Repeat the flag for multiple files (--evidence a.png --evidence b.png).
  • Severity is restricted to critical | high | medium | low | info.

finding list prints the current findings as a one-line-per-finding table — handy for sanity-checking what is captured so far without opening the file:

#  Severity  Title                        Service:Port
-  --------  ---------------------------  ------------
1  High      SMB null session enabled     smb:445
2  Medium    HTTP debug endpoint exposed  http:80

Browse the workflow registry

workflow list and workflow show expose the workflow registry directly — useful for "remind me what to check for LDAP" or for picking a starting point on a target you haven't scanned yet. Neither command needs a workspace or a scan file.

Workflows fall into three categories:

  • service-enum — per-service enumeration methodology (SMB, HTTP, LDAP, …). These are what suggest-next / workspace suggest auto-select from a scan.
  • post-foothold — what to do once you have a shell or a valid credential: linux-privesc, windows-privesc, ad-foothold.
  • lateral-movementpivoting: tunneling and internal network access.

Post-foothold and lateral-movement workflows have no ports, so a scan never auto-selects them — reach them with workflow show.

reconlab workflow list
Category          ID               Display          Priority  Ports
----------------  ---------------  ---------------  --------  --------------------
service-enum      smb              SMB              10        139/tcp, 445/tcp
service-enum      http             HTTP             15        80/tcp, 8000/tcp, …
…
post-foothold     linux-privesc    Linux Privesc    50        -
post-foothold     windows-privesc  Windows Privesc  51        -
post-foothold     ad-foothold      AD Foothold      52        -
lateral-movement  pivoting         Pivoting         60        -
# Print one workflow (Markdown) to stdout with placeholders intact
reconlab workflow show smb
reconlab workflow show linux-privesc

# Or substitute target metadata while rendering
reconlab workflow show ad-foothold --domain corp.local

The Markdown is the same per-workflow content that workspace suggest and suggest-next write into the methodology document. Those two commands also append an After a Foothold footer pointing at the post-foothold workflows, so the generated methodology carries you past initial access.

Initialize a report folder (deprecated)

Deprecated. Superseded by workspace init; will be removed in a future release. Running it prints a deprecation notice on stderr. Migrate with reconlab workspace init <name> — you get the same folder tree, plus persisted metadata and a richer report scaffold.

report-init is the simpler predecessor of workspace init — it creates the folder tree only, without metadata or the richer report scaffold.

reconlab report-init target --output-dir labs

Creates:

labs/target/
├── loot/
├── notes/
├── scans/
├── screenshots/
└── report.md

Generate an Obsidian note template (deprecated)

Deprecated. Superseded by workspace init + workspace suggest; will be removed in a future release. Running it prints a deprecation notice on stderr (the note itself still goes to stdout, so existing redirects keep working). Migrate to workspace suggest, whose generated vault is richer and stays in sync with scans.

obsidian-note is a simple single-file note scaffold from before the Obsidian vault renderer existed. For new work, prefer workspace init + workspace suggest — the generated vault is richer and stays in sync with scan results.

reconlab obsidian-note target --ip 10.10.10.5 > target.md

Suggest the next steps from an nmap scan

suggest-next is the underlying methodology generator. For the typical case (one workspace, drop a scan into scans/, get a vault back) prefer reconlab workspace suggest — it picks up the latest scan and the workspace metadata automatically. Reach for suggest-next directly when you want to point at an arbitrary scan file or override the target metadata.

It turns parsed nmap results into a service-based, prioritized methodology document. Each detected service gets a checklist, command table, expected output, verification steps, troubleshooting matrix, and a draft report note. Lab placeholders ([USER], [PASS], [LHOST], [LPORT]) are preserved for the operator to fill in.

Supported input formats:

  • xml — nmap XML (-oX or -oA); the most reliable parser.
  • normal — human-readable nmap output (.nmap files from -oN or -oA).
  • grepable — grepable nmap output (.gnmap files from -oG or -oA).
  • auto (default) — infers from the file extension; if the path has no extension, it is treated as an nmap -oA basename and the matching sibling file is probed in xml → normal → grepable priority.
# Auto-detect: scans/target resolves to scans/target.xml if present,
# otherwise scans/target.nmap, otherwise scans/target.gnmap.
reconlab suggest-next \
  -i scans/target \
  --input-format auto \
  --target 10.10.10.5 \
  --host app.corp.local \
  --domain corp.local \
  -o outputs/next.md

# Force a specific parser
reconlab suggest-next -i scans/target.nmap  --input-format normal   --target 10.10.10.5
reconlab suggest-next -i scans/target.gnmap --input-format grepable --target 10.10.10.5
reconlab suggest-next -i scans/target.xml   --input-format xml      --target 10.10.10.5

The simplest invocation derives the target IP from the scan and prints Markdown to stdout:

reconlab suggest-next -i scans/target.xml

Excerpt of the default md output:

# Methodology — 10.10.10.5

## Detected Services

| Port | Proto | Service | Product | Version |
|------|-------|---------|---------|---------|
| 445  | tcp   | microsoft-ds | Samba | 4.15.0 |
| 3389 | tcp   | ms-wbt-server | - | - |

## SMB (139/445) — Share & RPC Enumeration

### Checklist
- [ ] Fingerprint SMB dialect and signing posture.
- [ ] Attempt null-session share listing.
...

Supported service-enum workflows in this release: SMB, HTTP, HTTPS, FTP, SSH, DNS, SMTP, LDAP, Kerberos, MSSQL, MySQL, Oracle, RDP, WinRM, SNMP, NFS, rsync, Redis, VNC, IMAP/POP3 (20 total), plus three post-foothold workflows — linux-privesc, windows-privesc, ad-foothold — and one lateral-movement workflow, pivoting. Run reconlab workflow list for the live registry with categories, priorities, and port mappings. Open ports without a service-enum workflow are listed under an Unmapped Services section so nothing is silently dropped.

Obsidian vault output

--output-format obsidian writes a small Obsidian-friendly vault folder instead of a single Markdown file. The directory passed via -o is created (and intermediate parents) if it does not already exist.

reconlab suggest-next \
  -i scans/target \
  --target 10.10.10.5 \
  --host app.corp.local \
  --domain corp.local \
  --output-format obsidian \
  -o notes/target

Generated layout:

notes/target/
├── index.md          # MOC: frontmatter, scope, detected services, prioritized
│                     # wikilinks to each service note, optional report draft
├── services/
│   ├── smb.md        # frontmatter + Checklist / Commands / Expected output /
│   ├── http.md       # Verification / Troubleshooting / Report note / Related
│   ├── rdp.md
│   └── …             # one per detected & mapped service
└── unmapped.md       # only present when the scan has open ports without a workflow
  • Filenames use the lowercase canonical service ID (smb.md, winrm.md).
  • Cross-references render as aliased wikilinks: [[services/smb|SMB]], [[services/winrm|WinRM]] — paths are stable and machine-friendly, while the alias keeps the rendered text human-friendly.
  • Each note carries YAML frontmatter (title, target, service, priority, status: in-progress, tags) so Obsidian dataview / search queries work immediately.

By default the command refuses to overwrite existing files in the vault directory. Pass --force to overwrite, or point -o at an empty/new directory. Files in the target directory that the tool does not generate are left untouched.

# Re-render and overwrite previously generated notes
reconlab suggest-next -i scans/target --output-format obsidian -o notes/target --force

The md default behavior (single Markdown file, optional -o) is unchanged.

JSON output

--output-format json writes a single structured JSON document instead of Markdown or a vault: target metadata, detected and unmapped services, and the full prioritized per-workflow methodology (checklists, commands, troubleshooting, report notes) as data. Like md, it prints to stdout when -o is omitted.

# To a file, or piped into jq for scripting.
reconlab suggest-next -i scans/target --output-format json -o outputs/methodology.json
reconlab suggest-next -i scans/target --output-format json | jq '.workflows[].service_id'

Target placeholders ([TARGET_IP], [TARGET_HOST], [DOMAIN]) are substituted; operator placeholders ([USER], [PASS], ...) are left intact for downstream tooling. --output-format accepts md, json, and obsidian.

Development

Install the dev extras (pytest + ruff), then run syntax checks, lint, and tests:

python -m pip install -e ".[dev]"
python -m compileall src tests
ruff check .
python -m pytest

GitHub Actions runs ruff check . and pytest on every push and pull request across Python 3.11 and 3.13 (see .github/workflows/tests.yml).

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

reconlab-0.5.0.tar.gz (73.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

reconlab-0.5.0-py3-none-any.whl (57.7 kB view details)

Uploaded Python 3

File details

Details for the file reconlab-0.5.0.tar.gz.

File metadata

  • Download URL: reconlab-0.5.0.tar.gz
  • Upload date:
  • Size: 73.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for reconlab-0.5.0.tar.gz
Algorithm Hash digest
SHA256 4abb4508559fb1c7f913e87cea6d2e2400b8ab9be9675f6c0dfa727467a3cf83
MD5 3618abd26336e3bfc9b4a38ccb3e556c
BLAKE2b-256 d79c9be486e869bae5fb7820ac969fcb5d736ea24ec2e8349196b2a559d2559d

See more details on using hashes here.

Provenance

The following attestation bundles were made for reconlab-0.5.0.tar.gz:

Publisher: publish.yml on 0xsl0th/reconlab

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file reconlab-0.5.0-py3-none-any.whl.

File metadata

  • Download URL: reconlab-0.5.0-py3-none-any.whl
  • Upload date:
  • Size: 57.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for reconlab-0.5.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b017b12ed97f3036fc668b01988c59f774fb534968e95c398fa6c20236a3f713
MD5 4b0e811927de699b05c1fe74ac1a2300
BLAKE2b-256 d4f40060dd9d6533b46cb7137b49a2e920d58ef9fc3420c78fd93738077912b7

See more details on using hashes here.

Provenance

The following attestation bundles were made for reconlab-0.5.0-py3-none-any.whl:

Publisher: publish.yml on 0xsl0th/reconlab

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page