Harvard architecture MCUs binary exploitation.
The Harvard architecture is a computer architecture with physically separate storage and signal pathways for instructions and data. History of early mechanical computers used this kind of separation for convenience, and it was typical for that time, to have the program and data memory physically separated. Today Harvard architecture is less common, but there’s still some niche of usage. In the embedded devices world, dominated by tiny microcontrollers, Microchip PIC and the Atmel AVR families are implementing a modified Harvard architecture which allows the contents of the instruction memory to be accessed as if it were data, but not the data as code.
The binary exploitation involves taking advantage of a bug or vulnerability to cause unexpected execution of malicious code. Techniques such as stack overflow where the executable binary code is injected directly into the stack have no use in this world because once there, it can not be executed.
Question is: is there a way to craft a payload making a PIC or an AVR execute arbitrary code?
Recalling the various techniques used through the history of the binary exploitation, one may recall about when operating systems started to prevent the execution of code within the stack.
Operating systems are taking advantage from page execution right feature to mark certain areas of memory as non-executable. Von Neumann architectures tried to protect themselves emulating the distinctive Harward architectural behavior.
By the way, the answer to the previous question is: YES, you can get your Harward architecture MCU to execute arbitrary code under some conditions.
First, you must have an adequate amount of RAM dedicated to the stack.
Second, you must find in the existing executable code, the right sequence of ROPs.
Let’s clarify what we intend with ROP.
Return-oriented programming (ROP) is a computer security exploit technique that allows an attacker to execute code in the presence of security defenses such as executable space protection or, as in our situation, where no further executable code may be added.
ROPs aka gadget are short snippets of code taken from the ending part of preexisting functions. These gadgets are typically 2–7 instructions in length and end with a return or equivalent instruction.
Why are those so important?
Because both Von Neumann execution blocked CPUs and Harvard MCUs use the stack to store the PC when functions are called, attackers can use a well-crafted list of ROPs to execute a code that produces the behavior he wants.
Countermeasures to code reuse techniques are tricky and mostly unusable in the tiny embedded devices scenarios.
Historically, one of the most valid countermeasures is to produce code with randomization of the functions layout, but unfortunately, it is not practical and in some cases even possible in the tiny embedded device because of their architecture.
Another valid technique is known as Control-Flow Integrity, which tries to keep track of functions call flows and validate every return from calls. This second approach is possible in even the tiny embedded devices objected of this post, but it adds overhead in terms of code size, that cannot be practical.
Exein aims is integrate a separate Control Flow Integrity separate function in a very optimal way in order to re-write less part of the firmware itself.
More at https://www.exein.io/