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
@@ -0,0 +1,323 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+
4
+
5
+ # Author : Andre Henrique (@mrhenrike)
6
+ # GitHub : https://github.com/mrhenrike
7
+ # LinkedIn : https://linkedin.com/in/mrhenrike
8
+ # X/Twitter : https://x.com/mrhenrike
9
+
10
+ # python standard library
11
+ import re
12
+ import os
13
+ import sys # , urllib.error, urllib.parse
14
+
15
+ import requests
16
+ import urllib3
17
+
18
+ # local pret classes
19
+ from utils.helper import output, item
20
+
21
+ # ── SNMP backend selection ───────────────────────────────────────────────────
22
+ # Priority: pysnmp-lextudio v5+ hlapi (sync) → pysnmp v4 oneliner (legacy)
23
+ # pysnmp v7 (community fork) ships an asyncio-only API; we detect and use
24
+ # the synchronous shim when available.
25
+ _SNMP_BACKEND = None
26
+
27
+ import warnings as _pysnmp_warn
28
+ _pysnmp_warn.filterwarnings("ignore", category=RuntimeWarning)
29
+
30
+ try:
31
+ # pysnmp-lextudio ≥5 (hlapi synchronous, Python 3.8+) — primary backend
32
+ from pysnmp.hlapi import ( # type: ignore
33
+ getCmd, nextCmd, CommunityData, UdpTransportTarget,
34
+ ContextData, ObjectType, ObjectIdentity, SnmpEngine,
35
+ )
36
+ _SNMP_BACKEND = 'hlapi-v5'
37
+ except ImportError:
38
+ pass
39
+
40
+ if _SNMP_BACKEND is None:
41
+ try:
42
+ # pysnmp ≥7 community version exposes hlapi.asyncio; provide a sync shim
43
+ from pysnmp.hlapi.asyncio import ( # type: ignore
44
+ getCmd as _asyncGetCmd, CommunityData, UdpTransportTarget,
45
+ ContextData, ObjectType, ObjectIdentity, SnmpEngine,
46
+ )
47
+ import asyncio as _asyncio
48
+
49
+ def getCmd(*args, **kwargs): # type: ignore[override]
50
+ """Synchronous shim wrapping the asyncio getCmd."""
51
+ return _asyncio.get_event_loop().run_until_complete(
52
+ _asyncGetCmd(*args, **kwargs)
53
+ )
54
+
55
+ _SNMP_BACKEND = 'hlapi-v7'
56
+ except ImportError:
57
+ pass
58
+
59
+ if _SNMP_BACKEND is None:
60
+ try:
61
+ # pysnmp ≤4.x oneliner (legacy, deprecated in 3.12+)
62
+ from pysnmp.entity.rfc3413.oneliner import cmdgen # type: ignore
63
+ _SNMP_BACKEND = 'oneliner'
64
+ except ImportError:
65
+ pass
66
+
67
+
68
+ class capabilities():
69
+ urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
70
+ # set defaults
71
+ support = False
72
+ # default timeout - can be overridden in __init__
73
+ timeout = 1.5
74
+ # set pret.py directory
75
+ rundir = os.path.dirname(os.path.realpath(__file__)) + os.path.sep
76
+ '''
77
+ ┌──────────────────────────────────────────────────────────┐
78
+ │ how to get printer's capabilities? │
79
+ ├──────┬───────────────────────┬───────────────────────────┤
80
+ │ │ model (for db lookup) │ lang (ps/pjl/pcl support) │
81
+ ├──────┼───────────────────────┼───────────────────────────┤
82
+ │ IPP │ printer-description │ printer-description │
83
+ │ SNMP │ hrDeviceDescr │ prtInterpreterDescription │
84
+ │ HTTP │ html-title │ - │
85
+ | HTTPS| html-title | - |
86
+ └──────┴───────────────────────┴───────────────────────────┘
87
+ '''
88
+
89
+ def __init__(self, args, timeout=None):
90
+ # allow custom timeout to be passed
91
+ if timeout is not None:
92
+ self.timeout = timeout
93
+ # skip this in unsafe mode
94
+ if not args.safe:
95
+ return
96
+ # set printer language
97
+ if args.mode == 'ps':
98
+ lang = ["PS", "PostScript", "BR-Script", "KPDL"]
99
+ if args.mode == 'pjl':
100
+ lang = ["PJL"]
101
+ if args.mode == 'pcl':
102
+ lang = ["PCL"]
103
+ # get list of PostScript/PJL/PCL capable printers
104
+ self.models = self.get_models(args.mode + ".dat")
105
+ # try to get printer capabilities via IPP/SNMP/HTTP
106
+ if not self.support:
107
+ self.ipp(args.target, lang)
108
+ if not self.support:
109
+ self.http(args.target)
110
+ if not self.support:
111
+ self.https(args.target)
112
+ if not self.support:
113
+ self.snmp(args.target, lang)
114
+ # feedback on PostScript/PJL/PCL support
115
+ self.feedback(self.support, lang[0])
116
+ # in safe mode, exit if unsupported
117
+ if args.safe and not self.support:
118
+ print((os.linesep + "Quitting as we are in safe mode."))
119
+ sys.exit()
120
+ print("")
121
+
122
+ # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
123
+ # get capabilities via IPP (HTTP or HTTPS fallback)
124
+ def ipp(self, host, lang):
125
+ try:
126
+ sys.stdout.write("Checking for IPP support: ")
127
+ # IPP 1.1 GET-PRINTER-ATTRIBUTES request (binary)
128
+ body = (
129
+ b'\x01\x01\x00\x0b\x00\x01\xab\x10'
130
+ b'\x01G\x00\x12attributes-charset\x00\x05utf-8'
131
+ b'H\x00\x1battributes-natural-language\x00\x02en'
132
+ b'E\x00\x0bprinter-uri\x00\x14ipp://localhost/ipp/'
133
+ b'D\x00\x14requested-attributes\x00\x13printer-description\x03'
134
+ )
135
+ headers = {'Content-type': 'application/ipp'}
136
+ response_bytes = None
137
+
138
+ # IPP endpoints to probe (in priority order)
139
+ ipp_candidates = [
140
+ ('http', host, 631, '/'),
141
+ ('http', host, 631, '/ipp/'),
142
+ ('http', host, 631, '/ipp/print'),
143
+ ('https', host, 631, '/ipp/print'),
144
+ ('https', host, 631, '/ipp/'),
145
+ ('https', host, 631, '/'),
146
+ ]
147
+ for scheme, h, port, path in ipp_candidates:
148
+ try:
149
+ url = f"{scheme}://{h}:{port}{path}"
150
+ r = requests.post(url, data=body, headers=headers,
151
+ timeout=self.timeout * 2,
152
+ verify=False)
153
+ # 200 = success; 426 means TLS required → continue loop
154
+ if r.status_code == 200 and len(r.content) > 8:
155
+ response_bytes = r.content
156
+ break
157
+ except Exception:
158
+ continue
159
+
160
+ if response_bytes is None:
161
+ raise Exception("no IPP endpoint responded")
162
+
163
+ # Decode as latin-1 so binary bytes are preserved 1:1
164
+ response = response_bytes.decode('latin-1')
165
+
166
+ # Extract printer-device-id field (contains MDL: and CMD:)
167
+ # It appears as a length-prefixed string in IPP binary
168
+ model = item(re.findall(r"MDL:(.+?);", response))
169
+ langs = item(re.findall(r"CMD:(.+?);", response))
170
+
171
+ # Also scan document-format-supported for ESC/P, PWGRaster etc.
172
+ doc_fmts = re.findall(r"(application/vnd\.epson\.[^;\x00]+|"
173
+ r"application/postscript|"
174
+ r"application/pcl|"
175
+ r"image/pwg-raster)", response, re.I)
176
+ if doc_fmts:
177
+ self.doc_formats = doc_fmts
178
+ output().chitchat(f" IPP document formats: {', '.join(doc_fmts)}")
179
+
180
+ # Try to set language support from CMD: field
181
+ self.support = [x for x in [re.findall(
182
+ re.escape(pdl), langs, re.I) for pdl in lang] if x]
183
+ self.set_support(model)
184
+ output().green("found")
185
+ except Exception as e:
186
+ output().errmsg("not found", e)
187
+
188
+ # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
189
+ # get capabilities via HTTP
190
+ def http(self, host):
191
+ try:
192
+ sys.stdout.write("Checking for HTTP support: ")
193
+ # allow_redirects=False so an HTTP→HTTPS redirect doesn't cause SSL errors
194
+ html = requests.get(
195
+ "http://" + host, verify=False,
196
+ allow_redirects=False, timeout=self.timeout,
197
+ ).text
198
+ title = re.findall("<title.*?>\n?(.+?)\n?</title>",
199
+ html, re.I | re.M | re.S)
200
+ model = item(title)
201
+ self.set_support(model)
202
+ output().green("found")
203
+ except Exception as e:
204
+ output().errmsg("not found", e)
205
+
206
+ # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
207
+ # get capabilities via HTTPS
208
+ def https(self, host):
209
+ try:
210
+ # poor man's way get https title
211
+ sys.stdout.write("Checking for HTTPS support: ")
212
+ html = requests.get("https://" + host, verify=False).text
213
+ # cause we are to parsimonious to import BeautifulSoup ;)
214
+ title = re.findall("<title.*?>\n?(.+?)\n?</title>",
215
+ html, re.I | re.M | re.S)
216
+ # get name of device
217
+ model = item(title)
218
+ # get language support
219
+ self.set_support(model)
220
+ output().green("found")
221
+ except Exception as e:
222
+ output().errmsg("not found", e)
223
+
224
+ # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
225
+ # get capabilities via SNMP
226
+ def snmp(self, host, lang):
227
+ try:
228
+ sys.stdout.write("Checking for SNMP support: ")
229
+ if _SNMP_BACKEND is None:
230
+ raise NameError("pysnmp not installed")
231
+
232
+ # HOST-RESOURCES-MIB → hrDeviceDescr
233
+ desc_oid = '1.3.6.1.2.1.25.3.2.1.3'
234
+ # Printer-MIB → prtInterpreterDescription
235
+ pdls_oid = '1.3.6.1.2.1.43.15.1.1.5.1'
236
+ desc, pdls = [], []
237
+
238
+ if _SNMP_BACKEND in ('hlapi-v5', 'hlapi-v7'):
239
+ # pysnmp-lextudio v5 synchronous hlapi (also v7 via shim)
240
+ engine = SnmpEngine()
241
+ community = CommunityData('public', mpModel=0)
242
+ transport = UdpTransportTarget(
243
+ (host, 161), timeout=self.timeout, retries=0)
244
+ context = ContextData()
245
+
246
+ for oid_str, bucket in [(desc_oid, desc), (pdls_oid, pdls)]:
247
+ for err_ind, err_stat, _, var_binds in nextCmd(
248
+ engine, community, transport, context,
249
+ ObjectType(ObjectIdentity(oid_str)),
250
+ lexicographicMode=False,
251
+ ):
252
+ if err_ind:
253
+ break
254
+ if err_stat:
255
+ break
256
+ for var_bind in var_binds:
257
+ bucket.append(str(var_bind[1]))
258
+
259
+ elif _SNMP_BACKEND == 'oneliner':
260
+ # Legacy oneliner API (pysnmp ≤ 4.x, Python 3.8–3.11)
261
+ error, error_status, _idx, binds = cmdgen.CommandGenerator().nextCmd( # type: ignore
262
+ cmdgen.CommunityData('public', mpModel=0),
263
+ cmdgen.UdpTransportTarget((host, 161), timeout=self.timeout, retries=0),
264
+ desc_oid, pdls_oid,
265
+ )
266
+ if error:
267
+ raise Exception(error)
268
+ if error_status:
269
+ raise Exception(error_status.prettyPrint())
270
+ for row in binds:
271
+ for key, val in row:
272
+ if desc_oid in str(key):
273
+ desc.append(str(val))
274
+ if pdls_oid in str(key):
275
+ pdls.append(str(val))
276
+
277
+ # get name of device
278
+ model = item(desc)
279
+ # get language support
280
+ langs = ','.join(pdls)
281
+ self.support = [x for x in [re.findall(
282
+ re.escape(pdl), langs, re.I) for pdl in lang] if x]
283
+ output().green("found")
284
+ except NameError:
285
+ output().errmsg("not found", "pysnmp module not installed")
286
+ except Exception as e:
287
+ output().errmsg("not found", e)
288
+ # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
289
+ # feedback on language support
290
+
291
+ def feedback(self, support, lang):
292
+ sys.stdout.write("Checking for %-21s" % (lang + " support: "))
293
+ if support:
294
+ output().green("found")
295
+ else:
296
+ output().warning("not found")
297
+
298
+ # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
299
+ # set language support
300
+ def set_support(self, model):
301
+ # model_stripped = re.sub(r'(\d|\s|-)[a-zA-Z]+$', '', model)
302
+ '''
303
+ ┌───────────────────────────────────────────────────────┐
304
+ │ Experimental -- This might introduce false positives! │
305
+ ├───────────────────────────────────────────────────────┤
306
+ │ The stripped down version of the model string removes │
307
+ │ endings like '-series', ' printer' (maybe localized), │
308
+ │ 'd' (duplex), 't' (tray), 'c' (color), 'n' (network). │
309
+ └───────────────────────────────────────────────────────┘
310
+ '''
311
+ self.support = [x for x in [re.findall(
312
+ re.escape(m), model, re.I) for m in self.models] if x]
313
+
314
+ # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
315
+ # open database of supported devices
316
+ def get_models(self, file):
317
+ try:
318
+ with open(self.rundir + "db" + os.path.sep + file, 'r') as f:
319
+ models = [line.strip() for line in f if line.strip()]
320
+ return models
321
+ except IOError as e:
322
+ output().errmsg("Cannot open file", e)
323
+ return []