TL;DR: We show how to decrypt passwords from the configuration backup of a Xerox WorkCentre and how, during the reverse engineering, a command injection vulnerability was discovered (CVE-2021-27508).
The “printer trick” is how I’ve been calling the idea of using printers with default credentials to break into a network. It has become a common finding in our penetration tests. The first time I used this technique was during one of my first internal penetration tests in 2016, and in the customer’s infrastructure, we found a printer with default credentials. What’s more, a domain admin user was stored in the configuration to query the Active Directory (AD) for email addresses, in order to send scanned documents to the user’s email account. We could extract the domain admin’s password by configuring a fake LDAP server and changing the configuration of the printer such that our attacker machine was used as the LDAP server.
Fast forward to 2021, we still see printers with default credentials in many companies nowadays, either for all installed printers or just one that was configured differently or forgotten. The last time we encountered one was in February, while conducting a Red Teaming engagement. Once found, we accessed the printer’s administration panel with its default credentials. Here, an AD account was used for the “scan to folder” feature. In this case, there was no easy way to get the account’s password as the credentials are not transmitted in clear text via SMB (which was used for the “scan to folder” feature). However, this printer was a WorkCentre from Xerox, which has a feature that allows cloning the configuration in order to replicate it onto another device. I had already used this feature before to extract a password in clear text from the clone file. This time it didn’t work, the firmware was up to date and the password was encrypted within the clone file. This is a feature of newer firmwares.
Once extracted from the configuration file inside the clone file [1], the extracted value looked like this:0x549F5884D68E3E853E9AA29DDCCA83C4AA
How do we approach this now? Let’s start by assuming that the clone file can be imported onto other devices. As such, this must be an encrypted password and not a hash. Further, the encryption key must be known to both devices. After checking in the clone file, it was clear that it’s not stored in here. Thus, it must already be on the printer and chances are, that it’s present in the firmware. As the firmware updates are publicly available, I downloaded one[2] and, armed with lots of patience to compensate my lack of reverse engineering practice, started to dig in there.
First, you need to sort out what’s in the firmware, for me it looked a lot like Matryoshkas. I used a hex editor and the tar command before remembering that binwalk could analyze and extract the file system, before noticing that 7Zip could also do it. It goes like this[3]:
- the first archive
contains a second archiveWorkCentre_7845-55-system-sw07504000101210.zip
WorkCentre_7845-55-system-sw07504000101210.zip
- this second archive contains a DLM file in
dlms/WorkCentre7845-7855/WorkCentre_7845-55-system-sw#07504000101210#ENG_MOD.DLM
- this DLM file contains a file named
07504000101210/NC_App_075_041_01210.140
- once extracted, we can access the file system.
Here I did a very simple:
$ grep -Ri clone
And regretted it immediately, finding >1000 occurrences of the word, not even counting the binary files. I was more reasonable with the next command. Looking for the web page that creates the clone file in the web UI:
$ find . -name cloning.php ./var/opt/nc/dlms/http/data/htdocs/properties/cloning.php
In this page, we find the form that is submitted when creating the clone file:
[CUT BY COMPASS] <form action="/dummypost/xerox.set" method="POST"> <div> <input type="hidden" name="_fun_function" value="HTTP_Set_Config_Attrib_fn"> <input type="hidden" name="_fun_function" value="HTTP_Config_Cloning_fn"> <input type="hidden" name="NextPage" value="/properties/cloning_dl.php"> [CUT BY COMPASS]
It seems that some kind of function is called, HTTP_Config_Cloning_fn
. This time I could grep safely and found a library named libhttp_cloning.so
that seems to be exporting this function. After loading it into Ghidra, I quickly found the function in the exports:
And from there, found that this function calls another one at some point and makes a call to an OS binary, createClone
:
Back to the file system, we can find createClone
and its counterpart, installClone
, in /opt/nc/bin
. Here I tried to understand the whole process but this is a deep rabbit hole and a much faster way is to search for strings that include “crypt” and quickly find this function call:
Yes, this is the static encryption key and no, it’s not given in this blog post. With all the information you have already, it should be easy enough to find it yourself 😉
Back to topic, this is a function call to another library, libessCrypto.so
that we can also open in Ghidra. Here we learn that the last byte of the encrypted password (AA) specifies that AES256 is used and we see that a call to EVP_DecryptInit
is made:
This is a function of OpenSSL and we can find its prototype in the documentation[4]:
int EVP_DecryptInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type, const unsigned char *key, const unsigned char *iv);
So, we have OpenSSL decrypting our password with a static key and a null IV. It should be easy to do that on our own. And indeed, it turns out that one can do it with a simple one-liner:
$ echo "549F5884D68E3E853E9AA29DDCCA83C4" | xxd -r -p | openssl aes-256-cbc -K 4E6F745468654B6579596F752772654C6F6F6B696E67466F72 -iv 0 -d hex string is too short, padding with zero bytes to length hex string is too short, padding with zero bytes to length BurpIsNotBeef
And we get our password in clear text! Back to the story, we couldn’t use the password during the assessment, because it took me several evenings to figure all that out and the project was already finished by then. But it was worth the knowledge.
Bottom line: change the passwords on your printers and
Further, in the more recent versions of the firmware, one can additionally encrypt the clone file with a user-provided password. This would complicate the analysis as this first encryption layer has to be reversed before reaching the configuration files themselves. If the clone files have to be stored somewhere, make sure to use this feature. And if your printer doesn’t have it, update its firmware!
Bonus – CVE-2021-27508
If you read the TL;DR you may already have spotted it, the libhttp_cloning.so
library calls a shell command with system()
. As I used to do web application tests (rather than reverse engineering), I quickly verified, if any sanitization was performed and nothing stood out. I reported this to Xerox, they could confirm the bug. They released a security bulletin with links to the updated firmwares here [5]. We published an advisory together with this blog post. It’s available here: [6].
References
The basics about the Xerox clone files were found in the paper from Deral Heiland [1]
And recently, a great talk from Rapaël Rigo (@_trou_) was shared online by Infiltrate Con and goes into much more details about how he reverse engineered multiple Xerox printers and what were the outcomes [7]
[1] See http://h.foofus.net/goons/percx/Xerox_hack.pdf for some details about this.
[2] It was downloaded from https://www.support.xerox.com/en-us/product/workcentre-7800-series/content/150523
[3] the fourth, the fifth. The minor falls, the major lifts 🎵
[4] https://www.openssl.org/docs/man1.1.0/man3/EVP_DecryptInit.html
[5] Security bulletin XRX21J https://securitydocs.business.xerox.com/wp-content/uploads/2021/05/cert_Security_Mini_Bulletin_XRX21J_for_ConnectKey_v1.0.pdf
[6] Compass Security advisory https://www.compass-security.com/fileadmin/Research/Advisories/2021-04_CSNC-2021-002_OS_command_injection_RCE_in_Xerox_WorkCentre.txt
[7] Attacking Xerox Multifunction Printers – Raphaël Rigo https://vimeo.com/showcase/8085537
Leave a Reply