// HackTricks · Network Services

Internet Printing Protocol

Internet Printing Protocol

The Internet Printing Protocol (IPP) is the standard application protocol for network printing. The current IPP/1.1 specifications are RFC 8010 (encoding/transport) and RFC 8011 (model/semantics), which obsolete RFCs 2910 and 2911. IPP is carried over HTTP and supports print jobs, printer capability queries, and queue management. IPP-based profiles such as IPP Everywhere also support driverless printing, while PWG extensions reuse the model for additive-manufacturing/3D printers and bind the Cloud Imaging Model so printers can obtain jobs from shared network or cloud services.[7][8][9][10][11]

IPP normally uses TCP/631. UDP/631 is associated with legacy CUPS browsing/cups-browsed discovery rather than the IPP request transport itself. Exposing either surface can create risk on printers and Linux/Unix hosts running CUPS.[3][7]


Quick PoC – crafting raw IPP with Python

import struct
import requests

def attribute(tag, name, value):
    name = name.encode()
    value = value.encode()
    return bytes([tag]) + struct.pack(">H", len(name)) + name + struct.pack(">H", len(value)) + value

printer_uri = "ipp://printer:631/ipp/print"
ipp = struct.pack(">BBHI", 2, 0, 0x000B, 1)  # version 2.0, operation, request-id
ipp += b"\x01"  # operation-attributes-tag
ipp += attribute(0x47, "attributes-charset", "utf-8")
ipp += attribute(0x48, "attributes-natural-language", "en")
ipp += attribute(0x45, "printer-uri", printer_uri)
ipp += b"\x03"  # end-of-attributes

r = requests.post("http://printer:631/ipp/print", headers={"Content-Type": "application/ipp"}, data=ipp)
print(r.status_code, r.content[:40])

Enumeration & Recon

1. Nmap NSE

# run all CUPS/IPP scripts
nmap -sV -p631 --script=cups* <target>
# or only basic info
nmap -p631 --script=cups-info,cups-queue-info <target>

The cups-info script extracts model, state and queue statistics while cups-queue-info enumerates pending jobs.

2. IPP utilities from CUPS

  • ippfind – multicast/UDP discovery (works against cups-browsed):
    ippfind --timeout 3 --txt -v "@local and port=631"  # list printers
  • ipptool – arbitrary requests defined in a .test file:
    ipptool -tv ipp://<IP>/ipp/print get-printer-attributes.test
    The bundled get-printer-attributes.test file queries firmware version, supported document formats, etc.

3. Shodan / Censys dorks

shodan search 'product:"CUPS (IPP)" port:631'

More than 70 000 hosts were publicly exposing CUPS in April 2025.[1]

4. Emulating a rogue IPP printer in the lab

For client-side testing you do not need real hardware: ippeveprinter exposes a minimal IPP Everywhere server, can advertise itself over DNS-SD, optionally require HTTP Basic auth with -A, and can either write rendered jobs to a directory with -D or execute a helper for every printed document with -c.[4]

mkdir -p /tmp/ipp-spool /tmp/ipp-out

# Save rendered jobs into /tmp/ipp-out and listen on TCP/8631
ippeveprinter -v -p 8631 -d /tmp/ipp-spool -D /tmp/ipp-out \
  -f application/pdf,image/jpeg,image/pwg-raster "LabPrinter"

# Auth-enabled variant for testing client credential prompts
ippeveprinter -v -A -p 8631 "AuthLabPrinter"

Recent Vulnerabilities (2023-2025)

YearCVE ID(s)Affected componentImpact
2024CVE-2023-50739Lexmark firmware (IPP parser)Heap-overflow → RCE over Wi-Fi/LAN[5]
2024CVE-2024-47076, 47175, 47176, 47177cups-browsed, libcupsfilters, libppd, cups-filtersUnauthenticated rogue-printer installation leading to command execution when a victim prints[3]
2024CVE-2024-35235cupsd before the vendor fixSymlink-assisted permission change that can support local privilege escalation[2]
2023CVE-2023-0856 (Canon) + Pwn2OwnStack-overflow in sides attribute → remote code execution[6]

cups-browsed RCE chain (September 2024)

The 2024 cups-browsed bug chain is the most practical modern IPP attack path against UNIX endpoints.[3]

  1. cups-browsed listens on UDP/631 for printer advertisements.
  2. An attacker sends a single spoofed packet pointing to a malicious IPP URL (CVE-2024-47176).
  3. libcupsfilters automatically fetches the remote PPD without validation (CVE-2024-47076 & 47175).
  4. A crafted PPD abuses the foomatic-rip filter to execute arbitrary shell commands whenever anything is printed (CVE-2024-47177).

Public PoCs exist, and the attacker can either auto-install a new rogue printer or silently replace an existing printer URI so the payload triggers on the next print job.[3]

On LANs, the same path can be reached by spoofing Zeroconf/mDNS/DNS-SD advertisements instead of attacking a public UDP/631 listener directly, so it is worth pairing this with mDNS/DNS-SD abuse during local network operations.[3]

Execution normally happens when a user prints to the malicious queue, and the resulting code runs in the lp context on default Linux installs.[3]

Temporary mitigations

sudo systemctl stop cups-browsed
sudo systemctl disable cups-browsed
sudo ufw deny 631/udp  # or equivalent firewall rule

Update the whole printing stack together — cups-browsed, libcupsfilters/cups-filters, libppd, and CUPS — instead of treating this as a single-package issue.[1][3]

Install the coordinated fixed packages supplied by the target distribution. Do not rely on a single upstream version number because affected components and backported fixes vary by distribution.[1][3]

Placing a symbolic link in cupsd.conf’s Listen directive can make cupsd (often running as root) change permissions on an attacker-chosen path to world-writable, which is a solid local privilege-escalation primitive when you can influence the configuration or win the bind-time race.[2]


Offensive Techniques

  • Rogue printer replacement / auto-install – abuse cups-browsed discovery over UDP/631 or spoofed DNS-SD to register a malicious printer or replace a trusted printer URI, then wait for the next print job to reach attacker-controlled IPP metadata.[3]
  • Unauthenticated raw print job – test whether the printer accepts POST /ipp/print without authorization. Some PostScript-capable devices expose unsafe interpreter extensions, but system(...) command execution is device/firmware-specific and is not guaranteed by PostScript or IPP.
  • Job hijacking – if authorization checks are missing, operations such as Cancel-Job and Send-Document may let an attacker disrupt or replace another user’s job. The operation names alone do not bypass access control.[8]
  • SNMP → IPP combination – a default SNMP community such as public may reveal the queue or printer URI needed for subsequent IPP testing.

Defensive Best Practices

  1. Patch CUPS and printer firmware promptly; subscribe to vendor PSIRT feeds.
  2. Disable cups-browsed and UDP/631 unless zeroconf printing is required.
  3. Restrict TCP/631 to trusted subnets/VPN and enforce TLS (ipps://).
  4. Require Kerberos/Negotiate or certificate auth instead of anonymous printing.
  5. Monitor logs: /var/log/cups/error_log with LogLevel debug2 can reveal unsolicited PPD downloads or suspicious filter invocations.
  6. In high-security networks, move printing to a hardened, isolated print server that proxies jobs to devices via USB only.

References

☧ CPTS · ordered posts

Locked

Unlock with your Main_Key through local GPG.

Start the local GPG helper

In your cheatsheet checkout, run:

npm run unlock:helper

Open the link it prints, or paste its pairing code below. Keep the terminal open until GPG finishes.

Import an index you already decrypted

Download the encrypted index, then decrypt with GPG:

gpg --output report-index.json --decrypt report-index.gpg

Your private key stays in GPG. The decrypted index is saved in this browser so you can reopen it after navigation, refreshes and restarts. Lock this browser or clear this site's browser data to remove the saved index. Nothing is uploaded.