printerxpl-forge 6.2.0__py3-none-any.whl

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.
Files changed (97) hide show
  1. nse/README.md +204 -0
  2. nse/__init__.py +6 -0
  3. nse/install_nse.py +412 -0
  4. nse/lib/printerxpl.lua +238 -0
  5. nse/scripts/cups-info.nse +74 -0
  6. nse/scripts/cups-queue-info.nse +43 -0
  7. nse/scripts/hp-printers-cve-2022-1026.nse +121 -0
  8. nse/scripts/http-device-mac.nse +107 -0
  9. nse/scripts/http-hp-ilo-info.nse +121 -0
  10. nse/scripts/http-info-xerox-enum.nse +101 -0
  11. nse/scripts/http-vuln-cve2022-1026.nse +158 -0
  12. nse/scripts/lexmark-config.nse +89 -0
  13. nse/scripts/pjl-ready-message.nse +106 -0
  14. nse/scripts/printer-banner.nse +217 -0
  15. nse/scripts/printer-cups-rce.nse +189 -0
  16. nse/scripts/printer-cve-detect.nse +279 -0
  17. nse/scripts/printer-discover.nse +205 -0
  18. nse/scripts/printer-firmware-exposed.nse +219 -0
  19. nse/scripts/printer-hp-pjl.nse +192 -0
  20. nse/scripts/printer-http-ews.nse +293 -0
  21. nse/scripts/printer-ipp-info.nse +235 -0
  22. nse/scripts/printer-lexmark-ipp.nse +203 -0
  23. nse/scripts/printer-passback.nse +204 -0
  24. nse/scripts/printer-pjl-info.nse +146 -0
  25. nse/scripts/printer-printnightmare.nse +211 -0
  26. nse/scripts/printer-snmp-info.nse +176 -0
  27. nse/scripts/printer-vuln-check.nse +256 -0
  28. nse/scripts/snmp-device-mac.nse +93 -0
  29. nse/scripts/snmp-info.nse +146 -0
  30. nse/scripts/snmp-sysdescr.nse +70 -0
  31. printerxpl_forge-6.2.0.dist-info/METADATA +919 -0
  32. printerxpl_forge-6.2.0.dist-info/RECORD +97 -0
  33. printerxpl_forge-6.2.0.dist-info/WHEEL +5 -0
  34. printerxpl_forge-6.2.0.dist-info/entry_points.txt +4 -0
  35. printerxpl_forge-6.2.0.dist-info/licenses/LICENSE +21 -0
  36. printerxpl_forge-6.2.0.dist-info/top_level.txt +4 -0
  37. src/assets/fonts/gunplay.pfa +1671 -0
  38. src/assets/fonts/kshandwrt.pfa +315 -0
  39. src/assets/fonts/laksoner.pfa +2402 -0
  40. src/assets/fonts/paintcans.pfa +9699 -0
  41. src/assets/fonts/stencilod.pfa +4076 -0
  42. src/assets/fonts/takecover.pfa +26138 -0
  43. src/assets/fonts/topsecret.pfa +6652 -0
  44. src/assets/fonts/whoa.pfa +773 -0
  45. src/assets/mibs/HOST-RESOURCES-MIB +1540 -0
  46. src/assets/mibs/Printer-MIB +4389 -0
  47. src/assets/mibs/README.md +9 -0
  48. src/assets/mibs/SNMPv2-MIB +854 -0
  49. src/assets/overlays/hacker.eps +596 -0
  50. src/assets/overlays/smiley.eps +214 -0
  51. src/assets/overlays/smiley2.eps +240 -0
  52. src/core/attack_orchestrator.py +1025 -0
  53. src/core/capabilities.py +323 -0
  54. src/core/destructive_audit.py +430 -0
  55. src/core/discovery.py +488 -0
  56. src/core/osdetect.py +74 -0
  57. src/core/poly_runner.py +579 -0
  58. src/core/printer.py +1426 -0
  59. src/main.py +2134 -0
  60. src/modules/install_printer.py +318 -0
  61. src/modules/login_bruteforce.py +852 -0
  62. src/modules/pcl.py +506 -0
  63. src/modules/pjl.py +3575 -0
  64. src/modules/print_job.py +1290 -0
  65. src/modules/ps.py +1102 -0
  66. src/payloads/__init__.py +98 -0
  67. src/payloads/assets/overlays/notice.eps +9 -0
  68. src/protocols/__init__.py +19 -0
  69. src/protocols/firmware.py +738 -0
  70. src/protocols/ipp.py +216 -0
  71. src/protocols/ipp_attacks.py +609 -0
  72. src/protocols/lpd.py +141 -0
  73. src/protocols/network_map.py +1004 -0
  74. src/protocols/raw.py +173 -0
  75. src/protocols/smb.py +359 -0
  76. src/protocols/ssrf_pivot.py +427 -0
  77. src/protocols/storage.py +587 -0
  78. src/ui/__init__.py +6 -0
  79. src/ui/interactive.py +742 -0
  80. src/ui/spinner.py +112 -0
  81. src/ui/tables.py +132 -0
  82. src/utils/banner_grabber.py +852 -0
  83. src/utils/codebook.py +456 -0
  84. src/utils/config.py +522 -0
  85. src/utils/cve_loader.py +158 -0
  86. src/utils/default_creds.py +134 -0
  87. src/utils/discovery_online.py +1327 -0
  88. src/utils/exploit_manager.py +805 -0
  89. src/utils/fuzzer.py +220 -0
  90. src/utils/helper.py +732 -0
  91. src/utils/local_printers.py +307 -0
  92. src/utils/ml_engine.py +491 -0
  93. src/utils/operators.py +474 -0
  94. src/utils/ports.py +234 -0
  95. src/utils/vuln_scanner.py +823 -0
  96. src/utils/wordlist_loader.py +412 -0
  97. src/version.py +36 -0
nse/README.md ADDED
@@ -0,0 +1,204 @@
1
+ # PrinterXPL-Forge — Nmap NSE Scripts
2
+
3
+ > Author: André Henrique (@mrhenrike) | União Geek
4
+ > Repo: https://github.com/mrhenrike/PrinterXPL-Forge
5
+ > Docs: https://github.com/mrhenrike/PrinterXPL-Forge/wiki/NSE
6
+
7
+ ---
8
+
9
+ ## Overview
10
+
11
+ 12 Nmap Scripting Engine (NSE) scripts + 1 shared Lua library for **printer and MFP security assessment**.
12
+
13
+ These scripts complement the full PrinterXPL-Forge toolkit, providing:
14
+ - Multi-protocol banner grabbing and vendor fingerprinting
15
+ - CVE cross-reference against 80+ printer vulnerabilities
16
+ - Lightweight active probes (non-destructive)
17
+ - LDAP/SMB passback attack surface detection
18
+ - Firmware update endpoint exposure detection
19
+ - Exploit module suggestions for full exploitation
20
+
21
+ ---
22
+
23
+ ## Quick Install
24
+
25
+ ```bash
26
+ # 1. Install PrinterXPL-Forge with NSE extras
27
+ pip install printerxpl-forge[nse]
28
+
29
+ # 2. Deploy scripts to Nmap (requires elevated privileges)
30
+ printerxpl-nse install
31
+
32
+ # 3. Verify
33
+ printerxpl-nse status
34
+ ```
35
+
36
+ On Windows (Administrator PowerShell):
37
+ ```powershell
38
+ pip install printerxpl-forge[nse]
39
+ printerxpl-nse install
40
+ ```
41
+
42
+ ---
43
+
44
+ ## NSE Scripts
45
+
46
+ | Script | Ports | Description |
47
+ |--------|-------|-------------|
48
+ | `printer-discover.nse` | 9100, 631, 80, 443, 515, 23 | Fast multi-protocol printer discovery |
49
+ | `printer-banner.nse` | 9100, 631, 80, 443, 515 | Full banner grab + vendor fingerprint |
50
+ | `printer-pjl-info.nse` | 9100 | Deep PJL enumeration (NVRAM, FS, vars) |
51
+ | `printer-ipp-info.nse` | 631 | IPP Get-Printer-Attributes + CVE check |
52
+ | `printer-http-ews.nse` | 80, 443 | HTTP EWS fingerprint + default creds |
53
+ | `printer-snmp-info.nse` | 161/udp | SNMP Printer MIB enumeration |
54
+ | `printer-cve-detect.nse` | Any | CVE cross-reference (80+ CVEs, 15 vendors) |
55
+ | `printer-vuln-check.nse` | Any | Active non-destructive vuln validation |
56
+ | `printer-cups-rce.nse` | 631 | CUPS CVE-2024-47176 / CVE-2026-34980 |
57
+ | `printer-hp-pjl.nse` | 9100 | HP-specific PJL deep scan + CVE check |
58
+ | `printer-firmware-exposed.nse` | 80, 443 | Firmware update endpoint detection |
59
+ | `printer-passback.nse` | 80, 443 | LDAP/SMB passback attack surface |
60
+ | `printer-lexmark-ipp.nse` | 631, 80 | Lexmark-specific IPP + EWS CVE check |
61
+ | `printer-printnightmare.nse` | 445, 135 | Windows Print Spooler family check |
62
+
63
+ **Shared library:** `lib/printerxpl.lua` — vendor patterns, CVE DB, verdict formatting
64
+
65
+ ---
66
+
67
+ ## Usage Examples
68
+
69
+ ```bash
70
+ # Discovery across a subnet
71
+ nmap -sV --open -p 9100,631,80 --script printer-discover 192.168.1.0/24
72
+
73
+ # Full assessment on a single target
74
+ nmap -p 9100,631,80,443,427,515 --script 'printer-*' <target>
75
+
76
+ # HP-specific deep scan
77
+ nmap -p 9100 --script printer-hp-pjl <target>
78
+
79
+ # CUPS RCE check (CVE-2026-34980)
80
+ nmap -p 631 --script printer-cups-rce <target>
81
+
82
+ # CVE cross-reference only (safe, no active probes)
83
+ nmap -p 9100,631,80 --script printer-banner,printer-cve-detect <target>
84
+
85
+ # LDAP/SMB passback surface
86
+ nmap -p 80,443 --script printer-passback <target>
87
+
88
+ # Firmware endpoint exposure
89
+ nmap -p 80,443 --script printer-firmware-exposed <target>
90
+
91
+ # Windows Print Spooler (PrintNightmare family)
92
+ nmap -p 445,135 --script printer-printnightmare <target>
93
+
94
+ # SNMP printer MIB dump
95
+ nmap -sU -p 161 --script printer-snmp-info <target>
96
+
97
+ # Active vulnerability validation (intrusive)
98
+ nmap -p 9100,631,80,427,445 --script printer-vuln-check <target>
99
+ ```
100
+
101
+ ---
102
+
103
+ ## Verdict System
104
+
105
+ Each script returns one of:
106
+
107
+ | Verdict | Meaning |
108
+ |---------|---------|
109
+ | `VULNERABLE` | Active probe confirmed the vulnerability |
110
+ | `POSSIBLY VULNERABLE` | CVE match or passive indicator — confirm with printer-vuln-check |
111
+ | `NOT VULNERABLE` | No CVE match / active probe ruled out |
112
+ | `UNKNOWN` | Insufficient data — combine with other scripts |
113
+
114
+ ---
115
+
116
+ ## CVE Coverage (selected)
117
+
118
+ | CVE | CVSS | Vendor | Description |
119
+ |-----|------|--------|-------------|
120
+ | CVE-2026-34980 | 9.1 | CUPS | Unauthenticated RCE via PPD injection |
121
+ | CVE-2025-26506 | 9.8 | HP | LaserJet Enterprise PostScript RCE |
122
+ | CVE-2024-47176 | 9.9 | CUPS | cups-browsed unauthenticated RCE chain |
123
+ | CVE-2023-23560 | 9.0 | Lexmark | SSRF-to-RCE (Pwn2Own Toronto 2022) |
124
+ | CVE-2022-24673 | 9.8 | Canon | SLP pre-auth stack buffer overflow RCE |
125
+ | CVE-2022-45796 | 9.8 | Sharp | Unauthenticated OS command injection |
126
+ | CVE-2021-1675 | 9.8 | Microsoft | PrintNightmare — Windows Spooler RCE |
127
+ | CVE-2022-38028 | 7.8 | Microsoft | GooseEgg — APT28 Spooler LPE (KEV) |
128
+ | CVE-2017-2741 | 9.8 | HP | PJL path traversal to RCE |
129
+
130
+ Full CVE list: `src/data/cve_catalog.json` (80+ entries)
131
+
132
+ ---
133
+
134
+ ## Full Exploitation
135
+
136
+ When Nmap suggests a module, run the full exploit with PrinterXPL-Forge:
137
+
138
+ ```bash
139
+ pip install printerxpl-forge
140
+
141
+ # Scan all ports
142
+ printerxpl-forge scan --target <IP>
143
+
144
+ # Run specific module (dry-run first)
145
+ printerxpl-forge run --module xpl/edb-cve-2025-26506 --dry-run --target <IP>
146
+ printerxpl-forge run --module xpl/edb-cve-2025-26506 --target <IP>
147
+
148
+ # Check without exploiting
149
+ printerxpl-forge check --module xpl/edb-cve-2025-26506 --target <IP>
150
+ ```
151
+
152
+ ---
153
+
154
+ ## CLI Reference
155
+
156
+ ```
157
+ printerxpl-nse <command> [options]
158
+
159
+ Commands:
160
+ install Copy NSE scripts to Nmap scripts directory
161
+ uninstall Remove NSE scripts from Nmap
162
+ list List all bundled scripts
163
+ status Check installation status
164
+ path Show detected Nmap directories
165
+ verify Verify scripts load in Nmap
166
+
167
+ Options (install/uninstall):
168
+ --scripts-dir PATH Override Nmap scripts directory
169
+ --nselib-dir PATH Override Nmap nselib directory (for shared lib)
170
+ --no-db-update Skip nmap --script-updatedb after install
171
+ ```
172
+
173
+ ---
174
+
175
+ ## File Structure
176
+
177
+ ```
178
+ nse/
179
+ ├── __init__.py
180
+ ├── install_nse.py ← CLI installer (printerxpl-nse)
181
+ ├── README.md
182
+ ├── scripts/
183
+ │ ├── printer-banner.nse
184
+ │ ├── printer-pjl-info.nse
185
+ │ ├── printer-ipp-info.nse
186
+ │ ├── printer-http-ews.nse
187
+ │ ├── printer-snmp-info.nse
188
+ │ ├── printer-cve-detect.nse
189
+ │ ├── printer-vuln-check.nse
190
+ │ ├── printer-cups-rce.nse
191
+ │ ├── printer-hp-pjl.nse
192
+ │ ├── printer-firmware-exposed.nse
193
+ │ ├── printer-passback.nse
194
+ │ ├── printer-lexmark-ipp.nse
195
+ │ ├── printer-printnightmare.nse
196
+ │ └── printer-discover.nse
197
+ └── lib/
198
+ └── printerxpl.lua ← Shared Lua library
199
+ ```
200
+
201
+ ---
202
+
203
+ > Created by André Henrique (@mrhenrike) — União Geek
204
+ > https://github.com/Uniao-Geek
nse/__init__.py ADDED
@@ -0,0 +1,6 @@
1
+ # Author: André Henrique (@mrhenrike) | União Geek
2
+ """
3
+ PrinterXPL-Forge NSE package.
4
+ Provides: install_nse CLI and bundled Nmap scripts.
5
+ """
6
+ __version__ = "5.0.0"
nse/install_nse.py ADDED
@@ -0,0 +1,412 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ printerxpl-nse — NSE Script Installer for PrinterXPL-Forge
5
+ ===========================================================
6
+ Copies PrinterXPL-Forge Nmap NSE scripts and the shared printerxpl.lua library
7
+ into the active Nmap script directory so they become available system-wide.
8
+
9
+ Usage:
10
+ printerxpl-nse install # install scripts
11
+ printerxpl-nse uninstall # remove scripts
12
+ printerxpl-nse list # list installed scripts
13
+ printerxpl-nse status # check installation status
14
+ printerxpl-nse path # show detected nmap scripts dir
15
+ printerxpl-nse verify # verify nmap can load the scripts
16
+
17
+ Author: André Henrique (@mrhenrike) | União Geek
18
+ """
19
+
20
+ from __future__ import annotations
21
+
22
+ import argparse
23
+ import os
24
+ import platform
25
+ import shutil
26
+ import subprocess
27
+ import sys
28
+ from pathlib import Path
29
+
30
+ # ── Package layout ────────────────────────────────────────────────────────────
31
+ _THIS_DIR = Path(__file__).parent.resolve()
32
+ _SCRIPTS_DIR = _THIS_DIR / "scripts"
33
+ _LIB_DIR = _THIS_DIR / "lib"
34
+
35
+ NSE_SCRIPTS = sorted(_SCRIPTS_DIR.glob("*.nse"))
36
+ NSE_LIBS = sorted(_LIB_DIR.glob("*.lua"))
37
+ ALL_NSE = NSE_SCRIPTS + NSE_LIBS
38
+
39
+ SCRIPT_NAMES = [f.name for f in NSE_SCRIPTS]
40
+ LIB_NAMES = [f.name for f in NSE_LIBS]
41
+
42
+ BANNER = r"""
43
+ ____ _ _ __ ______ _
44
+ | _ \ _ __(_)_ __ | |_ ___ _ __ \ \/ / _ \| |
45
+ | |_) | '__| | '_ \| __/ _ \ '__| > <| |_) | |
46
+ | __/| | | | | | | || __/ | / /\ \ __/| |___
47
+ |_| |_| |_|_| |_|\__\___|_| /_/ \_\_| |_____| NSE Installer v5.0.0
48
+
49
+ André Henrique (@mrhenrike) | União Geek
50
+ https://github.com/mrhenrike/PrinterXPL-Forge
51
+ """
52
+
53
+
54
+ # ── Nmap detection ────────────────────────────────────────────────────────────
55
+
56
+ def _find_nmap() -> tuple[str | None, Path | None]:
57
+ """Return (nmap_binary_path, nmap_scripts_dir)."""
58
+ nmap_bin = shutil.which("nmap")
59
+ if not nmap_bin:
60
+ return None, None
61
+
62
+ # Ask nmap where its datadir is
63
+ try:
64
+ result = subprocess.run(
65
+ [nmap_bin, "--version"],
66
+ capture_output=True, text=True, timeout=10,
67
+ )
68
+ output = result.stdout + result.stderr
69
+ except Exception:
70
+ output = ""
71
+
72
+ # Common platform paths
73
+ candidates: list[Path] = []
74
+ system = platform.system()
75
+
76
+ if system == "Windows":
77
+ candidates += [
78
+ Path(r"C:\Program Files (x86)\Nmap\scripts"),
79
+ Path(r"C:\Program Files\Nmap\scripts"),
80
+ ]
81
+ nmap_dir = Path(nmap_bin).parent if nmap_bin else None
82
+ if nmap_dir:
83
+ candidates.insert(0, nmap_dir / "scripts")
84
+
85
+ elif system == "Darwin":
86
+ candidates += [
87
+ Path("/usr/local/share/nmap/scripts"),
88
+ Path("/opt/homebrew/share/nmap/scripts"),
89
+ Path("/usr/share/nmap/scripts"),
90
+ ]
91
+ else: # Linux
92
+ candidates += [
93
+ Path("/usr/share/nmap/scripts"),
94
+ Path("/usr/local/share/nmap/scripts"),
95
+ Path("/opt/nmap/share/nmap/scripts"),
96
+ ]
97
+
98
+ for c in candidates:
99
+ if c.is_dir():
100
+ return nmap_bin, c
101
+
102
+ return nmap_bin, None
103
+
104
+
105
+ def _find_nmap_nselib() -> Path | None:
106
+ """Find the nmap nselib directory for shared libraries."""
107
+ _, scripts_dir = _find_nmap()
108
+ if scripts_dir is None:
109
+ return None
110
+ # nselib is typically sibling of scripts
111
+ nselib = scripts_dir.parent / "nselib"
112
+ if nselib.is_dir():
113
+ return nselib
114
+ return None
115
+
116
+
117
+ # ── Install / uninstall ───────────────────────────────────────────────────────
118
+
119
+ def cmd_install(args: argparse.Namespace) -> int:
120
+ print(BANNER)
121
+ nmap_bin, scripts_dir = _find_nmap()
122
+
123
+ if not nmap_bin:
124
+ print("[ERROR] Nmap not found in PATH. Install nmap first:")
125
+ print(" https://nmap.org/download.html")
126
+ return 1
127
+
128
+ print(f"[INFO] Nmap binary : {nmap_bin}")
129
+
130
+ if scripts_dir is None:
131
+ if args.scripts_dir:
132
+ scripts_dir = Path(args.scripts_dir)
133
+ else:
134
+ print("[ERROR] Nmap scripts directory not found automatically.")
135
+ print(" Use: printerxpl-nse install --scripts-dir /path/to/nmap/scripts")
136
+ return 1
137
+
138
+ print(f"[INFO] Scripts dir : {scripts_dir}")
139
+
140
+ # NSE lib dir
141
+ nselib_dir = _find_nmap_nselib()
142
+ if nselib_dir is None and args.nselib_dir:
143
+ nselib_dir = Path(args.nselib_dir)
144
+
145
+ # Copy scripts
146
+ installed = []
147
+ errors = []
148
+
149
+ for src in NSE_SCRIPTS:
150
+ dst = scripts_dir / src.name
151
+ try:
152
+ shutil.copy2(src, dst)
153
+ print(f"[+] Installed {src.name} → {dst}")
154
+ installed.append(src.name)
155
+ except PermissionError:
156
+ print(f"[!] Permission denied: {dst}")
157
+ print(f" Retry with sudo / Administrator privileges")
158
+ errors.append(src.name)
159
+ except Exception as exc:
160
+ print(f"[!] Failed to copy {src.name}: {exc}")
161
+ errors.append(src.name)
162
+
163
+ # Copy shared library (printerxpl.lua)
164
+ for lib in NSE_LIBS:
165
+ # Try nselib first, fall back to scripts dir
166
+ lib_target_dir = nselib_dir or scripts_dir
167
+ dst = lib_target_dir / lib.name
168
+ try:
169
+ shutil.copy2(lib, dst)
170
+ print(f"[+] Installed {lib.name} → {dst}")
171
+ installed.append(lib.name)
172
+ except PermissionError:
173
+ print(f"[!] Permission denied: {dst}")
174
+ errors.append(lib.name)
175
+ except Exception as exc:
176
+ print(f"[!] Failed to copy {lib.name}: {exc}")
177
+ errors.append(lib.name)
178
+
179
+ # Update nmap script database
180
+ if installed and not args.no_db_update:
181
+ print("[INFO] Updating nmap script database (nmap --script-updatedb)…")
182
+ try:
183
+ subprocess.run([nmap_bin, "--script-updatedb"],
184
+ timeout=30, check=False)
185
+ except Exception as exc:
186
+ print(f"[WARN] --script-updatedb failed: {exc}")
187
+
188
+ print()
189
+ if errors:
190
+ print(f"[WARN] {len(errors)} file(s) failed — re-run with elevated privileges")
191
+ print(f"[OK] {len(installed)} file(s) installed successfully")
192
+ return 1
193
+ else:
194
+ print(f"[OK] {len(installed)} NSE files installed successfully")
195
+ _print_usage_hint()
196
+ return 0
197
+
198
+
199
+ def cmd_uninstall(args: argparse.Namespace) -> int:
200
+ print(BANNER)
201
+ _, scripts_dir = _find_nmap()
202
+ if scripts_dir is None and not args.scripts_dir:
203
+ print("[ERROR] Nmap scripts directory not found. Use --scripts-dir")
204
+ return 1
205
+ if args.scripts_dir:
206
+ scripts_dir = Path(args.scripts_dir)
207
+
208
+ nselib_dir = _find_nmap_nselib()
209
+
210
+ removed = 0
211
+ for name in SCRIPT_NAMES:
212
+ target = scripts_dir / name
213
+ if target.exists():
214
+ try:
215
+ target.unlink()
216
+ print(f"[-] Removed {target}")
217
+ removed += 1
218
+ except Exception as exc:
219
+ print(f"[!] Could not remove {target}: {exc}")
220
+
221
+ for name in LIB_NAMES:
222
+ for search_dir in [nselib_dir, scripts_dir]:
223
+ if search_dir is None:
224
+ continue
225
+ target = search_dir / name
226
+ if target.exists():
227
+ try:
228
+ target.unlink()
229
+ print(f"[-] Removed {target}")
230
+ removed += 1
231
+ except Exception as exc:
232
+ print(f"[!] Could not remove {target}: {exc}")
233
+
234
+ print(f"\n[OK] {removed} file(s) removed")
235
+ return 0
236
+
237
+
238
+ def cmd_list(_: argparse.Namespace) -> int:
239
+ print(BANNER)
240
+ print(f"PrinterXPL-Forge NSE Bundle ({len(NSE_SCRIPTS)} scripts + {len(NSE_LIBS)} libs)\n")
241
+ print("Scripts:")
242
+ for s in NSE_SCRIPTS:
243
+ # Extract first @usage line for description
244
+ try:
245
+ lines = s.read_text(encoding="utf-8", errors="replace").splitlines()
246
+ desc = next((l.strip().lstrip("-").strip() for l in lines if l.strip().startswith("--") and len(l) > 10), "")
247
+ except Exception:
248
+ desc = ""
249
+ print(f" {s.stem:<35} {desc[:60]}")
250
+ print()
251
+ print("Shared Libraries:")
252
+ for lib in NSE_LIBS:
253
+ print(f" {lib.name}")
254
+ return 0
255
+
256
+
257
+ def cmd_status(_: argparse.Namespace) -> int:
258
+ _, scripts_dir = _find_nmap()
259
+ nmap_bin, _ = _find_nmap()
260
+
261
+ print(f"Nmap binary : {nmap_bin or 'NOT FOUND'}")
262
+ print(f"Scripts dir : {scripts_dir or 'NOT FOUND'}")
263
+ print()
264
+
265
+ if scripts_dir is None:
266
+ print("[NOT INSTALLED] nmap scripts directory not found")
267
+ return 1
268
+
269
+ ok = 0; missing = 0
270
+ for name in SCRIPT_NAMES + LIB_NAMES:
271
+ target = scripts_dir / name
272
+ if target.exists():
273
+ print(f" [OK] {name}")
274
+ ok += 1
275
+ else:
276
+ print(f" [MISSING] {name}")
277
+ missing += 1
278
+
279
+ print()
280
+ if missing == 0:
281
+ print(f"[INSTALLED] All {ok} files present in {scripts_dir}")
282
+ _print_usage_hint()
283
+ return 0
284
+ elif ok == 0:
285
+ print("[NOT INSTALLED] No files installed yet — run: printerxpl-nse install")
286
+ return 1
287
+ else:
288
+ print(f"[PARTIAL] {ok} installed, {missing} missing — re-run install")
289
+ return 1
290
+
291
+
292
+ def cmd_path(_: argparse.Namespace) -> int:
293
+ nmap_bin, scripts_dir = _find_nmap()
294
+ print(f"Nmap binary : {nmap_bin or 'not found'}")
295
+ print(f"Scripts dir : {scripts_dir or 'not found'}")
296
+ nselib = _find_nmap_nselib()
297
+ print(f"NSElib dir : {nselib or 'not found'}")
298
+ return 0
299
+
300
+
301
+ def cmd_verify(_: argparse.Namespace) -> int:
302
+ nmap_bin, scripts_dir = _find_nmap()
303
+ if not nmap_bin:
304
+ print("[ERROR] Nmap not found"); return 1
305
+ if scripts_dir is None:
306
+ print("[ERROR] Scripts dir not found"); return 1
307
+
308
+ print("Verifying NSE scripts with nmap --script-help…\n")
309
+ errors = 0
310
+ for name in SCRIPT_NAMES:
311
+ target = scripts_dir / name
312
+ if not target.exists():
313
+ print(f" [MISSING] {name}")
314
+ errors += 1
315
+ continue
316
+ try:
317
+ result = subprocess.run(
318
+ [nmap_bin, "--script-help", name.replace(".nse", "")],
319
+ capture_output=True, text=True, timeout=10,
320
+ )
321
+ if result.returncode == 0:
322
+ print(f" [OK] {name}")
323
+ else:
324
+ print(f" [FAIL] {name} — {result.stderr.strip()[:80]}")
325
+ errors += 1
326
+ except Exception as exc:
327
+ print(f" [ERROR] {name} — {exc}")
328
+ errors += 1
329
+
330
+ print()
331
+ if errors:
332
+ print(f"[WARN] {errors} script(s) failed verification")
333
+ return 1
334
+ print(f"[OK] All {len(SCRIPT_NAMES)} scripts verified")
335
+ return 0
336
+
337
+
338
+ def _print_usage_hint() -> None:
339
+ print()
340
+ print("=" * 68)
341
+ print(" PrinterXPL-Forge NSE scripts are now available in Nmap!")
342
+ print()
343
+ print(" Quick discovery:")
344
+ print(" nmap -p 9100,631,80 --script printer-discover <target>")
345
+ print()
346
+ print(" Full scan (all scripts):")
347
+ print(" nmap -p 9100,631,80,443,427,515 \\")
348
+ print(" --script 'printer-*' <target>")
349
+ print()
350
+ print(" Targeted checks:")
351
+ print(" nmap -p 9100 --script printer-hp-pjl <target>")
352
+ print(" nmap -p 631 --script printer-cups-rce <target>")
353
+ print(" nmap -p 9100,631,80 --script printer-cve-detect <target>")
354
+ print(" nmap -p 80,443 --script printer-passback <target>")
355
+ print(" nmap -p 445 --script printer-printnightmare <target>")
356
+ print()
357
+ print(" Full exploitation:")
358
+ print(" pip install printerxpl-forge")
359
+ print(" printerxpl-forge scan --target <IP>")
360
+ print("=" * 68)
361
+
362
+
363
+ # ── Entry point ───────────────────────────────────────────────────────────────
364
+
365
+ def main(argv: list[str] | None = None) -> int:
366
+ parser = argparse.ArgumentParser(
367
+ prog="printerxpl-nse",
368
+ description="PrinterXPL-Forge — Nmap NSE script installer",
369
+ formatter_class=argparse.RawDescriptionHelpFormatter,
370
+ )
371
+ sub = parser.add_subparsers(dest="cmd", metavar="COMMAND")
372
+
373
+ # install
374
+ p_install = sub.add_parser("install", help="Install NSE scripts to Nmap")
375
+ p_install.add_argument("--scripts-dir", metavar="PATH",
376
+ help="Override Nmap scripts directory")
377
+ p_install.add_argument("--nselib-dir", metavar="PATH",
378
+ help="Override Nmap nselib directory (for printerxpl.lua)")
379
+ p_install.add_argument("--no-db-update", action="store_true",
380
+ help="Skip nmap --script-updatedb after install")
381
+
382
+ # uninstall
383
+ p_uninstall = sub.add_parser("uninstall", help="Remove NSE scripts from Nmap")
384
+ p_uninstall.add_argument("--scripts-dir", metavar="PATH",
385
+ help="Override Nmap scripts directory")
386
+
387
+ # list / status / path / verify
388
+ sub.add_parser("list", help="List all NSE scripts in this bundle")
389
+ sub.add_parser("status", help="Check installation status")
390
+ sub.add_parser("path", help="Show detected Nmap directories")
391
+ sub.add_parser("verify", help="Verify scripts load correctly in Nmap")
392
+
393
+ args = parser.parse_args(argv)
394
+
395
+ dispatch = {
396
+ "install": cmd_install,
397
+ "uninstall": cmd_uninstall,
398
+ "list": cmd_list,
399
+ "status": cmd_status,
400
+ "path": cmd_path,
401
+ "verify": cmd_verify,
402
+ }
403
+
404
+ if args.cmd in dispatch:
405
+ return dispatch[args.cmd](args)
406
+
407
+ parser.print_help()
408
+ return 0
409
+
410
+
411
+ if __name__ == "__main__":
412
+ sys.exit(main())