Talos Vulnerability Report

TALOS-2021-1311

Microsoft Azure Sphere Security Monitor SECTION_ABIDepends denial of service vulnerability

August 10, 2021
CVE Number

CVE-2021-26430

Summary

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.

Tested Versions

Microsoft Azure Sphere 21.01

Product URLs

https://azure.microsoft.com/en-us/services/azure-sphere/

CVSSv3 Score

6.0 - CVSS:3.0/AV:L/AC:L/PR:H/UI:N/S:C/C:N/I:N/A:H

CWE

CWE-20 - Improper Input Validation

Details

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.

Timeline

2021-06-08 - Vendor Disclosure
2021-08-10 - Public Release

Credit

Discovered by Claudio Bozzato and Lilith >_> of Cisco Talos.