Metadata-Version: 2.4
Name: reconlab
Version: 0.5.0
Summary: Minimal CLI helpers for authorized penetration-testing lab organization and reporting.
Project-URL: Homepage, https://github.com/0xsl0th/reconlab
Project-URL: Repository, https://github.com/0xsl0th/reconlab
Project-URL: Changelog, https://github.com/0xsl0th/reconlab/blob/main/CHANGELOG.md
Project-URL: Issues, https://github.com/0xsl0th/reconlab/issues
Author: 0xsl0th
License-Expression: MIT
License-File: LICENSE
Keywords: cli,lab,methodology,nmap,pentest,security,workflow
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Information Technology
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Security
Classifier: Topic :: Utilities
Requires-Python: >=3.10
Requires-Dist: typer>=0.12.0
Provides-Extra: dev
Requires-Dist: pytest>=8.0.0; extra == 'dev'
Requires-Dist: ruff>=0.6.0; extra == 'dev'
Description-Content-Type: text/markdown

# 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)

```bash
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)

```bash
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.

```bash
# 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`:

```text
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

```bash
reconlab parse-nmap scans/target.xml
```

Example output:

```text
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.

```bash
# 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:

```text
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:

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

Output:

```text
# 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):

```bash
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.

```bash
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`):

```bash
# 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.

```bash
# From inside the workspace, or point at one explicitly.
reconlab workspace status
reconlab workspace status ~/labs/target
```

```text
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.

```bash
# From inside the workspace, or point at one explicitly.
reconlab workspace check
reconlab workspace check ~/labs/target
```

```text
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.

```bash
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:

```text
#  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-movement`** — `pivoting`: 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`.

```bash
reconlab workflow list
```

```text
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        -
```

```bash
# 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.

```bash
reconlab report-init target --output-dir labs
```

Creates:

```text
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.

```bash
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.

```bash
# 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:

```bash
reconlab suggest-next -i scans/target.xml
```

Excerpt of the default `md` output:

```markdown
# 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.

```bash
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:

```text
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.

```bash
# 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.

```bash
# 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:

```bash
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`).
