Wednesday, January 29, 2025

Successful Fault Injection (glitching) with the Bus Pirate


Introduction

In this post, I'll discuss using power fault injection (glitching) to bypass UART password authentication in an application running on a simple Arduino dev board using the Bus Pirate.  (Spoiler - it works!)

The Bus Pirate is an open source hardware/firmware debugging and test tool that is capable of many, many things useful to an embedded engineer and/or hacker.  In this case, we'll be using the UART functionality to communicate with and time, generate, and inject a power fault into our target (an Arduino Uno).

Background

For a recent project, I was connected to a consumer IoT device's UART port and found that I could break into the U-Boot bootloader at which time I prompted to enter a password.  I noticed that once the password prompt mode was entered, it would allow infinite retries of password until the correct password was entered (not a good idea from a product security standpoint).  I later pulled the entire firmware from the flash of the device and reverse engineered the vendor's implementation of password entry in U-Boot.

This gave me the idea to use that experience to create a more simple, affordable, and easily understood introduction/example of power glitching.

Bus Pirate Code and Custom Glitching Circuit

The basic sequence that I wanted was:
  1. Send an '\r' (return) character from the Bus Pirate over UART to the target
  2. Wait a precise amount of time after the UART line goes back high from step 1
  3. Turn on one of the outputs from the Bus Pirate for a very precise and short amount of time
  4. Read the response from the target over UART - analyze that response to see if it looks different than the normal "### Please enter password ###" prompt.  If the response is different, stop and announce that the glitch was successful; otherwise, jump back to step 1.
This was easy to do as the Bus Pirate has open source firmware.  The microcontroller inside of the BP5 (Bus Pirate 5) is the Raspberry Pi RP2040 - this MCU has the PIO feature which allows for simple hardware based state machines.  One of these PIO state machines was used to control the timing needed in step 2 and 3 above.  All of this functionality was put together to create the "glitch" command for use in the BP5's UART mode.

The "glitch" command has been pulled into the main Bus Pirate firmware and can be found in the main branch of the project's github.  The three files that do most of the work are glitch.c, glitch.h, and glitch.pio.

A useful feature of the Bus Pirate is the "plank" accessory.  These are just small circuit boards that can be plugged into the BP's connector to perform a specific function or to interface to something.  One of these planks is the "blank plank"; basically a prototyping area which allows one to make whatever circuit they would like.

I used the blank plank to make a glitching plank:


(I had to rework the plank a few times, so the soldering is a little messy)

A rough schematic of my glitching plank:


I used the "Pin headers for measurements" to connect a scope across the FET to see the actual waveform of the glitch.  The "Pin header for logic analyzer" was used to help time the glitch.

What would I change about it?  The next version will have a small resistor in series with the FET's source; I've burned out a couple of FETs already from having the glitch "on" time too long.

The Target

As noted earlier, the target is an Arduino Uno development board.  This target was chosen because of low cost and wide availability.  I had two Sparkfun RedBoards in my parts drawer to use.

This board uses the Atmel ATMega32p microcontroller - an 8-bit RISC Harvard architecture chip with 32K of internal flash and 2K of internal SRAM running at 16MHz.  Programming can be done with the Arduino IDE and downloaded using USB.

To begin with, the schematic was reference to find a place to make a connection on the power circuit to inject the fault:


For best results, the point to do this should be very physically near the chip, so the usual place to connect to "short" the incoming power is across a decoupling capacitor near the microcontroller itself.  According to the schematic, the only decoupling capacitor appears to be C2, and it is not near the chip.

The 5VDC supply to the chip (VCC) comes in on pins 4 and 6, with pins 3 and 5 being ground.  Short wires were soldered on to pins 3 and 4 which then connected to an SMA coax connector:


The SMA connector was affixed to the board with hot-melt glue.  The SMA connector was used so a short coax cable could connect the target to the glitching hardware - this reduces unwanted parasitic capacitance or inductance in that connection.

Target Firmware

As stated earlier in this post, I was working on a consumer IoT device that had custom password verification added to U-Boot.  I eventually extracted the bootloader and reversed engineered that password code.  

That password verification code was included in the target's Arduino sketch:

int simpleCLILoop(const char* prompt) {

char password[MAX_PWD_LEN] = {'\0'};
uint8_t pwdInx;
int readChar;
int compareResult;

// if password has been entered (consoleEnabled == true), then
// skip this whole block. Otherwise keep trying until correct
// password has been entered.
while (!consoleEnabled) {
Serial.println("### Please enter password ###\r\n"); // prompt user
pwdInx = 0; // entered password character counter

// loop runs continuously until <RETURN> key pressed
while (true) {
if (Serial.available() > 0) { // wait for UART rx
readChar = Serial.read(); // get that char
readChar &= 0xff; // mask off lower 8 bits

if (readChar == '\r') { // user hit <RETURN>
break; // so break out of forever while() loop
} else if (readChar == '\b') { // user hit <BACKSPACE>
if (pwdInx > 0) { // if at least one char has been entered
--pwdInx; // decrement entered password char count
Serial.print("\b \b"); // send backspace, space, backspace over UART
} // to clear the last '*'
} else { // not <RETURN> or <BACKSPACE>
password[pwdInx] = readChar; // append the this char to the user's password entry
++pwdInx; // increment the entered password char count
Serial.print('*'); // print out an asterix
} // testing entered UART char
} // waiting for UART char
} // main while() loop

password[pwdInx] = '\0'; // null terminate user entered password

// compare user entry to "good" password
compareResult = strcmp(PASSWORD, password);

if (!compareResult) {
consoleEnabled = true; // set bit to indicate password is good!
}

Serial.println(""); // print out a newline
} // while (!consoleEnabled)

*consoleBuffer = '\0';
return (readCommandFromUART(prompt));
}

(Yes, I know there's a stack-based buffer overflow here, and that it's a bit sketchy in general, but this is the code I pulled from a real-world consumer IoT device.  The only difference between the consumer device and this is that I'm being lazy and using the Arduino "Serial" class instead of directly reading/writing to the ATMega 328's "UDR0" register.)

The code to target here is:

if (!compareResult) {
consoleEnabled = true; // set bit to indicate password is good!
}

If we can inject a fault at the right time, the code could skip over the if() statement and assign a "true" to the global "consoleEnabled" variable.

For even more detail, the disassembly from the region near the password check looks like this:

    code:02f4 91 e0           ldi      R25,0x1
    code:02f5 0e 94 be 03     call     strcmp                               

    code:02f7 89 2b           or       R24,R25
    code:02f8 11 f4           brbc     LAB_code_02fb,Zflg
    code:02f9 a0 92 d4 02     sts      consoleEnabled,R10  
                      LAB_code_02fb                         XREF[1]:  code:02f8(j)  
    code:02fb 85 ea           ldi      R24,0xa5
    code:02fc 91 e0           ldi      R25,0x1

This line:

code:02f5 0e 94 be 03     call     strcmp 

calls strcmp(), the result is returned as a 16-bit integer in registers R24 and R25.  The next line:

code:02f7 89 2b           or       R24,R25

performs a logical OR on those two registers.  Why do that when we are trying to compare the return value to zero?  The OR instruction for AVR will set the Z flag in the status register if the result of the OR is zero (all bits clear).  To compare a 16-bit integer to zero takes more than one instruction, so the compiler is smart enough to optimize down to the OR.  Following the OR is this line:

code:02f8 11 f4           brbc     LAB_code_02fb,Zflg

this is a branch instruction which will branch to the label LAB_code_02fb if the Z flag in the status register is cleared.  In other words, jump to that label if the password was incorrect.  If the Z flag was clear (strcmp() returned non-zero), the code will skip this next line:  

code:02f9 a0 92 d4 02     sts      consoleEnabled,R10

which sets the global "consoleEnabled" to be "true".  (The compiler reused register R10 from some previous thing here.)

Looking at that, the specific instruction to "glitch" or skip over would be the brbc branching instruction.  It's also possible to inject a fault into the code of the strcmp() routine so it returns zero, but this is where I am targeting.


Connecting Things Up

Here is the BP with glitching plank connected to the Arduino.  


In the upper right are the UART TX and RX signals from the Arduino  going to the BP.  Next is the coax cable connecting the two together; the +5VDC (VCC) right at the AVR chip across the FET.  The two wires from the lower header on the target connect the Arduino's 5V and gnd to the glitching plank.  The BP is using the target's voltage to power the I/O buffers.

The logic analyzer (not shown) would be connected to the 2-pin header for RX/TX for timing.

Finding the Right Time

As described above, the key is finding the right time to inject the fault.  I used a logic analyzer to help figure this out.  The analyzer was connected to the TX and RX lines and recorded the sequence of transmit from the BP and receive from the Arduino:


The top line shows the serial TX line from the BP sending a '\r' (return).  Then the lower line shows the Arduino responding with "### Please enter password ###".  The timing markers show that the time between the two is about 29 microseconds.  I ran this several times and found this timing to be fairly consistent.

For this attack, the fault should be injected at some point during the 29 microseconds after the BP does its transmission.  A guess would be at some point near the middle of this time.  It will take some trial and error to find the "ideal" time.  

The same applies to the duration of the injected fault.  Too long and it'll trip the brown out detector of the microcontroller and cause it to reset; too short and it won't have the desired effect.  Again, trial and error.

Performing the Fault Injection Attack

Now is the time to actually do the attack!  First, connect to the Bus Pirate's serial console and enable UART mode.  Once that's done, I issued the "bridge" command and powered up the Arduino:


(The Bus Pirate powers up in a safe High Impedance mode; the "m 3" command is shorthand for mode 3 - UART).  The bridge command sets the BP's UART into "transparent bridge", and shows the target is in password mode.  

Bridge command was exited with the BP's button and the "glitch" command was issued:

Breaking all of that down, first the glitch configuration information is shows (and can be edited):

  • Glitch trigger character: The ASCII value of what to send to trigger the whole sequence.  In this case, it's ASCII 13, a RETURN character.  
  • Glitch trigger delay:  How long after sending the trigger character to delay before turning on the output that fires the FET?  This value is in terms of nanoseconds * 10; so a value of 14 is 14,000 nanoseconds, or 14 microseconds.  That puts it in the window shown on the logic analyzer
  • Glitch vary time: This is an additive time to vary the glitching timing, again in nanoseconds * 10.  In this case, it's a 5; the actual glitches will be fired at 14.00us, 14.01us, 14.02us, 14.03us, 14.04us, and 14.05us.
  • Glitch output on time: How long to keep the FET gate turned on.  This should be a short time; too long and you can trip the brown out detect and reset the device, too short won't trigger a glitch
  • Glitch cycle delay: Minimum time between attempts; this is used to keep the FET or other hardware from overheating
  • Normal response character: The ASCII value of something returned by the target when operating normally.  In this case, it's an ASCII 80, which is a capital 'P'.  If the glitch did not trigger the bypass, the target will respond with "### Please enter password ###".  Therefore, if a capital "P" was RX'd by the UART, the code knows it didn't succeed
  • Number of glitch attempts: The number of cycles to attempt before giving up.  A cycle is a series of attempts including all variations based on the Glitch vary time.
  • Bypass 'READY' input checking: The glitching code is generic enough to be used in different ways; for example, to trigger an external device that may need to recharge between attempts.  To accommodate that, the glitching firmware can wait until an input has been turned on by that external device.  In this case, the FET-based plank doesn't need this, so it is bypassed.
Next we see this:

UART glitching.  Press Bus Pirate button to exit.
Attempt   1, delay 14000ns RX: ### Please enter pa
Attempt   1, delay 14010ns RX: ### Please enter pa
Attempt   1, delay 14020ns RX: ### Please enter pa
Attempt   1, delay 14030ns RX: ### Please enter pa
Attempt   1, delay 14040ns RX: ### Please enter pa
Attempt   1, delay 14050ns RX: $> 
Target glitch success!

On the 6th attempt, the BP was able to glitch past the password check on the Arduino!  The BP will output information for each attempt: the delay (calculated by the base plus the current amount of variation), and the data received from the target.

In the first 5 tries, the Arduino returned the message to enter password (the code only shows the first part of the response).  Those responses contained a capital "P", so it was obvious it didn't succeed.

However, the 6th response was "$>".  That didn't contain a "P", so it was declared a success!

After that, I re-entered the "bridge" command.

UART> bridge
UART bridge. Press Bus Pirate button to exit.

$> help
This is just a small example, there really isn't any kind of command
processing.  Only commands are 'help', 'reboot', and 'info.
$> info
Target info:
'consoleEnabled': true
$> 

This time, the UART showed an interactive user session with a "$>" prompt.  In the Arduino code, this is a very simple thing with only 3 commands to show that the user is past the password entry.  The "info" command outputs the current value of the global "consoleEnabled" flag, which is true.

Conclusion

This example showed that fault injection can be used to bypass simple authentication.  It didn't require expensive hardware or lab equipment.

Comment below if you try this or something like this, I'd love to see how it works for others!

References

Web references:

/******************************************************
* sample code to exercise glitching a 328p
*
* After powering up, the code will put out a short
* identifier, then start asking for a password. (over UART)
*
* User can try as many times as they want, there is
* no limit.
*
* If correct password is entered, the user will get a
* "$>" prompt.
*
* The goal is the inject a power or other fault just
* as the password is being checked and thereby bypass
* password checking.
*******************************************************/

#define MAX_PWD_LEN 32
#define CONSOLE_BUFFER_LEN 64

static const char* PASSWORD = "myP4ssw0rd";
static bool consoleEnabled = false;

char consoleBuffer[CONSOLE_BUFFER_LEN] = {'\0'};

int simpleCLILoop(const char* prompt);
int readCommandFromUART(const char* prompt);

void setup() {
Serial.begin(115200);
Serial.println("************************************\r\n Test glitch target (victim), v 0.9\r\n************************************");
}

void loop() {
// put your main code here, to run repeatedly:
simpleCLILoop("$> ");
}


/******************************************
* This method is called continually to get
* user interactivity over UART. If the
* password has not yet been entered, this
* method will continually poll for it
* until it is found.
*
* This method may seem strange, and even
* a bit contrived, but it is somethine that
* I pulled almost exactly from a consumer
* IoT device.
*
* Yes, there is a stack-based buffer overflow
* here (and is in the actual device out in
* the world, too.)
******************************************/
int simpleCLILoop(const char* prompt) {

char password[MAX_PWD_LEN] = {'\0'};
uint8_t pwdInx;
int readChar;
int compareResult;

// if password has been entered (consoleEnabled == true), then
// skip this whole block. Otherwise keep trying until correct
// password has been entered.
while (!consoleEnabled) {
Serial.println("### Please enter password ###\r\n"); // prompt user
pwdInx = 0; // entered password character counter

// loop runs continuously until <RETURN> key pressed
while (true) {
if (Serial.available() > 0) { // wait for UART rx
readChar = Serial.read(); // get that char
readChar &= 0xff; // mask off lower 8 bits

if (readChar == '\r') { // user hit <RETURN>
break; // so break out of forever while() loop
} else if (readChar == '\b') { // user hit <BACKSPACE>
if (pwdInx > 0) { // if at least one char has been entered
--pwdInx; // decrement entered password char count
Serial.print("\b \b"); // send backspace, space, backspace over UART
} // to clear the last '*'
} else { // not <RETURN> or <BACKSPACE>
password[pwdInx] = readChar; // append the this char to the user's password entry
++pwdInx; // increment the entered password char count
Serial.print('*'); // print out an asterix
} // testing entered UART char
} // waiting for UART char
} // main while() loop

password[pwdInx] = '\0'; // null terminate user entered password

// compare user entry to "good" password
compareResult = strcmp(PASSWORD, password);

if (!compareResult) {
consoleEnabled = true; // set bit to indicate password is good!
}

Serial.println(""); // print out a newline
} // while (!consoleEnabled)

*consoleBuffer = '\0';
return (readCommandFromUART(prompt));
}


/******************************************
* *
******************************************/
int readCommandFromUART(const char* prompt) {
bool enterd = false;
int readChar = 0;
int readInx = 0;

Serial.print(prompt);

while (!enterd) {
if (Serial.available() > 0) {
readChar = Serial.read();
readChar &= 0xff;

if (readChar == '\r') {
break;
} else if (readChar == '\b') {
if (readInx > 0) {
--readInx;
Serial.print("\b \b");
}
} else {
consoleBuffer[readInx] = readChar;
++readInx;
Serial.print((char)readChar);

// dont allow a buffer overflow here
if (readInx == (CONSOLE_BUFFER_LEN - 1)) {
break;
}
}
}
}

consoleBuffer[readInx] = '\0';
Serial.println("");

if (strlen(consoleBuffer)) {
if (!strcmp("info", consoleBuffer)) {
Serial.println("Target info:");
Serial.print("\t'consoleEnabled': ");
(consoleEnabled) ? Serial.println("true") : Serial.println("false");
} else if (!strcmp("help", consoleBuffer)) {
Serial.println("\tThis is just a small example, there really isn't any kind of command");
Serial.println("\tprocessing. Only commands are 'help', 'reboot', and 'info.");
} else if (!strcmp("reboot", consoleBuffer)) {
// kind of a sledgehammer - jump to the reset vector to reboot.
asm("jmp 0");
} else {
Serial.print("'");
Serial.print(consoleBuffer);
Serial.println("' isn't a supported command.");
}
}

return (strlen(consoleBuffer));
}
 

I'll be speaking at CypherCon!

 Just a short note here - I'll be speaking at CypherCon in early April.  My topic is about hacking a cheap IP camera, and what the vendor could have done to make it less hackable.


Hope to see you there!

Saturday, March 30, 2024

Bus Pirate 5!

I've been a happy user of the Bus Pirate for several years now - it's perfect for probing circuits to get at TTL level UARTs, sniffing SPI and I2C, generic JTAG, and other shenanigans.  From a hardware/firmware developer use case, it's great to be able to sniff bus traffic during debug.  From a red team standpoint, I've used it to extract and modify the contents of serial EEPROMs and serial flash chips - good clean fun :)

I noticed that there's a new version of the hardware finally available, so of course I immediately ordered one.  It arrived this morning and I spent a couple of hours playing with it.

Ordering and Shipping

It can be ordered from Dirty PCBs  (link at end of blog).  I already had a Dirty PCB account from some projects a few years back - they do a pretty good job of cheaply producing PCBs if you don't mind waiting a bit to get them.  Ordering was straight forward; the only thing I noted was that it would be shipped after February 19th due to the lunar new year holiday.  I ordered the Bus Pirate v5 and a set of premium test leads.



It arrived on Saturday, March 30th after a week and a half in transit.  Luckily I was home as I had to sign for the package.  It was well packaged and looked fully intact after shipment.


Inside were two boxes - one containing the Bus Pirate itself, and another with the test leads and clips.  I liked the branding and labels on the product, it looks more like a professional tool than previous versions


The Bus Pirate itself was sealed in the anti-static bag with a "Genuine" seal.  Also included are a couple of colored button caps that you can swap out.


Comparing with V3.5

This image shows both the "classic" V3.5 BP at the top with the new V5 below.  Major differences I noted right away:

  • The V3.5 was shipped as just a PCB.  I 3D printed a bottom shell for it so I didn't have to worry about it shorting to a board it might be laying on.  The V5 has a full injection molded case.
  • V3.5 has a USB B Mini connector (yes, Mini, not even Micro - I have to go find a cable every time I use it).  V5 has USB C
  • I prefer the pin header on the V5, it comes out parallel to the board instead of 90 degrees like the V3.5
  • Of course, the screen on the V5.  I can see how it will be very useful, but I am a little concerned about protecting it.  I have a case with all of my "hardware hacking" stuff, and while it's pretty well organized, I'm worried about the screen getting damaged.
  • The V5 is physically larger than the V3.5.  It's not enough to be a problem; just noting it.
  • First Impressions

    This version comes fully enclosed, unlike previous versions (which were just the PCB).  There are addressable LEDs around the outside, a nice IPS screen, USB C, and the connector.  



    The display is great - it saves from having to read the tiny silkscreen and cross reference to the website to know which signals were on which pins.  The display dynamically shows pin assignments based on mode.  




    There's also the button near the USB connector that is handy for breaking out of different modes (see below).

    I decided I would try to use the V5 without referring to any documentation.  I am very familiar with the v3.5 BP, so I figured it would be a good test to see how much has changed.  

    Running 'dmesg' while plugging it in to my Linux box showed that it presents itself as two USB serial ports and a removable disk.  Obviously quite a bit more going on that with the previous versions!

    Jumping right in, I opened minicom sessions to both the old and new Bus Pirates (V5 on the left in purple, v3.5 on the right in green):


    One obvious difference is the VT100 mode of the V5.  The bottom of the screen shows the states of the IO pins, a very nice feature to be able to always see that!  

    The info command has more information for the new model; one obvious thing I saw is that it has fewer communications modes.  Not too surprising as it is pretty new and I expect there will be more added as the firmware is updated.

    I had been using the older BP earlier in the week for TTL UART and found that it wasn't able get to the baud rate I needed - it tops out at 115,200 baud and the device I was trying to connect to was at 230,400.  Setting UART mode on the V5 made it appear that 230,400 was possible:

    Test Usage

    I set it up in UART mode at 230,400 buad and hooked up the I/O lines as shown on the display.  Again, I can't say enough about how useful that little screen is.  I used UART macro (1) for transparent bridge mode.  

    First thing I noticed is the feedback that you can press the BP's button to exit transparent bridge - previous BP would require resetting to exit that mode.  Very useful as the user doesn't need to start the Bus Pirate back up, reconfigure mode, etc. after exiting transparent bridge.

    BP V5 was able to keep up with the higher baud rate with no problems; not that I was really expecting any, but it was nice to see.  The communications from the BP to the serial terminal on was still 115,200 baud, so I assume if there's lots of traffic on the TTL side it would eventually overrun the Pirate's serial buffer.

    Conclusions

    I'm very impressed with the V5 so far.  I only spent an hour or so with it, but it was able to do something the V3.5 couldn't (UART at 230K baud).  

    I'm already thinking of things I want to try; for example I was unable to sniff some SPI serial Flash traffic on a device because the data rate was too high for the V3.5, maybe the V5 will be able to do it.

    Now that I have it in hand and have played a bit, I'll read through the documentation to learn more.  I can't wait to see where this product goes and will be looking forward to updates and more functionality :)

    References

    The product page for the V5 can be found here
    The product page for the V3.5 can be found here
    Order the V5 here (also get the premium cable set, well worth the money!)



    Successful Fault Injection (glitching) with the Bus Pirate

    Introduction In this post, I'll discuss using power fault injection (glitching) to bypass UART password authentication in an application...