Hardware Attack - Stack Smashing And Protection

    asmita-jha
    18-February-2020


Stack exploitation based on buffer overflow has been one of the well-known security exploits. Refer here for the basic understanding of buffer overflow based vulnerabilities on x86 architecture. Embedded devices are an integral part of the IoT ecosystem. These devices generally have ARM/MIPS architecture based controllers/processors that control various sensors and actuators.

In this blog, we would understand buffer overflow based attacks on these embedded devices. We would also see the step that should be taken on ARM architecture-based devices to mitigate stack exploitation. For demonstration purposes, I have prepared an attack case scenario using DIVA as the hardware platform.

Case Scenario Description

In this system, there are 8 virtual doors. The hardware board DIVA uses the STM32F411x microcontroller (ARM Cortex-M4). The controller controls the corresponding GPIOs that controls the access to the doors. The access to the virtual door is demonstrated by controlling LEDs connected to corresponding GPOIs. The system gives user, the permission to access door 5 to 8. The user has to enter the choice of door 5 to 8 using a host machine that communicates with the device serially via virtual COM Port. The LEDs corresponding to respective doors are shown below.

Image1

After entering 5 as user input, the LED corresponding to door 5 is ON indicating Access Granted.

Image1

Image1

After entering 8 as user input, the LED corresponding to door 8 is ON indicating Access Granted.

Image4

Image4

The access to door 1 to 4 is restricted. The LEDs corresponding to respective doors 1 to 4 remain OFF.

Image4

Image4

Our target is to get access to the restricted doors i.e. turn ON the restricted GPIOs of the controller.

Look for attack surface

It is found that the JTAG port of the hardware is accessible. The firmware of the device is then extracted using ExpliotNano via JTAG Port. The extracted firmware is then opened using Ghidra for analysis.

Image4

The JTAG access on the hardware gives the opportunity to remotely debug the device. The communication between the device and the host is setup using the Openocd tool and GDB via FTDI based Exploit Nano interface.

In one terminal open openocd using - openocd -f /path/to/jtagConfigFile.cfg

Image4

In the next terminal, open gdb using - gdb-multiarch and pass the following commands : * set arch arm * target remote localhost:3333 * monitor reset halt

Image4

In Ghidra, under defined string column, look for strings coming on the console. Check for the reference address of the string. Here, the reference address corresponding to string “Enter any door number 5 to 8 ” at is found at 0x08002554. It gives the hint to the address of the function at 0x08002550 where the user input is being handled. For remote debugging, inside GDB, put breakpoints to analyze the value of registers and the stack data.

Image4

  • We put a breakpoint at 0x08002554 i.e. the address of function when entrance string is loaded; using tb *0x08002554 .
  • By observing the decompiled function, we find that on the user console, the input from the user is expected after the print of two statements “Enter any door number 5 to 8 that you want to open. \n Which door do you want to get in?”. We put another breakpoint at 0x08002566 i.e. the address where the user input function is called; using tb *0x08002566.
  • To check for the stack data after accepting user input, we put another breakpoint after returning from the function at address 0x0800256c; using tb *0x0800256c.

Image4

Continue the system operation using command c on GDB. We encounter the first breakpoint at the entry of the first statement on the console at 0x08002554. Check for register values using the command i r It is found that the value of link register lr is 0x0800252b

Image4

Again, Continue the system operation using command c on GDB. We encounter another breakpoint just before receiving user input at 0x08002566. Check for the stack data using command x/8x $sp

Image4

It is found that the stack pointer value is 0x2001ffe0 and the value of lr 0x0800252b is at address 0x2001ffec on the stack i.e at the offset of 12 bytes from the stack pointer. Continue the system operation using command c on GDB. On the user interface side, let’s try by giving input like: “aaaaaaaaaa

Image4

After entering, the system halts at another breakpoint at address 0x0800256c. On gdb terminal, check the values inside stack after this breakpoint using the command x/8x $sp. You can observe 10 times 0x61 (ascii value of ‘a’, i.e. the input that we passed). The values in stacks show that the buffer offset value is 0x2001ffe0.

Image4

You can observe that since we entered only 10 bytes in user input, the lr value is not overwritten as it is at the offset of 12 bytes from stack pointer (mentioned above). If we now continue on gdb using c command, you can observe that the system runs normally stating invalid input and waiting for another input from the user.

Image4

It means if the user enters more than 12 bytes, the lr value will be overwritten. Yayyyy !! We found that we can exploit this input buffer and hence perform RCE by exploiting the stack.

Perform Stack Exploitation Attack.

Create a shellcode to be executed after stack smash. Next, create a python script to pass user input to the system such that the lr value in the stack gets overwritten leading to the execution of vulnerable shellcode.

It is found that the virtual doors (represented by LEDs) are controlled by GPIOC of the microcontroller. We write an assembly code (here named as led.s) for direct access of GPIOC register. As per the datasheet GPIOC is at address 0x4002 0800 - 0x4002 0BFF.

Image4

So, in order to access door 1 to 4 directly, we populate the GPIOC register with value 0xff. The shellcode will write value 0xff at memory address 0x40020814 leading to direct access of restricted doors.

Image4

Compile the arm assembly code using arm-none-eabi-as -mlittle-endian -mcpu=cortex-m4 led.s -o led.o For shellcode, do arm-none-eabi-objdump -d led.o

Image4

We can now observe the 12 bytes of machine instructions as : \x25ff\xf640\x0614\xf2c4\x0602\x6035. Since it’s little-endian , we get shell code as : \xff\x25\x40\xf6\x14\x06\xc4\xf2\x02\x06\x35\x60. We now write a python script to send the user input to the system serially via host machine. As observed above, the value of lr is at offset 0x2001ffec i.e. 12 bytes from the stack pointer. We send 12bytesOfShellcode + OffsetAddress(start address of shellcode) \xFF\x25\x40\xF6\x14\x06\xC4\xF2\x02\x06\x35\x60\xE1\xFF\x01\x20. As observed, the buffer offset address as 0x2001ffe0, since it’s in thumb mode, so the last four bytes of the above string is 0x2001ffe1

Image4

Smash the stack

Now, we will see how buffer overflow based exploit can be performed to divert the system from the main firmware logic and execute the vulnerable code. In continuation with the above mentioned setup in GDB, after running the python script; we encounter the breakpoint at address 0x0800256c. At this breakpoint, the python script had sent 16 bytes of data containing shellcode and the offset address. Observe that the stack contains 12 bytes of shellcode starting at offset address 0x2001ffe0 . The lr value 0x0800252b at 0x2001ffec is overwritten by the buffer offset address 0x2001ffe1 (thumb mode).

Image4

On gdb, pass the continue command c, observe that the system gets stuck and GPIOC has now been populated with value 0xff. That is, despite of invalid input, we got access to the restricted GPIOs.

Image4

Image4

Hence, the stack got smashed leading to the execution of vulnerable shellcode instead of actual firmware logic. Great, we can now see even the LEDs 1 to 4 i.e. corresponding to restricted doors is ON. Yayyy!! we got access to the restricted doors now.

Mitigate the Attack

In this section, we will discuss the measure that developers can take to stop the execution of vulnerable codes on the system. Here we will show protection steps for ARM-based devices.

-fstack-protector enables the stack protection. If the stack does not encounter any type of smash, then the value of *__stack_chk_guard remains unchanged. When it is detected that the guard variable on the stack has been modified, the run-time environment is notified by calling the function __stack_chk_fail(void). At this point, the __stack_chk_fail(void) function is executed. Depending on the implementation of this function, it can exit the system operation, stopping the vulnerable code to get executed.

We can now see the the demonstration of it. Here we would stop the above vulnerable shellcode from being executed. Inside the main source code of the system, in Makefile we add -fstack-protector. Then, initialize the guard variable *__stack_chk_guard = 0xabcdabcd and define the function __stack_chk_fail(void).

Image4

Image4

As mentioned previously, open the firmware using Ghidra, perform remote debugging using openocd and GDB. In Ghidra, find the reference point to the entry of the function by searching for string “Enter any door number 5 to 8 that you want to open” under defined strings colomn.

Image4

Observing the function address, we give breakpoint in GDB at address 0x08002d26. Then continue the system operation using the command c on GDB. At entrance of the function, the system halts at this breakpoint. Observe the value of registers using command i r. It is found that the lr value is 0x8002cd7

Image4

We put 2nd breakpoint at address 0x08002d38, just before the function that accepts input from the user. Continue using using the command c on GDB. At 2nd breakpoint the system halts, observe the value of stack at this point.

Image4

It is found that the lr value 0x8002cd7 is at the offset of 20 bytes from the stack pointer 0x2001ffc8. Another most important thing to observe is that the __stack_chk_guard variable 0xabcdabcd is present on the stack at the offset of 12 bytes from the stack pointer. We put another breakpoint at the address 0x08002d3e after the return from the receiving function. Continue using the command c on GDB. For testing, we pass “ccccccccc” as the user input.

Image4

The breakpoint is encountered at the address 0x08002d3e. Then the data on stack is observed using x/8x $sp on GDB.

Image4

It is observed that the stack contains 9 bytes of 0x63 (ascii of ‘c’) from the offset of 4 bytes from the stack pointer. It is found that in this case eventhough the value of lr register 0x08002cd7 is not overwritten but the value of __stack_chk_guard variable 0xabcdabcd is modified, this leads to the detection of stack smash by the sytem that executes the __stack_chk_fail(void) function and the system halts.

Image4

Now, we would test to execute the above vulnerable shellcode. We write a python script (as above) to send the user input to the system. As observed above, the value of lr is at the offset of 20 bytes from the stack pointer and 16 bytes from the buffer. We send 12bytesOfShellcode + 4bytesOfDummyData + OffsetAddress(start address of shellcode) \xFF\x25\x40\xF6\x14\x06\xC4\xF2\x02\x06\x35\x60\x41\x41\x41\x41\xCD\xFF\x01\x20. As observed, the buffer offset address is at 0x2001ffcc, since it’s in thumb mode, so the last four bytes of the above string is 0x2001ffcd

Image4

This time, we send the user input using the above python script. As set previously, the breakpoint is encountered at the address 0x08002d3e. Then the data on stack is observed using x/8x $sp on GDB.

Image4

At this breakpoint, the python script had sent 20 bytes of data containing shellcode, dummy data and the offset address. Observe that the stack contains 12 bytes of shellcode starting at offset address 0x2001ffcc and the lr value 0x8002cd7 is overwritten by the buffer offset address 0x2001ffcd (thumb mode). But the shellcode is now unable to control the restricted GPIOs.

Image4

Image4

Hence we observe that eventhough , the lr value was overwritten by the address of vulnerable shellcode but the detection of modified value of __stack_chk_guard variable, executed __stack_chk_fail(void) function. This didn’t allow the shellcode to execute. It can be seen in above images that the system halted after smash detection without any LEDs being set ON. Thus enabling -fstack-protector stopped the remote code execution of vulnerable shellcode.

References:

Research Powered Cybersecurity Services and Training

Close the overlay

I am looking for
Please click one!

Latest news See all news

21-May-2020
Webinar, Online

Visit

Arun Magesh will be delivering a webinar on <em>Introduction to IoT Reversing Firmware</em> and discussing how to get started with IoT pentesting with hands-on.

25-April-2020
Workshop, Online

Visit

Ashfaq Ansari is conducting a workshop to get you started with kernel vulnerability analysis and exploitation in the Android platform.

15-April-2020
Virtual Conference, Online

Visit

Aseem Jakhar will be delivering the talk - “Busting the IoT Security Assessment Blues with Super Powers” at IoXt Alliance Spring Virtual Conference.