Root shell on a credit card terminal

Jun 1, 2025 - 20:45
 0  0
Root shell on a credit card terminal

In this project, I started to reverse engineer payment card terminals because they seemed to be an interesting target for security research, given the high stakes involved. Although I initially didn’t knew much about this industry, I did expect a ton of security features and a very security-hardened device. And to some degree, this was also correct.

First Look

The model I went with is a Worldline Yomani XR terminal. Although it seems to be discontinued at the time of writing, this is the model that is everywhere in Switzerland. From big grocery chains to the small repair shop on the corner, everyone has one or a whole fleet of this exact terminal.

After booting it up and aimlessly clicking through the UI, I did a quick port scan, but couldn’t find anything interesting. So naturally, I started to take it apart.

The housing and the PCBs appear to be well-made. The design consists of multiple PCBs: a small connector board for the outward-facing connectors, the main board, and a vertical board the card slot sits on. The main SoC seems to be a custom ASIC, a dual-core Arm processor code-named “Samoa II” in the firmware, but I am jumping ahead. According to Worldline documentation, this seems to indeed be a custom ASIC, rather than just a rebranded off-the-shelf chip. Next to it, there is a small external flash and RAM.

Tamper Protections

During disassembly, I kept looking for a tamper switch that would detect when the device’s housing was opened, like I had seen previously on laptops and other devices. However, I couldn’t find such a switch. Rather, they use the board-to-board interconnects as a way of detecting when the device is opened. Because they use relatively pressure-sensitive Zebra strips between the boards, they have to be tightly screwed together. Even unscrewing some of the screws is enough to break contact and trigger a tamper event. Of course, the tamper detection must also work when the power is disconnected, so that’s the purpose of the coin cell battery.

But this is not all in terms of tamper resistance: The “vulnerable” PCBs are covered by zick-zack traces that act as a tamper detection mechanism. Accidentally breaking a single copper trace during a physical penetration attempt (hole drill etc.) is enough to trigger the tamper detection.

Trace meander on the display PCB acting as tamper detection.

The card slot itself is contained in an additional, internal housing. Wrapped around this housing, there is a flex PCB acting as tamper protection.

Card reader assembly wrapped in a tamper detection flex PCB.

After putting the device back together, it was clear that my intrusion had not gone undetected. Sure enough, the device would now only show a big red screen screaming “TAMPER DETECTED”. In this mode, the device seems to be fully unresponsive to any kind of external input. So, game over?

Chip-Off Firmware Extraction

Since any “runtime” exploration seems to be futile now, I wanted to take a look a the firmware. For this, I desoldered the on-board flash chip, soldered some wires to it in “dead bug” style and proceeded to dump the contents.

BGA flash chip of the card terminal desoldered and connected to a flash reader.

To my surprise, the contents seemed to be entirely unencrypted! However, the contents seemed to have a strange ECC layout. Instead of following the flash chip’s inherent page layout and putting the ECC data in the interleaved spare areas, it appeared as if the some ECC data was present in the page and some clear text was in the spare areas. With the help of some friends, I figured out the layout: instead of using the standard 2048 byte payload + 64 byte ECC/spare layout, it uses 3x 694 byte chunks of data each followed by 10 ECC bytes. The ECC bytes do not appear to be all used. Instead, the last 16 bytes of the spare area seem to act as metadata for the YAFFS2 file system. Now normally, there are less ECC bytes per page and therefore the usable metadata area for the filesystem is larger than 16 bytes. For this reason, the YAFFS2 filesystem had to be patched to work with smaller metadata structures.

I implemented a compatible filesystem reader and with it, I could successfully dump the filesystem contents! View yomani-unpacker on Github

Now it was clear that this device runs Linux. I found a standard Linux filesystem with a lot of interesting files to browse through. The system runs a 3.6 kernel, built with Buildroot 2010.02 (!) in February of 2023. The system seems to use a custom bootloader, “Booter v1.7”. Although I don’t know how recent the firware version was that I ended up dumping, it must have been released after February 2023. So finding such an ancient kernel is rather concerning. Userspace-wise, the system uses classy init scripts, busybox, and uClibc (final release was 13 years ago). libcrypt has version 0.9.26, ouch.

Finding a Root Shell on Accident

Having seen the firmware gave me some new confidence that there might be more stuff to find. So I reattached the flash chip using wires, ignoring everything I know about signal integrity. To my surprise the device booted up again (showing the tamper message).

Flash chip reunited with the PCB, as good as new.

My next goal was it to find the serial console of the Linux system. Surely, it must have one for debugging. By looking at a boot log, I might get some more valuable information. So, equipped with a logic analyzer, I started poking.

Probing the debug connector.

I didn’t take long until I found some activity on one pad of the unpopulated debug connector. Bingo!

------------------------------------------------------------------------
Booter: 1.7b+00002:gbe6b338 Jun  3 2014 08:51:58 owi
Reset reason: Tamper
Start USB boot ...
Got address 0x00000015
Enumerated.
Dfu timeout
yaffs: checkpoint restore ... KO!
yaffs: clean up the mess caused by an aborted checkpoint
file "hwinfo-l0" found
file "hwinfo-l1" found
file "hwinfo-l2" found
file "loadercode" found
file "mp1.img" found
file "linux" found
Uncompressing Linux... done, booting the kernel.
Linux version 3.6.0-samoa-01844-g1f05798 (ppd@debian) (gcc version 4.3.4 (Buildroot 2010.02) ) #0 Fri, 10 Feb 2023 16:26:07 +0100
cpufreq: initial frequency: 264000 kHz
MAC-1G DMA: 430ab000 - 430ab9ff
MAC addr = 00:08:19:4e:56:2c
eth0: ioaddr: d00d0000, dev: c30ac000
probing samoafb: rc = 0
  DMA = 4F500000->c3a00000, IO =   (null)
UART 1 probing
UART 1 probing OK
UART 2 probing
UART 2 probing OK
UART 3 probing
UART 3 probing OK
pca953x 0-0049: failed reading register
ba315 ba315.0: NAND ID: id[0-3]=’EF A1 00 95’, manu=’Winbond’, dev=’NAND 128MiB 1,8V 8-bit’
drivers/rtc/hctosys.c: unable to open rtc device (rtc0)
yaffs: Attempting MTD mount of 31.0,"mtdblock0"
yaffs: yaffs_read_super: is_checkpointed 0
starting pid 398, tty ’’: ’/etc/init.d/rcS’
/etc/init.d/rcS started
Mounting local file systems: ok
rootfs on / type rootfs (rw)
/dev/root on / type yaffs2 (rw,relatime)
proc on /proc type proc (rw,relatime)
devpts on /dev/pts type devpts (rw,relatime,mode=600)
tmpfs on /tmp type tmpfs (rw,relatime)
none on /sys type sysfs (rw,relatime)
Mounting usbfs: failed
Terminal is initializing\nPlease wait
...
dropbear is not present
emv-engine-4.3e-with-trace is not present
tim-server-nexo-config_3.1.6.0-1140_arm is not present
mp1-samoa2-eft-sr-prod is not present
Checking for FW updates\nPlease wait

 FW is up to date.

Starting Application Monitoring Daemons
Mounting USB stick: failed
starting pid 600, tty ’/dev/ttyCU’: ’/sbin/getty 115200 ttyCU’

samoa login: 

It even shows a login prompt, neat! So this is definitely the Linux boot log. Many embedded Linux systems will have such a more or less exposed serial console, but most of the time the login is disabled altogether or a random, hard-to-crack password is either hard-coded or generated at boot. Not expecting much, just out of curiosity, I entered “root” as the login, and...

samoa login: root
~ #

Wait, what!? That’s it? I’m in?

Well, yes. That was the boring story of how I got the root shell. It is just there, exposed. No sophisticated exploit chain, no brute-force password cracking required. Additionally, everything seems to still work although the device still shows the tamper message.

Now you may say: well okay, that’s not ideal, but in order to get access to the exposed root shell, you need to open up the device, which triggers the tamper protection and effectively renders the device useless. But in fact, the serial port is accessible from the outside!. Without opening up the device and triggering the tamper protection, the debug connector can be accessed through a little hatch on the back of the device. All an attacker needs is just 30 seconds alone with the device to attach to the serial port, log in, deploy malware, and leave. This sounds really bad.

The debug connector with the serial console is accessible from the outside of the device.

Is This as Bad as It Looks?

All this fancy hardware made useless by some lazy software engineers?

Actually, no. Hear me out: During my analysis of this device, it became clear that the Linux system is not the whole story. For example, there seems to be no graphics driver for the display and the only framebuffer device does not seem to do anything. Instead, only text strings seem to be passed to a binary (display_tool), that issues some inter-processor messages. The same goes for the key pad or the card reader itself. I could not find any evidence that these peripherals could be accessed directly from Linux.

Instead, there is an entirely separate processor, refered to as mp1, that seems to handle all the “secure” stuff, like handling the card, getting the pin and showing information on the screen. The “insecure” Linux, running on the second processor, mp2, only handles the networking, the updating, and the business logic.

The Linux core seems to always boot, regardless of the tamper state. From there, the secure core is booted. For this, Linux apparently loads a secure bootloader (named loadercode) into memory. This loadercode checks whether the tamper protections have been triggered and based on the result, either show the red screen or continue to boot the actual “secure” image (mp1.img, in the Linux filesystem). This secure image seems to be properly encrypted and signed by two entities.

My current understanding of the Yomani boot process featuring the Samoa II ASIC. The first core (insecure, application) always boots Linux, which in turn loads a secure bootloader and the secure image on the second core. The loadercode is what displays the tamper messages on screen. The secure image, that handles the card, display, and key pad, is properly encrypted and signed.

Disclosure Timeline

14/11/2024 Discovered the root shell
15/11/2024 Informed manufacturer, announced 90 days until publication
18/11/2024 Manufacturer confirms that they got the report
--- I forgot this project existed ---
01/06/2025 Publication

Conclusion

While concerning, the exposed root shell does not seem to be as big of a risk as initially feared. While still being a huge unnecessary attack surface, and a massive oversight from the engineers in my opinion, I could not find any evidence that sensitive data, such as card details, could become compromised this way. Also, I could not definitively proof which firmware versions were vulnerable. During my research, I also encountered devices that had a disabled root login. My guess is that somehow this debug feature accidentally made it into production firmware at some point. Chances are that this was discovered and fixed internally before I reported it to the manufacturer (as I had no way of updating the firmware, or verifying that I was running the latest firmware).

This project was a lot of fun and I wish I had some more time to dig deeper into the firmware and explore more possibilities. If you want to take on this challenge, feel free to reach out to me. I’d like to thank anyone involved in this project for their valuable input.

What's Your Reaction?

Like Like 0
Dislike Dislike 0
Love Love 0
Funny Funny 0
Angry Angry 0
Sad Sad 0
Wow Wow 0