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:

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
A screenshot of Hex Fiend, showing a file 176 bytes in length. The first few bytes appear to be a header, continuing with padding. XML data is then present, and further continuing with padding.

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:

<SSD>
<SN>ALL</SN>
<MOD>ALL</MOD>
<CURFW>3B2QEXM7</CURFW>
<NEWFW>4B2QEXM7</NEWFW>
<MFW>4B2QEXM7_30211125.bin</MFW>
</SSD>

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 :)