Firmware

Embedded Linux Architecture

  • ARM

  • MIPS

  • Custom ones

Firmware in Embedded Linux

combination of all code running on the device, with many packages:

  • Bootloader

    • initializations

    • HW description

    • It boots up the kernel image

    • It passes control to the kernel with pointers to:

      • info about HW

      • kernel command line

  • Kernel

  • File System

  • Other resources

Main pentesting activities

  • Find secrets

    • backdoor

    • passwords

    • API keys

    • private certificates

  • Vulnerabilities in binaries

  • Binaries and Firmware emulation

  • Creation of a malicious firmware image

  • Reverse engineering of the binaries

Firmware retrieval

From:

  • Web

  • Dump of the device's flash chip

  • Sniffing of the OTA update

  • Reverse engineering of mobile application and similar software

Firmware vulnerability analysis

  • Extract the firmware and look for specific component related security issues

  • Configuration files and hardcoded secrets

  • Use qemu to emulate firmware binaries and firmware

  • Attach it to a debugger and analyse

  • Reverse patches and diff two different versions of a firmware

  • Analyse firmware binaries (.bin, .img, .pkg, .zip)

  • Run strings and hexdump on them

Extract File System

Manual method

  • Identify the firmware type

    file <firmware_file>
  • Identify the offset of the file system by grepping the HEX and ASCII stringified firmware by the FS magic number (i.e. hsqs for most common file system SquashFS)

    hexdump -C <firmware_file> | grep -i 'hsqs'
  • Dump the file system from the firmware

    dd if=<firmware_file> bs=1 skip=$((0x<offset>)) of=<output_fs>

    -if=<firmware_file>: input file -of=<output_fs>: output file -if: buffer size (1 = 1MB) -skip=$((0x<offset>)): starts from offset 0x<offset>

  • Extract FS files from the FS (e.g. SquashFS)

    sudo apt install squashfs-tools
    unsquashfs <input_fs>
  • Navigate the File system

    cd squashfs-root

Automated method

Extraction with multiple FS support using binwalk

  • Show different sections

    binwalk <firmware_file>
  • Extract the various sections

    binwalk -e <firmware_file>
  • Show Entropy (to understand if the firmware is encrypted or not)

    binwalk -E <firmware_file>
  • Hex diff betwween two files

    binwalk -W <file1> <file2>
  • Recursively extract files from deeply embedded archives

    binwalk -Me firmware.bin

Extract protected archive of the firmware with password

fcrackzip -u -b -v <zip_file.zip> 
  • -u: unzip

  • -b: brute-force

  • -v: verbose

Encrypted Firmware

Constant entropy for every offset

XOR

  • Look for the end of the where there are many NULL bytes

hexdump -C <firmware_file> | tail -n 100
  • Look for the identified sequence in the firmware file (e.g. aa aa aa aa aa aa aa aa)

hexdump -C <firmware_file> | grep -i "aa aa aa aa aa aa aa aa aa"
  • Decrypt the binary using the previous pattern as keys

hexdump -C <firmware_file> | python3 decrypt_firmware.py "aa aa aa aa aa aa aa aa" > decrypted_firmware.bin

decrypt_firmware.py

#!/usr/bin/env python3
import sys

# Convert hex string to bytes
key = bytes.fromhex(sys.argv[1])

# Read input as bytes
data = sys.stdin.buffer.read()

# XOR decryption
result = bytearray()
key_len = len(key)

for i, b in enumerate(data):
    result.append(b ^ key[i % key_len])

# Write raw binary to stdout
sys.stdout.buffer.write(result)
  • Run binwalk on decrypted_firmware.bin

Binary emulation

  • Install qemu

    sudo apt update
    sudo apt install qemu-user
  • Identify the Linux architecture (e.g. ARM, MISP and Endianess)

    file <binary_to_be_run>
  • Move to the root folder of the firmware FS

  • Copy the qemu-<arch> binary to the current folder to avoid issues when you will change the root folder in the next step

  • Run the emulator on the binary (e.g. mips) and change the root folder to the current folder for the emulation (to be sure that dynamic links or references to other programs are working)

    • Big Endian

      sudo chroot . qemu-mips <binary_to_be_run>
    • Little Endian

      sudo chroot . qemu-mipsel <binary_to_be_run>
    • Debug option (-g)

      sudo chroot . qemu-mipsel -g <gdb_port> <binary_to_be_run>

Attach debugger

  • Launch the program with qemu and -g <gdb_port> (qemu will be pending for the connection of the debugger)

gdg-multiarch <binary_file>

After launching it:

  • set architecture type

set architecture mips
  • set a breakpoint

  • connect to the remote qemu execution

target remote localhost:<gdb_port>
  • continue

c

Category

GDB Command

Description

Start/Run

gdb ./program

Start GDB with executable

Start/Run

run [args] or r [args]

Run program with optional arguments

Start/Run

start

Run until main() and stop

Start/Run

kill

Stop running program

Start/Run

quit

Exit GDB

Breakpoints

break main or b main

Break at main()

Breakpoints

break file.c:42 or b file.c:42

Break at line 42 of file.c

Breakpoints

break function_name

Break at start of function

Breakpoints

break *0x8048400

Break at specific memory address

Breakpoints

delete [n]

Delete breakpoint number n

Breakpoints

info breakpoints or i b

List all breakpoints

Breakpoints

disable [n] / enable [n]

Temporarily disable/enable breakpoint n

Execution

continue or c

Resume execution until next breakpoint

Execution

next or n

Step over to next line (don’t enter functions)

Execution

step or s

Step into function calls

Execution

finish

Run until current function returns

Execution

until [line]

Run until a specific line

Execution

return [value]

Force current function to return value

Inspect

print var or p var

Print variable value

Inspect

display var

Automatically display variable each step

Inspect

info locals

Show all local variables in current function

Inspect

info args

Show function arguments

Inspect

x/[format] address

Examine memory at address, e.g., x/16xb buf

Inspect

x/[format] $<register_name>

Examine content of register <register_name>

Inspect

info registers or i r

Show CPU registers

Inspect

bt or backtrace

Show call stack

Inspect

frame [n]

Switch to stack frame n

Inspect

up / down

Move up/down the call stack

Watchpoints

watch var

Stop when var changes

Watchpoints

rwatch var

Stop when var is read

Watchpoints

awatch var

Stop when var is read or written

Watchpoints

info watchpoints

List all watchpoints

Watchpoints

delete watch n

Delete watchpoint n

Assembly

set disassembly-flavor intel

Use Intel syntax

Assembly

disassemble [function]

Show assembly for function

Assembly

layout src

TUI mode showing source code

Assembly

layout asm

TUI mode showing assembly

Assembly

layout regs

TUI mode showing registers

Misc

info threads

List all threads

Misc

thread n

Switch to thread n

Misc

set args arg1 arg2

Set program arguments without restarting

Misc

set $<register_name>="VALUE"

Set the value of the register <register_name>

Misc

help

Show GDB help

Misc

help command

Show help for a specific command

Monitor system calls

sudo strace chroot . ./qemu-mips-static <binary_file>

Firmware emulation with FAT

Backdooring a firmware

Use Firmware-mod-kit to repack the firmware with changes:

Extract the firmware

  • Move to firmware-mod-kit folder

  • Extract the Firmware

sudo extract-firmware.sh <firmware_bin>
  • Access to the results folder <firmware_name>:

cd <firmware_name>
<firmware_name>/
├── image_parts/
│   ├── header.img
│   └── rootfs.img
├── logs/
└── rootfs/

Compile the C backdoor

  • Compile the program with a multi-platform compiler Buildroot and move to the folder

make menuconfig
  • Set all the parameters you want (e.g. architectures, external libraries and so on)

  • Identify the correct compiler in output/host/usr/bin:

cd output/host/usr/bin
ls -al
  • Compile the program

sudo ./mipssel-builroot-linuxòuclibc-gcc <program>.c -static -o <program>

Re-pack the firmware

  • Move back to firmware-mod-kit folder

  • Compile the firmware

sudo ./build-firmware.sh -nopad -min
  • Move to the previously created <firmware_name> folder where you will find the repacked firmware new-firmware.bin

<firmware_name>/
├── image_parts/
│   ├── header.img
│   └── rootfs.img
├── logs/
├── new-filesystem.squashfs
├── new-firmware.bin
└── rootfs/

Last updated