Accounting bypass

From http://hacking-printers.net/wiki/index.php/Accounting_bypass

Introduction

Printing without permission can itself be a security risk or breach of company policy. In environments where print jobs are charged for, an inside attacker has a motivation to bypass the accounting system. Furthermore, being able to ‘print’ is a precondition for most attacks against network printers.

There are two major approaches when it comes to print job accounting: Either let the printer handle it directly or use a print server in between. The first approach is vendor-specific, usually involves some kind of special ‘printer driver’ and is not further discussed here. The other approach involves a separate print server – usually a software implementation like CUPS or LPRng – to handle the accounting and is quite common in companies and institutions. The print server may speak LPD, IPP or further printing protocols and forwards jobs to the actual printer. It is important to note that direct network access to the printer must be restricted, otherwise an attacker can easily bypass the print server and its accounting mechanisms. This means filtering access to typical and atypical ports (LPD, IPP, raw, HTTP, SMB, FTP, SNMP).

There are basically two approaches to circumvent the print job accounting systems: either impersonate another user or manipulate the counter of printed pages. In the following both options are discussed for LPRng (v3.8.B) and CUPS (v2.1.4) installations which are popular open-source printing systems used in academic and corporate environments. A comparison of the security features of both systems is given below.

Authentication bypasses

LPRng and CUPS both offer SSL based channel encryption and secure authentication schemes like Kerberos, PGP signed print jobs or HTTP basic/digest authentication. If configured properly and in case the attacker cannot access the printer directly she will be not be able to impersonate other users. Those security features however are optional and rarely applied in the real-world print servers. Instead, the usernames given as LPD (LPRng) or IPP (CUPS) parameters are logged and accounted for – which can be set to arbitrary values by the client side. The reasons for this is a simple cost-benefit consideration in most institutions: Kerberos needs a special setup on every client and HTTP authentication requires users to enter a password whenever they want to print something while the costs of a few unaccounted printouts are bearable.

You can verify proper authentication trying to print with a custom username like this:

lp -U nobody test.ps

Page counter manipulation

Hardware page counters

For correct accounting the number of printed pages must be determined by the printing system which is not a trivial task. The authors of LPRng make the assumption that the printer has some sort of non-volatile page counter mechanism that is reliable and impervious to power on/off cycles. Such hardware page counters are supported by most printers and read by LPRng using PJL after every print job. HP has even documented a feature to write to the page counter variable by setting the printer into service mode. This way, the page counter of the HP LaserJet 1200, HP LaserJet 4200N and HP LaserJet 4250N can be manipulated within a print job. At the end of the document to be printed and separated by the UEL, the counter simply has to be reset to its original value (for example, 2342):

\x1b%-12345X@PJL JOB
This page was printed for free
\x1b%-12345X@PJL EOJ
\x1b%-12345X@PJL JOB
@PJL SET SERVICEMODE=HPBOISEID
@PJL SET PAGES=2342
\x1b%-12345X@PJL EOJ

An attacker might set a negative number of printed pages. Note that resetting the device to Factory defaults also resets the page counter to zero on some of the tested devices. Lowering the page counter can also be used to sell a printer above its price as it can be compared to the odometer when buying a second-hand car. It is however worth emphasising that resetting the page counter is not necessarily for malicious purposes: It is a well-known business model to sell overpriced ink for low-cost inkjet devices and block third-party refill kits by refusing to print after a certain number of pages – to handle such unethical practices it is absolutely legitimate to reset the page counter.

On older HP laserjets the pagecountcommand of PRET can be used to easily set hardware pagecounters:

./pret.py -q printer pjl
Connection to printer established

Welcome to the pret shell. Type help or ? to list commands.
printer:/> pagecount 10
Old pagecounter: 53214
New pagecounter: 10

Software page counters

CUPS uses software page counters which have been implemented for all major page description languages. For PostScript, an easy way to bypass accounting is to check if the PageCount system parameter exists – which will return false when interpreted in CUPS/Ghostscript – before actually printing the document as shown below.

currentsystemparams (PageCount) known {
  <@\textit{[...] code which is only executed on a printer device [...]}@>
} if

This way, the accounting software used by CUPS renders a different document than the printer. CUPS only accounts for one page – which seems to be a hardcoded minimum – while the real print job can contain hundreds of pages. Note that using the IPP ‘raw’ queue/option is mandatory, otherwise CUPS parses the code with a PostScript-to-PostScript filter (Ghostscript's ps2write) before it reaches the page counter.

How to test for this attack?

Wrap an arbitrary multi-page PostScript document in the code above and print. Then go to http://printserver:631/jobs?which_jobs=all and check CUPS's page counter for this print job. Note that have to establish a raw queue. This is, a queue where the filtering system is not involved and the print job goes directly to a printer. For CUPS, this is done by setting the content type to application/vnd.cups-raw. If your system is already configured to use the print server to be tested, simply use:

lp -o raw test.ps

Last updated