A denial-of-service vulnerability exists in the networkd mDNS functionality of Microsoft Azure Sphere 20.07. A specific bind call can cause a denial of service, requiring manual recovery. An attacker can bind to port 5353 to trigger this vulnerability.
Microsoft Azure Sphere 20.07
https://azure.microsoft.com/en-us/services/azure-sphere/
5.9 - CVSS:3.0/AV:L/AC:H/PR:N/UI:N/S:C/C:N/I:N/A:H
CWE-284 - Improper Access Control
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.
The main controller of all things networking related on Azure Sphere is the networkd
binary. Normally spawned as uid 1001 in /mnt/config/uid_map
, this binary is granted all the permissions mentioned in its app_manifest.json
:
"Policy": {
"Groups": [
"net-adm",
"net-restricted",
"wifi-config",
"sys-log",
"tmp-admin",
"rtc"
],
"LinuxCapabilities": [
"CAP_NET_ADMIN",
"CAP_NET_RAW",
"CAP_NET_BIND_SERVICE",
"CAP_SYS_TIME"
]
}
In examining what exactly this binary utilizes these permissions for, we see the following:
> cat /proc/net/udp
sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode ref pointer drops
74: 0100007F:0035 00000000:0000 07 00000000:00000000 00:00000000 00000000 1001 0 216 2 00000000 0
89: 00000000:0044 00000000:0000 07 00000000:00000000 00:00000000 00000000 1001 0 261 2 00000000 0
254: 00000000:14E9 00000000:0000 07 00000000:00000000 00:00000000 00000000 1001 0 218 2 00000000 0
Which in a more simplified version (without networkd
’s 1001 uid however) looks more like:
udp 0 0 127.0.0.1:53 0.0.0.0:* -
udp 0 0 0.0.0.0:68 0.0.0.0:* -
udp 0 0 0.0.0.0:5353 0.0.0.0:* -
The only other binary on the Azure Sphere platform that actually binds to a service like this is gatewayd
, binding to TCP port 0.0.0.0:443 for a webserver that allows for configuration over the sl0
usb interface. But looking back at networkd
, the usual guess would be that udp:53
is for dns and udp:5353
for multicast dns requests, but currently this cannot be gleaned as firewall restrictions prevent us from sending to udp:53
. udp:5353
is much more interesting, allowing one to send traffic to it, even unprivileged, but whether or not it processes this traffic has not yet been discovered.
Since networkd
binds to port udp:5353
, a port that anyone can bind to without privileges (since it’s over 1024), there exists a race condition on startup of the machine: if an application can bind to udp:5353
, the device becomes unresponsive until and a manual recovery over usb (via azsphere dev recover
) is required.
There would be more of a description of what actually goes on here, but when triggered, the device locks up and it’s impossible to get any more info out of it. It’s not a continuous bootloop, since we can see that there’s no abort
call if we look at networkd
at this bind()
call:
// rebase address: 0x10000
0003aae4 0df14603 add r3, sp, #0x46
0003aae8 41f2e940 movw r0, #5353 // [1]
0003aaec 03f90f87 vst1.8 {d8}, [r3]
0003aaf0 13ab add r3, sp, #0x4c
0003aaf2 03f90f87 vst1.8 {d8}, [r3]
0003aaf6 0223 movs r3, #2
0003aaf8 adf84430 strh r3, [sp, #0x44] {var_3c} {0x2}
0003aafc d9f7d2e9 blx #htons
0003ab00 adf84600 strh r0, [sp, #0x46] {var_3c+0x2} // [2]
0003ab04 1022 movs r2, #0x10
0003ab06 606f ldr r0, [r4, #0x74] {big_dns_struct::mdns_sock}
0003ab08 3946 mov r1, r7 {var_3c}
0003ab0a d9f72eed blx #bind // [3]
0003ab0e 0028 cmp r0, #0
0003ab10 1eda bge #0x3ab50
0003ab12 d9f7a2ed blx #__errno_location // [4]
0003ab16 0568 ldr r5, [r0]
0003ab18 0021 movs r1, #0
0003ab1a 5348 ldr r0, [pc, #0x14c] {data_3ac68}
0003ab1c 002d cmp r5, #0
0003ab1e b8bf it lt
0003ab20 6d42 rsbs r5, r5, #0
0003ab22 c5f31305 ubfx r5, r5, #0, #0x14
0003ab26 65f31301 bfi r1, r5, #0, #0x14
0003ab2a 68f31f51 bfi r1, r8, #0x14, #0xc
0003ab2e 7844 add r0, pc {data_58b12}
0003ab30 45ea0855 orr r5, r5, r8, lsl #20
0003ab34 ddf75efa bl #log_errno // [5]
0003ab38 2846 mov r0, r5
0003ab3a fdf7cffc bl #check_if_that_worked
0003ab3e 48b9 cbnz r0, #0x3ab54
At [1], we see port 5353 being loaded into the htons()
call and stored into a sockaddr_in
structure at [2]. If the bind()
at [3] fails due to another application having bound to that port already, then it falls through to the __errno_location()
function at [4], logs the error at [5], and continues on its merry way. Shortly after this race, however, there is a soft-lockup that immediately stops all functionality of the device.
It should be noted that due to the race-condition occurring on execution of the networkd
binary, one would need a separate vulnerability to trigger this vulnerability. Either the ability to cause networkd
to crash (at which point it will restart), or the ability to maintain persistence on the device (e.g. flashing an arbitrary application) such that the exploit runs on startup before networkd
can bind.
2020-08-18 - Vendor Disclosure
2020-12-18 - Public Release
Discovered by Lilith >_>, Claudio Bozzato and Dave McDaniel of Cisco Talos.
This vulnerability has not been disclosed and cannot be viewed at this time.