index.md (5180B)
1 +++ 2 title = 'Exploitation for embedded systems' 3 +++ 4 # Exploitation for embedded systems 5 Typical embedded systems vulnerabilities: 6 - weak access control/authentication 7 - insecure config 8 - vulnerable web interfaces 9 - improper use of cryptography 10 - programming errors: 11 - can easily lead to buffer overflows, memory corruption 12 - classic defenses (ASLR, canaries..) may not be present 13 14 ## ARM architecture 15 32-bit ("aarch32") 16 - 32 bit regs and address space 17 - little/big endian 18 - 32-bit fixed-width instructions, 16-bit with Thumb instruction set 19 - Thumb instruction set: 20 - 15-bit encoding for improved code density 21 - different processor states: "ARM" and "Thumb", switched via `bx` and `blx` instruction 22 23 64-bit ("aarch64") 24 - new instruction set, 64-bit regs and address space, 32-bit instruction length 25 - user-space compatible with aarch32 26 27 Application binary interface: Procedure Call Standard for the ARM Architecture (AAPCS) 28 29 ![AAPCS table](aapcs.png) 30 31 ARM Linux system calls: 32 - arguments in r0-r6 33 - return value r0 34 - EABI: system call via `svc #0` instruction with call number in r7 35 - OABI: system call via `swi NR` instruction 36 - (`swi` and `svc` are the same instruction) 37 38 39 ## ARMv6-M (Cortex-M0+) 40 Thumb-2, so classic 32-bit ARM not supported. 41 Has a built-in interrupt controller. 42 Optional privileged/unprivileged and MPU (memory protection unit) support, both present on STM32G0B1RET6 (the board we have). 43 44 Protected Memory System Architecture (PMSAv6): 45 - provides memory protection unit (MPU) 46 - separates flat address space into regions, smallest size 32 byte 47 - implementation-dependent number of regions 48 - requires privileged/unprivileged extension 49 - can be configured via MMIO 50 - provides access permissions and "execute never" (XN) bit 51 52 ![PMSAv6 bits table](pmsav6-bits-table.png) 53 54 Nested Vector Interrupt Controller (NVIC) 55 - interrupts can occur (and be served) while an interrupt is already being handled 56 - vector set up via VTOR 57 - up to 32 external interrupts, 6 predefined exceptions 58 59 xPSR: combined program status register: 60 - application program status register (APSR): flags 61 - interrupt program status register (IPSR): exception number 62 - execution program status register (EPSR): thumb-bit (always 1) 63 64 ![xPSR diagram](xpsr.png) 65 66 Assembly: 67 - arithmetic: `MNEMONIC{s} Rdest, Rsrc1, Rsrc2` (`Rsrc2` can also be `#imm`) 68 - S-suffix updates condition flags, optional for ADD/SUB but mandatory for other arithmetic 69 - examples: 70 - `ADD r0, r1, r2`: `r0 = r1 + r2` 71 - `EORS r0, r0, r0`: `r0 = r0 XOR r0`, updating flags 72 - `SUBS r3, r4, #8`: `r3 = r4 - 8`, updating flags 73 - `MOV`: can only mov to register, from register/immediate 74 - `MOVT` moves immediate into top halfword 75 - `MVN` moves negative (logical ones' complement) 76 - `PUSH` 77 - only registers 78 - r0 to r12 and lr 79 - example: `PUSH {r0, lr}` 80 - `POP` 81 - only registers 82 - r0 to r12 and pc, or r0 to r12 and lr 83 - examples: `POP {pc}`, `POP {r0-r6, lr}` 84 - load/store: `LDR`, `STR` 85 - `MNEMONIC Rdst, [Rsrc, #offset]` (`#offset` can also be register) 86 - examples: 87 - `LDR r0, [pc, #16]`: `r0 = *(pc+16)` 88 - `STR r0, [r3, #0]`: `*r3 = r0` 89 - branches: 90 - `B`: branch relative to `pc`, allows `c` suffix for conditional 91 - `BX` (branch and exchange): branch via register and exchange instruction set 92 - "exchange instruction set" means to switch between THUMB and ARM mode 93 - information of mode is stored in LSB of address 94 - this works because in ARM, instructions always aligned on 2-byte or 4-byte granularity 95 - ARMv6-M is Thumb-2 only, so all addresses need LSB set to 1 96 - `BLX` (branch with link and exchange): set `lr` and branch relative to `pc` or via register 97 - `BL` (branch with link): sets link register and branches relative to `pc`, like a `call` 98 99 ## Exploitation techniques 100 32-byte ARM usually has null bytes, but if you switch to thumb mode, instruction set compression makes null bytes unlikely: 101 102 ```asm 103 add r3, pc, #1 104 bx r3 105 ``` 106 107 Example shellcode (from [shell-storm](https://shell-storm.org)): 108 109 ```asm 110 add r3, pc, #1 // switch to thumb mode 111 bx r3 112 113 mov r0, pc // prepare arguments 114 adds r0, #8 115 subs r1, r1, r1 // r1 = 0 116 subs r2, r2, r2 // r2 = 0 117 118 movs r7, #11 // set syscall number 119 svc 1 // execute syscall 120 121 str r7, [r5, #32] // set up data: /bin/sh\0 122 ldr r1, [r5, #100] 123 strb r7, [r5, #12] 124 lsls r0, r5, #1 125 ``` 126 127 ROP on ARM: 128 - if XN memory, or no OS with system call abstraction 129 - strategy: overwrite stack with attacker-controlled data, chain "gadgets" to form meaningful program 130 - usually fewer gadgets than x86, e.g. `pop {pc}` is much less common than `ret` 131 - don't forget about Thumb-bit -- faults if set wrongly 132 133 Heap exploitation: 134 - implementations are application/device specific 135 - usually fewer consistency checks than on desktop 136 - often need reverse engineering heap implementation 137 - might be on vendor-provided toolchain though 138 139 Interrupt oriented programming: 140 - interrupts push SR+PC onto stack, interrupts are nestable, and ROM resides below RAM in memory 141 - so, stack growing exploit: 142 - nest interrupts until RAM exceeded 143 - stack grows into ROM 144 - unable to write SR+PC, so subsequent return from IRQ will use value from ROM