Shooting Yourself in the .flags – Jailbreaking the Sonos Era 100

We discussed this vulnerability during Episode 231 on 18 December 2023

A series of issues in the Sonos Era 100 speaker that was exploited for pwn2own by nccgroup. During some initial recon on the speaker, they discovered breakout pads for serial/UART, as well as pins for Embedded MultiMedia Card (EMMC) communication, which allowed them access to the flash which stored firmware. While most of the data on this flash is encrypted and verified, the boot logs they obtained over UART suggested that this speaker is similar to other sonos devices that were researched in the past, and so they looked for vulns in the U-Boot image using plaintext binaries from other devices as a guide.

Issue 1: Arbitrary environment config Due to the CONFIG_ENV_IS_NOWHERE flag not being set in the U-Boot image, it will attempt to load the environment from the flash at 0x500000. By writing to this offset as an attacker, control over the environment can be obtained for critical variables such as bootcmd. This essentially bypasses the intent of the password-protected console.

Issue 2: Unchecked return on setenv() One of the environment variables that eventually makes its way to the linux kernel command line args is bootargs, and the bootcmd=sonosboot handler will try to ensure this variable is set properly. The problem is, they never check if this setenv() call succeeded, and it’s possible to make it fail as an attacker by marking the bootargs variable as a read-only variable in the bootcmd flags, which they could do by passing .flags=bootargs:sr. An attacker could now have control over kernel cmdline args, including the ability to set a custom initrd (ramdisk) offset to get code execution.

Issue 3: Improper header validation on firmware image While the first two issues can allow code exec, getting arbitrary data at a known location is still somewhat difficult due to the firmware images being encrypted and signed. However, the header is in plaintext, and contains a field for where the kernel binary is via kernel_offset. While this kernel_offset field is usually 0x40, it’s not validated, and so by increasing it, you can give yourself a ‘cave’ so to speak of data that won’t be validated against the kernel binary signature check.

Putting these issues together can be used to obtain code execution on the speaker.