..

InCTF 18 Write-Ups

Reversing

Debug (993 pts, 5 solves)

Chall Description:

Difficulty Level : Easy

One of our friends found this old hex file in his Flash Folder, do you mind telling him about what the file does?

Let’s take a look at the file.

file debug.ino.hex

Output

debug.ino.hex: ASCII text, with CRLF line terminators

And taking a careful look at the file name, gives us the clue, ‘ino’, the file format for the Arduino programs. So, we now know that we’re looking at a Arduino flash file. So we have here a hex file, file to reverse. Pretty simple eh? A simple hex file reversing.

But how to get the binary out of the hex file? We first need to convert the hex file into a binary file, inorder to dissassemble it.

Since we know that most of the Arduino’s use AVR arch, let’s use it’s objcopy to convert our hex files.

avr-objcopy -v -I ihex -O binary debug.ino.hex test.bin

We now have a file test.bin.

file test.bin

test.bin: ELF 32-bit LSB executable, Atmel AVR 8-bit, version 1 (SYSV), statically linked, stripped

Stripped binary, that means no function names, which only makes the RE a tad more difficult.

strings test.bin

Pin mismatch

An interesting output, could give us a clue about the program is about.

Again to reverse this file, we can have 2 approaches :

  • Statically disassemble the whole file
  • Dynamically load the hex/ELF into a simulator and debug simultaneously.

Static Analysis

Let’s start looking at the static disassembly of the program. There’s good support for AVR with radare2, so let’s use radare2 to load our program.

r2 -A test.bin

Taking a look at all the functions using afl.

0x00000000   13 3530 -> 88   entry0
0x00000118    9 70           fcn.00000118
0x0000015e    6 86           fcn.0000015e
0x0000021e    1 24           fcn.0000021e
0x00000236    3 20           fcn.00000236
0x0000024a    4 66           fcn.0000024a
0x0000035e    4 20           fcn.0000035e
0x00000372   18 82           fcn.00000372
0x000003c4    7 82           fcn.000003c4
0x00000416    9 96           fcn.00000416
0x00000476    9 120          fcn.00000476
0x000004ee    4 74   -> 64   fcn.000004ee
0x00000538    1 24           fcn.00000538
0x00000550   16 188          fcn.00000550
0x00000626   70 938          fcn.00000626
0x00000c32    3 384          fcn.00000c32
0x00000db2    1 12           fcn.00000db2
0x00000dbe    3 12   -> 14   fcn.00000dbe

We need to look for points that emulate the functions that show the printf or in our case digitalWrite, this is to ensure that the we are on the right track!

Looking at the entry point’s disassembly:

/ (fcn) entry0 88
|   entry0 ();
|           ; CODE XREF from fcn.0000035e (0x36c)
|           0x00000000      0c946200       jmp 0xc4                    ; [06] ---- section size 62 named .shstrtab
..
  |||||||   ;-- aav.0x0000008a:
  | |||||||   ; CODE XREF from entry0 ()
  | |||||||   0x000000c4      1124           clr r1
  | |||||||   0x000000c6      1fbe           out 0x3f, r1                ; '?' ; IO SREG: flags
  | |||||||   0x000000c8      cfef           ser r28
  | |||||||   0x000000ca      d8e0           ldi r29, 0x08
  | |||||||   0x000000cc      debf           out 0x3e, r29               ; '>' ; IO SPH: Stack higher bits SP8-SP10
  | |||||||   0x000000ce      cdbf           out 0x3d, r28               ; '=' ; IO SPL: Stack lower bits SP0-SP7
  | |||||||   0x000000d0      11e0           ldi r17, 0x01
  | |||||||   0x000000d2      a0e0           ldi r26, 0x00
  | |||||||   0x000000d4      b1e0           ldi r27, 0x01
  | |||||||   0x000000d6      ecec           ldi r30, 0xcc
  | |||||||   0x000000d8      fde0           ldi r31, 0x0d
  | ========< 0x000000da      02c0           rjmp 0xe0
  | |||||||   ; CODE XREF from entry0 (0xe4)
  | --------> 0x000000dc      0590           lpm r0, z+
  | |||||||   0x000000de      0d92           st x+, r0
  | |||||||   ; CODE XREF from entry0 (0xda)
  | --------> 0x000000e0      aa34           cpi r26, 0x4a
  | |||||||   0x000000e2      b107           cpc r27, r17
  | ========< 0x000000e4      d9f7           brne 0xdc
  | |||||||   0x000000e6      22e0           ldi r18, 0x02
  | |||||||   0x000000e8      aae4           ldi r26, 0x4a               ; 'J'
  | |||||||   0x000000ea      b1e0           ldi r27, 0x01
  | ========< 0x000000ec      01c0           rjmp 0xf0
  | |||||||   ; CODE XREF from entry0 (0xf4)
  | --------> 0x000000ee      1d92           st x+, r1
  | |||||||   ; CODE XREF from entry0 (0xec)
  | --------> 0x000000f0      af38           cpi r26, 0x8f
  | |||||||   0x000000f2      b207           cpc r27, r18
  | ========< 0x000000f4      e1f7           brne 0xee
  | |||||||   0x000000f6      10e0           ldi r17, 0x00
  | |||||||   0x000000f8      c2e6           ldi r28, 0x62               ; 'b'
  | |||||||   0x000000fa      d0e0           ldi r29, 0x00
  | ========< 0x000000fc      04c0           rjmp 0x106
  | |||||||   ; CODE XREF from entry0 (0x10a)
  | --------> 0x000000fe      2197           sbiw r28, 0x01
  | |||||||   0x00000100      fe01           movw r30, r28
  | |||||||   0x00000102      0e94d906       call fcn.00000db2
  | |||||||   ; CODE XREF from entry0 (0xfc)
  | --------> 0x00000106      c136           cpi r28, 0x61
  | |||||||   0x00000108      d107           cpc r29, r17
  | ========< 0x0000010a      c9f7           brne 0xfe
  | |||||||   0x0000010c      0e941906       call fcn.00000c32
  | ========< 0x00000110      0c94e406       jmp 0xdc8
  ..
  |   | |::   ;-- aav.0x00000704:
  |       |   ; CODE XREF from entry0 (0x110)
  |       |   ; CODE XREF from fcn.00000dbe (0xdc4)
  \ ------`-> 0x00000dc8      f894          cli 

We can here notice that the loop function is fcn.0000c32 .

Let’s take a look at the fcn.0000c32 function.

|       .-> 0x00000d9a      8191           ld r24, z+
|       :   0x00000d9c      8927           eor r24, r25
|       :   0x00000d9e      8d93           st x+, r24
|       :   0x00000da0      81e0           ldi r24, 0x01
|       :   0x00000da2      e338           cpi r30, 0x83
|       :   0x00000da4      f807           cpc r31, r24
|       `=< 0x00000da6      c9f7           brne 0xd9a
|           ; CODE XREF from fcn.00000c32 (0xdb0)
|       .-> 0x00000da8      0e941303       call fcn.00000626
|       :   0x00000dac      0e94af01       call fcn.0000035e
\       `=< 0x00000db0      fbcf           rjmp 0xda8

Again giving us 2 different functions to look at.

The fcn.00000626 seems like a pretty big function to reverse, let’s take the look at fcn.0000035e.

/ (fcn) fcn.0000035e 20
|   fcn.0000035e ();
|           ; CALL XREF from fcn.00000c32 (0xdac)
|           0x0000035e      80e0           ldi r24, 0x00
|           0x00000360      90e0           ldi r25, 0x00
|           0x00000362      892b           or r24, r25
|       ,=< 0x00000364      29f0           breq 0x370
|       |   0x00000366      0e941b01       call fcn.00000236
|      ,==< 0x0000036a      8111           cpse r24, r1
|      ||   0x0000036c      0c940000       jmp 0x0                     ; entry0
|      ||   ; CODE XREFS from fcn.0000035e (0x364, 0x36a)
\      ``-> 0x00000370      0895           ret
/ (fcn) fcn.00000236 20
|   fcn.00000236 ();
|           ; CALL XREF from fcn.0000035e (0x366)
|           0x00000236      83e8           ldi r24, 0x83
|           0x00000238      91e0           ldi r25, 0x01
|           0x0000023a      0e940f01       call fcn.0000021e
|           0x0000023e      21e0           ldi r18, 0x01
|           ; DATA XREF from fcn.00000626 (0x894)
|           0x00000240      892b           or r24, r25
|       ,=< 0x00000242      09f4           brne 0x246
|       |   0x00000244      20e0           ldi r18, 0x00
|       |   ; CODE XREF from fcn.00000236 (0x242)
|       `-> 0x00000246      822f           mov r24, r18
\           0x00000248      0895           ret
(fcn) fcn.0000021e 24
|   fcn.0000021e ();
|           ; CALL XREF from fcn.00000236 (0x23a)
|           0x0000021e      fc01           movw r30, r24
|           ; DATA XREF from aav.0x00000704 (+0x4ac)
|           0x00000220      918d           ldd r25, z+25
|           ; DATA XREF from aav.0x00000704 (+0x494)
|           0x00000222      228d           ldd r18, z+26
|           0x00000224      892f           mov r24, r25
|           ; DATA XREF from aav.0x00000704 (+0x498)
|           0x00000226      90e0           ldi r25, 0x00
|           0x00000228      805c           subi r24, 0xc0
|           0x0000022a      9f4f           sbci r25, 0xff
|           0x0000022c      821b           sub r24, r18
|           0x0000022e      9109           sbc r25, r1
|           0x00000230      8f73           andi r24, 0x3f              ; '?'
|           0x00000232      9927           clr r25
\           0x00000234      0895           ret

Which seems to load some values and call other functions, possibly a part of serial_write function.

Let’s take a look at the fcn.00000626 , which seems like a probable canditate for the major loop function.

The function is very big, therefore I would only be putting the CFG ;)

---------------------------------------------------------------------------.
                                                                           |
                                                                     .--------------------.
                                                                     |  fcn.00000626      |
                                                                     `--------------------'
                                                                           v
                                                                           |
      .--------------------------------------------------------------------|
      |                         .------------------------------------------|
      |                         .------------------------------------------|
      |                         |                         .----------------|
      |                         |                         |                |--------.
      |                         |                         .----------------|        |
      |                         .------------------------------------------|        |
      |                         |                         |                |----------------------------------.
      .--------------------------------------------------------------------|        |                         |
      |                         |                         |                |------------------------------------------------------------.
      |                         |                         |                |--------------------------------------------------------------------------------------.
      |                         |                         |                |--------------------------------------------------------------------------------------.
---------------------------------------------------------------------------'        |                         |                         |                         |
      |                         |                         |                '------------------------------------------------------------.                         |
      |                         |                         |                         |                         |                         |                         |
.--------------------.    .--------------------.    .--------------------.    .--------------------.    .--------------------.    .--------------------.    .--------------------.
|  fcn.00000538      |    |  fcn.00000476      |    |  fcn.00000416      |    |  fcn.000003c4      |    |  fcn.00000550      |    |  fcn.0000015e      |    |  fcn.000004ee      |
`--------------------'    `--------------------'    `--------------------'    `--------------------'    `--------------------'    `--------------------'    `--------------------'

As I mentioned eariler will have to make sure that we find out the function responsible for digital writing data. And since this seems the function running in the loop, we must be able to find the write function amongnst the above functions. fcn.000003c4 and fcn.00000416 seems like possible candidates for the write function. But fcn.00000416 seems to be the function as it has lot of instructions loading memories and writing it to various modes.

There for we need to make sure that we see that the conditions that are compared.

Taking a look at the whole function, we can arrive at the following psuedo-code.

int n=0;
for(n=0;n<4;)
    {
        char input = Key.getKey();
        if(input)
            {
                Serial.print(input);
                if(input!=in[n])
                    {   
                       Serial.print(??);
                       delay(1200);
                       fucn(); //The func we are reversing
                    }
                inputer[n]=input;
                n++;
             }
        for (int i = 0; i < 4; i++)
            input_intg = 10 * input_intg + inputer[i];
        Serial.print(??FLAG??);  
}

Which then causes use to wonder how to find out the required input? One could either check for the assmebly to find out the PIN and then follow the function, and possibly follow to find the code.

But still how to emulate the ELF file? Not everyone has a Arduino at home :(

Dynamic Analysis

That’s where simavr comes handy, since the author had a example case ready for the Arduino Uno ready. (Wondering where we got Uno from, check the strings on the file again) Steps to emulate:

  1. Compile the program. Follow the instructions in the README.md
  2. Take a look at the examples/board_simduino directory.
  3. Again compile the program.
  4. Run ./simduino.elf
read_ihex_chunks: ATmegaBOOT_168_atmega328.ihex, unsupported check type 03
atmega328p booloader 0x07800: 1950 bytes
avr_special_init
uart_pty_init bridge on port *** /dev/pts/3 ***
uart_pty_connect: /tmp/simavr-uart0 now points to /dev/pts/3
note: export SIMAVR_UART_XTERM=1 and install picocom to get a terminal
  1. Then run

avrdude -p m328p -c arduino -P /dev/pts/?? -U flash:w:debug.ino.hex

avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.00s

avrdude: Device signature = 0x1e950f (probably m328p)
avrdude: NOTE: "flash" memory has been specified, an erase cycle will be performed
To disable this feature, specify the -D option.
avrdude: erasing chip
avrdude: reading input file "debug.ino.hex"
avrdude: input file debug.ino.hex auto detected as Intel Hex
avrdude: writing flash (4180 bytes):

Writing | ################################################## | 100% 0.14s

avrdude: 4180 bytes of flash written
avrdude: verifying flash memory against debug.ino.hex:
avrdude: load data flash data from input file debug.ino.hex:
avrdude: input file debug.ino.hex auto detected as Intel Hex
avrdude: input file debug.ino.hex contains 4180 bytes
avrdude: reading on-chip flash data:

Reading | ################################################## | 100% 0.28s

avrdude: verifying ...
avrdude: 4180 bytes of flash verified

avrdude: safemode: Fuses OK (E:00, H:00, L:00)
ioctl("TIOCMGET"): Invalid argument

avrdude done.  Thank you.
  1. And for serial communication

picocom /tmp/simavr-uart0

  1. To remotely debug the program using a GDB stub

simavr -g -m atmega328p test.bin

And then use avr-gdb to connect.

Using any of the above methods you can find out that the PIN was 7331 and the Flag : InCTF{4Vr_!sNt_B4D}

If you found the challenge difficult,you could try the unstripped binary for starters :) ELF

P.S I intend to do a short series of blog-posts on AVR Reversing and Assembly, stayed tuned!
Not AI generated