ENPM809V

Baremetal Security

Agenda

  • Baremetal Embedded vs. Linux Embedded
  • Short Introduction to ARM64E
  • Walk Through of Embedded Security

What are we going to be talking about?

Embedded Systems

  • Embedded systems are systems that are designed for a specific function
    • They are not general purpose like our computers
  • Significantly smaller in processing power, memory, and storage than general purpose computers
  • Can have an operating system (generally Linux)
  • Can have RTOS (real time operating systems)
  • Don't have to have an operating system (baremetal)

Examples of Embedded Systems

  • Medical devices
  • Parts in Automotive Systems
    • Engine control units, infotainment systems
  • Industrial robots
  • Air conditioning systems
  • Digital cameras
  • etc.

Embedded Linux

  • Same exact kernel as general purpose Linux, but compiled to meet certain constraints
    • Higher reliability
    • Tighter security
    • System constraints
  • Many distributions support it (including Ubuntu)
  • The way it operates depends on how you compile it, the distribution, and the goal of the device.

RTOS (FreeRTOS)

  • Small operating system designed to be fast and lightweight
  • Created to only have the things you need for an operating system
    • Low-overhead
  • Less configurable
  • Able to easily be put on microarchitectures
    • Doesn't require an memory management unit as part of the hardware

Baremetal Embedded Systems

  • No operating system at all!
  • This means no features that operating systems bring
    • Virtual Memory - You will be coding directly to physical memory
    • File System Implementation
    • Any user space/kernel space features
  • You should do this if size of the firmware and processing power really matters.

Why do we care?

  • These systems might have access to sensitive parts of a system.
    • We need to ensure that they are protected
  • Botnets are a real thing! Especially with internet connected embedded systems
  • You are only as strong as your weakest link!
  • These devices might contain sensitive information! (Video, audio, statistics, controlling a car).

What we have to keep in mind?

  • This might be one part of the entire system.
    • The embedded device may not do anything that an attacker can do malicious, but it might give insight
    • Pivot to another device
    • Persistence
    • Entry vector

Challenges with Baremetal

  • You will not have symbols!
  • While at compile time the ELF symbols are generated, the firmware will not have it on the device generally
  • Controlling the device is sensitive!
    • You can break the hardware if you are not careful
  • Depending on the device,  you may not be able to do much. Even if you have an exploit

What if we find a vulnerability?

  • Need to update! But this is challenging
    • Might require physical access to the device
    • Updates may never happen (not worth it to the vendor)
  • Add layers of abstraction
    • Insecure embedded devices shouldn't be connected to sensitive components/the internet
    • Secure Boot
    • Trusted Platform Module
    • Binary Transformations
  • etc.

Examples of Insecure Embedded Systems

  • Cars - The cambus is generally known to have vulnerabilities
    • Well protected through layers of abstraction
  • Cheap IOT devices - Cameras, smart speakers, not from name brand
    • Even name brands have issues
  • Medical devices
    • this is scary....
  • Electrical grids
    • Also scary....

How do we work with this?

No Hardware? No Problem

  • We are going to be using QEMU to emulate the baremetal firmware!
  • QEMU is a full system emulator
  • Allows for us to run cross architecture software as well!

How do we do this?

  • Go to https://www.qemu.org/download/
  • Download the latest version of QEMU
  • Unzip it on your virtual machine
  • Install Dependencies:
    • sudo apt-get install git libglib2.0-dev libfdt-dev libpixman-1-dev zlib1g-dev ninja-build
  • ./configure
  • make
  • sudo make install

What else do we need?

  • sudo apt install gdb-multiarch
    • This adds ARM support (for x86 machines)
    • Nice to also have many architectural support
  • Optional:
    • sudo apt install gcc-arm-none-eabi gcc-aarch64-none-eabi

Running the Firmware

  • Standard: qemu-system-aarch64 -M raspi0 -kernel $(KERN).img -serial null -serial stdio [-semihosting] (be careful when using -semihosting)
  • GDB: qemu-system-arm -M raspi0 -kernel kernel.img -serial null -serial stdio -S -gdb tcp::XXXX -boot c
    • To connect, run gdb[-multiarch] and then do target remote localhost:XXXX
    • If you have the ELF file, you can do gdb <kernel.elf> when launching GDB for symbols

Reverse Engineering

  • Radare2 or Ghidra are the best for baremetal firmware!
  • You will need to figure out the base address of the firmware image
    • Bets way to determine this is by looking at the strings
  • We will go through this when we demo

Accessing today's Challenges

  • https://github.com/ENPM809V/baremetal-firmware-challenges

Basics of ARM Assembly

To simplify things, we will focus on 32 bit ARM; however, the principals are the same!

 

32 bit arm processors are still common as they are smaller!

What is ARM Architecture

  • ARM is a RISC based architecture
    • Fewer instructions than x86
  • Commonly used in smaller devices (IOT, Phones, Embedded Systems, etc.)
    • Becoming more popular in general purpose computers (Apple Silicon)

What does RISC mean?

  • Reduced Instruction Set Computing
    • Fewer instructions that CISC based architectures
  • Instructions can be executed more quickly because it reduces clock cycles per isntructions
  • Means that authors/compilers need to write efficient ARM assembler.

More About ARM

  • ARM is a Load/Store based model
    • Move instructions can't access memory directly
  • It has a mode called thumb mode
    • We will get into this
  • More registers
  • Multi-endianness (generally stick with little endian)
  • Instructions are fixed length generally
    • ARM Mode - 4 bytes
    • Thumb mode - 2 or 4 bytes.

ARM Registers

Aarch64 (ARM64) Registers

CSPR

CSPR

ARM Vs. Thumb

  • Two main states of the ARM processor
  • The difference between ARM and Thumb is the instruction sets
    • Not privilege level
  • ARM is always 32 bits while thumb can be either 16 bit or 32 bit
    • All processors support the same ARM instruction set
    • Not all processors support the same thumb instruction set
  • ARM supports conditional execution instructions
  • Thumb instructions have a .w suffix
  • To switch between states, use either BX or BLX and set/unset the reigster's least significant bit to/from 1.

ARM Instruction Set

MNEMONIC{S}{condition} {Rd}, Operand1, Operand2
  • MNEMONIC     - Short name (mnemonic) of the instruction

  • {S} - An optional suffix

    • If specified, the condition flag is updated based on the result of the operaiton 

  • {condition} - Condition necessary to execute the instruction
  • {Rd} - Destination register
  • Operand1 - The first operand (either register or immediate value)
  • Operand2 - Second operand (either register or immediate value with optional shift)

 

What this looks like

ADD   R0, R1, R2         
ADD   R0, R1, #2         
MOVLE R0, #5             
MOV   R0, R1, LSL #1

Accessing Memory

  • Unlike x86_64, we cannot memory directly with the MOV instruction
  • We have to use ldr and str instructions
    • ldr Ra, [Rb, Offset] - Ra is the destination, Rb is the base, Offset is either a register or immediate as an offset
    • ldr Ra, [Rb, Index]! - Pre-indexed value
      • Ra = Rb+Index
      • Rb = Rb+Index
    • ldr Ra, [Rb], index - Post-indexed value
      • Ra = Rb
      • Rb = Rb+index
  • Note: index is still an offset, not like an array offset index

Accessing Memory

  • Unlike x86_64, we cannot memory directly with the MOV instruction
  • We have to use ldr and str instructions
    • ldr Ra, [Rb, Offset] - Ra is the destination, Rb is the base, Offset is either a register or immediate as an offset
    • ldr Ra, [Rb, Index]! - Pre-indexed value
      • Ra = Rb+Index
      • Rb = Rb+Index
    • ldr Ra, [Rb], index - Post-indexed value
      • Ra = Rb
      • Rb = Rb+index
  • Note: index is still an offset, not like an array offset index

Accessing Memory

  • Unlike x86_64, we cannot memory directly with the MOV instruction
  • We have to use ldr and str instructions
    • str Ra, [Rb, Offset] - Ra is the source, Rb is the base, Offset is either a register or immediate as an offset
      • Rb is unmodified
    • str Ra, [Rb, Index]! - Pre-indexed value
      • Ra = Source
      • Memory Location = Rb+Index
      • Rb is modified to Rb+Index
  • Note: index is still an offset, not like an array offset index

Accessing Memory

  • Can have a shifter applied to the end as well!
    • Example: str r2, [r1, r2, LSL#2]
    • ldr r3, [r1], r2, LSL#2  
  • Can load and store multiple at a time (won't go into this right now)

Stack

  • We can either have ascending or descending stack!
  • Yes this is a weird concept, but this will help us when trying to access values for buffer overflows/stack based attacks/vulnerabilities.
  • This can be found by looking at the load/store instructions
    • Empty = Stack pointers points to the next space on the stack that is not utilized
    • Full = stack points at the last thing before an empty slot

Stack

Stack

Caling Convention

  • Three main parts: prologue, body, epilogue
  • Prologue saves previous state
  • Body is the main part of the code
  • Epilogue cleans up the function and loads the previous state

Sounds almost exactly like x86 right?

Caling Convention

  • Three main parts: prologue, body, epilogue
  • Prologue saves previous state
  • Body is the main part of the code
  • Epilogue cleans up the function and loads the previous state

Sounds almost exactly like x86 right?

Caling Convention

push {r11, lr}
add  r11, sp, #8
sub  sp,  sp, $16
mov r0, #1
mov r1, #2
bl  some_func
sub  sp, r11, #8
pop  {r11, pc}

Caling Convention

/* azeria@labs:~$ as func.s -o func.o && gcc func.o -o func && gdb func */
.global main

main:
	push   {r11, lr}    /* Start of the prologue. Saving Frame Pointer and LR onto the stack */
	add    r11, sp, #0  /* Setting up the bottom of the stack frame */
	sub    sp, sp, #16  /* End of the prologue. Allocating some buffer on the stack */
	mov    r0, #1       /* setting up local variables (a=1). This also serves as setting up the first parameter for the max function */
	mov    r1, #2       /* setting up local variables (b=2). This also serves as setting up the second parameter for the max function */
	bl     max          /* Calling/branching to function max */
	sub    sp, r11, #0  /* Start of the epilogue. Readjusting the Stack Pointer */
	pop    {r11, pc}    /* End of the epilogue. Restoring Frame pointer from the stack, jumping to previously saved LR via direct load into PC */

max:
	push   {r11}        /* Start of the prologue. Saving Frame Pointer onto the stack */
	add    r11, sp, #0  /* Setting up the bottom of the stack frame */
	sub    sp, sp, #12  /* End of the prologue. Allocating some buffer on the stack */
	cmp    r0, r1       /* Implementation of if(a<b) */
	movlt  r0, r1       /* if r0 was lower than r1, store r1 into r0 */
	add    sp, r11, #0  /* Start of the epilogue. Readjusting the Stack Pointer */
	pop    {r11}        /* restoring frame pointer */
	bx     lr           /* End of the epilogue. Jumping back to main via LR register */

Caling Convention

  • 32 bit ARM keeps state, parameters, return values, on the stack.
    • Stack Frame = bottom of stack, Frame Pointer = top of the stack
  • 64 bit ARM (aarch64) keeps first seven parameters in x0-x7 (v0-v7 for floating point)

Using Immediate Values

  • Can't just use any immediate values
  • After allocating bits for instruction menomic, condition codes, destination register, operand register, etc., we have 12 bits left
    • Can only have 4096 different values
  • Anything greater means we have to split it up into multiple parts!

Using Immediate Values

How to learn more?

https://azeria-labs.com/writing-arm-assembly-part-1/ - Seven part series

https://modexp.wordpress.com/2018/10/30/arm64-assembly/

https://medium.com/codex/reverse-engineering-bare-metal-low-level-kernel-images-with-qemu-getting-started-c705b7b14d35

https://medium.com/@ragnarsecurity/reverse-engineering-bare-metal-kernel-images-part-2-6a52a4afa3ef

https://medium.com/geekculture/reverse-engineering-bare-metal-firmware-part-3-analyzing-arm-assembly-and-exploiting-3b2dbe219f19

Demo

Class Summary

What we covered

  • We went through many vulnerabilities and how they can be exploited
    • ROP Chain
    • Heap
    • Sandboxing
    • Kernel
    • Embedded
  • We also went over tooling for exploiting! (pwntools, GDB)

What we covered

  • These are all necessary to understand how to defend systems
    • Vulnerability research
    • Information Security
    • Penetration Testing
  • You can't defend unless you understand how the exploits work!

What to do from here?

  • Continue on your journey!
    • The closest job that will work at this level is vulnerability research!
      • Learn how to reverse engineer
      • Learn how to use fuzzers
      • Learn how to use SMT Solvers
    • Start learning low-level software engineering!
    • Learn embedded even further
      • hardware (we did not go over)
      • firmware/software (touched the surface)
    • Develop penetration tools
  •  

What to do from here?

  • To do more binary  exploitation
    • Practice CTFs/Pwn.college/Pwnable.kr
    • Work on red teams
    • Develop your own challenges!
  • Gaining more experience
    • Internships/networking - talk with people within the department
    • Research - CMNS has many research opportunities
    • Cyber Security Club - Lots of sponsors!
    • Certifications
      • Not many for binary exploitation, but lots for penetration testing

Do not hack anything you aren't permitted to hack! You have been warned!

My own reflections of the course

  • Great first semester! Challenging but fair
    • Could have made a couple of the homework easier
    • Learned a little bit on how to structure the homework
    • pwn.college infrastructure worked mostly well!
  • What I would change
    • Apply a little more fundamentals and tooling into this course until the new version of ENPM691 is rolled out
    • Maybe spend some time on reverse engineering tooling?
    • Remove embedded??? - Not enough time to cover Userspace, Kernelspace, and Embedded systems
    • Figure out how to foster more collaboration on Discord

My own reflections of the course

  • What did all of you think?
  • If you don't want to say now, send it via the course evaluation
  • What would you liked? What did you want to be changed from next time?

Thank you for a wonderful semester!

No class next week, will be replaced with office hours!

 

This week's office hours: Wednesday 5-6:30pm

ENPM809V Baremetal Embedded Security

By Ragnar Security

ENPM809V Baremetal Embedded Security

  • 46