Tags: timing-attack avr hardware
Rating: 3.0
# Google CTF 2020 AVR writeup
![AVR Freaks](images/Atmel_Freaks_logo_large.png)
By: David Rimon & Roy Hoffman @Shablul team.
## Part 1
This is a writeup for the hardware AVR challenge in Google CTF 2020.
The challenge is about breaking the security of a system running on Atmega328p chip.
**Note** for the second part of the challenge, jump for part 2.
The challenge begins with the following message:
![1](images/1.png)
Downloading the attachments we get the following files:
1. `code.c` - The code of the device we want to hack. This is the file that interests us.
2. `simduino.elf`, `code.hex` - files needed for simulating the system locally on your pc.
3. `Makefile`, `simavr_diff` - files needed for downloading and compiling the simulator from the source.
Lets take a look at `code.c`
The code starts with some data initializing and definition.
```c
#undef F_CPU
#define F_CPU 1000000UL
#include <avr/io.h>
#include <avr/sleep.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <avr/cpufunc.h>
#include <stdio.h>
#include <string.h>
#define BAUD 125000UL
#include <util/setbaud.h>
#ifndef PASS1
#define PASS1 "PASSWORD_REDACTED_XYZ"
#endif
#ifndef PASS2
#define PASS2 "TOPSECRET_PASSWORD_ALSO_REDACTED_TOPSECRET"
#endif
#ifndef FLAG
#define FLAG "CTF{_REAL_FLAG_IS_ON_THE_SERVER_}"
#endif
const char* correctpass = PASS1;
const char* top_secret_password = PASS2;
const char* top_secret_data =
"INTELLIGENCE REPORT:\n"
"FLAG CAPTURED FROM ENEMY.\n"
"FLAG IS " FLAG ".";
char buf[512];
char secret[256] =
"Operation SIERRA TANGO ROMEO:\n"
"Radio frequency: 13.37MHz\n"
"Received message: ATTACK AT DAWN\n";
char timer_status[16] = "off";
volatile char logged_in;
int top_secret_index;
```
Next there are some functions defined to interact with the device's uart port. UART is basic IO method to interact with embedded devices. Read more at: https://en.wikipedia.org/wiki/Universal_asynchronous_receiver-transmitter
```c
volatile char uart_ready;
ISR(USART_RX_vect) {
uart_ready = 1;
}
void uart_init(void) {
UBRR0H = UBRRH_VALUE;
UBRR0L = UBRRL_VALUE;
UCSR0C = (1<<UCSZ01) | (1<<UCSZ00);
UCSR0B = (1<<RXEN0) | (1<<TXEN0) | (1<<RXCIE0);
}
static int uart_getchar(FILE* stream) {
while (1) {
cli();
if (!uart_ready) {
sleep_enable();
sei();
sleep_cpu();
sleep_disable();
}
cli();
if (uart_ready) {
uart_ready = 0;
unsigned int c = UDR0;
sei();
return c;
}
sei();
}
}
static int uart_putchar(char c, FILE* stream) {
loop_until_bit_is_set(UCSR0A, UDRE0);
UDR0 = c;
return 0;
}
static FILE uart = FDEV_SETUP_STREAM(uart_putchar, uart_getchar, _FDEV_SETUP_RW);
```
Lest work from the bottom up.
The developers here wanted to make a simple way to use the UART in a similar way to `stdin` and `stdout` (as we soon will se in the `main` function). To do that, they define a `FILE` object named `uart`, and defined specific functions for reading and writing characters.
The function `uart_puchar` is for outputting a character, and `uart_getchar` is for reading one.
I will talk about `cli` and `sei` functions at the end of this writeup.
`uart_init` is for initializing the UART port - defining speed, digits, and receive interrupt, which is defended by `ISR(USART_RX_vect) `. All the interrupt does is signaling that there is more input to get by setting the `uart_ready` variable to 1.
(For the sake of clarity, in this part I`m not showing the functions in the same order in the file)
```c
void quit() {
printf("Quitting...\n");
_delay_ms(100);
cli();
sleep_enable();
sleep_cpu();
while (1);
}
void read_data(char* buf) {
scanf("%200s", buf);
}
void print_timer_status() {
printf("Timer: %s.\n", timer_status);
}
```
The function `quit` is used, well, for getting a one million dollar prize!
Nahh not really. Its used to exiting the program. Really, promise.
`read_data` and `print_timer_status` are used to hunt little puppies in the forest.
```c
volatile uint32_t overflow_count;
uint32_t get_time() {
uint32_t t;
cli();
t = (overflow_count << 16) + TCNT1;
sei();
return t;
}
void timer_on_off(char enable) {
overflow_count = 0;
strcpy(timer_status, enable ? "on" : "off");
if (enable) {
TCCR1B = (1<<CS10);
sei();
}
else {
TCCR1B = 0;
}
}
ISR(TIMER1_OVF_vect) {
if (!logged_in) {
overflow_count++;
// Allow ten seconds.
if (overflow_count >= ((10*F_CPU)>>16)) {
printf("Timed out logging in.\n");
quit();
}
}
else {
// If logged in, timer is used to securely copy top secret data.
secret[top_secret_index] = top_secret_data[top_secret_index];
timer_on_off(top_secret_data[top_secret_index]);
top_secret_index++;
}
}
```
First, you need to understand how timers work on AVR, see these links:
https://exploreembedded.com/wiki/AVR_Timer_programming
http://maxembedded.com/2011/06/introduction-to-avr-timers/
`timer_on_off` function is used to start a timer. On Atmega chip, to start a timer we need to set the `TCC1B` register to value that will tell the system timer how fast to run.
`get_time` will measure the current time by checking the the `overflow_count` which specifies how many timer overflows we had by now, essentially meaning how much time has passed since we started the timer.
`ISR(TIMER1_OVF_vect)` is the timer interrupt handler - every time we hit timer overflow, this handler will be called.
If we are not logged in to the system (we will soon see how we do), then the `overflow_count` will increase, until it passed a certain limit (representing about 10 seconds), and will quit the program.
we will talk about the `else ` clause later on.
lets stat with the `main` function. This is the first half.
```c
int main() {
uart_init();
stdout = &uart;
stdin = &uart;
TCCR1A = 0;
TIMSK1 = (1<