Carbonara is a memory corruption exploit targeting MediaTek devices. It allows loading unverified code during the Download Agent upload process for V5 and V6, basically letting you bypass the signature checks.

How the Exploit Works

Carbonara abuses the boot_to command in DA1 to overwrite the stored reference hash. When you send boot_to followed by something like a4de2200000000002000000000000000, that hex string tricks boot_to into writing at the DA2 hash position.

Breaking down that hex string:

  • a4de22 translates to 0x22dea4 in little endian, which is the exact memory address where the legitimate DA2 hash is stored
  • The 20000000 is 0x20 (32 bytes) in little endian, this is the hash length parameter telling DA1 to expect a 32-byte SHA-256 hash (would be 0x14 for SHA-1)
  • The rest of the zeros are just a conseguence of packing the two parameters as two u64 (unsigned long long)

The attack works like this: send boot_to, send that crafted payload that points to the hash storage location and specifies the hash length, then send your malicious DA2’s hash. This overwrites the reference hash with your own. When the actual malicious DA2 gets uploaded later through the normal process, its calculated hash matches the reference hash you just planted, so verification passes.

The device returns a DA_HASH_MISMATCH error (0xc0070004) after the first attempt, but the hash is already overwritten in memory at this point. You just resend boot_to and load your malicious DA2, which now passes verification because its hash matches what you planted.

Technical Details

Communication with DA1 happens through the XFlash or XML protocol. The boot_to command expects:

  • Length and load address of the data that’s going to be sent
  • The actual data

Carbonara tricks boot_to into writing at arbitrary addresses by crafting specific payloads. The DA2 hash location (like 0x22dea4 in the example) varies between DA versions but can be found by scanning DA1’s binary for the legitimate DA2’s hash.

The vulnerability exists because boot_to accepts any address, even those in DA1’s own memory space (typically around 0x200000), while DA2 normally loads at 0x40000000. In particular, the data being read from serial com is first stored into a buffer, then wrote into memory without first performing out of bounds checks or veryfing it beforehand. This gap lets you overwrite DA1’s stored hash before loading your modified DA2.

The Fix

MediaTek fixed this by completely removing user control over the load address in boot_to. The patched versions now ignore whatever address you send and always force DA2 to load at 0x40000000.

Since the hash is stored in DA1’s memory space (around 0x200000 range), you can no longer reach it with boot_to. Simple but effective, they just hardcoded the address instead of trying to validate user input.

Before:

After:

Going more in depth of how this works, we need to understand what the channel->read function does in this context. This function reads the data the host is sending from the serial port vcom, taking as arguments the buffer and length of the data being read.

The boot_to cmd expects the host to send some metadata about the data that it is going to be sent.

As we seen above, the first data sent is the boot address and size of the data that follows. In the vulnerable DA, the address is trusted and used as the point where to put the data that is going to be read.

In addition, DA Extensions might be unavailable for Carbonara patched DAs even if a new exploit is found, because of the fix hardcoding the boot_to address.

Checking Vulnerability

This can be checked by looking for specific patterns in the DA1 region. The mtkclient implementation checks for these byte patterns that indicate the patch is present.

Generally:

  • Devices released before 2024 are vulnerable unless a DA update has been issued
  • Devices released during or after 2024 aren’t guaranteed to work, but there’s been instances (e.g. Motorola G24, Honor 200 Lite)

Note

Unless the device is unfused, a signed DA1 is required for this exploit to work!