ARM crash course - hardwear.io

Black Box Debugging of Embedded Systems Introduction: Alexandru Ariciu

Background in hacking Worked as a hacker for my whole life Worked in corporate security before (Pentester) Currently an ICS Penetration Tester / Vulnerability Researcher for Applied Risk

Linkedin: https://www.linkedin.com/in/alexandru-ariciu-856bb566 Twitter: @1n598 Target Device

Data acquisition and transmission device Used in distributed control systems Over 300 directly connected to the internet. More connected internally, mostly in level 0 and level 1 SCADA networks

Prerequisites ARM knowledge Reverse engineering Some hardware hacking (we will cover that part) Goal

Provide a means to develop additional advanced functionality to this device; such as execution of arbitrary code By means of: Injecting the device with modified firmware, to enable debugging on the device, and step trough custom code without bricking the device Complication: There is no datasheet of the chip available, firmware is proprietary

ARM crash course

ARM is a 32 bit RISC processor Processor is little endian

Opcodes are 32bit, and align on a 4 byte boundary All code, data and peripherals share the same 32 bit memory address space After a (re)boot code starts running from 0x00000000 ARM has 16 32-bit base registers and a CPSR (current program status register) Most opcodes can be modified by condition fields

A 3 stage pipeline is used, so PC is 2 instructions (8 bytes) ahead of the currently executed instruction A branch flushes the pipeline Used ARM Instruction Set Mnemonics

Description ADD AND B BL CMP

LDR(B) add two 32 bit values logical bitwise AND of two 32 bit values branch relative +/- 32MB relative branch with link compare two 32 bit values

load a single value from a virtual address in memory store multiple 32 bit registers to memory move a 32 bit value into a register move to ARM register from a status register (cpsr or spsr) move to a status register (cpsr or spsr)

from an ARM register logical bitwise OR of two 32 bit values store multiple 32 bit registers to memory store register to a virtual address in memory subtract two 32 bit values left shift a 32 bit register

LDMFD MOV MRS MSR ORR STMFD STR(B)

SUB LSL ARM Condition field modifiers ARM Registers

Outline Output console

Initial Infection Initial firmware patch with basic debugger Advanced debugging capabilities implementation The process we will follow 1. Evaluate ways to interact with the device (UART, webserver, ) 2. Evaluate ways to make the device run custom code (buffer overflow,

firmware modification, ) 3. Find a suitable place to inject code, to create reliable behavior(e.g. when calling a certain function) 4. Reverse engineer how the device interacts with the interfaces, and find functions such as printf that we can reuse 5. Combine existing functionality with our custom code, to provide (printf) feedback to our code execution

From here on out we can reverse engineer more functions to perform more advanced actions such as; getc, so we can interact with our running code read/write memory to evaluate and modify other system behavior Process: Step 1 Evaluate ways to interact with the device (UART, webserver, )

Interacting with the device: Output Console UART, Serial, JTAG, others Process: Step 2 Evaluate ways to make the device run custom code

Process: Step 3 Find a suitable place to inject code, to create reliable behavior Finding where to put our code: Initial basic debugger Load the code into IDA Select ARM Little Endian as the processor type

Select 0x20 as file offset Click OK Initial basic debugger The idea now is to find a function that is printing stuff in the console We will patch that function to print a string whenever we call that console command

We used sys mem (function for displaying memory in the console) Initial basic debugger We will modify this so that when we call sys mem in the console Hello ! will appear Initial basic debugger

Lets find the function in IDA Initial basic debugger This is the assembly for the function sys mem We will patch this to jump to our initial patch Process: Step 4

Reverse engineer how the device interacts with the interfaces, and find functions such as printf that we can reuse Initial basic debugger It seems our sys mem function already calls a printf function we can reuse

Process: Step 5 Combine existing functionality with our custom code, to provide (printf) feedback to our code execution Initial basic debugger The initial patch will contain three simple elements 1. Load in R0 a string of our choosing

2. Call to printf 3. A return to where we left off (so that the device continues working) Lets dive into some more details Initial basic debugger We will modify the BL sub_0x644c0 to jump to our code Our code will be hosted in a place in the binary (our choosing)

Initial basic debugger BL is relative That is, it will jump not to definitive addresses but to addresses that are calculated relative to the PC position at the moment of the jump BL is more like ADD PC, PC, #jump It also stores the current address in the link register so that the processor

knows where to come back Initial basic debugger The BL instruction has the ARM opcode 0xEB The remainder of the three bytes are the address where to make the jump We need to calculate this

Initial basic debugger

If we are at position X in the binary (0x2714 for us) And we want to jump at Y Then the address where to make the jump is like this (Y-X)/4-0x2 This is because we can only jump 4-bytes at a time(1 instruction=4 bytes), and the PC is always 2 instructions ahead due to instruction pipelining For BL to 0x6440 this would be

(0x644C0-0x2714)/4-0x2 = 0x18769 Initial basic debugger Find space to host the shellcode (for the initial infection) We will terminate one of the strings early so that we dont modify the length of the binary

A good place is where the Free/Memory string is Initial basic debugger We will modify the string at address 0x10F6A2 (with the initial offset it will be 0x10F6A2 +0x20 )

Add 0D 0A 00 00 00 00 (We will end the string with a null terminator) Initial basic debugger

We will store the shellcode starting with 0x10F6A8 So our BL should be like BL *(0x10F6A8) Based on the calculation it is (0x10F6A8-0x2714)/4 0x2 = 0x433E3 So the opcode should be 0xEB0433E3

Lets patch and watch in IDA Initial basic debugger When opening in IDA, the assembly should point to our location if we did the right calculations It seems its working

Initial basic debugger Well the code is not really what we expected But we didnt patch it to contain our code Yet Initial basic debugger This location must be patched to do the following:

Patch a string in memory Load a string in the R0 register Jump to printf Return (load link register in PC) Initial basic debugger Loading a string can be done using

SUB R0, PC, 0x22 This basically will load in R0 a string located 22 bytes before the program counter. So we need to calculate (0x10F6A8 + 0x8) - 0x22 = 0x10F68E The string is Hello ! In the hexeditor, starting at address 0x0010F6AB modify the code to contain 0D 0A 00 48 65 6C 6C 6F 21 0D 00 00 00

We patched the Hello! in the memory without breaking stuff around Initial basic debugger It should look like this in the Hex Editor Initial basic debugger Load the String in R0

0x0010F6C8 : 22 00 4F E2 # SUB R0, PC, 0x22 Lets load again in IDA Initial basic debugger We need to jump to printf The BL is relative to 0x10F6A8 The opcode is 0x0010F6CC : 83 53 FD EB # BL printf(0x644C0)

Initial basic debugger Now we need to return 0x0010F6D0 : 0E F0 A0 E1 # MOV PC, LR (RET) Looks perfect Process: Moving on to advanced debugging

From here on out we can reverse engineer more functions to perform more advanced actions What we developed so far can be used for debugging, in case something goes wrong. We will focus on reverse engineering; getchar(), so we can interact with our running code read/write memory functions to evaluate and modify system behavior

Advanced Debugging Capabilities: Goals We want to create an interactive debugger using the serial input and output We will implement a loop that in pseudocode would be similar to this: While (1): char = getchar() if char == 0:

exit if char == 6: print tst if char == x: do_y() We already have the printf() for writing output We need the getchar() function for capturing user input

Advanced Debugging Capabilities: finding getchar() Advanced Debugging Capabilities: finding getchar() Advanced Debugging Capabilities

Advanced Debugging Capabilities Advanced Debugging Capabilities: our getchar() Byte getchar(void), returns 1 char in R0 Advanced Debugging Capabilities: the assembler We need the assembler to know where cyg_io_read is (and also printf)

The ORG directive helps us doing that The _start directive tells the assembler at what memory address the code is located, so that Branches can be calculated accordingly Advanced Debugging Capabilities: calling getchar() Basic loop that will read a character and exit if its 0 If the character is 6, then the shellcode will print tst

Advanced Debugging Capabilities: printf() If the character is 6, then the shellcode will print tst we define the string; 'tst/n, at the bottom, in the code section Advanced Debugging Capabilities: first compile Write the whole assembly code in a text file

Advanced Debugging Capabilities Assemble everything Link and convert the object code to binary Split the file, so that only the shellcode at 0x11C394 is left

Advanced Debugging Capabilities

We have getc We have printf We can exit The initial loop is done (just with exit functionality) Time to add some debugging capabilities

Advanced Debugging Capabilities Adding functionality for reading words (so that we can use them to read/write memory addresses) Advanced Debugging Capabilities Adding read memory

capabilities (read and display memory to the user) Advanced Debugging Capabilities Adding write memory capabilities (write into the device memory)

Advanced Debugging Capabilities Breakpoints: stop normal execution for analysis of current processor state, and code stepping Creating our breakpoint mechanism: stopping code execution calling our debugger from the running code

We just patch a branch-instruction from where we want to call our debugger, and restore the original instruction on exit Advanced Debugging Capabilities: calling our debugger Storing registers on the stack on initial call

Restoring the registers on exit Advanced Debugging Capabilities Adding read register capabilities Advanced Debugging Capabilities Adding write register capabilities

Advanced Debugging Capabilities Adding breakpoint capabilities: restoring the original code Advanced Debugging Capabilities Literal pools and string definitions

Advanced Debugging Capabilities Adding breakpoint capabilities: writing a new breakpoint Advanced Debugging Capabilities Adding breakpoint capabilities: writing a new breakpoint, and storing the old instruction for restoration on the next call

Advanced Debugging Capabilities We now have a basic debugger that can read/write memory, read/write registers and set breakpoints. We have written everything in Assembler language, now we need to assemble it again Advanced Debugging Capabilities

Uploading the debugger on the device requires some more manual tasks to prepare the binary with a hex editor The sys mem function jump that we used at the beginning must be patched to jump to our shellcode, by hex editor The shellcode must be added to the firmware file at a suitable place such as the address 0x11c394 by hex editor Check the code in IDA before uploading. Make sure the code works

as expected (it should look almost identical with the code in code.s) Advanced Debugging Capabilities Upload the firmware on the device Run sys mem in the console Press 6 to check if it works. The console should display tst Test other capabilities

Next steps Conclusions & implications Use proper firmware verification Use hardware based integrity verification checks Dont connect ICS to the internet

Questions?

Recently Viewed Presentations

  • Présentation PowerPoint - Harvard-Smithsonian Center for ...

    Présentation PowerPoint - Harvard-Smithsonian Center for ...

    According to Perevalov's notation, the studied spectral region concerns the series of vibrational transitions P = 4, 6 and 7 with P the pseudo-quantum number: P = 5v1 + 3v2 + 5v3 + v4 + v5 . MEASUREMENT PROCEDURE To...
  • HEALTH AND SOCIAL CARE SUBSTITUTION NOW Home Secondary

    HEALTH AND SOCIAL CARE SUBSTITUTION NOW Home Secondary

    Installation of assistive devices Refined Bundle 2 Addition to multidisciplinary team of technician, geriatrician, chiropodist, social worker Assistive devices to match patient's needs (from list in Table 5.2b and 5.2c) COHORTS DISTRIBUTION BY AGE GROUP AND GENDER [8 missing data...
  • Microsoft Office 2007 Excel Chapter 8 Formula Auditing,

    Microsoft Office 2007 Excel Chapter 8 Formula Auditing,

    Double-click the Answer Report 1 tab and type Optimal Schedule Answer Report1 as the worksheet name. Click cell A1. Right-click the Optimal Schedule Answer Report1 tab and then point to Tab Color on the shortcut menu. Click Dark Teal, Text...
  • CHAPTER 11.1 Basic Patterns of Human Inheritance

    CHAPTER 11.1 Basic Patterns of Human Inheritance

    11.3 Chromosomes & Human Heredity. Can occur during Meiosis I and II. Nondisjuction is when the sister chromatids do not fully separate resulting in one gamete getting too many chromosomes (Trisomy) and another too few chromosomes (monosomy)
  • Human Geography of South Asia: A Region of

    Human Geography of South Asia: A Region of

    Mountain Kingdoms. Evolving Monarchies • In past, both countries split into religious kingdoms, ruling states • Unified kingdoms emerge, led by hereditary monarchs • Today both are . constitutional monarchies - kingdoms where ruler's power is limited by.
  • Five Types of Conflict - Ereading Worksheets

    Five Types of Conflict - Ereading Worksheets

    Antagonist The character, group of characters, or institution that opposes the protagonist. Example The Wolf from "The Boy Who Cried Wolf" Cinderella's wicked stepmother from "Cinderella" The antagonist is usually considered to be unlikeable or evil, but this is not...
  • Activities of the Aerosol and Cloud Microphysics Group of ...

    Activities of the Aerosol and Cloud Microphysics Group of ...

    However, under experimental conditions optimized for calibrating our cavity ring-down instrument, a concentration factor attained was 4 to 5. During calibration experiments, maximum realized particle number densities were 190, 300 and 1600 cm-3 for the 900-nm, 700-nm and 500-nm spheres,...
  • Diapositiva 1 - moodle.isisfacchinetti.it

    Diapositiva 1 - moodle.isisfacchinetti.it

    Le frequenze in uso in Italia. Le frequenze più basse (800 MHz; 900 MHz) sono in grado di coprire distanze maggiori con più facilità rispetto alle frequenze più alte, inoltre sono le uniche a garantire una soddisfacente copertura in-door (quindi...