reconpro 2.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- reconpro-2.0.0/LICENSE +21 -0
- reconpro-2.0.0/PKG-INFO +109 -0
- reconpro-2.0.0/README.md +83 -0
- reconpro-2.0.0/pyproject.toml +38 -0
- reconpro-2.0.0/reconpro/__init__.py +25 -0
- reconpro-2.0.0/reconpro/cli.py +338 -0
- reconpro-2.0.0/reconpro/http.py +163 -0
- reconpro-2.0.0/reconpro/modules/__init__.py +15 -0
- reconpro-2.0.0/reconpro/modules/auth.py +126 -0
- reconpro-2.0.0/reconpro/modules/bot.py +127 -0
- reconpro-2.0.0/reconpro/modules/chain.py +176 -0
- reconpro-2.0.0/reconpro/modules/gorgon.py +174 -0
- reconpro-2.0.0/reconpro/modules/nhi.py +159 -0
- reconpro-2.0.0/reconpro/modules/oblivion.py +210 -0
- reconpro-2.0.0/reconpro/modules/recon.py +307 -0
- reconpro-2.0.0/reconpro/modules/vibesec.py +206 -0
- reconpro-2.0.0/reconpro/scanner.py +150 -0
- reconpro-2.0.0/reconpro.egg-info/PKG-INFO +109 -0
- reconpro-2.0.0/reconpro.egg-info/SOURCES.txt +23 -0
- reconpro-2.0.0/reconpro.egg-info/dependency_links.txt +1 -0
- reconpro-2.0.0/reconpro.egg-info/entry_points.txt +2 -0
- reconpro-2.0.0/reconpro.egg-info/requires.txt +1 -0
- reconpro-2.0.0/reconpro.egg-info/top_level.txt +1 -0
- reconpro-2.0.0/setup.cfg +4 -0
- reconpro-2.0.0/setup.py +50 -0
reconpro-2.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 ReconPro Security
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
reconpro-2.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: reconpro
|
|
3
|
+
Version: 2.0.0
|
|
4
|
+
Summary: ReconPro Enterprise — The Security Reconnaissance Platform. Eight Blades. One Target. One Verdict.
|
|
5
|
+
Home-page: https://github.com/reconpro-security/reconpro
|
|
6
|
+
Author: ReconPro Security
|
|
7
|
+
Author-email: ReconPro Security <security@reconpro.io>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
Keywords: security,scanner,reconnaissance,vulnerability,reconpro,vibesec,pentest,red-team,auth-bypass,ssrf,bot-detection,nhi,cloud-security
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Environment :: Console
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Intended Audience :: Information Technology
|
|
14
|
+
Classifier: Intended Audience :: System Administrators
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Topic :: Security
|
|
17
|
+
Classifier: Topic :: Software Development :: Testing
|
|
18
|
+
Requires-Python: >=3.8
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
License-File: LICENSE
|
|
21
|
+
Requires-Dist: rich>=13.0.0
|
|
22
|
+
Dynamic: author
|
|
23
|
+
Dynamic: home-page
|
|
24
|
+
Dynamic: license-file
|
|
25
|
+
Dynamic: requires-python
|
|
26
|
+
|
|
27
|
+
# ReconPro Enterprise
|
|
28
|
+
|
|
29
|
+
> **Eight Blades. One Target. One Verdict.**
|
|
30
|
+
|
|
31
|
+
The full-spectrum security reconnaissance platform. 8 scanning modules, one CLI command.
|
|
32
|
+
|
|
33
|
+
## Installation
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
pip install reconpro
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Or from source:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
git clone https://github.com/reconpro-security/reconpro.git
|
|
43
|
+
cd reconpro
|
|
44
|
+
pip install .
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Quick Start
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
# Scan with default modules (recon, vibesec, auth, chain, oblivion)
|
|
51
|
+
reconpro example.com
|
|
52
|
+
|
|
53
|
+
# Run all 8 modules
|
|
54
|
+
reconpro example.com --all
|
|
55
|
+
|
|
56
|
+
# Pick specific modules
|
|
57
|
+
reconpro example.com --modules recon,auth,nhi
|
|
58
|
+
|
|
59
|
+
# Quick VibeSec benchmark only
|
|
60
|
+
reconpro vibesec example.com
|
|
61
|
+
|
|
62
|
+
# JSON output
|
|
63
|
+
reconpro example.com --json -o report.json
|
|
64
|
+
|
|
65
|
+
# Skip TLS verification
|
|
66
|
+
reconpro example.com --insecure
|
|
67
|
+
|
|
68
|
+
# Adjust timeout and rate limit
|
|
69
|
+
reconpro example.com --timeout 5 --rate-limit 5
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Modules
|
|
73
|
+
|
|
74
|
+
| Module | ID | Description |
|
|
75
|
+
|--------|----|-------------|
|
|
76
|
+
| **RECON** | `recon` | 13-category surface reconnaissance (DNS, ports, TLS, headers, tech, WAF, cookies, CORS) |
|
|
77
|
+
| **AUTH BYPASS** | `auth` | 15 auth bypass techniques (header injection, method tampering, path traversal, IDOR) |
|
|
78
|
+
| **CHAIN HUNTER** | `chain` | SSRF + redirect chain hunting (cloud metadata, open redirects) |
|
|
79
|
+
| **BOT HUNTER** | `bot` | C2 / bot infrastructure detection + honeypot identification |
|
|
80
|
+
| **GORGON ULTRA** | `gorgon` | AI red team (SQLi, XSS, path traversal, HTTP methods, content-type) |
|
|
81
|
+
| **OBLIVION** | `oblivion` | 23-stage deep analysis with DREAD scoring (info disclosure, JS secrets, deep headers) |
|
|
82
|
+
| **VIBESEC** | `vibesec` | AI/vibe-coding vulnerability benchmark (100-point score, A+–F grades, GitHub badge) |
|
|
83
|
+
| **NHI GRAPH** | `nhi` | Non-Human Identity detection (cloud metadata SSRF, leaked tokens, credential files) |
|
|
84
|
+
|
|
85
|
+
## Scoring
|
|
86
|
+
|
|
87
|
+
- **100-point** benchmark system
|
|
88
|
+
- **A+** (90+) → **F** (0–34) grades
|
|
89
|
+
- GitHub-ready **badge** for your README
|
|
90
|
+
- Per-module breakdowns with severity counts
|
|
91
|
+
|
|
92
|
+
## Output
|
|
93
|
+
|
|
94
|
+
Rich terminal UI with:
|
|
95
|
+
- Color-coded severity tables
|
|
96
|
+
- Module-by-module breakdown
|
|
97
|
+
- Progress spinners
|
|
98
|
+
- Score bars and grade indicators
|
|
99
|
+
- JSON export for CI/CD integration
|
|
100
|
+
|
|
101
|
+
## Requirements
|
|
102
|
+
|
|
103
|
+
- Python 3.8+
|
|
104
|
+
- No other dependencies (stdlib-only networking)
|
|
105
|
+
- `rich` for terminal UI (auto-installed)
|
|
106
|
+
|
|
107
|
+
## License
|
|
108
|
+
|
|
109
|
+
MIT
|
reconpro-2.0.0/README.md
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# ReconPro Enterprise
|
|
2
|
+
|
|
3
|
+
> **Eight Blades. One Target. One Verdict.**
|
|
4
|
+
|
|
5
|
+
The full-spectrum security reconnaissance platform. 8 scanning modules, one CLI command.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install reconpro
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Or from source:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
git clone https://github.com/reconpro-security/reconpro.git
|
|
17
|
+
cd reconpro
|
|
18
|
+
pip install .
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Quick Start
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
# Scan with default modules (recon, vibesec, auth, chain, oblivion)
|
|
25
|
+
reconpro example.com
|
|
26
|
+
|
|
27
|
+
# Run all 8 modules
|
|
28
|
+
reconpro example.com --all
|
|
29
|
+
|
|
30
|
+
# Pick specific modules
|
|
31
|
+
reconpro example.com --modules recon,auth,nhi
|
|
32
|
+
|
|
33
|
+
# Quick VibeSec benchmark only
|
|
34
|
+
reconpro vibesec example.com
|
|
35
|
+
|
|
36
|
+
# JSON output
|
|
37
|
+
reconpro example.com --json -o report.json
|
|
38
|
+
|
|
39
|
+
# Skip TLS verification
|
|
40
|
+
reconpro example.com --insecure
|
|
41
|
+
|
|
42
|
+
# Adjust timeout and rate limit
|
|
43
|
+
reconpro example.com --timeout 5 --rate-limit 5
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Modules
|
|
47
|
+
|
|
48
|
+
| Module | ID | Description |
|
|
49
|
+
|--------|----|-------------|
|
|
50
|
+
| **RECON** | `recon` | 13-category surface reconnaissance (DNS, ports, TLS, headers, tech, WAF, cookies, CORS) |
|
|
51
|
+
| **AUTH BYPASS** | `auth` | 15 auth bypass techniques (header injection, method tampering, path traversal, IDOR) |
|
|
52
|
+
| **CHAIN HUNTER** | `chain` | SSRF + redirect chain hunting (cloud metadata, open redirects) |
|
|
53
|
+
| **BOT HUNTER** | `bot` | C2 / bot infrastructure detection + honeypot identification |
|
|
54
|
+
| **GORGON ULTRA** | `gorgon` | AI red team (SQLi, XSS, path traversal, HTTP methods, content-type) |
|
|
55
|
+
| **OBLIVION** | `oblivion` | 23-stage deep analysis with DREAD scoring (info disclosure, JS secrets, deep headers) |
|
|
56
|
+
| **VIBESEC** | `vibesec` | AI/vibe-coding vulnerability benchmark (100-point score, A+–F grades, GitHub badge) |
|
|
57
|
+
| **NHI GRAPH** | `nhi` | Non-Human Identity detection (cloud metadata SSRF, leaked tokens, credential files) |
|
|
58
|
+
|
|
59
|
+
## Scoring
|
|
60
|
+
|
|
61
|
+
- **100-point** benchmark system
|
|
62
|
+
- **A+** (90+) → **F** (0–34) grades
|
|
63
|
+
- GitHub-ready **badge** for your README
|
|
64
|
+
- Per-module breakdowns with severity counts
|
|
65
|
+
|
|
66
|
+
## Output
|
|
67
|
+
|
|
68
|
+
Rich terminal UI with:
|
|
69
|
+
- Color-coded severity tables
|
|
70
|
+
- Module-by-module breakdown
|
|
71
|
+
- Progress spinners
|
|
72
|
+
- Score bars and grade indicators
|
|
73
|
+
- JSON export for CI/CD integration
|
|
74
|
+
|
|
75
|
+
## Requirements
|
|
76
|
+
|
|
77
|
+
- Python 3.8+
|
|
78
|
+
- No other dependencies (stdlib-only networking)
|
|
79
|
+
- `rich` for terminal UI (auto-installed)
|
|
80
|
+
|
|
81
|
+
## License
|
|
82
|
+
|
|
83
|
+
MIT
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=64", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "reconpro"
|
|
7
|
+
version = "2.0.0"
|
|
8
|
+
description = "ReconPro Enterprise — The Security Reconnaissance Platform. Eight Blades. One Target. One Verdict."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
requires-python = ">=3.8"
|
|
12
|
+
authors = [
|
|
13
|
+
{name = "ReconPro Security", email = "security@reconpro.io"},
|
|
14
|
+
]
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Development Status :: 4 - Beta",
|
|
17
|
+
"Environment :: Console",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"Intended Audience :: Information Technology",
|
|
20
|
+
"Intended Audience :: System Administrators",
|
|
21
|
+
"Programming Language :: Python :: 3",
|
|
22
|
+
"Topic :: Security",
|
|
23
|
+
"Topic :: Software Development :: Testing",
|
|
24
|
+
]
|
|
25
|
+
keywords = [
|
|
26
|
+
"security", "scanner", "reconnaissance", "vulnerability",
|
|
27
|
+
"reconpro", "vibesec", "pentest", "red-team", "auth-bypass",
|
|
28
|
+
"ssrf", "bot-detection", "nhi", "cloud-security",
|
|
29
|
+
]
|
|
30
|
+
dependencies = [
|
|
31
|
+
"rich>=13.0.0",
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
[project.scripts]
|
|
35
|
+
reconpro = "reconpro.cli:main"
|
|
36
|
+
|
|
37
|
+
[tool.setuptools]
|
|
38
|
+
packages = ["reconpro", "reconpro.modules"]
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""ReconPro Enterprise — The Security Reconnaissance Platform.
|
|
2
|
+
|
|
3
|
+
Eight Blades. One Target. One Verdict.
|
|
4
|
+
|
|
5
|
+
Modules:
|
|
6
|
+
recon 13-category surface reconnaissance
|
|
7
|
+
auth 15 auth bypass techniques
|
|
8
|
+
chain SSRF + redirect chain hunting
|
|
9
|
+
bot C2 / bot infrastructure detection
|
|
10
|
+
gorgon 15-stage AI red team
|
|
11
|
+
oblivion 23-stage analytical dissolution
|
|
12
|
+
vibesec AI/vibe-coding vulnerability benchmark
|
|
13
|
+
nhi Non-Human Identity & blast-radius mapping
|
|
14
|
+
|
|
15
|
+
Usage:
|
|
16
|
+
reconpro example.com
|
|
17
|
+
reconpro example.com --modules recon,auth,vibesec
|
|
18
|
+
reconpro example.com --all --json -o report.json
|
|
19
|
+
reconpro vibesec example.com
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
__version__ = "2.0.0"
|
|
23
|
+
__all__ = ["scan", "ReconProResult", "__version__"]
|
|
24
|
+
|
|
25
|
+
from .scanner import scan, ReconProResult # noqa: E402
|
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import json
|
|
5
|
+
import sys
|
|
6
|
+
import time
|
|
7
|
+
|
|
8
|
+
from rich.console import Console, Group
|
|
9
|
+
from rich.panel import Panel
|
|
10
|
+
from rich.progress import Progress, SpinnerColumn, TextColumn, TimeElapsedColumn
|
|
11
|
+
from rich.table import Table
|
|
12
|
+
from rich.text import Text
|
|
13
|
+
from rich.columns import Columns
|
|
14
|
+
from rich.rule import Rule
|
|
15
|
+
|
|
16
|
+
from . import __version__
|
|
17
|
+
from .scanner import scan, MODULE_REGISTRY, ALL_MODULES, DEFAULT_MODULES
|
|
18
|
+
|
|
19
|
+
console = Console()
|
|
20
|
+
|
|
21
|
+
BANNER = r"""[bold bright_white]
|
|
22
|
+
██████╗ ███████╗ ██████╗██╗ ██╗███████╗██████╗ ███████╗██████╗ ██████╗ ██╗ ██╗
|
|
23
|
+
██╔══██╗██╔════╝██╔════╝██║ ██║██╔════╝██╔══██╗██╔════╝██╔════╝██║██╗ ██╔╝
|
|
24
|
+
██████╔╝█████╗ ██║ ███████║█████╗ ██████╔╝█████╗ ██║ ██╔╝██╗██║
|
|
25
|
+
██╔═══╝ ██╔══╝ ██║ ██╔══██║██╔══╝ ██╔══██╗██╔══╝ ██║ █████╔╝██║
|
|
26
|
+
██║ ███████╗╚██████╗██║ ██║███████╗██║ ██║███████╗╚██████╗██╔╝██╗██║
|
|
27
|
+
╚═╝ ╚══════╝ ╚═════╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝╚══════╝ ╚═════╝╚═╝ ╚═╝╚═╝
|
|
28
|
+
[/bold bright_white][dim] E I G H T B L A D E S . O N E T A R G E T . O N E V E R D I C T.[/dim]
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
SEV_COLORS = {
|
|
33
|
+
"critical": "bright_red",
|
|
34
|
+
"high": "red",
|
|
35
|
+
"medium": "yellow",
|
|
36
|
+
"low": "green",
|
|
37
|
+
"info": "dim",
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
GRADE_COLORS = {
|
|
41
|
+
"A+": "bright_green",
|
|
42
|
+
"A": "green",
|
|
43
|
+
"B": "yellow",
|
|
44
|
+
"C": "red",
|
|
45
|
+
"D": "bright_red",
|
|
46
|
+
"F": "bold bright_red",
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
# ── Rich rendering ──────────────────────────────────────────────────────
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def _render_summary(result) -> None:
|
|
54
|
+
score = result.total_score
|
|
55
|
+
grade = result.grade
|
|
56
|
+
grade_color = GRADE_COLORS.get(grade, "bold bright_red")
|
|
57
|
+
sc = result.severity_counts
|
|
58
|
+
total = len(result.findings)
|
|
59
|
+
|
|
60
|
+
bar_width = 50
|
|
61
|
+
filled = int(score / 100 * bar_width)
|
|
62
|
+
bar = "█" * filled + "░" * (bar_width - filled)
|
|
63
|
+
|
|
64
|
+
console.print(Panel(
|
|
65
|
+
Group(
|
|
66
|
+
Text(f"\n {bar} [bold {grade_color}]{score}/100 ({grade})[/{grade_color}]"),
|
|
67
|
+
Text(f"\n Target: [cyan]{result.target}[/]"),
|
|
68
|
+
Text(f" Modules: [dim]{', '.join(result.modules_run)}[/]"),
|
|
69
|
+
Text(""),
|
|
70
|
+
Text(
|
|
71
|
+
f" Findings: [bold]{total}[/] "
|
|
72
|
+
f"[bright_red]{sc.get('critical', 0)} critical[/], "
|
|
73
|
+
f"[red]{sc.get('high', 0)} high[/], "
|
|
74
|
+
f"[yellow]{sc.get('medium', 0)} medium[/], "
|
|
75
|
+
f"[green]{sc.get('low', 0)} low[/], "
|
|
76
|
+
f"[dim]{sc.get('info', 0)} info[/]",
|
|
77
|
+
),
|
|
78
|
+
*(
|
|
79
|
+
[Text(f"\n VibeSec Score: [bold bright_green]{result.vibesec_score}/100 ({result.vibesec_grade})[/]")]
|
|
80
|
+
if result.vibesec_score is not None else []
|
|
81
|
+
),
|
|
82
|
+
),
|
|
83
|
+
border_style=grade_color,
|
|
84
|
+
title="[bold]RECONPRO[/bold]",
|
|
85
|
+
title_align="left",
|
|
86
|
+
padding=(1, 2),
|
|
87
|
+
))
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def _render_findings_table(result) -> None:
|
|
91
|
+
if not result.findings:
|
|
92
|
+
console.print("\n [bright_green]No findings. Target is clean.[/]")
|
|
93
|
+
return
|
|
94
|
+
|
|
95
|
+
table = Table(
|
|
96
|
+
title=f"Findings — {len(result.findings)} detected",
|
|
97
|
+
border_style="bright_white",
|
|
98
|
+
header_style="bold bright_white",
|
|
99
|
+
show_lines=False,
|
|
100
|
+
)
|
|
101
|
+
table.add_column("Severity", style="bold", width=10)
|
|
102
|
+
table.add_column("Module", style="cyan", width=12)
|
|
103
|
+
table.add_column("Category", style="magenta", width=18)
|
|
104
|
+
table.add_column("Finding", style="white")
|
|
105
|
+
table.add_column("Pts", style="yellow", width=5)
|
|
106
|
+
|
|
107
|
+
for f in result.findings[:50]:
|
|
108
|
+
sev = f.get("severity", "info")
|
|
109
|
+
color = SEV_COLORS.get(sev, "white")
|
|
110
|
+
table.add_row(
|
|
111
|
+
f"[{color}]{sev.upper()}[/{color}]",
|
|
112
|
+
f.get("module", ""),
|
|
113
|
+
f.get("category", ""),
|
|
114
|
+
f.get("title", "")[:70],
|
|
115
|
+
str(f.get("points_deducted", 0)),
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
console.print(table)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def _render_module_breakdown(result) -> None:
|
|
122
|
+
if not result.module_results:
|
|
123
|
+
return
|
|
124
|
+
|
|
125
|
+
modules_table = Table(
|
|
126
|
+
title="Module Breakdown",
|
|
127
|
+
border_style="dim",
|
|
128
|
+
header_style="bold dim",
|
|
129
|
+
)
|
|
130
|
+
modules_table.add_column("Module", style="bold", width=16)
|
|
131
|
+
modules_table.add_column("Findings", style="white", width=10)
|
|
132
|
+
modules_table.add_column("Critical", style="bright_red", width=10)
|
|
133
|
+
modules_table.add_column("High", style="red", width=8)
|
|
134
|
+
modules_table.add_column("Medium", style="yellow", width=8)
|
|
135
|
+
|
|
136
|
+
for mod_id, mod_data in result.module_results.items():
|
|
137
|
+
findings = mod_data.get("findings", [])
|
|
138
|
+
crit = sum(1 for f in findings if f.get("severity") == "critical")
|
|
139
|
+
high = sum(1 for f in findings if f.get("severity") == "high")
|
|
140
|
+
med = sum(1 for f in findings if f.get("severity") == "medium")
|
|
141
|
+
modules_table.add_row(
|
|
142
|
+
mod_id.upper(),
|
|
143
|
+
str(len(findings)),
|
|
144
|
+
str(crit),
|
|
145
|
+
str(high),
|
|
146
|
+
str(med),
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
console.print(modules_table)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def _render_badge(result) -> None:
|
|
153
|
+
if result.badge_markdown:
|
|
154
|
+
console.print(Panel(
|
|
155
|
+
Group(
|
|
156
|
+
Text(" GitHub README Badge (copy-paste):", style="bold dim"),
|
|
157
|
+
Text(f" {result.badge_markdown}", style="cyan"),
|
|
158
|
+
),
|
|
159
|
+
border_style="dim",
|
|
160
|
+
title="[dim]Badge[/dim]",
|
|
161
|
+
title_align="left",
|
|
162
|
+
padding=(0, 2),
|
|
163
|
+
))
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
# ── CLI entry point ─────────────────────────────────────────────────────
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def _add_scan_args(p: argparse.ArgumentParser) -> None:
|
|
170
|
+
"""Add shared scan arguments to a parser."""
|
|
171
|
+
p.add_argument("target", help="Target domain or URL")
|
|
172
|
+
p.add_argument("--json", dest="json_output", action="store_true",
|
|
173
|
+
help="Output as JSON")
|
|
174
|
+
p.add_argument("-o", "--output", dest="output_file", type=str,
|
|
175
|
+
help="Save JSON to file")
|
|
176
|
+
p.add_argument("--timeout", "-t", type=int, default=8,
|
|
177
|
+
help="Per-request timeout in seconds (default: 8)")
|
|
178
|
+
p.add_argument("--insecure", "-k", action="store_true",
|
|
179
|
+
help="Skip TLS verification")
|
|
180
|
+
p.add_argument("--rate-limit", type=float, default=10.0,
|
|
181
|
+
help="Max requests per second (default: 10)")
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def main(argv: list[str] | None = None) -> None:
|
|
185
|
+
parser = argparse.ArgumentParser(
|
|
186
|
+
prog="reconpro",
|
|
187
|
+
description=(
|
|
188
|
+
"ReconPro Enterprise — Eight Blades. One Target. One Verdict.\n"
|
|
189
|
+
"The full-spectrum security reconnaissance platform."
|
|
190
|
+
),
|
|
191
|
+
epilog="Examples:\n"
|
|
192
|
+
" reconpro example.com\n"
|
|
193
|
+
" reconpro example.com --modules recon,auth,vibesec\n"
|
|
194
|
+
" reconpro example.com --all --json -o report.json\n"
|
|
195
|
+
" reconpro vibesec example.com",
|
|
196
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
parser.add_argument("--version", "-v", action="version",
|
|
200
|
+
version=f"ReconPro {__version__}")
|
|
201
|
+
|
|
202
|
+
subparsers = parser.add_subparsers(dest="subcommand")
|
|
203
|
+
|
|
204
|
+
# vibesec quick subcommand
|
|
205
|
+
vibesec_p = subparsers.add_parser("vibesec", help="Quick VibeSec benchmark")
|
|
206
|
+
_add_scan_args(vibesec_p)
|
|
207
|
+
|
|
208
|
+
# scan subcommand (default behavior)
|
|
209
|
+
scan_p = subparsers.add_parser("scan", help="Full scan with module selection")
|
|
210
|
+
scan_p.add_argument("target", help="Target domain or URL")
|
|
211
|
+
scan_p.add_argument("--modules", "-m", type=str, default=None,
|
|
212
|
+
help="Comma-separated module list")
|
|
213
|
+
scan_p.add_argument("--all", "-a", action="store_true",
|
|
214
|
+
help="Run all 8 modules")
|
|
215
|
+
scan_p.add_argument("--json", dest="json_output", action="store_true")
|
|
216
|
+
scan_p.add_argument("-o", "--output", dest="output_file", type=str)
|
|
217
|
+
scan_p.add_argument("--timeout", "-t", type=int, default=8)
|
|
218
|
+
scan_p.add_argument("--insecure", "-k", action="store_true")
|
|
219
|
+
scan_p.add_argument("--rate-limit", type=float, default=10.0)
|
|
220
|
+
|
|
221
|
+
# list subcommand
|
|
222
|
+
subparsers.add_parser("list", help="List available modules")
|
|
223
|
+
|
|
224
|
+
# Catchall: if first positional doesn't match a subcommand, treat as scan
|
|
225
|
+
args, remaining = parser.parse_known_args(argv)
|
|
226
|
+
|
|
227
|
+
# List modules
|
|
228
|
+
if args.subcommand == "list":
|
|
229
|
+
console.print("\n[bold]Available Modules:[/bold]\n")
|
|
230
|
+
for mid, entry in MODULE_REGISTRY.items():
|
|
231
|
+
default = " (default)" if mid in DEFAULT_MODULES else ""
|
|
232
|
+
console.print(f" [cyan]{mid:12}[/] {entry['name']:18}{default}")
|
|
233
|
+
console.print(f"\n [dim]Default: {', '.join(DEFAULT_MODULES)}[/]")
|
|
234
|
+
console.print(f" [dim]Use --all to run all 8 modules[/]\n")
|
|
235
|
+
return
|
|
236
|
+
|
|
237
|
+
# Handle vibesec subcommand
|
|
238
|
+
if args.subcommand == "vibesec":
|
|
239
|
+
if not args.target:
|
|
240
|
+
parser.parse_args(["vibesec", "--help"])
|
|
241
|
+
sys.exit(1)
|
|
242
|
+
target = args.target
|
|
243
|
+
modules = ["vibesec"]
|
|
244
|
+
json_output = args.json_output
|
|
245
|
+
output_file = args.output_file
|
|
246
|
+
timeout = args.timeout
|
|
247
|
+
verify_tls = not args.insecure
|
|
248
|
+
rate_limit = args.rate_limit
|
|
249
|
+
# Handle explicit scan subcommand
|
|
250
|
+
elif args.subcommand == "scan":
|
|
251
|
+
if not args.target:
|
|
252
|
+
parser.parse_args(["scan", "--help"])
|
|
253
|
+
sys.exit(1)
|
|
254
|
+
target = args.target
|
|
255
|
+
modules = ([m.strip().lower() for m in args.modules.split(",")]
|
|
256
|
+
if args.modules else None)
|
|
257
|
+
json_output = args.json_output
|
|
258
|
+
output_file = args.output_file
|
|
259
|
+
timeout = args.timeout
|
|
260
|
+
verify_tls = not args.insecure
|
|
261
|
+
rate_limit = args.rate_limit
|
|
262
|
+
all_modules = args.all
|
|
263
|
+
# Handle implicit scan (no subcommand, first arg is the target)
|
|
264
|
+
elif remaining and not args.subcommand:
|
|
265
|
+
target = remaining[0]
|
|
266
|
+
# Re-parse with explicit scan subcommand to get flags
|
|
267
|
+
scan_args = parser.parse_args(["scan"] + remaining)
|
|
268
|
+
modules = ([m.strip().lower() for m in scan_args.modules.split(",")]
|
|
269
|
+
if scan_args.modules else None)
|
|
270
|
+
json_output = scan_args.json_output
|
|
271
|
+
output_file = scan_args.output_file
|
|
272
|
+
timeout = scan_args.timeout
|
|
273
|
+
verify_tls = not scan_args.insecure
|
|
274
|
+
rate_limit = scan_args.rate_limit
|
|
275
|
+
all_modules = scan_args.all
|
|
276
|
+
else:
|
|
277
|
+
parser.print_help()
|
|
278
|
+
sys.exit(1)
|
|
279
|
+
|
|
280
|
+
target = target.strip()
|
|
281
|
+
|
|
282
|
+
# Banner
|
|
283
|
+
console.print(BANNER)
|
|
284
|
+
console.print(f" [dim]v{__version__} | {target} | modules: {modules or 'default'}[/]\n")
|
|
285
|
+
console.print(f" [bold]Scanning [cyan]{target}[/] ...[/]\n")
|
|
286
|
+
|
|
287
|
+
try:
|
|
288
|
+
with Progress(
|
|
289
|
+
SpinnerColumn(),
|
|
290
|
+
TextColumn("[bold]{task.description}[/]"),
|
|
291
|
+
TimeElapsedColumn(),
|
|
292
|
+
console=console,
|
|
293
|
+
) as progress:
|
|
294
|
+
task = progress.add_task("ReconPro scanning...", total=None)
|
|
295
|
+
result = scan(
|
|
296
|
+
target,
|
|
297
|
+
modules=modules,
|
|
298
|
+
all_modules=all_modules if args.subcommand == "scan" else False,
|
|
299
|
+
timeout=timeout,
|
|
300
|
+
verify_tls=verify_tls,
|
|
301
|
+
rate_limit=rate_limit,
|
|
302
|
+
)
|
|
303
|
+
progress.update(task, completed=True)
|
|
304
|
+
except KeyboardInterrupt:
|
|
305
|
+
console.print("\n [yellow]Scan interrupted.[/]")
|
|
306
|
+
sys.exit(130)
|
|
307
|
+
except Exception as exc:
|
|
308
|
+
console.print(f" [bright_red]Error:[/] {exc}")
|
|
309
|
+
sys.exit(1)
|
|
310
|
+
|
|
311
|
+
# Output
|
|
312
|
+
if json_output:
|
|
313
|
+
text = json.dumps(result.to_dict(), indent=2, default=str)
|
|
314
|
+
if output_file:
|
|
315
|
+
with open(output_file, "w") as fp:
|
|
316
|
+
fp.write(text)
|
|
317
|
+
console.print(f" [green]JSON report saved to [cyan]{output_file}[/][/]")
|
|
318
|
+
else:
|
|
319
|
+
console.print(text)
|
|
320
|
+
else:
|
|
321
|
+
_render_summary(result)
|
|
322
|
+
console.print()
|
|
323
|
+
_render_module_breakdown(result)
|
|
324
|
+
console.print()
|
|
325
|
+
_render_findings_table(result)
|
|
326
|
+
_render_badge(result)
|
|
327
|
+
|
|
328
|
+
if output_file:
|
|
329
|
+
with open(output_file, "w") as fp:
|
|
330
|
+
fp.write(json.dumps(result.to_dict(), indent=2, default=str))
|
|
331
|
+
console.print(f"\n [green]JSON report saved to [cyan]{output_file}[/][/]")
|
|
332
|
+
|
|
333
|
+
console.print()
|
|
334
|
+
sys.exit(0)
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
if __name__ == "__main__":
|
|
338
|
+
main()
|