None
A denial of service vulnerability exists in the Security Monitor SECTION_ABIDepends functionality of Microsoft Azure Sphere 21.01. A specially-crafted set of syscalls can lead to denial of service (boot loop), requiring manual intervention for recovery. An attacker can flash a malicious image to trigger this vulnerability.
The versions below were either tested or verified to be vulnerable by Talos or confirmed to be vulnerable by the vendor.
Microsoft Azure Sphere 21.01
Azure Sphere - https://azure.microsoft.com/en-us/services/azure-sphere/
6.0 - CVSS:3.0/AV:L/AC:L/PR:H/UI:N/S:C/C:N/I:N/A:H
CWE-20 - Improper Input Validation
Microsoft’s Azure Sphere is a platform for the development of internet-of-things applications. It features a custom SoC that consists of a set of cores that run both high-level and real-time applications, enforces security and manages encryption (among other functions). The high-level applications execute on a custom Linux-based OS, with several modifications to make it smaller and more secure, specifically for IoT applications.
Assuming that one has the ability to flash a user application, via OTA, USB, or with elevated privileges (e.g. kernel code execution), there exists a sizable lump of code within the parsing of the application’s metadata that an attacker could get to be executed. A metadata section is appended to the end of every firmware file provided to Azure Sphere, from Trusted Keystore to lowly user application. There are no exceptions. So let us now examine a sample metadata section:
000074b0 34 58 34 4d 05 00 00 00 49 44 24 00 02 00 00 00 |4X4M....ID$.....| // [1]
000074c0 d0 62 bf 16 7e f4 e6 11 83 9c 00 15 5d 9f 1e 00 |.b..~.......]...|
000074d0 47 19 90 35 1d 22 70 4b a7 93 29 fb a9 6f 55 16 |G..5."pK..)..oU.|
000074e0 53 47 18 00 8f 9e 62 6c 3f 4b 87 94 97 4d 57 fe |SG....bl?K...MW.|
000074f0 cc f8 3b 4d 8c c2 a4 f7 01 00 00 00 44 42 28 00 |..;M........DB(.|
00007500 a7 ee 74 60 00 00 00 00 50 6c 75 74 6f 6e 20 52 |..t`....Pluton R| // [2]
00007510 75 6e 74 69 6d 65 00 00 00 00 00 00 00 00 00 00 |untime..........|
00007520 00 00 00 00 00 00 00 00 52 56 04 00 03 00 00 00 |........RV......|
00007530 4e 50 0c 00 01 00 00 00 01 00 00 00 01 00 00 00 |NP..............|
00007540 94 00 00 00 fe 77 16 ca ff dc f9 24 6f 74 3e c1 |.....w.....$ot>.|
00007550 00 3c c3 9e 2c dc 2e d5 c0 a9 58 0c 93 7d 69 0f |.<..,.....X..}i.|
00007560 f9 43 4f d2 ab 40 9c 09 0c 8e af 83 60 e1 69 4b |.CO..@......`.iK|
00007570 7b 63 0a bd d1 0b 4f f8 93 f7 ab d1 7c 93 79 94 |{c....O.....|.y.|
00007580 99 72 75 72 |.rur|
Without much knowledge, we can first see the magic bytes denoting a metadata section: 4X4M
[1], and at [2] we can see that this data was dumped from a ‘Pluton Runtime’ image. Breaking down the first 0x10 bytes for more detail:
000074b0 34 58 34 4d // 4X4M
000074b4 05 00 00 00 // # of sections
000074b8 49 44 // [1] Section identifier
000074ba 24 00 // [2] Size of section
000074bc 02 00 00 00 // [3]
The first two bytes after the number of sections denote the current section’s identifier; in our case ID
at [1], which is the IdentityMetadataSection
. The next uint16_t
is the size of the section’s data [2] (little endian), and the IdentityMetadataSection
itself starts at [3]. Each section type has a different corresponding structure, and the list of defined section types is as such:
0x4244 => SECTION_Debug
0x4441 => SECTION_LegacyABIDepends
0x4449 => SECTION_Identity
0x444e => SECTION_ABIDepends
0x474c => SECTION_Legacy
0x4753 => SECTION_Signature
0x4d43 => SECTION_Compression
0x4f52 => SECTION_RequiredFlashOffset
0x5041 => SECTION_LegacyABIProvides
0x504e => SECTION_ABIProvides
0x5054 => SECTION_TemporaryImage
0x5652 => SECTION_Revocation
After all the sections also lies a signature, length 0x40 or 0x60 bytes, that is used in order to verify the legitimacy of the image itself.
In this advisory we discuss the simplistic SECTION_ABIDepends
, whose structure looks like so:
struct SECTION_ABIDepends{
uint32_t list_size;
uint64_t abi_list[list_size / 8];
}
While this metadata structure can only have a max size of 0x80 bytes, the list_size
field is never checked by secmon, though it acts as the conditional for a reading loop:
803d8590 int32_t end_of_0x444e = &metadata_0x444e_0x80[0]:4 + (metadata_0x444e_0x80[0].d << 3) // [1]
803d8594 int64_t* cursor_0x444e = &metadata_0x444e_0x80
803d859a while (end_of_0x444e != cursor_0x444e + 4) // [2]
803d859e int32_t cursor_0x444e_val = *(cursor_0x444e + 4)
803d85a4 if (*(cursor_0x444e + 8) == 3 && biggest_entry u< cursor_0x444e_val)
803d85a8 biggest_entry = cursor_0x444e_val
803d85aa cursor_0x444e = cursor_0x444e + 8
803d85ae outbuf->highest_abi_needed = biggest_entry
At [1], we see secmon grabbing our SECTION_ABIDepends
length and adding it to the pointer in memory pointing to the section. After that, the only thing letting us escape the loop at [2] is if the entire buffer is walked, which can easily be set large enough to be out of bounds.
While completely useless for information disclosure, this code path is hit during a rather pivotal section of execution: boot. As such, assuming there is a user application with a malformed SECTION_ABIDepends
metadata section, the device is rendered a brick until manual recovery, resulting in a denial of service.
An attacker with enough privileges can use SMSyscallInstallStagedImages
(together with other necessary syscalls) to install such an image and trigger the denial of service.
2021-06-08 - Vendor Disclosure
2021-08-10 - Public Release
Discovered by Claudio Bozzato and Lilith >_> of Cisco Talos.