Decrypting Samsung NVMe Firmware
Background
After remembering the issue of SanDisk-derivative drives failing after 32,768 hours and 40,000 hours respectively, I was interested in what the firmware for this Samsung 970 EVO Plus might look like.
Obtaining
This story begins innocently: We simply head over to Samsung's firmware website. Immediately under the "Samsung SSD Firmware" grouping, we find "NVMe SSD-970 EVO Plus Firmware". Nice - no need to search further!
It claims to be a 26 MB ISO. That's... a little big, but what do I know about storage device firmware, anyway? A warning sits ominously at the bottom:
- Notice: ISO files may be used only via DOS using a bootable CD/DVD.
Of course, it's.. an ISO. This isn't just ISO 9660 with the NVMe firmware + maybe an updater installed... this is a flat-out ISOLINUX-made ISO that you boot.
We can use 7z
to inspect the ISO a little more closely:
EFI
boot
bzImage
initrd
isolinux
...huh. Okay, what's file bzImage
say?
bzImage: Linux kernel x86 boot executable bzImage, version 4.5.3 (root@amit.kp-ubuntu) #10 SMP Tue Oct 18 17:34:21 IST 2016, RO-rootFS, swap_dev 0X7, Normal VGA
Samsung Linux
My NVMe's vendor wants me to stop everything I'm doing and boot a random operating system.
Let's continue. boot/grub/grub.cfg
has the following:
menuentry "Samsung" {
set gfxpayload=keep
linux /bzImage
initrd /initrd
}
That's not as bad, I suppose. Let's take a look at initrd
- it's gzip compressed, so nothing fancy.
> cd initrd
> cat etc/os-release
NAME=Buildroot
VERSION=2016.05
ID=buildroot
VERSION_ID=2016.05
PRETTY_NAME="Buildroot 2016.05"
Oh, Buildroot! I suppose that if you're going to make an entire Linux-based environment to flash firmware, you might as well use Buildroot. The entire thing appears to be very simple, containing just enough to have Busybox up-and-running via uClibc.
Let's poke around in /root
. We can immediately find fumagician
as a subdirectory - "firmware update magician", presumably. (Unfortunately, there's no /root/.ash_history
with anything fun.)
fumagician
Let's take a peek:
> ls root/fumagician
4B2QEXM7.enc
DSRD.enc
fumagician
fumagician.sh
4B2QEXM7
... hm, where have I seen that before? Aha:
> sudo nvme list
Node FW Rev
--------------------- --------
/dev/nvme0n1 4B2QEXM7
Good, we're on the right path! At least I don't need to update this thing's firmware...
As their file extension suggests, 4B2QEXM7.enc
and DSRD.enc
appear to be encrypted. They both begin with 015EA399 90DE95CD FD05435A 40B8734A
.
Let's take a look at fumagician
itself. We'll use Ghidra.
It turns out there's not much of a challenge there, as the binary ships with full symbols:
- We can immediately find a function named
SDRM_AES256_Decryption
.- It's referenced by two functions:
DSRDMgr::DecryptFileToBuffer
DSRDMgr::DecryptFileToFile
- Good, we know it is truly encrypted.
- It's referenced by two functions:
- The key is passed via a buffer written by
DSRDMgr::DecodeBase64
. - We can immediately find a
std::basic_string
passed fromthis
. - By creating the structure and finding references, we can find a base64 string hardcoded within main:
QE9rvhXMNZY15kG5/asu4Ig4UHirMeTs3wZmW8WUp7s=
. - Indeed, this decodes to 32 bytes:
404F6BBE15CC359635E641B9FDAB2EE088385078AB31E4ECDF06665BC594A7BB
, perfect for a 256-bit AES key.
Hm.. alright, then. Can't hurt to try.
Extracting
Around this time, I just searched to see if anyone else put in effort to decrypt. It turns out one GitHub user already had, noting this is AES-256-ECB. Curiously, the key they used to decrypt differs - unclear if it does across firmware versions, or model revisions.
So, let's give it a try:
openssl enc -aes-256-ecb -d -in DSRD.enc -out DSRD.bin -nopad -K 404F6BBE15CC359635E641B9FDAB2EE088385078AB31E4ECDF06665BC594A7BB
After editing DSRD.bin
, we see a header of _icianMAG_@*!.8&
- good! Per the binary, this is intended. Afterwards, we see a uint32_t reading to be 129 bytes - the length of the XML within:
ALL
ALL
3B2QEXM7
4B2QEXM7
4B2QEXM7_30211125.bin
We can then do the same to 4B2QEXM7.enc
. After the header and length, we find the notorious PK
file magic, indicating that the contents are... a ZIP file.
> unzip 4B2QEXM7.bin
Archive: 4B2QEXM7.bin
inflating: 4B2QEXM7_30211125.enc
Huh. Well, let's try decrypting it with the same method.
Manipulating the firmware
After opening our now decrypted firmware in Hex Fiend once more, we see the first 0x600 bytes appear to be binary data - seemingly encrypted, unlike previous firmware versions per analysis by others. Thankfully, we then see FW_IMAGE_META_SIGNATURE_________4B2QEXM7
- indicating we did decrypt correctly! Unfortunately, 0x4000, the binary continues to be encrypted.
It appears that this firmware does not appear to utilize the same key as previously. This brings this blog post to a halt - will have to continue researching :)
Conclusion
To reiterate, my NVMe's vendor wants me to stop everything I'm doing and boot a random operating system.
I think I would somewhat understand if this was only available via a Windows-only tool. Instead, there's a Linux distrubution with needless - and useless - obfuscation, hindering firmware research. Where did we go wrong?
(Dear Samsung: Given that this drive updates via standard Firmware Download Image/Commit - it would be nice to have this on LVFS :)