Where’s the Money - Supplemental Findings
While creating the content for my DefCon 32 talk, Where’s the Money: Defeating ATM Disk Encryption, I observed two additional vulnerabilities that had been overlooked in the heat of the research. These issues were reported to Diebold Nixdorf and later identified as low impact issues and, thus, did not receive additional patching. The impact of these issues vary across the different versions of Superschaf, the Linux architecture supporting the FDE module of Diebold Nixdorf’s Vynamic Security Suite (VSS), detailed in my white-paper. As of VSS v3.3.0 SR16, they are little more than information discovery tools but provide some additional insight to the remediation controls implemented by Diebold Nixdorf. In this article I plan to publicly disclose these additional details as supplemental content to my white-paper, linked above.
As a refresher, Diebold Nixdorf’s Vynamic Security Suite (VSS) employs the software solution CryptoPro Security Disk for BitLocker, aka CryptoPro. This solution introduces an abstraction layer to the system through the addition of a small Linux partition aka Superschaf, located at the end of a GUID partition table. The purpose of this environment is to conduct file integrity checks to assert a known system state, performing a number cryptographic routines with a SHA256 index table. This index table is hardcoded into the EFI binary Bootxsa.efi
and contains a SHA sum for a number of files, within the Linux partition, that should be validated to assert system integrity. These sum values are represented as a double hash, where the SHA256 sum of the target file is generated and then that value is summed again. Additionally, this software solution is designed to work with or without a TPM and supports TPMs of version 1.1, 1.2, and 2.0.
Once CryptoPro is installed, the system will operate in a dual-boot state, switching between Linux and Windows. Each boot sequence will run through both operating systems before the ATM becomes fully operational. In this architecture, system integrity validation is done between UEFI and Linux - this process is defined as Pre-Boot Authorization (PBA) Phase I and Phase II. Additionally, CryptoPro updates the firmware keychain information and activates SecureBoot, disabling the execution of unsigned or untrusted EFI binaries.
From an information security perspective, exploitation of the secured architecture requires bypassing of PBA Phase I, or the UEFI initialization process, and obtaining code execution prior to the initialization of PBA Phase II. The following graphic depicts this circular boot sequence:
Vynamic Security Suite - PBA Boot Cycle
CVE-2024-46916
In my original content, I described an attack surface where /etc/fstab
could be moved and linked from /etc/mtab
, labeled as CVE-2023-24063. This slight system change disabled the creation of several temporary file systems and gave persistence to /root
. From this vantage point, root’s .profile
script could be modified - allowing for code execution during system initialization. This path of compromise was removed from the next patch release of VSS, version 3.3.0 SR10, as the rm /etc/mtab
instruction was removed from /etc/rc.d/init.d/mountfs
. However, there were two additional delete instructions that perpetuated this attack /fastboot
and /forcefsck
, also located in /etc/rc.d/init.d/mountfs
:
# Remove fsck-related file system watermarks.
rm -f /fastboot /forcefsck
...
boot_mesg "Recording existing mounts in /etc/mtab..."
> /etc/mtab
mount -f / || failed=1
mount -f /proc || failed=1
mount -f /sys || failed=1
mount -f /sys/kernel/security || failed=1
(exit ${failed})
evaluate_retval
Before I continue with the details surrounding this attack surface, I would like to highlight that the PBA Phase I EFI index table for v3.3.0 SR9 and SR10 only contains about 58 elements that are validated as part of the Linux file system. Extraction of this index is elementary with the use of strings
and a filter:
$ strings /EFI/CPSD/Bootxsa.efi | awk '/^\/[a-z]+\// && !/(main|debug)/ {print $0}'
/bin/bash
/bin/cat
/bin/chmod
/bin/dmesg
/bin/echo
/bin/grep
/bin/keyctl
/bin/mkdir
/bin/mknod
/bin/mount
/bin/sh
...
Having visibility of this content is critical to properly construct an exploit against the platform. As this list represents the Linux integrity SHA256 index table, contained in Bootxsa.efi
. However, the full partition is not integrity validated and only the files that physically exist or selected are checked. Therefore, content that does not already exist or is not indexed, is fair game. As a result, there is a fairly large file based attack surface for the Linux partition. The default rootfs
is listed below, notice it only contains a list of directories:
$ ls -l ./
total 84
drwxr-xr-x 2 root root 4096 Sep 14 2022 bin
drwxr-xr-x 3 root root 4096 Nov 10 2022 boot
drwxr-xr-x 2 root root 4096 Apr 18 2008 dev
drwxr-xr-x 22 root root 4096 Sep 14 2022 etc
drwxr-xr-x 2 root root 4096 Apr 21 2008 home
drwxr-xr-x 8 root root 4096 Sep 14 2022 lib
drwxr-xr-x 3 root root 4096 Sep 14 2022 libexec
drwxr-xr-x 2 root root 4096 Nov 17 2022 LOG
drwx------ 2 root root 16384 Sep 14 2022 lost+found
drwxr-xr-x 2 root root 4096 Nov 17 2022 mnt
drwxr-xr-x 2 root root 4096 Apr 18 2008 proc
drwxr-xr-x 2 root root 4096 Nov 17 2022 root
drwxr-xr-x 4 root root 4096 Aug 19 2021 run
drwxr-xr-x 2 root root 4096 Sep 14 2022 sbin
drwxr-xr-x 2 root root 4096 Apr 18 2008 sys
drwxr-xr-x 2 root root 4096 Nov 17 2022 tmp
drwxr-xr-x 13 root root 4096 Sep 14 2022 usr
drwxr-xr-x 2 root root 4096 Nov 17 2022 var
Since /fastboot
and /forcefsck
don’t exist, they are open targets. As you may have guessed, yes, this vulnerability does provide an alternative code execution path in both VSS v3.3.0 SR9 and SR10, overlapping both CVE-2023-24063 and CVE-2023-24062. This vantage point of code execution is ultimately disabled with the introduction of SR12, where an rm
and mkdir
instruction set is introduced to /etc/rc.d/init.d/mountfs
. This, of course, superseeds the rm
instruction for /fastboot
and /forcefsck
.
# remove and re-create /root /var /tmp /mnt
rm -rf /root /var /tmp /mnt
mkdir /root /var /tmp /mnt
# Remove fsck-related file system watermarks.
rm -f /fastboot /forcefsck
This attack path is further shackled by the introduction of the PBA Phase I additions, in SR15 and SR16, which contain null hash sum and symlink validation checks. However, relevance of this attack surface does not end there. In VSS v3.3.0 SR16 the rm
and mkdir
instructions were commented out of /etc/rc.d/init.d/mountfs
- reintroducing some aspects of this vulnerability!
# remove and re-create /root /var /mnt
# rm -rf /root /var /mnt
# mkdir /root /var /mnt
# Remove fsck-related file system watermarks.
rm -f /fastboot /forcefsck
Removal of these instructions now provide a vantage point to again delete /etc/fstab
and obtain visibility to the otherwise inaccessible content of the TMPFS
protected directories.
$ ls -al etc/fstab
lrwxrwxrwx 1 root root 9 Mar 31 08:50 etc/fstab -> /fastboot
$ ls -al ./
total 96
drwxr-xr-x 20 root root 4096 Mar 31 08:50 .
drw------- 6 root root 4096 Mar 31 08:49 ..
drwxr-xr-x 2 root root 4096 Jun 5 2023 bin
drwxr-xr-x 3 root root 4096 Jul 14 2023 boot
drwxr-xr-x 2 root root 4096 Apr 18 2008 dev
drwxr-xr-x 22 root root 4096 Mar 31 08:50 etc
-rw-r--r-- 1 root root 675 Nov 22 2019 fastboot
drwxr-xr-x 2 root root 4096 Apr 21 2008 home
drwxr-xr-x 8 root root 4096 Jun 5 2023 lib
drwxr-xr-x 3 root root 4096 Jun 5 2023 libexec
...
As a result, we are able to get some insight into /root
and /var
. From /var
we can pull the bootlog
.
# ls -al root
total 96
drwx------ 10 root root 4096 Apr 23 08:28 .
drwxr-xr-x 20 root root 4096 Apr 23 08:28 ..
-rw-r--r-- 1 root root 420 Mar 18 2016 .bashrc
drwx------ 2 root root 4096 Apr 24 2013 .cache
drwx------ 4 root root 4096 Apr 17 2018 .config
-rwxr-xr-x 1 root root 83 Oct 14 2008 console.sh
drwx------ 3 root root 4096 Apr 23 08:28 .dbus
drwxr-xr-x 2 root root 4096 Jul 18 2012 .devilspie
drwx------ 2 root root 4096 Apr 23 08:28 .fluxbox
-rwxr-xr-x 1 root root 6894 Jan 26 2011 lang
drwxr-xr-x 3 root root 4096 Apr 28 2009 .local
-rwxr-xr-x 1 root root 616 Jan 29 2009 mount_fatstore.sh
-rw-r--r-- 1 root root 631 Aug 23 2012 .profile
drwx------ 4 root root 4096 Sep 24 2012 .scim
-rwxr-xr-x 1 root root 111 Nov 23 2010 startx_local.sh
-rwxr-xr-x 1 root root 363 Apr 28 2021 startx.sh
-rw-r--r-- 1 root root 521 Aug 17 2021 startx.sh.sig
-rwxr-xr-x 1 root root 920 Jan 22 2019 sushe_start.sh
-rw-r--r-- 1 root root 521 Aug 17 2021 sushe_start.sh.sig
drwxr-xr-x 3 root root 4096 Sep 2 2009 .themes
-rw------- 1 root root 0 Oct 28 2010 .Xauthority
-rw-r--r-- 1 root root 0 Apr 23 2013 .Xdefaults
-rw-r--r-- 1 root root 37 Apr 25 2008 .xinitrc
# tree
...
├── log
│ ├── boot.log
│ ├── btmp
│ ├── hotplug
│ ├── lastlog
│ ├── wtmp
│ └── Xorg.0.log
# cat boot.log
Apr 23 12:28:34 +00:00 (none) Mounting virtual file systems: /run /proc /sys /tmp /dev /sys/kernel/security OK
Apr 23 12:28:34 +00:00 (none) Creating IMA keyringApr 23 12:28:34 +00:00 (none) Loading IMA policiesApr 23 12:28:34 +00:00 (none) Bringing up the loopback interface... OK
Apr 23 12:28:34 +00:00 (none) Setting hostname to (none)... OK
Apr 23 12:28:34 +00:00 (none) Populating /dev with device nodes... OK
Apr 23 12:28:35 +00:00 (none) Activating all swap files/partitions... OK
Apr 23 12:28:35 +00:00 (none) /fastboot found, will omit file system checks as requested.
...
But unfortunately this does not give us any insight to the contents of /tmp
🙁.. This directory is protected in VSS v330 SR16 via /etc/rc.d/init.d/mountvirtfs
, where additional mitigation controls have been introduced. Let me briefly take you back to VSS v330 SR9 and mountkrnfs
, the predecessor of mountvirtfs
:
...
if ! mountpoint /run > /dev/null; then
boot_mesg "Mounting /run" ${INFO}
mount /run || failed=1
fi
mkdir -p /run/lock /run/shm
chmod 1777 /run/shm /run/lock
boot_mesg -n "Mounting kernel-based file systems:" ${INFO}
if ! mountpoint /proc >/dev/null; then
boot_mesg -n " /proc" ${NORMAL}
mount -n /proc || failed=1
fi
if ! mountpoint /sys >/dev/null; then
boot_mesg -n " /sys" ${NORMAL}
mount -n /sys || failed=1
fi
if ! mountpoint /dev >/dev/null; then
boot_mesg " ${INFO}/dev"
mount -o mode=0755,nosuid /dev || failed=1
fi
if ! mountpoint /sys/kernel/security >/dev/null; then
boot_mesg " ${INFO}/sys/kernel/security"
mount -n /sys/kernel/security || failed=1
fi
...
his file is responsible for mapping kernel runtime memory to user space during sysinit
as the first executed script of SystemV:
# ls -al nix/etc/rc.d/rcsysinit.d
total 8
drwxr-xr-x 2 root root 4096 Nov 25 2019 .
drwxr-xr-x 11 root root 4096 Oct 12 2010 ..
lrwxrwxrwx 1 root root 21 Oct 12 2010 S00mountkernfs -> ../init.d/mountkernfs
lrwxrwxrwx 1 root root 13 Nov 25 2019 S01ima -> ../init.d/ima
lrwxrwxrwx 1 root root 20 Oct 12 2010 S02consolelog -> ../init.d/consolelog
lrwxrwxrwx 1 root root 17 Oct 12 2010 S05modules -> ../init.d/modules
lrwxrwxrwx 1 root root 14 Oct 12 2010 S10udev -> ../init.d/udev
lrwxrwxrwx 1 root root 14 Oct 12 2010 S20swap -> ../init.d/swap
lrwxrwxrwx 1 root root 17 Oct 12 2010 S30checkfs -> ../init.d/checkfs
lrwxrwxrwx 1 root root 17 Oct 12 2010 S40mountfs -> ../init.d/mountfs
lrwxrwxrwx 1 root root 17 Oct 12 2010 S45cleanfs -> ../init.d/cleanfs
lrwxrwxrwx 1 root root 20 Oct 12 2010 S50udev_retry -> ../init.d/udev_retry
lrwxrwxrwx 1 root root 17 Oct 12 2010 S70console -> ../init.d/console
lrwxrwxrwx 1 root root 18 Oct 12 2010 S80localnet -> ../init.d/localnet
lrwxrwxrwx 1 root root 16 Oct 12 2010 S90sysctl -> ../init.d/sysctl
You will notice that mountfs
is also executed shortly after mountkernfs
, to establish the rest of the file system. If we examine the contents of mountvirtfs
from v330 SR16 there are several additional mitigation controls to prevent persistent access of /tmp
:
...
Loop ()
{
while [ "1" == "1" ]
do
let i=5
done
}
case "${1}" in
start)
# make some sanity checks
if [ ! -x /bin/mountpoint -o ! -x /bin/rm -o ! -x /sbin/shutdown ]
then
Loop
fi
# Make sure /run is available before logging any messages
rm -rf /run
mkdir /run
if ! mountpoint /run >/dev/null; then
mount /run || failed=1
fi
mkdir -p /run/lock /run/shm
chmod 1777 /run/shm /run/lock
log_info_msg "Mounting virtual file systems: ${INFO}/run"
if ! mountpoint /proc >/dev/null; then
log_info_msg2 " ${INFO}/proc"
mount -o nosuid,noexec,nodev /proc || failed=1
fi
if ! mountpoint /sys >/dev/null; then
log_info_msg2 " ${INFO}/sys"
mount -o nosuid,noexec,nodev /sys || failed=1
fi
if ! mountpoint /tmp >/dev/null; then
log_info_msg2 " ${INFO}/tmp"
mount /tmp || failed=1
fi
if ! mountpoint /dev >/dev/null; then
log_info_msg2 " ${INFO}/dev"
...
Ok, there are a few things going on here. First, mountvirtfs
will confirm if execute permissions have been removed from /bin/mountpoint
or /sbin/shutdown
and then block forever. That’s pretty cool, a mitigation control that introduces a DoS event - useful. This was added to prevent an attacker from disabling mountpoint
, which is obviously used by mountvirtfs
to validate the file system, and use of shutdown
, the exit instruction used during sysinit
to kill the bootup sequence.
This now brings us to /tmp
; mountvirtfs
checks if this mountpoint exists and, if not, mounts it. Since this is carried out as the first script during sysinit
there is not much of an attack surface to circumvent this configuration. You may have noticed the rm -rf /run
and mkdir /run
instructions at the start of the script and thought to yourself, “This would be a clever way of removing mountpoint
from this script”. You would not be wrong. However, the default state of the kernel mounts the rootfs
as read-only and, thus, those instructions accomplish nothing.
During disclosure of this issue with Diebold Nixdorf, they found no risk to VSS and no patch was released. As a result, the rm
instruction for /fastboot
and /forcefsck
continues to remain. Based on my research and in the context of SR16, this issue is of low severity and mostly useful for information reconnaissance.
My original research concluded with VSS v3.3.0 SR16 and Superschaf Version 7.2-72242. However, this rm
instruction has also been observed in newer versions of CryptoPro. Below is an excerpt of mountfs
from Superschaf Version 7.6-76204.
log_info_msg "Remounting root file system in read-write mode..."
mount --options remount,rw / >/dev/null
evaluate_retval
# Remove fsck-related file system watermarks.
rm -f /fastboot /forcefsck
# Make sure /dev/pts exists
mkdir -p /dev/pts
# This will mount all filesystems that do not have _netdev in
# their option list. _netdev denotes a network filesystem.
log_info_msg "Mounting remaining file systems...\n"
mount --all --test-opts no_netdev >/dev/null
evaluate_retval
This vulnerability has been MITRE registered as CVE-2024-46916 with the following timeline:
- July 31, 2024 - Vulnerability identification
- August 02, 2024 - Vendor notification
- August 26, 2024 - Vendor acknowledgement and acceptance
- September 13, 2024 - MITRE registration
CVE-2024-46917
To provide background context on the second issue I will be discussing, I would like to return to VSS v3.3.0 SR12. In this release, the rm
and mkdir
instructions were added to remove /root
, /var
, /tmp
, and /mnt
from the system disk prior to the execution of the mount instructions:
# remove and re-create /root /var /tmp /mnt
rm -rf /root /var /tmp /mnt
mkdir /root /var /tmp /mnt
# Remove fsck-related file system watermarks.
rm -f /fastboot /forcefsck
The attack surface I publicly released against this configuration was based on logic within /etc/rc.d/rcsysinit.d/S00mountvirtfs
, where kernel runtime resources were mapped into user space:
if ! mountpoint /proc >/dev/null; then
log_info_msg2 " ${INFO}/proc"
mount -o nosuid,noexec,nodev /proc || failed=1
fi
if ! mountpoint /sys >/dev/null; then
log_info_msg2 " ${INFO}/sys"
mount -o nosuid,noexec,nodev /sys || failed=1
fi
if ! mountpoint /dev >/dev/null; then
log_info_msg2 " ${INFO}/dev"
mount -o mode=0755,nosuid /dev || failed=1
fi
if ! mountpoint /sys/kernel/security >/dev/null; then
log_info_msg2 " ${INFO}/sys/kernel/security"
mount -n /sys/kernel/security || failed=1
fi
In the SystemV initialization process, S00mountvirtfs
was executed before S40mountfs
:
$ ls -l rcsysinit.d
total 0
lrwxrwxrwx 1 root root 21 Apr 26 2021 S00mountvirtfs -> ../init.d/mountvirtfs
lrwxrwxrwx 1 root root 13 Aug 13 2021 S01ima -> ../init.d/ima
lrwxrwxrwx 1 root root 17 Apr 26 2021 S05modules -> ../init.d/modules
lrwxrwxrwx 1 root root 18 Apr 26 2021 S08localnet -> ../init.d/localnet
lrwxrwxrwx 1 root root 14 Apr 26 2021 S10udev -> ../init.d/udev
lrwxrwxrwx 1 root root 14 Apr 26 2021 S20swap -> ../init.d/swap
lrwxrwxrwx 1 root root 17 Apr 26 2021 S30checkfs -> ../init.d/checkfs
lrwxrwxrwx 1 root root 17 Apr 26 2021 S40mountfs -> ../init.d/mountfs
lrwxrwxrwx 1 root root 12 Apr 27 2021 S41at -> ../init.d/at
lrwxrwxrwx 1 root root 17 Apr 26 2021 S45cleanfs -> ../init.d/cleanfs
lrwxrwxrwx 1 root root 20 Apr 26 2021 S50udev_retry -> ../init.d/udev_retry
lrwxrwxrwx 1 root root 17 Apr 26 2021 S70console -> ../init.d/console
lrwxrwxrwx 1 root root 16 Apr 26 2021 S90sysctl -> ../init.d/sysctl
This order of operations allowed for ../init.d/mountfs
to be moved to a mount path in S00mountvirtfs
, disabling the mitigation controls introduced in mountfs
- once mountvirtfs
was executed. However, this was not the only path of compromise, one could also set the immutability bit for the /root
directory. Doing so would disable the ability for the rm -rf /root
command to be carried out as the directory would be immutable.
root# ls -al root
drwx------ 9 root root 4096 May 19 10:00 root
root# chattr +i root
root# rm -rf root
rm: cannot remove 'root/mount_fatstore.sh': Operation not permitted
rm: cannot remove 'root/.scim': Operation not permitted
rm: cannot remove 'root/startx.sh.sig': Operation not permitted
rm: cannot remove 'root/.xinitrc': Operation not permitted
rm: cannot remove 'root/.themes': Operation not permitted
...
This vulnerability has been MITRE registered as CVE-2024-46917 with the following timeline:
- July 31, 2024 - Vulnerability identification
- August 02, 2024 - Vendor notification
- August 26, 2024 - Vendor acknowledgement and acceptance
- September 13, 2024 - MITRE registration
Conclusion
To repeat the message I had discussed during my talk, it is a cat & mouse game - attempting to protect an unencrypted Linux partition from offline data manipulation. Even with static integrity validation, there will always be a bypass method if the full content of the disk is not validated and/or encrypted.
For additional background content please see the following references:
- DefCon32 - Where’s the Money: Defeating ATM Disk Encryption
- White Paper - Where’s the Money: Defeating ATM Disk Encryption
- Vynamic Security Suite - Vynamic Security Hard Disk Encryption Secure Sensitive Consumer Data
- SEC Consult - Manipulation of pre-boot authentication in CryptWare CryptoPro Secure Disk for Bitlocker
- Diebold Nixdorf - EULA for Vynamic Security Suite 3.0
- Secure Disk for BitLocker
- Flowblok's Blog - Shell Startup Scripts
- ATMIA - ATM Operator Training
- CVE-2023-24062
- CVE-2023-24063
- CVE-2023-24064
- CVE-2023-28865
- CVE-2023-33206
- CVE-2023-40261