CVE-2021-21903
A stack-based buffer overflow vulnerability exists in the CMA check_udp_crc function of Garrett Metal Detectors’ iC Module CMA Version 5.0. A specially-crafted packet can lead to a stack-based buffer overflow during a call to strcpy. An attacker can send a malicious packet to trigger this vulnerability.
Garrett Metal Detectors iC Module CMA Version 5.0
https://garrett.com/security/walk-through/accessories
9.8 - CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
CWE-120 - Buffer Copy without Checking Size of Input (‘Classic Buffer Overflow’)
The Garrett iC Module provides network connectivity to either the Garrett PD 6500i or Garrett MZ 6100 models of walk-through metal detectors. This module enables a remote user to monitor statistics such as alarm and visitor counts in real time as well as make configuration changes to metal detectors.
The Garrett iC Module exposes a discovery service on UDP port 6877. The “CMA Connect” software, used to interact with the iC modules from a remote system, can broadcast a particularly formatted UDP packet onto the network. iC modules that receive this packet will reply with various descriptors such as MAC address, serial number, and location. A function call to strcpy within the CRC validation logic of these UDP packets is vulnerable to a stack-based buffer overflow.
The UDP packet is composed of a set of text fields, delimited by semi-colons and terminated with a CRC value. The CRC is represented as the ASCII-encoded decimal representation of the CRC. For example, if the calculated CRC of the payload is 0xA7CF
then the UDP packet will be terminated with the string “42959”.
The following chunk of code is responsible for identifying the offset of the CRC field and copying it into a fixed-size buffer.
.text:0001D178 SUB R3, R11, #-msg_buf
.text:0001D17C MOV R0, R3 ; s
.text:0001D180 MOV R1, #0x3B ; ';' ; c
.text:0001D184 BL strrchr
.text:0001D188 STR R0, [R11,#end_of_data] [1] v2 = strrchr(msg, ';') // Find the last
.text:0001D18C LDR R3, [R11,#end_of_data]
.text:0001D190 ADD R2, R3, #1
.text:0001D194 STR R2, [R11,#end_of_data] [2] end_of_data = v2 + 1
.text:0001D198 CMP R3, #0 [3] if ( !v2 ) { return 1 }
.text:0001D19C BEQ loc_1D23C
.text:0001D1A0 SUB R3, R11, #-input_crc_str [4] char input_crc_str[8]
.text:0001D1A4 MOV R0, R3 ; s
.text:0001D1A8 MOV R1, #0 ; c
.text:0001D1AC MOV R2, #8 ; n
.text:0001D1B0 BL memset [4] memset(input_crc_str, 0, 8)
.text:0001D1B4 SUB R3, R11, #-input_crc_str
.text:0001D1B8 MOV R0, R3 ; dest
.text:0001D1BC LDR R1, [R11,#end_of_data] ; src
.text:0001D1C0 BL strcpy [5] strcpy(input_crc_str, end_of_data)
The function identifies the CRC field by searching for the last semi-colon in the packet and then moving the pointer forward one byte. This is referred to in the code as end_of_data
but may also be thought of as start_of_crc
. The software allocates an 8-byte character array, called input_crc_str
, on the stack and then will strcpy
the CRC into input_crc_str
. The call to strcpy
is unbounded and no validation occurs to ensure the data following the last semi-colon is appropriately sized.
Therefore, supplying a UDP packet whose CRC field is sufficiently longer than expected will cause a straightforward buffer overflow. This overflow directly leads to attacker control of the program counter, which may be seen in the debugger output below.
Thread 2 "cma" received signal SIGSEGV, Segmentation fault.
0x4d4d4d4c in ?? ()
──────────────────────────────────────────────────────────────────────────────────────────────── registers ────
$r0 : 0x1
$r1 : 0x0
$r2 : 0x6b251d4c
$r3 : 0x1
$r4 : 0x0
$r5 : 0xb636b6b0 → "eth0"
$r6 : 0x0
$r7 : 0x152
$r8 : 0xbefffbe0 → 0xb6ff86d0 → 0xb6ff8db8 → 0x00000001
$r9 : 0xb6ff86d0 → 0xb6ff8db8 → 0x00000001
$r10 : 0xb636c460 → 0x00000001
$r11 : 0x4d4d4d4d ("MMMM"?)
$r12 : 0xa
$sp : 0xb636b6a0 → 0xb636b700 → 0x00000000
$lr : 0x0001d22c → <check_udp_crc+248> mov r3, #1
$pc : 0x4d4d4d4c ("LMMM"?)
$cpsr: [negative ZERO CARRY overflow interrupt fast THUMB]
─────────────────────────────────────────────────────────────────────────────────────────── code:arm:THUMB ────
[!] Cannot disassemble from $PC
[!] Cannot access memory at address 0x4d4d4d4c
────────────────────────────────────────────────────────────────────────────────────────────────────────────────
2021-08-17 - Vendor Disclosure
2021-11-10 - Talos granted disclosure extension
2021-12-13 - Vendor patched
2021-12-15 - Talos tested patch
2021-12-20 - Public Release
Discovered by Matt Wiseman of Cisco Talos.