Can't be arsed? Click here for a page summary (spoiler warning)
TL;DR (Too Long; Didn't Read)
There are 'Zebra' brand label printers on each of my co-workers' desks.
During a network scan, I discovered at least one printer with a default pin-code. I put the printer into debug mode, and obtained it's label metrics.
I then learnt about the programming language used to communicate with the printers, crafted my own labels using said language, covered my tracks by pretending to be another printer, and sent the labels to all printers.
The Programs and Documents I used are linked at the very bottom of this page.
...Are you pleased now, you impatient bastard?
This post was originally titled How to get fired from your day-job, as I planned to go on a much larger (and slightly more hostile) offensive, that would likely have resulted in my termination.
My colleagues convinced me to narrow the scope of the 'attack', which then turned into a proof of concept, and gave birth to a moderately useful Windows application.
For those unaware, I work a temp-job on an assembly line, for a fairly well known manufacturer of Digital set-top boxes.
A set-top box arrives on a conveyor - you take said box, replace any parts that have cosmetic damage (ie: enclosure or front panel), then you send it on it's way
Repeat the aforementioned task roughly 180 times per day to meet target, and you'll get paid just enough to scrape by.
Here's an idea of what the environment looks like, from the point-of-view of my bench:
The pixelated guy is Kev - He's naturally pixelated, it's a hereditary condition.
The role I applied (and was approved) for was far more technical, higher paying, and involved component level repair. I was placed here by the company 'temporarily' as the start date was delayed by a few weeks.
Months have now passed, and after many excuses, it would seem that I've been had -- And that the aforementioned role doesn't actually exist, at least for me.
With that said and with a tight job market, it's still far better than a kick in the sack. My team-mates are also fantastic, and it's in this role that I realised dick-jokes cross cultural boundraries
So I'm near broke, living paycheque to paycheque and understandably peeved... Which brings me to this whole printer hi-jacking, thing.
On each workbench is at least one 'Zebra' brand barcode printer, most of which are TLP-2844-Z models:
They are all fitted with 'ZebraNet PrintServer II' modules, which are either internally installed or externally attached to the printer's Centronics ("LPT") port
It's worth noting that our workstations run a text-based 'console' application for data-entry, and they never directly communicate with the printers; All printing is handled by the server, which hosts said application.
So it's lunchtime, and I figure it's time to do some probing. I plug in a USB key, which contains a handful of useful portable apps for such an occasion:
Turns out I need to be an Administrator to install new hardware.
...Well, shit. I guess we can fix this.
They're running an outdated version of Windows, making it possible to use any one of several privelege escalation attacks (ie: Sticky Keys) to install new hardware. We'll shelve this for now, as mass storage is more of a luxury than a necessity.
At this point I wonder if the print-servers are running a web-management interface, like every other freakin' device on the planet.
I enter the printer's IP address in a browser, and sure enough:
It does indeed have a web-management interface, and it's pin-protected.
Viewing the page source, I see that the text-box used to enter the "pin code" has a nominal length of four characters. Might as well try a couple of default'ish codes, maybe 0000 or 1234
To test the code, I entered the pin and hit the 'Feed' button:
HAH! Oops. The pin code is 1234, and out popped a blank label from the printer.
There also doesn't seem to be any restriction on the number of pin entry attempts, so we could've even brute-forced our way in, trying every code from 0000 to 9999, if it came to that.
Browsing the configuration pages, there seem to be many, many other options I could now use to wreak complete havoc
...Even just using the Printer controls page, one could 'script' all printers to spew out their label spools overnight, leaving a shit-tonne of labels everywhere by morning.
What I'd really like to do, though, is print to the damn things.
I remember seeing something about "Raw Port 9100" while browsing the configuration pages; Most network printers I've worked with will print any plaintext sent to TCP port 9100, as long as the text is terminated with a Carriage Return
So I fire up a terminal (putty), connect to the printer on TCP port 9100 and begin to type gibberish, hoping that I'll get a print-out:
Nothing. Not even a peep.
With only a few minutes left of lunch and no hope in immediate sight, one always turns to Lord Google
I found a page that seemed useful, and so I of course read absolutely jack of the context. Apparently sending the ASCII character sequence ^XA~JD^XZ enables diagnostic mode.
...I have no idea what diagnostic mode does, but I'm absolutely certain that I want it:
Still nothing. THIS IS BULLSHIT! Clearly the printer is broken.
By this time lunch break is over, and it's back to work.
Just as I scan a job to print off a barcode label, the printer starts to shit out a sausage-string of labels, which actually looks pretty damn interesting:
Of course, I start to panic and rush to take the printer out of debug mode. I shove the labels into my backpack and pretend nothing happened for the rest of the afternoon.
I'm now tripping absolute balls with excitement, and time seems to dilate as I rush to get to the car to drive home.
Unable to contain my excitement during the 20 minute drive, I pull over into a laneway, browse Zebra's website on my smartphone, and download a copy of the "Zebra ZPL Programming Guide".
As it turns out, enabling Debug Mode causes the printer to print out whatever data it receives, in both ASCII and HEX formats:
...So I've indirectly captured the source code of a label that was sent by the server! BRILLIANT! - Now I can get to work appending DickButt to all my labels
Only kidding. Sort of.
The printout contains valuable information about the label metrics (being custom die-cut labels), as well as configuration data (ie: Direct thermal or Transfer, webbed or continuous, etc)
I leave a little earlier for work the next morning, logon to my workstation, and manually type the data present on the labels, exactly as written, while connected to TCP/9100 on the printer.
Something magical happens (serial number censored for obvious reasons):
Out pops a perfect replica of the set-top-box labels! Exciting.
Hmm. If you could send a customized label to all label printers in your department, what would it look like?
I thought maybe an ISIS flag, modified to demand that a six-pack of Red Bull be left in the fridge, or the printers will cease to function indefinitely... But I didn't want to have the feds called in on me.
...I did mention that I originally planned on getting fired for this.
Everyone here is terrified of not being able to meet their daily target (quota). In fact, the word 'target' is used in every other sentence
The target has also recently increased, and will likely continue to increase in the near future - fairly normal for larger companies looking to expand and/or increase profits.
So how about something like this?
Yes it's tame (and not all that funny), and it's three labels instead of one - But I figure it'll hit home with any employee here.
...It'll also be a refreshing change from the sterile barcodes normally printed from these printers
So now we've got to work out how to send these labels to the printer, using the ZPL programming language.
Fortunately (as discovered from the diagnostics printout), the label metrics are committed to the printers flash memory on every print request (nice way to wear out flash) - so each printer already knows exactly the type of label reel, ink, etc that it contains.
The printers also contain their own scalable (outline) fonts - So all we need to do is send positioning, font size, text and image data, properly encapsulated in ZPL-speak
Full-disclosure: I went through a huge number of trial and error print-outs in getting positioning right for everything that follows, so I thought it'd be wise to swap out the company-supplied roll of labels with my own roll of cheap thermal 'receipt' paper.
Rather than bore you with a compelete breakdown of ZPL, here's an example of what a 'Hello World' Label looks like:
Sending the above text (minus comments) to the printer on TCP port 9100 would result in the following print-out:
By adjusting the field text, changing the field origin, and adding a second text block, we can generate the "Love Anonymous" label, minus the heart graphic:
...Which results in the following print-out:
Now to add the heart image to the label. Images must first be converted to a format the printer can understand (.GRF files)
According to the ZPL manual, GRF files are simply PCX format images, with all headers removed, and the bitmap represented in pure hexadecimal (ie: "plaintext binary")
Aint nobody got time for that shit - Instead we'll use Zebra Font Downloader to convert the image for us.
The image is stored in "R: drive" (Static RAM) on the printer, which is volatile, meaning data stored in R: is lost on power down
There's also a small amount of non-volatile Flash in each printer (E:), but R: has a much higher chance of being available across all printers.
The image filename is HRT_S.GRF; to call it for insertion on a label, we use the ^XG instruction, followed by the path and image filename:
...Which results in the following print-out:
Now we repeat these steps for the remaining two 'pages' of the label, and we have our final result:
You can view the complete ZPL source for this printout HERE, as I'm a little short on space.
So now that we've generated our labels, it's time to plan our attack. First we'll need to locate all other label printers on the network.
Zebra printers have a neat identification feature - If you send them the ASCII character sequence ^XA~HI^XZ, they'll respond with their make, model and storage capabilities in plain text.
Unfortunately, If you sent that sequence to a non-zebra (ie: office laser) printer, It'd physically print it out and you'd be shafted.
We don't know if there are any non-zebra printers on the network, so the safest technique for discovery would be to run a slow 'port-scan', for the known ports used by the printer. By default, these are ports 23, 80 and 9100
As an additional bugger, each printer also stores a log of the last ten access attempts, including IP address - So at this point it's best to try and cover our tracks before doing anything drastic.
...Wouldn't it be awesome if we could somehow pretend to be another label printer? So all the attacks, print-outs and scans, would appear to be coming from a humble peripheral?
Of course it would. To do this, we'd need to clone the MAC address of an unused/idle printer onto our workstation. This will cause the DHCP server to hand out the printer's IP to us, as long as the printer is offline.
Unfortunately, we don't have the administrative priveleges required to change network settings, including the MAC address
There are a couple of registry (.reg) files on my Desktop, put there by the SysAdmin - and I know the MAC address is stored in the registry. I wonder if that means i'll be able to add stuff to the Windows Registry without administrative priveleges?
So I open a command prompt and run the 'reg' command, instructing it to insert a key in the "Run" section of the registry - This should cause windows to automatically run NotePad on the next startup:
The command was successful! Now to reboot and...
Now that we've confirmed our ability to modify the Windows Registry, we'll need an unrestricted machine (ie: one with Administrator access) to determine where the MAC Address setting is stored.
I'm using a WindowsXP Virtual Machine on my laptop - We'll be taking a snapshot of the registry before and after setting up a new MAC address, then we'll use WinMerge to compare both files, to find out what's changed.
First we'll export the entire HKEY_LOCAL_MACHINE hive, which stores system-wide settings for all users:
Next, we change the MAC address through the Network Settings Dialog (Network Connections ⇒ LAN Properties ⇒ Configure Adaptor ⇒ Advanced ⇒ Locally Administered Address)
Next, we'll export the HKEY_LOCAL_MACHINE hive again, this time with a different filename:
We now have our registry hives before and after setting a new MAC address - After loading both files into WinMerge and scrolling down, we find one key difference between both file versions:
Found it! It's worth noting that the location of this key may vary if the machine has more than one Network Interface
Now, we can create a "patch" file named "newMacAddress.reg" in notepad, ready for import onto the target machine:
Double click the file on the target machine then Import ⇒ Reboot ⇒ IPConfig /ALL ⇒ Shit-eating grin
Finally, we can start scanning the network with the confidence that we're a teensy bit further away from being immediately foiled.
We'll use AngryIPScanner to search all addresses on our subnet for open ports 23, 80 and 9100. Any hits with all three ports open is likely to be a [Zebra] printer:
Results! In all there were twenty eight hits with all three ports open on my subnet.
After checking each address manually in a browser, only fourteen appear to be Zebra printers - the rest were Office Lasers and surprisingly, managed ethernet switches (why on earth would switches have port 9100 open?)
Now that we have our list of targets, we'll need a way to send out our payload to each of them - Rather than re-invent the wheel, we'll use a purpose-designed tool: NCat Portable
NCat is a tool that allows you to read and write data over the network; The portable edition is statically compiled, and hence does not require installation; perfect for restricted machines.
First we'll run a test on a single printer - Our payload (ie: the label we created) was placed in a text file named Payload.txt:
...And we get the following print-out
As we're only targetting fourteen printers, it's feasible to manually create a batch file with the following contents, to print to each printer in sequence:
The file is saved as anarchy.bat - The '-v' option was added to the command line to increase verbosity - It provides you with more information about what NCat is doing
Now we run the batch file in a command prompt -
The total attack time was approximately 15 seconds, NCat appeared to hang between every four targets (I assume there's some caching witchcraft going on) - Surprisingly all the printers shit out their labels at about the same time!
I really wish I had a video of the reactions to show you guys, but I obviously couldn't be seen holding a camera.
They were both sad and hilariously awkward - Ranging from Fucking Ahmad! I know it was you, to utter panic, to an inferred "How dare you make the girl I like smile", and even complete nonchalance.
In conclusion: Secure your fucking network. Always assume someone is trying to break into your shit, even if you think your staff are knuckle-dragging neanderthals struggling to make
Edit: Thanks to Hirudinea from Hack-A-Day for the image in the redacted link
...And here's a screenshot of that simple moderately useful Windows application that came of all this:
Hint: It's a label generator for faulty units, that need to be sent back for soak testing, diagnostics, HI-POT, etc
[Website] Putty - SSH client and terminal emulator
[Website] ZPL PG - Programmers reference for the Zebra ZPL language
[Website] Zebra Setup Utility - Convert fonts/images to Zebra format
[Website] WinMerge - Compares files and creates patches
[Website] Angry IP Scanner - Brilliant network/port scanning tool
[Website] NCat - Reads and Writes raw data to the network
See you in the next post!