 Without further ado, I'm gonna let Sheila take, it is Sheila, yes, man it's been a rough morning, I'm gonna let Sheila take it away. Okay, I don't want to break something, it's okay? Oh, I'm easy, okay. Uh, hi everyone, thanks for being here despite being Sunday morning, I'm really happy to be here sharing this moment with all of you, and a little bit sleepy too. Well, let me introduce myself briefly, my name is Sheila, and I'm a fancy security researcher because I love right-hand stuff. I come from Buenos Aires, Argentina, a city 10,000 kilometers far from here near the end of the world. And also a developer in assembly for microcontrollers and microprocessors, C++, Python and Go. And as a speaker, this is my second time giving a talk at Defcon. I shot the noob last year. And was also a speaker at Black Hat, EcoParty, Hacking Box and other security conferences. But let's go to the important thing. Uh, in the last month, there were many, many news about backdoors inside hardware wars. We all know that these kind of backdoors exist, and they could be inside smartphones, computers, routers, VMCs, and so on. So, backdoors, backdoors everywhere. Uh, along the years I've been published many research about different ways of factoring devices through their own hardware components. However, most of those research focuses on devices based on powerful microprocessors like ARM, Intel, or AMD, instead of microcontrollers. So, let's see some technical differences between them. On one hand, we have microprocessors, which are entirely CPU. All the components that a microprocessor needs to work, like memories, input and output uses, um, are physically separated. They are also bigger than a microcontroller and have greater processing capacity because of their size and separated components. Um, most microprocessors have a modified hardware memory organization, and 32 of 64 bits of architecture. And in the other hand, we have microcontrollers. They have inside a little CPU, and all the necessary components to get it working. I mean, inside a microcontroller, we have the CPU, RAM, ROM, input and output uses, as well as other peripherals. Um, the fact that microcontrollers are putting it all together in a very tiny space makes them with a less processing capacity and slower than microprocessors. There are other technical differences too. Um, microcontrollers have hardware memory organization, and 16 bits of architecture. They also have a little stack. For example, pick a team, have a stack able to store up to 31 memory addresses, and if it gets overflowed, the pick will reset itself. That's all information. So, after seeing some technical differences between microprocessors and microcontrollers, a question that co-arises is, what sound would use a microcontroller instead of a powerful microprocessor? Well, usually microprocessors are implemented on multitasking devices that need to run an entirely operative system. On the other hand, microcontrollers are used for doing a specific tax. Usually the same work dealing with the same kind of team, input and output, like automatizing our routine. It's like comparing a Raspberry Pi, which has a arm microprocessor, to an Arduino, which has an ATML microcontroller. Both are useful devices, but they are used for different purposes. Um, microcontrollers have evolved a lot, and microchip is a clear example. Too many years ago, pick 12, very simple pinouts with basic input and output ports, and a few very feral. Pick 16. Um, they have more very feral, it's more familiar for us maybe, because someone has learned to program in microcontrollers using these devices. They have more very feral, including user communication and CCP modules. Pick 18, also called high performance microcontrollers, are my favorite ones. They have a lot of very feral, supporting different communication protocols, like USB and ASM, as well as all common very feral, such as timers, CCP modules, analog, digital converters, among others. And finally, we have the 32-bit microcontrollers. They are the most similar thing to a powerful microprocessor. Uh, even they use a Cortex MTPU, but it's still being a microcontroller. So after all, targeting microcontrollers worth it for, um, nowadays they are responsible for controlling a wide range of systems, like physical security system, sound cards, IQ, semaphores, elevators, sensors, components of industrial systems, uh, some home appliances, and even robots. This is an example, it's a car's IQ that handles the fuel injection, and it's fully controlled by a pick 18 microcontroller. So, there are interesting devices to target them too. Um, all microcontrollers need to be programmed, otherwise they will do nothing. So as I said, there is a little CPU inside them, which is able to execute every assembly instruction of a program loaded in the microcontrollers program memory. These are the steps for programming microcontrollers, and we can develop the firmware in assembly or C. And after compiling an assembly lead, we're gonna get the hex file, which is the firmware. To load such hex file into the microcontroller, we have to use the programmer's software and hardware, usually provided by the microcontrollers manufacturer. And similar to the world of microprocessors, um, every microcontroller manufacturer has their own assembly instruction set for the CPU of their devices. This is an example to turn it on, uh, a lead in a pick microcontroller. I love programming them in assembly, but you can use, well, uh, assembly or C. For microchip devices, we can use the MPLAB ID, which is free to develop and compile firmware. By building the project, we're gonna get the hex file, which is the firmware, ready to be written in the microcontrollers program memory. As I said, there is, is necessary to use the programmer's software and hardware to, to load the firmware into the microcontroller. These are the microchip official tools. We can use the MPLAB ID or IP together with the pick it free, uh, and load the firmware into the microcontroller. Uh, the interesting thing is that, as well as these tools can be used to read, sorry, to write the program memory of a microcontroller, they can be used to read the program memory. I mean, we can write a firmware or we can dump the firmware. So, let's see how we can dump the program memories. More interesting for us. Uh, first of all, this is the memory organization, um, for microchip devices. We have the program memory where is the firmware is located and it's the memory that we will dump. But there are other two memories. The RAM memory, which contains the S for R, Special Function Registers and CPR, General Propose Registers and the RAM memory where the program can store data that won't be left after our research. So, the RAM and program memory are non-volatile, while the RAM is, is, RAM is volatile. Uh, to make a memory dump, the first step is connecting the target microcontroller to the pick it free. There are other tools for doing this process, but I prefer to use the official tool because it's works very well and it's cheap. It costs around 40 dollars. So, this is an example of connection. We have to match the pins of the target device, the target microcontroller with the pins of the pick it free connector. For example, the VPP pin of the microcontroller must be connected to the VPP pin of the pick it free. And so on with the other pins. It's, it's very easy. Then, we connect the pick it free to the, to our computer and we can use the MPLAB ID to read the firmware. The first step is create a, a standalone project inside the MPLAB ID and specify what microcontroller has our target device. Fortunately, it's very easy to get this information because the pick model is printed on the microcontroller. And then we must set the programmer hardware, in this case, the pick it free. And finally, we can use this option in the MPLAB ID to read the firmware and dump it into our hex file. The MPLAB ID has a disassembler. So, we can love the hex file and go to target memory views, program memory. And there we'll see the disassembly view where we can find all the assembly instruction of the firmware, together with their respective opcodes to be executed by the CPU. And also the memory address is the memory address where each one is located. Let's compare. In one side we have the source code and in the other side the disassembly view. This program after the start has five assembly instructions and we can find them in a disassembly view. The only, it's very, it's almost equal. The only difference is the access word after some instructions. It means that data memory access is performed because port D and 3D are special function registers located at the RAM. That's why the access word is present. And by observing the opcodes, we can match the assembly instruction in the hex dump. They're going to be better because of the little Indian format, like most microprocessors, microcontrollers use little Indian to store bytes in memory. Okay, and now that we learned how to dump a firmware, let's see how we can modify the hex file and reload the firmware with something injected in order to alter the original behavior of the target device. When injecting a payload into a binary process, it's necessary to find a place where our payload gets executed at least once. In this case we need the same. So the necessary step is to find a place inside the firmware where we could inject a malicious score of payload. I will explain three different injection techniques. The first one is about injecting at the entry point. I mean when the program starts. But where is the entry point? Well, this is the standard structure of a program for microchip devices. The first four sections are self-plained and they are not important for us at this moment. So, let's focus on the recent vector. This is always present in every microchip device of the memory address 0000. And it's followed by a Godot start, which is a shamp to the first assembly structure of the program. Basically the entry point. In the middle of the interrupt vector is present at the address 8 or 18. But we'll go deeper on that later. Here we can observe a shamp to the entry point in the source code as well as in the disassembly view. This little program does not use interruptions. So the Godot in the recent vector is making a very short shamp. But in large programs like this other one, the shamp is going to be quite longer. So remember, the recent vector will be always at the address 0000. It's the first line in the disassembly view. There we're going to find a Godot to the entry point. In the first case, the entry point is at the address 06. And in the second case is at 7F84. Those are the memory addresses where we should inject our payload to get it executed when the program starts. So the next question is what payload we should inject? How can we build a payload for these kinds of devices? Well, we have to use the specific assembly structure set for our target device. This is an example to turn it on two different leds in a microcontroller. But we need to get the obcodes of these instructions. An option to get them is by writing all the assembly instructions of our payload in an assembly file inside a standard project in the MPLAV ID and then compile it so we can see the disassembly view and get the obcodes. Those are going to be the obcodes of our payload. But remember the leader and the informants. So that's going to be our final payload. With the bytes in Parker. So we are ready to make the injection. In this example, the entry point is at the address 28. So we have to locate this address in the hex amp. We can look for the base memory address first, 20 in this case. And then count until eight bytes. There is where the entry point is located and where we should inject the obcodes of our payload. But there is something that we should keep in mind is the checksum. It's at the end of every line. And if we modify something, we must recalculate it for every affected line. But first, we're going to inject our payload at the entry point. And the original bytes in that part will be shipped to the right. But remember not to move the byte of the checksum. Because we're going to recalculate it. This is the method we should do to recalculate the checksum. For example, if we have this line, we should make a sum of all the bytes of the line. And then make a not plus one. And the last byte of the outcome is going to be our checksum. But there is always a life saver. And we can use this website to calculate the checksum. So remember, for every affected line after payload injection, we have to fix the checksum. If we don't, we're going to get an error at the moment of loading this modified firmware into the target device. Okay, so we are ready. We can use the MPLAB ID or IP to load this modified firmware into the target device in the microcontrollers program memory of our target device. And what's the result? This is the target device with the original firmware. And this is what happened after loading the modified firmware. And the first light is on because it's part of the original program. But there are other two lights on because of our payload. So the proof of concept work. This is like pop a kite, but hardware version. So let's see a real case. This is a dashboard for observing the behavior of a car secue. And the car secue is for handling the firmware injection. So we have four blue led for the four petrol injectors and other four yellow led, or lights for the CNG or CNB injectors. In normal behavior the ACUE starts injecting petrol and then switches on CNG. In the firmware of this car ACUE TNT point is at the 11528. I played a little paleo there to modify the right behavior and continue injecting petrol after switching. I mean, the ACUE will be injecting both petrol and CNG at the same time. That's not, not, not be cool for the car. So let's hear a video. This is the car secue. And we, we start seeing the, I will keep the sound because it's very good. So we start seeing the normal behavior, the blue lights are on because the car starts using petrol and then it switched to CNG. So the petrol injector stopped working and the car is using CNG. Now I'm loading the modified firmware into the microcontrollers of the ACUE. And we repeat the process. The car starts using petrol. I speed up the car to reach out the condition to automatically switch to CNG. But when it's a cure, the car is using both, the ACUE is injecting both petrol and CNG at the same time. This is just an example, something bad for the car. Okay. Let's talk about the second injection technique. And maybe we prefer to get our payload executed not when the program starts, but when a specific action occurs. It might be associated with an interruption. And in big programs, it will always be interruption because of the microcontroller, for interruption to alert that, for example, the time is allowed to digital converter, DC audio transmit, parallel of different communication protocols, as other protocols. Execution flow when the car occurs. And in other words, the microcontroller is doing, it will interrupt vector, okay, the address eight for high priority interruptions and 18 for low priority interruptions. Once the car starts here, a procedure known as, is used to detect who triggers the interruption. It's what's a timer, the analog to digital converter or who was. After detecting who was, the corresponding code routine is executed. The red fine instruction at the end will go to program counter and go to memory address immediately after the interruption occurred. There are some special function registers that aims interruption handling. When a program is using interruptions, the bits he, IE and PIE of the input register will be set to one. In assembly, it looks like this. The bits SF instruction is used for sets to one bit of the register. So, when we dump a firmware, we can look for these two instructions in the disassembly view, in order to know if interruption are enabled in our target device. For every periphera that could figure an interruption, there are two bits inside a special register. The interruption enabled bit and the interruption flag bit. As example, we can quote the timer zero. It's interruption bits are located in the input register. When a program wants to use this timer, the TNR zero IE bit in the input register must be set to one. When the timer triggers an interruption, the TNR zero IF will be automatically set to one. While not, this flag will be to zero. Due to in the latest microcontrollers, there are too many peripherals. The special registers pi one, pi two, and even pi three have interruption enabled bits, while pi one, pi two, and pi three have their respective interruption flags for different hardware peripherals. So, as I said, a procedure known as polling is used at the interruption vector to detect who triggers an interruption. This process is done using the BTFSC instruction for testing the value of the interruption flags. In this example, we have four peripherals that could have trigger an interruption. The polling process will start testing the flag of one of them. If the flag is set to one, the call below will be done, jumping to a call routine that must be executed every time that this specific peripheral trigger sign interruption. If not, the polling will continue testing the other flags until find the flag set to one. This is how the polling process looks in the disassembly view. By inspecting the polling, we are able to know what peripherals are being used for our target device. Remember that the polling will be always located at the address eight for high priority interruptions or 18 for low priority. If we do some in one of the interruption flags, we observe that the bit five is being tested of the P1 register. But what is the bit five? In the data sheet of our target device, we found that the bit five corresponds to the RC interruption flag. This is used as communication peripherals when the microcontroller receives data from any communication protocol, it will trigger an interruption that will set this specific flag to one. In the polling process, if this flag is to one, the call will be executed jumping to a call routine that must be executed in this case located at the address 48. Such call routine will do something with the data received by this peripheral. So by inspecting the polling, we not only know what peripherals are being used, but we can get different memory addresses where we could inject our payload. For example, if we want to do something when the microcontroller receives data from a communication protocol, we should inject our payload at the RC interruption routine. In this case it's located at the address 48. Or if we want to do something when the timer zero triggers an interruption, we should inject at the address for E and so on. The idea is to modify the original behavior of the target device when the microcontroller is using its different hardware peripherals. So let's see an example of factoring the user communication using this technique. The first step is locating where the RC interruption routine begins. By inspecting the polling, we got that in this case the memory address is 48. So we have to locate this memory address in the Hex Dam. So we can look for the base memory address 40 and then count until 8 bytes. And there is where the RC interruption routine begins and where we should inject our payload. But what payload? But we could get payload that makes our relaying of the received data to a transmission port that we are able to monitor storage. I mean the microcontroller will receive data from anywhere and it will trigger an interruption. At that moment our payload will be executed to catch such information and relay it to us. This is the payload. And first we got the received data and we move it to the W register. Then the transmission is enabled, the operation mode is set as a synchronous, and the TX pin is set as an output. And finally we move the received data in W to the TX drive. Anything written in such register will be transmitted through the TX pin to a USB interface or wireless module. In my case I will use a USB interface because it's easier to use what happened, but it could be a wireless module. This instruction could vary a little depending on the target device. These are the op codes of every assembly instruction and our final payload. So we are ready to make the injection. And we have to inject the payload factor when, where the RC interruption routine begins. So in this case it's at the other 48. And we'll place the payload in the same way that we did in previous examples. So let's see a demo. In the next video you will see a hardware board receiving information from a smartphone. That's when the interruption occurs and the data is relayed to our computer. Okay. And the vector firmware has been loaded in the target device and we are listening to the USB interface. So we send a message to the hardware board. That's when the interruption occurs and the information is relayed to our computer. So as I said I'm using a USB interface in this case but it could be replaced by a wireless module for mode connection and it's going to work in the same way. Nice. Okay. At the moment of injecting a payload at whatever place we are making a shift in a spite that could affect the call and go to instruction of the original program. Because now they are champion to memory addresses whose original bytes have been moved. In the last program this is a real problem that we had to solve. For example in the graph we can see a call instruction champion to the address 10 while after payload injection it should be championed to the address 16. We had to fix this to avoid a flow corruption. These are the opcodes of Godot call instructions. In PK team microcontrollers the assembly instructions are 16 bits in length. So 8 bits are used for the opcode and 8 bits for the memory address where it has to jump to. But two more bytes are reserved in case of needing champion more than 2,255 positions. This we can see an example of Godot call. The first shamp is to the offset 6 and the second one to the offset 467. In the disassembly view we're going to see the memory address. So we have to make, we have to divide it by 2 to get the offset and then be able to locate the shamp in the hex down. The first shamp is to the offset 6 and the second one to the offset 467. In the disassembly view we're going to see the memory address where we have to be able to locate the shamp in the hex down. To fix it we have to keep in mind the memory address where we have injecting our payload and the payload length. And we have to fix only those shamps to memory addresses located after the one where we have injected. For example if we inject our payload at the address 48 and we have a call at 56 we have to recalculate the shamp by making a sum of the original memory address plus the payload length. So in log programs we'll probably need to fix some shamps. In this case I have to fix three call instructions. Make the injection, fix the shamps and the injection might be tedious especially in large programs. That's why I'm working on a little tool for automating this process. The tool receives a parameter the hex down, the payload, the offset where it has to be injected and the name of the output file. And basically the tool makes it on and fix all the necessary things. I hope to be able to put this tool on my give cap in these days. So stay tuned. So let's talk about the last second, that's sorry, the lax injection technique. And I will explain how we can alter the microcontrollers stack and take control of the program flow. In microchip device there are four function registers to manipulate the stack. The first one contains the stack pointer and the toss and toss composes the top of the stack. In the graph we can see an example. The stack pointer is pointing to the second entry of the stack which is value is 001834. In practical implementation of these registers, first we should increment the stack pointer and then write the toss registers with the memory address where we want to jump to. And finally we have to execute our return. This is how it looks in assembly. First we increment the stack pointer and then we write all the necessary values to the toss registers. In this case to jump to the address 000072. And finally it's the return. In this assembly view we are going to see something like this. When the return is executed the program will jump to the memory address 24 in this case. From this example we can get the opcode of these instructions. So regarding payload injection at this moment we have two alternatives. And one how we could inject our payload anywhere inside the firmware and then write the toss registers with the corresponding memory address. Or well we can do a rock chain writing the toss with memory addresses from part of the code that we want to execute. I mean create a payload with assembly instructions already written in the original program. This is an example of rock. And at the left we see all the memory addresses of our rub gadgets. That means the memory addresses from part of the code that we want to execute. And in the other side we see all the necessary opcodes to write the memory addresses in the stack. All those opcodes including the final red will compose our payload. Microcontrollers use a leaf of stack too. So the first rub gadget executed will be the one located at the address 28 in this case. It's the last one injected in the rub chain. This is an example of rub gadget. It starts at the address 40 and ends at 46 with a rattle w. All gadgets must end at the time of rattle w to continue executing the other gadgets in the right way. So let's see a demo start. In the next video you will see a light turning on for every rub gadget being executed. It's a nice way that I found to know what happened. Okay. It's embedded but you can observe eight gadgets being executed. Of course they could be more or less. It's just an example. So finally let's talk about memory protections. And from a security point of view we cannot avoid that someone overwrites the whole program memory of our microcontroller. But we can protect it against memory dumps and with that avoid payload injections. And at the beginning of a program before the main code it's necessary to set some configuration bits for microchip devices. Among them is the code protection bit. But by enabling only these ones the memory dumps will work. So if you assemble your program with these specific code protections, um, anyone else will be able to dump your program and disassemble it. So to prevent memory dumps we have to use the boot protection which is the CPV bit and also the data protection is useful too. If we enable these two bits, um, program memory dumps won't work and if someone tried to dump your firmware the hacks file will contain only zeros. This is just an example of protection for microchip devices. Really I don't have, I didn't have time to, to get deep in protections but it's something that you can do. Uh, conclusions. Vactoring microcontroller is possible and there are a lot of interesting devices that are fully controlled by them. Um, I explained three different injection techniques. I wrote a white paper explaining each one of the details. Um, and though I focus on microchip I think that most concepts can be extended to other vendors. And finally I want to thank to Sol and Nico Weisman for their help while I was writing the white paper and also to the people of DreamLab for all the support. And thanks to you.