The Quest for the Unfused Device

For years, "unfused" devices—where manufacturers neglect to blow security fuses enabling Secure Boot—existed only as legends in mobile security research. These rare configurations skip critical signature checks, allowing execution of custom code from the BootROM onward. Recently, a researcher encountered such a device: a POS terminal with a Qualcomm QCM2150 chip. This discovery unlocked a rare opportunity to execute a full-chain attack from BootROM to Android root, bypassing every layer of Qualcomm's security architecture.

Why "Unfused" Matters

Qualcomm's Secure Boot relies on eFuses storing a hash of the root public key. When unfused:

$ fastboot getvar secure
secure: no

The system defaults to a non-secure state, skipping root certificate validation. Images still need valid signatures, but the root key can be arbitrary—enabling custom-signed firmware execution.

Bypassing the Firehose Loader Shortage

With no public Firehose loader for the obscure QCM2150, the researcher pivoted creatively:

"Could I use the SBL1 to replace the Firehose loader?"

They patched and re-signed the device's SBL1 (Secondary Boot Loader) to execute in EDL mode. Key hurdles:
1. Signature Validation: Reverse-engineered Qualcomm's 3-tiered certificate structure using sectools for re-signing:

$ python sectools.py secimage -i sbl1.mbn -c config/2150/2150_secimage.xml -s

2. Blind Execution: Patched an infinite loop → reboot sequence to confirm code execution:
LOAD:08019E48 B.W boot_hw_reset  ; Force reboot into EDL after patch

Forcing a Normal Boot from EDL

SBL1 in EDL mode lacks critical initialization. Two critical patches enabled normal boot progression:

  1. EDL Mode Detection Override:
    LOAD:08019D40 boot_dload_entry
    MOVS R0, #0  ; Always return "not EDL"
    BX LR
  2. Hardcoded Storage Type: Set flash type to MMC_FLASH (5) since storage isn't initialized in EDL.

After patching, the device booted into Aboot (Android Bootloader)—but with stripped-down fastboot commands.

Weaponizing Fastboot

With only getvar and download functional, the researcher transformed getvar into a memory-access gadget:

void cmd_getvar(char *arg, char *data, unsigned sz) {
    int *ibuff = (int *)0xA0100400;
    if (ibuff[0] == 0x4ead) { // Magic opcode
        int value = *(int *)ibuff[1]; // Read arbitrary address
        // ... return value via fastboot
    }
}

A hidden upload command in Aboot accelerated memory dumping:

def Upload(self, dst_file, length):
    self._protocol.SendCommand(b'upload')
    buff = self._protocol.usb.BulkRead(length)
    # Save to file

Kernel Patching: The Gzip Gambit

To gain root, the kernel (boot.img) required patching. A critical constraint: recompressed size must match the original. The solution exploited gzip format nuances:

  1. Decompress kernel, patch syscalls for root.
  2. If compressed size increases: replace low-entropy strings (e.g., logs) to reduce size.
  3. If smaller: pad using gzip's optional filename field:
    /* Kernel decompressor skips filename without length checks */
    if (zbuf[3] & 0x8) { while (*strm->next_in++); }

Implications: A Rare but Powerful Attack

This exploit chain demonstrates:
- Supply Chain Risks: Unfused devices bypass hardware-rooted trust.
- Defense Depth Matters: Missing Firehose loaders forced creative SBL1 reuse—a testament to layered security.
- Persistence Without Persistence: All patches were memory-resident; no disk writes needed.

As manufacturers phase out test modes, such vulnerabilities will vanish—but until then, they remain potent attack vectors.


Source: Exploiting a Qualcomm QCM2150 with Secure Boot Disabled