Saturday, 4 November 2017

CTF Writeup - Flare-On 2017 - 09: remorse.ino.hex


  • Name - remorse.ino.hex
  • Category - Reverse Engineering
  • Points - 1
  • Binary - Download here

The 9th Flare-On challenge was an Arduino one. When I saw the contents of remorse.ino.hex I was confused as to what it was. It didn't look remotely like any other RE challenge I've seen before:

:100000000C9462000C948A000C948A000C948A0070
:100010000C948A000C948A000C948A000C948A0038
:100020000C948A000C948A000C948A000C948A0028
:100030000C948A000C948A000C948A000C948A0018

[ ... snip ... ]


After some research I found that this I was dealing with an Intel hex file for an Arduino UNO, i.e. an ATmega328P microcontroller. From here I've tried several methods to run the file such as using Atmel Studio or simavr but I couldn't find ways of interacting with the running program. I was even contemplating running it on a real Arduino. At the end I decided to load it in IDA and try my luck using static analysis.

To load it properly in IDA, open the file, select ATMEL AVR and then select ATmega323_L. IDA nicely annotates some of the registers and pins for us too. After some time looking at the functions, sub_536() in particular caught my eye. The following are 2 screenshots of the entire function:


Notice the comparison with the character '@' in small red basic block. This hinted that we were probably dealing with an email address, and hence the key. Before we can understand what is happened, we need to learn a few AVR instructions. The following are the necessary ones to understand what is happening in the green and yellow basic blocks:
  • LD - Load Indirect from Data Space to Register
  • LDI - Load Immediate
  • ST - Store Indirect From Register to Data Space
  • STD - Store Indirect From Register to Data Space
  • EOR - Exclusive OR
  • SUBI - Subtract Immediate
  • CPI - Compare with Immediate

Nothing too fancy! The instructions are very simple. Using our newly acquired knowledge we can see that in the green basic block, 0x17 bytes are being loaded starting from the Y register. In the yellow basic block, for each of the previous bytes, it XOR's it with an unknown value taken from register Z+ and adds the counter value to it, which is held in register r18. At each iteration, register r18 is incremented and compared with value 0x17.

As the only unknown value here is Z+, and we're dealing with an 8-bit processor, we can easily bruteforce the solution. The following is a python program that does this:

encrypted = [0xb5,0xb5,0x86,0xb4,0xf4,0xb3,0xf1,0xb0,0xb0,0xf1,0xed,0x80,0xbb,0x8f,0xbf,0x8d,0xc6,0x85,0x87,0xc0,0x94,0x81,0x8c]

for y in range (255):
    answer = ''
    for x in range(len(encrypted)):
        answer += chr(((encrypted[x] ^ y) + x) % 256)
        
    if answer[10] == '@':
        print answer
        break

Running the script:

Command Prompt
C:\>python solution.py no_r3m0rs3@flare-on.com C:\>

No comments:

Post a Comment