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
src/modules/pcl.py ADDED
@@ -0,0 +1,506 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ PCL Module for PrinterXPL-Forge
5
+ ===================================
6
+ Complete PCL (Printer Command Language) penetration testing module
7
+
8
+ Based on PRET pcl.py but enhanced for PrinterXPL-Forge
9
+ """
10
+
11
+ # Author : Andre Henrique (@mrhenrike)
12
+ # GitHub : https://github.com/mrhenrike
13
+ # LinkedIn : https://linkedin.com/in/mrhenrike
14
+ # X/Twitter : https://x.com/mrhenrike
15
+
16
+ import re
17
+ import os
18
+ import random
19
+ import time
20
+
21
+ from core.printer import printer
22
+ from utils.helper import log, output, conv, file, item, const as c
23
+
24
+
25
+ class pcl(printer):
26
+ """
27
+ PCL shell for PrinterXPL-Forge - Complete Implementation
28
+ """
29
+
30
+ def __init__(self, args):
31
+ super().__init__(args)
32
+ self.prompt = f"{self.target}:pcl> "
33
+ self.macros = {} # Track macros for virtual filesystem
34
+
35
+ # --------------------------------------------------------------------
36
+ # Help overview (category-based, PJL-style)
37
+ # --------------------------------------------------------------------
38
+ def do_help(self, arg):
39
+ """Show help for commands (PCL)"""
40
+ topic = (arg or "").strip()
41
+ if topic:
42
+ # Delegate to base generic help for specific topics
43
+ return super().do_help(topic)
44
+
45
+ categories = {
46
+ "information": [
47
+ "id", "info", "selftest"
48
+ ],
49
+ "virtualfs": [
50
+ "ls", "put", "get", "delete"
51
+ ],
52
+ "control": [
53
+ "reset", "formfeed", "copies"
54
+ ],
55
+ "attacks": [
56
+ "flood", "execute"
57
+ ],
58
+ }
59
+
60
+ implemented = {name for name in dir(self) if name.startswith("do_")}
61
+ def exists(cmd):
62
+ return f"do_{cmd}" in implemented
63
+
64
+ print()
65
+ print("PrinterXPL-Forge - PCL Commands")
66
+ print("=" * 70)
67
+ print("Available command categories:")
68
+ total = 0
69
+ for cat, cmds in categories.items():
70
+ avail = [c for c in cmds if exists(c)]
71
+ total += len(avail)
72
+ label = cat.ljust(13)
73
+ print(f" {label}- {len(avail)} commands")
74
+ print()
75
+ print(f"Total: {total} PCL commands available")
76
+ print("Use 'help <command>' for specific details")
77
+ print()
78
+ for cat, cmds in categories.items():
79
+ avail = [c for c in cmds if exists(c)]
80
+ if not avail:
81
+ continue
82
+ print(cat.capitalize() + ":")
83
+ print("-" * 70)
84
+ colw = max(len(x) for x in avail) + 2
85
+ cols = max(1, 70 // colw)
86
+ for i in range(0, len(avail), cols):
87
+ row = avail[i:i+cols]
88
+ print("".join(x.ljust(colw) for x in row))
89
+ print()
90
+
91
+ # --------------------------------------------------------------------
92
+ # Low-level PCL send/receive
93
+
94
+ def cmd(self, str_send, wait=True, crop=True, binary=False):
95
+ """
96
+ Send a PCL command and optionally wait for its reply.
97
+ """
98
+ token = "PCLECHO -" + str(random.randrange(2**16))
99
+ footer = c.ESC + f"*s-{random.randrange(2**16)}X" if wait else ""
100
+ payload = c.UEL + c.PCL_HEADER + str_send + footer + c.UEL
101
+
102
+ # log the command
103
+ log().write(self.logfile, str_send + os.linesep)
104
+ # send
105
+ self.send(payload)
106
+
107
+ if not wait:
108
+ return ""
109
+
110
+ # receive until token with timeout
111
+ try:
112
+ if hasattr(self.conn, '_sock') and self.conn._sock:
113
+ self.conn._sock.settimeout(30.0)
114
+
115
+ raw = self.recv(re.escape(token) + r".*$", wait, True, binary)
116
+ except Exception as e:
117
+ output().errmsg(f"Failed to receive response: {str(e)}")
118
+ return ""
119
+
120
+ return raw
121
+
122
+ def on_connect(self, mode):
123
+ """
124
+ Initialize PCL environment on first connect.
125
+ """
126
+ if mode == "init":
127
+ # Enter PCL mode
128
+ self.cmd(c.ESC + "E", False) # PCL reset
129
+
130
+ # --------------------------------------------------------------------
131
+ # 📋 SYSTEM INFORMATION COMMANDS
132
+ # --------------------------------------------------------------------
133
+
134
+ def do_id(self, *args):
135
+ "Show printer identification (PCL-specific)"
136
+ print("PCL Printer Identification:")
137
+ print("=" * 60)
138
+
139
+ # Get printer information via PCL
140
+ result = self.cmd(c.ESC + "*s1M" + c.ESC + "*s0M") # Enter/exit config
141
+ if result:
142
+ print(f"Response: {result}")
143
+
144
+ def help_id(self):
145
+ """Show help for id command"""
146
+ print()
147
+ print("id - Show PCL printer identification")
148
+ print("=" * 60)
149
+ print("DESCRIPTION:")
150
+ print(" Displays printer identification using PCL commands.")
151
+ print()
152
+ print("USAGE:")
153
+ print(" id")
154
+ print()
155
+
156
+ def do_selftest(self, *arg):
157
+ "Perform printer self-test"
158
+ output().message("Initiating PCL self-test...")
159
+ self.cmd(c.ESC + "z") # Self-test
160
+ output().message("Self-test initiated")
161
+
162
+ def help_selftest(self):
163
+ """Show help for selftest command"""
164
+ print()
165
+ print("selftest - Perform PCL self-test")
166
+ print("=" * 60)
167
+ print("DESCRIPTION:")
168
+ print(" Triggers the printer's built-in self-test routine.")
169
+ print()
170
+ print("USAGE:")
171
+ print(" selftest")
172
+ print()
173
+
174
+ # --------------------------------------------------------------------
175
+ # 📁 VIRTUAL FILESYSTEM (PCL Macros)
176
+ # --------------------------------------------------------------------
177
+
178
+ def do_ls(self, arg):
179
+ "List PCL macros (virtual filesystem)"
180
+ if not self.macros:
181
+ output().info("No macros stored (virtual filesystem empty)")
182
+ return
183
+
184
+ print("PCL Macros (Virtual Files):")
185
+ print("=" * 60)
186
+ for macro_id, info in sorted(self.macros.items()):
187
+ name = info.get('name', 'unnamed')
188
+ size = info.get('size', 0)
189
+ print(f"Macro {macro_id:5d} {size:8d} bytes {name}")
190
+
191
+ def help_ls(self):
192
+ """Show help for ls command"""
193
+ print()
194
+ print("ls - List PCL macros (virtual filesystem)")
195
+ print("=" * 60)
196
+ print("DESCRIPTION:")
197
+ print(" PCL doesn't have a real filesystem, but macros can be used")
198
+ print(" to store data virtually. This lists all stored macros.")
199
+ print()
200
+ print("USAGE:")
201
+ print(" ls")
202
+ print()
203
+ print("NOTES:")
204
+ print(" - Each macro is like a virtual file")
205
+ print(" - Macros persist until printer reset")
206
+ print()
207
+
208
+ def do_put(self, arg):
209
+ "Upload file as PCL macro"
210
+ if not arg:
211
+ output().errmsg("Usage: put <local_file>")
212
+ return
213
+
214
+ if not os.path.exists(arg):
215
+ output().errmsg(f"File not found: {arg}")
216
+ return
217
+
218
+ data = file().read(arg)
219
+ if not data:
220
+ return
221
+
222
+ # Assign macro ID
223
+ macro_id = len(self.macros) + 1000
224
+
225
+ # Create macro with file data
226
+ macro_cmd = c.ESC + f"&f{macro_id}y{len(data)}X" + data.decode('latin-1', errors='ignore')
227
+ self.cmd(macro_cmd, False)
228
+
229
+ # Track macro
230
+ self.macros[macro_id] = {
231
+ 'name': os.path.basename(arg),
232
+ 'size': len(data)
233
+ }
234
+
235
+ output().message(f"Uploaded {arg} as macro {macro_id}")
236
+
237
+ def help_put(self):
238
+ """Show help for put command"""
239
+ print()
240
+ print("put - Upload file as PCL macro")
241
+ print("=" * 60)
242
+ print("DESCRIPTION:")
243
+ print(" Stores a local file as a PCL macro on the printer.")
244
+ print(" PCL macros serve as a virtual filesystem.")
245
+ print()
246
+ print("USAGE:")
247
+ print(" put <local_file>")
248
+ print()
249
+ print("EXAMPLES:")
250
+ print(" put document.txt # Store as macro")
251
+ print(" put data.bin # Store binary data")
252
+ print()
253
+
254
+ def do_get(self, arg):
255
+ "Download PCL macro"
256
+ if not arg:
257
+ output().errmsg("Usage: get <macro_id>")
258
+ return
259
+
260
+ try:
261
+ macro_id = int(arg)
262
+ except ValueError:
263
+ output().errmsg("Macro ID must be numeric")
264
+ return
265
+
266
+ # Request macro execution/output
267
+ result = self.cmd(c.ESC + f"&f{macro_id}X")
268
+ if result:
269
+ info = self.macros.get(macro_id, {})
270
+ name = info.get('name', f"macro_{macro_id}.dat")
271
+ file().write(name, result.encode())
272
+ output().message(f"Downloaded macro {macro_id} to {name}")
273
+
274
+ def help_get(self):
275
+ """Show help for get command"""
276
+ print()
277
+ print("get - Download PCL macro")
278
+ print("=" * 60)
279
+ print("DESCRIPTION:")
280
+ print(" Retrieves a PCL macro from the printer.")
281
+ print()
282
+ print("USAGE:")
283
+ print(" get <macro_id>")
284
+ print()
285
+ print("EXAMPLES:")
286
+ print(" get 1000 # Download macro 1000")
287
+ print()
288
+
289
+ def do_delete(self, arg):
290
+ "Delete PCL macro"
291
+ if not arg:
292
+ output().errmsg("Usage: delete <macro_id>")
293
+ return
294
+
295
+ try:
296
+ macro_id = int(arg)
297
+ except ValueError:
298
+ output().errmsg("Macro ID must be numeric")
299
+ return
300
+
301
+ # Delete macro
302
+ self.cmd(c.ESC + f"&f{macro_id}d1X")
303
+ if macro_id in self.macros:
304
+ del self.macros[macro_id]
305
+ output().message(f"Deleted macro {macro_id}")
306
+
307
+ # --------------------------------------------------------------------
308
+ # 📊 PCL INFORMATION COMMANDS
309
+ # --------------------------------------------------------------------
310
+
311
+ # PCL location types for info queries (fix: issue #89 — hard disk fonts missed)
312
+ _PCL_LOCATIONS = {
313
+ '1': '(Selected)',
314
+ '2': '(All Locations)',
315
+ '3': '(Internal)',
316
+ '4': '(Downloaded)',
317
+ '5': '(Cartridge)',
318
+ '6': '(Hard Disk)',
319
+ '7': '(ROM/SIMMs)',
320
+ }
321
+
322
+ # PCL entity codes: (location_type_code, inquiry_entity_code, description)
323
+ _PCL_ENTITIES = {
324
+ 'fonts': ('0', 'Fonts'),
325
+ 'macros': ('1', 'Macros'),
326
+ 'patterns': ('2', 'User-defined Patterns'),
327
+ 'symbols': ('3', 'Symbol Sets'),
328
+ 'extended': ('4', 'Fonts Extended'),
329
+ }
330
+
331
+ def do_info(self, arg):
332
+ "Get PCL information: info <fonts|macros|patterns|symbols|extended>"
333
+ if not arg:
334
+ print("Available info categories:")
335
+ print(" fonts - Show installed fonts (all locations incl. hard disk)")
336
+ print(" macros - Show installed macros")
337
+ print(" patterns - Show user-defined patterns")
338
+ print(" symbols - Show symbol sets")
339
+ print(" extended - Show extended fonts")
340
+ return
341
+
342
+ if arg == "macros":
343
+ self.do_ls("")
344
+ return
345
+
346
+ entity_info = self._PCL_ENTITIES.get(arg)
347
+ if not entity_info:
348
+ output().errmsg(f"Unknown category: {arg}. Use: fonts, macros, patterns, symbols, extended")
349
+ return
350
+
351
+ entity_code, entity_desc = entity_info
352
+
353
+ # Iterate all location types to catch fonts on hard disk (issue #89)
354
+ found_any = False
355
+ for loc_code, loc_label in sorted(self._PCL_LOCATIONS.items()):
356
+ str_send = "*s" + loc_code + "T" # set location type
357
+ str_send += c.ESC + "*s0U" # set location unit (all units)
358
+ str_send += c.ESC + "*s" + entity_code + "I" # set inquire entity
359
+ result = self.cmd(str_send)
360
+ if result and result.strip():
361
+ print(f"{entity_desc} {loc_label}:")
362
+ print(result.strip())
363
+ print()
364
+ found_any = True
365
+
366
+ if not found_any:
367
+ output().info(f"No {entity_desc.lower()} found across all locations.")
368
+
369
+ def help_info(self):
370
+ """Show help for info command"""
371
+ print()
372
+ print("info - Get PCL information")
373
+ print("=" * 60)
374
+ print("DESCRIPTION:")
375
+ print(" Retrieves various types of information from PCL printer.")
376
+ print()
377
+ print("USAGE:")
378
+ print(" info <category>")
379
+ print()
380
+ print("CATEGORIES:")
381
+ print(" fonts - Installed fonts")
382
+ print(" macros - Stored macros")
383
+ print(" patterns - User patterns")
384
+ print(" symbols - Symbol sets")
385
+ print()
386
+
387
+ # --------------------------------------------------------------------
388
+ # ⚙️ PCL CONTROL COMMANDS
389
+ # --------------------------------------------------------------------
390
+
391
+ def do_reset(self, *arg):
392
+ "Reset printer to default state"
393
+ output().warning("Resetting printer...")
394
+ self.cmd(c.ESC + "E") # PCL reset
395
+ self.macros = {} # Clear macro tracking
396
+ output().message("Printer reset")
397
+
398
+ def help_reset(self):
399
+ """Show help for reset command"""
400
+ print()
401
+ print("reset - Reset printer to default state")
402
+ print("=" * 60)
403
+ print("DESCRIPTION:")
404
+ print(" Sends PCL reset command, clearing all macros and settings.")
405
+ print()
406
+ print("USAGE:")
407
+ print(" reset")
408
+ print()
409
+
410
+ def do_formfeed(self, *arg):
411
+ "Eject current page"
412
+ self.cmd(c.ESC + "&l0H") # Formfeed
413
+ output().message("Page ejected")
414
+
415
+ def do_copies(self, arg):
416
+ "Set number of copies"
417
+ if not arg:
418
+ output().errmsg("Usage: copies <number>")
419
+ return
420
+
421
+ try:
422
+ num = int(arg)
423
+ self.cmd(c.ESC + f"&l{num}X")
424
+ output().message(f"Copies set to {num}")
425
+ except ValueError:
426
+ output().errmsg("Number of copies must be numeric")
427
+
428
+ def help_copies(self):
429
+ """Show help for copies command"""
430
+ print()
431
+ print("copies - Set number of copies")
432
+ print("=" * 60)
433
+ print("DESCRIPTION:")
434
+ print(" Sets the number of copies to print.")
435
+ print()
436
+ print("USAGE:")
437
+ print(" copies <number>")
438
+ print()
439
+ print("EXAMPLES:")
440
+ print(" copies 5 # Print 5 copies")
441
+ print()
442
+
443
+ # --------------------------------------------------------------------
444
+ # 💥 PCL ATTACK COMMANDS
445
+ # --------------------------------------------------------------------
446
+
447
+ def do_flood(self, arg):
448
+ "Flood printer with PCL commands"
449
+ size = conv().int(arg) or 10000
450
+ output().warning(f"Flooding with {size} PCL commands...")
451
+
452
+ flood_cmd = (c.ESC + "E") * size
453
+ self.cmd(flood_cmd, False)
454
+ output().message("Flood sent")
455
+
456
+ def help_flood(self):
457
+ """Show help for flood command"""
458
+ print()
459
+ print("flood - Flood printer with PCL commands")
460
+ print("=" * 60)
461
+ print("DESCRIPTION:")
462
+ print(" Sends a large number of PCL reset commands to test")
463
+ print(" for buffer overflow vulnerabilities.")
464
+ print()
465
+ print("USAGE:")
466
+ print(" flood [size]")
467
+ print()
468
+ print("EXAMPLES:")
469
+ print(" flood # Flood with 10000 commands")
470
+ print(" flood 50000 # Larger flood test")
471
+ print()
472
+
473
+ def do_execute(self, arg):
474
+ "Execute arbitrary PCL command"
475
+ if not arg:
476
+ output().errmsg("Usage: execute <pcl_sequence>")
477
+ return
478
+
479
+ # Interpret escape sequences
480
+ pcl_cmd = arg.replace("\\e", c.ESC).replace("<Esc>", c.ESC)
481
+ result = self.cmd(pcl_cmd)
482
+ if result:
483
+ print("Output:")
484
+ print(result)
485
+
486
+ def help_execute(self):
487
+ """Show help for execute command"""
488
+ print()
489
+ print("execute - Execute arbitrary PCL command")
490
+ print("=" * 60)
491
+ print("DESCRIPTION:")
492
+ print(" Sends raw PCL escape sequences to the printer.")
493
+ print()
494
+ print("USAGE:")
495
+ print(" execute <pcl_sequence>")
496
+ print()
497
+ print("EXAMPLES:")
498
+ print(" execute \\eE # Reset (use \\e for ESC)")
499
+ print(" execute \\e&l1H # Eject page")
500
+ print()
501
+ print("NOTES:")
502
+ print(" - Use \\e to represent ESC character")
503
+ print(" - Requires PCL knowledge")
504
+ print(" - May crash printer if invalid")
505
+ print()
506
+