Skip to content

Latest commit

 

History

27 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Hacking the Icotera i4882: A Multi-Year Quest for Open Firmware

Chapter 1: The Black Box in the Corner

For years, the Icotera i4882 sat on my desk like an impenetrable fortress. Provided by fiber ISPs across Scandinavia, this optical network terminal (ONT) and router was designed to be completely locked down. No open ports, no public firmware downloads, and no straightforward way to see what was running under the hood.

Every attempt at breaking through via standard network attacks hit a dead end. But as anyone passionate about hardware reverse engineering knows, when software walling leaves you stranded, you look at the physical silicon.


Chapter 2: Shaking the Silicon (NAND Glitching into U-Boot)

I knew that if I could intercede early enough in the boot sequence, I could intercept control before the Operating System locked the door behind itself. The target was the SECOND-stage bootloader: U-Boot.

I attached my probes to the serial lines and located the NAND flash memory chip on the PCB. The plan was Fault Injection (NAND Glitching).

  1. The Target: The data/control lines between the System-on-Chip (SoC) and the NAND flash memory.
  2. The Execution: Right as the router powered on and U-Boot attempted to read its environment parameters and boot commands from flash, I momentarily shorted a NAND data pin to ground.
  3. The Result: The deliberate read corruption triggered a boot failure in U-Boot’s automated script execution (bootcmd). Instead of launching the locked Linux kernel, the bootloader dropped straight into an interactive command shell:
U-Boot > 

We were inside the bootloader.


Chapter 3: Dumping the Flash & The Ghidra Breakthrough

From the U-Boot shell, I extracted the raw contents of the NAND flash memory to my workstation. Mounting the extracted file system revealed the internal binaries and shared libraries powering the router.

In one shared library file: libcliic.so. This library handled internal command-line interface utilities, firmware validation, and update routines.

I loaded libcliic.so into Ghidra for static reverse engineering. After tracing cryptography-related symbols, I stumbled upon a crucial function: ict_cli_ssl_decrypt_firmware

Looking closely at the references inside this function, two static data arrays emerged in the data segment, starting at address DAT_0041f648:

DAT_0041f648        XREF[1]:     ict_cli_ssl_decrypt_firmware:004
0041f648 10 DF 0C 2A CF FB 9E 22 1E C4 0E 9B D3 A6 70 DB
0041f658 F9 DF 58 BD 55 3D 6C 44 4E D6 B8 10 C7 0A F7 83
...

The raw bytes weren't the plain AES key. The disassembly revealed a custom XOR transformation and bit-shifting loop applied across these arrays to reconstruct the actual decryption key in memory.


Chapter 4: Reconstructing the Key Generator

To extract the real key without having to execute the code live on the MIPS/ARM architecture, I translated the Ghidra decompiler output into a standalone Python script:

def generate_ict_key():
    # DAT_0041f648 (64 bytes)
    data_648 = bytes.fromhex("10df0c2acfbf9e221ec40e9bd3a670dbf9df58bd553d6c444ed6b810c70af7833301e728458393a1c2c4aabb3b7d36d7314e8b345ef2fff6d2e3eed22d0011a1")
    
    # DAT_0041f688 (32 bytes)
    data_688 = bytes.fromhex("3301e728458393a1c2c4aabb3b7d36d7314e8b345ef2fff6d2e3eed22d0011a1")

    local_90 = list(data_648[:64])
    local_50 = list(data_688[:32])
    
    uVar5 = 0
    for i in range(64):
        if uVar5 > 31:
            uVar5 = 0
            
        b1 = local_50[uVar5]
        b2 = local_90[i]
        
        # XOR and bitwise manipulations derived from Ghidra decompilation
        res_xor = b1 ^ b2
        uVar2 = (res_xor << 24) & 0xFFFFFFFF
        
        uVar3 = (uVar2 & 0x18ffffff) | ((res_xor << 31) & 0xFFFFFFFF) |                 ((uVar2 >> 31) << 24) | ((((uVar2 & 0x7effffff) << 6) >> 31) << 30) |                 ((((uVar2 & 0x7effffff) << 1) >> 31) << 25)
        
        val = (uVar3 >> 24) & 0xe7
        val |= ((((uVar2 & 0x3cffffff) << 5) >> 31) << 29) >> 24
        val |= ((((uVar2 & 0x3cffffff) << 2) >> 31) << 26) >> 24
        val |= (((uVar3 << 4) >> 31) << 28) >> 24
        val |= (((uVar3 << 3) >> 31) << 27) >> 24
        
        local_90[i] = val & 0xFF
        uVar5 += 1

    return bytes(local_90[:32])

key = generate_ict_key()
print(f"AES-256 Key: {key.hex()}")

Executing this gave us the master AES-256 decryption key: c47bd740511eb0c13b00250417db62301389cb91d0f3c94d39ac6a4357506744


Chapter 5: Unpacking the Firmware

With the key in hand, analyzing the structure of an official Icotera .bin firmware file showed:

  • Bytes 0–128: Proprietary header and metadata
  • Bytes 129–144: The 16-byte Initialization Vector (IV)
  • Bytes 150+: The AES-256-CBC encrypted payload

Combining this knowledge into a single Bash pipeline:

tail -c +150 firmware.bin |   openssl enc -aes-256-cbc -nosalt -d   -K 'c47bd740511eb0c13b00250417db62301389cb91d0f3c94d39ac6a4357506744'   -iv $(dd skip=129 count=16 if=firmware.bin bs=1 status=none | hexdump -e '16/1 "%02x"')   -nopad -out firmware.tar.gz

Running tar -xzf firmware.tar.gz finally cracked open the encrypted vault that had been sealed for years.


Chapter 6: The Crown Jewel

I didn't achieve a full local root shell on the live running router system yet—that remains an active milestone for the future. But unpacking the firmware exposed the raw configuration files, internal scripts, and hidden Web Interface credentials.

Deep inside the default configuration parameters, I discovered the operator-level account credentials used by ISPs to control the Web UI:

Device UserInterface X_GETOUI_Webui Operator Username operator
Device UserInterface X_GETOUI_Webui Operator Password L4ss0tF4ng4ralg3n!

After years of curiosity and endless trial and error, the black box was finally transparent.


Conclusion & Future Work

This journey started with physical hardware hacking and ended with full firmware decryption and hidden credential extraction.

Technical Specifications & Architecture

Through serial interface analysis and firmware extraction, the specific hardware architectures for the Icotera devices were identified:

  • Icotera i4882: Powered by a MIPS architecture processor.
  • Icotera i3552 / i3552i: Powered by a Synopsys ARC700 processor.
  • UART Serial Interface: Both devices expose UART headers operating at 115200 8N1 (115200 baud, 8 data bits, no parity, 1 stop bit).
  • FileSystem: Decrypted firmware payloads contain a standard SquashFS file system, which can be extracted using standard tools like binwalk or unsquashfs.

Final Findings & Security Constraints

After extensive testing and dynamic analysis, several core security boundaries were mapped out:

  1. U-Boot Intercept: Interrupting the early boot process via CTRL+X opens a password prompt. However, static reverse engineering in Ghidra revealed that the password check is either non-functional or bypassed—the bootloader drops to a console regardless of the input provided.
  2. Cryptographic Firmware Signing: Flashing custom/modified firmware to the NAND flash is currently impossible. Icotera enforces strict RSA cryptographic signature verification during the flash and boot phases. Without the private vendor key, any modified image will be rejected or brick the device.
  3. Local Root Shell: Achieving a persistent local root shell on a running unit was not achieved due to signed image constraints and hardened execution environments.
  4. Primary Achievement: Despite the signed firmware barrier, the complete reverse engineering of the firmware decryption pipeline allows for full offline inspection of the system, extracting hardcoded ISP operator credentials, configuration files, and internal logic.

About

working firmware decryption and key extraction for Icotera i3552i / i4882 routers via NAND glitching and Ghidra reverse engineering

Resources

Stars

1 star

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages