Skip to content

Commit

Permalink
RHME2 jumpy
Browse files Browse the repository at this point in the history
  • Loading branch information
Yohanes Nugroho committed Mar 5, 2017
1 parent e682c80 commit 2514e9f
Show file tree
Hide file tree
Showing 3 changed files with 152 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Expand Up @@ -7,3 +7,4 @@ Current write-up:

* [Flare On 2015](flare-2015)
* [Google CTF 2016](google-ctf)
* [RHME 2 (Nov 2016 - Feb 2017)](rhme2)
96 changes: 96 additions & 0 deletions rhme2/README.md
@@ -0,0 +1,96 @@
# RHME 2

I didn't have CHIP Whisperer and only solved most things that doesn't require special hardware.

## Introduction and Notes

This is mostly for myself so that I would remember how to do AVR reversing again in the future, but hopefully it is clear enough for others to learn.

### Tools used

Main tools that I used for solving the challenges are:

* avr-gcc and avr-binutils (especially avr-objdump)
* vim
* simulavr (using [this fork](https://github.com/Traumflug/simulavr) )
* platformio
* sigrok

Documentations

* [AVR Instruction Set Manual](http://www.atmel.com/images/Atmel-0856-AVR-Instruction-Set-Manual.pdf)
* [Atmega 328 datasheet](http://www.atmel.com/Images/Atmel-42735-8-bit-AVR-Microcontroller-ATmega328-328P_Datasheet.pdf)

As for the hardware:

* My own arduino nano for testing
* cypress development board as logic analyzer

### Setup

The purpose of my setup was so I could solve the challenges remotely. So I plugged the RHME Arduino Nano to my Raspberry Pi 2 (RPI2). During some challenges I attached another Nano for testing some undocumented behavior (e.g: what happens if you try to read past the flash size? would it wrap around?). During other challenges, I attached the cypress logic analyzer

It turns out its quite useful: once in a while we can't reprogram the board unless we replug it, using RPI2, I can just shutdown the USB power and start it again. If that didn't work, I just rebooted the RPI2 remotely.

### Tools notes

Except for Reversing challenges, we are given only *encrypted* hex files which we can not reverse. For the reversing tasks we are also given the corresponding ELF file. When we are given an ELF file, we can convert it into hex so we can write it to our own arduino:

avr-objcopy

Unfortunately for the impostor challenge, there is a jump to the bootloader that makes it not possible to run the code in our own Arduino.

### Reversing Notes

In desktop app, we will usually find basic calls to `printf` or `getc` as our starting point and start tracing back from ther. Since I/Os are done using serial port, we will try to find the most basic instruction sequence that accessed the serial port/UART. Instruction that called the basic `putc` is `puts`. Comparing this with `avr-gcc` output, we can conclude that the challenges were written using gcc and they used the included standard C library.

From the documentation to read or write to serial port we will need to access USART I/O Data Register 0 (UDR0). This is located at offset `C6`. Here is a piece of code that reads `C6` (from [Jumpy](jumpy)) challenge:

2ba: 86 ec ldi r24, 0xC6 ; 198
2bc: 90 e0 ldi r25, 0x00 ; 0
2be: fc 01 movw r30, r24
2c0: 80 81 ld r24, Z

And a piece of code that writes to `C6`

ea: 86 ec ldi r24, 0xC6 ; 198
ec: 90 e0 ldi r25, 0x00 ; 0
ee: 29 81 ldd r18, Y+1 ; 0x01
f0: fc 01 movw r30, r24
f2: 20 83 st Z, r18

After we identify the basic instructions, we will see that calls to this functions are passed with strange address, which doesn't seem to contain printable ASCII characters. We need to go to the initial instructions, to see that there is a copy instruction from ROM to RAM. This is mostly done for simplicity reason: AVR uses separate data and instruction bus, and also has different address space for data and program. To make it easy for compiler, data are moved to RAM for easy access.


## Solved Tasks

### Reversing

I solved all the reversing tasks as it doesn't require any special hardware.

* [Jumpy](jumpy)
* [Impostor](impostor)
* [FridgeJIT](fridge-jit)

### Exploitation

The exploitation tasks are a bit disappointing, mostly trial and error to exploit format string bugs, except for the Weird Machine.

* [Animals](animals)
* [Casino](casino)
* [Photo Manager](photo-manager)
* [Weird Machine](weird-machine)

### Crypto

Crypto tasks requires intelligent guessing

* [Key Server](key-server)
* [Secure Filesystem](secure-filesystem)
* [Secure Filesystem v1.92r1](secure-filesystem-v1.92r1)

### Others

* [Whac the mole](whack-the-mole)
* [Secret Sauce](secret-sauce)

55 changes: 55 additions & 0 deletions rhme2/jumpy/README.md
@@ -0,0 +1,55 @@
# Jumpy (Chal 5, 100pts)

>> We really need access to this lab protected with an Arduino-based access control system. Our operatives obtained a flash dump from a non-personalized engineering sample, but we are having trouble reverse engineering it.
>> Can you help us get the password to get through?
Please note: after solving this outside of the device, you need to enter the password *on* the RHME device to get the flag.

In this task we are given a hex and ELF file. This is one of the tasks that can be solved without having the RHME device. When we run the ELF, using another Arduino Nano or using simulavr, we will be presented with a password query.

The "Jumpy" in the title is because the program seems to jump around checking if our password is correct. This is accomplished by setting up stack contents so that when a subroutine returns, it will return to another subroutine.

Since this is the first AVR program that I reversed, I was not really sure about my static analysis capability, so the easiest way for me was to run `simulavr`. Using the trace option, I was able to see all the addresses of the subroutines.

The checks are done per two characters, overlapping with previous check, for example, the first check is: `ord(password[0])*ord(password[1])==0x13b7`. We can find that the factor is 7, 7, and 103, and since passwords uses printable characters we can guess that first character and second character is `1` and `g`, but the order may be `g` then `1`.


620: cf 93 push r28
622: df 93 push r29
624: cd b7 in r28, 0x3d ; 61
626: de b7 in r29, 0x3e ; 62
628: 80 91 2e 01 lds r24, 0x012E ; 0x80012e -> first char
62c: 48 2f mov r20, r24
62e: 50 e0 ldi r21, 0x00 ; 0
630: 80 91 2f 01 lds r24, 0x012F ; 0x80012f -> second char
634: 28 2f mov r18, r24
636: 30 e0 ldi r19, 0x00 ; 0
638: 42 9f mul r20, r18 ; a*b
63a: c0 01 movw r24, r0 ; copy to r25:24
63c: 43 9f mul r20, r19 ; *0
63e: 90 0d add r25, r0 ;
640: 52 9f mul r21, r18 ; *0
642: 90 0d add r25, r0 ;
644: 11 24 eor r1, r1
646: 87 3b cpi r24, 0xB7 ; 183 'g' '1' or '1' 'g'
648: 93 41 sbci r25, 0x13 ; 19


The second check is `ord(password[1]) + ord(password[2]) == 0xA7`. We were not sure if `password[1]` is `1` or `g`, if it is `1`, then the second character will be `v`, otherwise it will be `@`.

5a0: 80 91 2f 01 lds r24, 0x012F ; 0x80012f 'char 1'
5a4: 28 2f mov r18, r24
5a6: 30 e0 ldi r19, 0x00 ; 0
5a8: 80 91 30 01 lds r24, 0x0130 ; 0x800130 'char 2'
5ac: 88 2f mov r24, r24
5ae: 90 e0 ldi r25, 0x00 ; 0
5b0: 82 0f add r24, r18
5b2: 93 1f adc r25, r19
5b4: 87 3a cpi r24, 0xA7 ; 167 '@' or 'v'
5b6: 91 05 cpc r25, r1
5b8: 51 f4 brne .+20 ; 0x5ce

There are more series of checks like these. If you didn't solve the first challenge, this is a good simple exercise to do the rest.

The final password is `g1v3_1t_t0_m3`

0 comments on commit 2514e9f

Please sign in to comment.