# 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

  ```bash
  file <firmware_file>
  ```

  ![](https://3928478158-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FhjMjdRXwO33Lfo7uCpl6%2Fuploads%2Fgit-blob-a0104602734eecc42dc566673bc2e6461828bdc9%2Ffirmware_file.png?alt=media)
* 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*)

  ```bash
  hexdump -C <firmware_file> | grep -i 'hsqs'
  ```

  ![](https://3928478158-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FhjMjdRXwO33Lfo7uCpl6%2Fuploads%2Fgit-blob-cd3527b598620312149b513a23a08c7ef9af7cf3%2Ffs_offset.png?alt=media)
* Dump the file system from the firmware

  ```bash
  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>`

  ![](https://3928478158-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FhjMjdRXwO33Lfo7uCpl6%2Fuploads%2Fgit-blob-44bc1025454ce08889b3592b510dcc33cfba60c6%2Ffs_dump.png?alt=media)
* Extract FS files from the FS (e.g. *SquashFS*)

  ```bash
  sudo apt install squashfs-tools
  unsquashfs <input_fs>
  ```

  ![](https://3928478158-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FhjMjdRXwO33Lfo7uCpl6%2Fuploads%2Fgit-blob-1e5815a94ec0662dbc19209eb9180af4c779e42c%2Funsquashfs.png?alt=media)
* Navigate the File system

  ```bash
  cd squashfs-root
  ```

### Automated method

Extraction with multiple FS support using `binwalk`

* Show different sections

  ```bash
  binwalk <firmware_file>
  ```
* Extract the various sections

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

  ```bash
  binwalk -E <firmware_file>
  ```
* Hex diff betwween two files

  ```bash
  binwalk -W <file1> <file2>
  ```
* Recursively extract files from deeply embedded archives

  ```bash
  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

```bash
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`)

```bash
hexdump -C <firmware_file> | grep -i "aa aa aa aa aa aa aa aa aa"
```

* Decrypt the binary using the previous pattern as keys

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

***decrypt\_firmware.py***

```python
#!/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`

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

  ```bash
  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***

    ```bash
    sudo chroot . qemu-mips <binary_to_be_run>
    ```
  * ***Little Endian***

    ```bash
    sudo chroot . qemu-mipsel <binary_to_be_run>
    ```
  * ***Debug option (***`-g`***)***

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

![](https://3928478158-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FhjMjdRXwO33Lfo7uCpl6%2Fuploads%2Fgit-blob-5032447e312b817b63e8d4e59a14ece2ba7b6070%2Fqemu_busybox.png?alt=media)

### Attach debugger

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

```bash
gdg-multiarch <binary_file>
```

After launching it:

* set architecture type

```bash
set architecture mips
```

* set a breakpoint
* connect to the remote qemu execution

```bash
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

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

## Firmware emulation with FAT

* [Firmadyne](https://github.com/firmadyne/firmadyne)
* [Firmware Analysis Toolkit](https://github.com/attify/firmware-analysis-toolkit)

## Backdooring a firmware

Use [Firmware-mod-kit](https://github.com/rampageX/firmware-mod-kit) to repack the firmware with changes:

### Extract the firmware

* Move to **firmware-mod-kit** folder
* Extract the Firmware

```bash
sudo extract-firmware.sh <firmware_bin>
```

* Access to the results folder `<firmware_name>`:

```bash
cd <firmware_name>
```

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

### Compile the C backdoor

* Compile the program with a multi-platform compiler [Buildroot](https://github.com/buildroot/buildroot) and move to the folder

```bash
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`:

```bash
cd output/host/usr/bin
ls -al
```

* Compile the program

```bash
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

```bash
sudo ./build-firmware.sh -nopad -min
```

* Move to the previously created `<firmware_name>` folder where you will find the repacked firmware `new-firmware.bin`

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