0xd13a

A rookie in a world of pwns

FLARE-ON 2017 Writeup: remorse.ino.hex

Tackling an Arduino challenge was intimidating, I have never dealt with that processor before. However things turned out to be not that complicated.

The first step was to familiarize myself with the instruction set.

Luckily IDA Pro knows how to open HEX files (you just have to select the right processor). Disassembly of HEX files can also be done in www.onlinedisassembler.com.

A big help was an annotated decompile of a simple Arduino application originally posted at https://pastebin.com/kH5jpdpX.

I quickly saw similarities between that and the decompile of the challenge binary, spotting standard functions that do initialization and printing (and therefore can be separated from the actual application logic). Namely functions at addresses 0x39b and 0x31d can be called write functions, and function at address 0x332 can be called writeWithNewline.

Let’s assume that the write routine will eventually be used to write out the flag and cross reference all uses of these functions in the code. It turns out that there is a particular function (sub_536) that uses writes and does other interesting behavior that looks like decoding of a flag.

In the function there are several sections:

  • 0x548-0x572 - encrypted flag bytes are stored in memory

  • 0x575-0x57c - flag is decrypted

  • 0x57d-0x580 - flag character at position 10 is checked to be ‘@’

  • 0x58c-0x590 - flag is printed out

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
ROM:0536          sub_536:                                ; CODE XREF: sub_5A0+1E
ROM:0536 93CF          push    r28
ROM:0537 93DF          push    r29
ROM:0538 B7CD          in      r28, SPL  
ROM:0539 B7DE          in      r29, SPH 
ROM:053A 95DA          dec     r29
ROM:053B B60F          in      r0, SREG 
ROM:053C 94F8          cli
ROM:053D BFDE          out     SPH, r29 
ROM:053E BE0F          out     SREG, r0 
ROM:053F BFCD          out     SPL, r28 
ROM:0540 01FE          movw    r30, r28
ROM:0541 9631          adiw    r30, 1
ROM:0542 01DF          movw    r26, r30
ROM:0543 EF9F          ser     r25
ROM:0544 0F9E          add     r25, r30
ROM:0545
ROM:0545          loc_545:                                ; CODE XREF: sub_536+11
ROM:0545 921D          st      X+, r1
ROM:0546 139A          cpse    r25, r26
ROM:0547 CFFD          rjmp    loc_545
ROM:0548 EB95          ldi     r25, 0xB5 ;
ROM:0549 8399          std     Y+1, r25  ;  store byte 0xb5
ROM:054A 839A          std     Y+2, r25  ;  store byte 0xb5
ROM:054B E896          ldi     r25, 0x86 ;
ROM:054C 839B          std     Y+3, r25  ;  store byte 0x86
ROM:054D EB94          ldi     r25, 0xB4 ;
ROM:054E 839C          std     Y+4, r25  ;  store byte 0xb4
ROM:054F EF94          ldi     r25, 0xF4 ;
ROM:0550 839D          std     Y+5, r25  ;  store byte 0xf4
ROM:0551 EB93          ldi     r25, 0xB3 ;
ROM:0552 839E          std     Y+6, r25  ;  store byte 0xb3
ROM:0553 EF91          ldi     r25, 0xF1 ;
ROM:0554 839F          std     Y+7, r25  ;  store byte 0xf1
ROM:0555 EB20          ldi     r18, 0xB0 ;
ROM:0556 8728          std     Y+8, r18  ;  store byte 0xb0
ROM:0557 8729          std     Y+9, r18  ;  store byte 0xb0
ROM:0558 879A          std     Y+0xA, r25;  store byte 0xf1
ROM:0559 EE9D          ldi     r25, 0xED ;
ROM:055A 879B          std     Y+0xB, r25;  store byte 0xed
ROM:055B E890          ldi     r25, 0x80 ;
ROM:055C 879C          std     Y+0xC, r25;  store byte 0x80
ROM:055D EB9B          ldi     r25, 0xBB ;
ROM:055E 879D          std     Y+0xD, r25;  store byte 0xbb
ROM:055F E89F          ldi     r25, 0x8F ;
ROM:0560 879E          std     Y+0xE, r25;  store byte 0x8f
ROM:0561 EB9F          ldi     r25, 0xBF ;
ROM:0562 879F          std     Y+0xF, r25;  store byte 0xbf
ROM:0563 E89D          ldi     r25, 0x8D ;
ROM:0564 8B98          std     Y+0x10, r25; store byte 0x8d
ROM:0565 EC96          ldi     r25, 0xC6 ;
ROM:0566 8B99          std     Y+0x11, r25; store byte 0xc6
ROM:0567 E895          ldi     r25, 0x85 ;
ROM:0568 8B9A          std     Y+0x12, r25; store byte 0x85
ROM:0569 E897          ldi     r25, 0x87 ; 
ROM:056A 8B9B          std     Y+0x13, r25; store byte 0x87
ROM:056B EC90          ldi     r25, 0xC0 ; 
ROM:056C 8B9C          std     Y+0x14, r25; store byte 0xc0
ROM:056D E994          ldi     r25, 0x94 ;
ROM:056E 8B9D          std     Y+0x15, r25; store byte 0x94
ROM:056F E891          ldi     r25, 0x81 ;
ROM:0570 8B9E          std     Y+0x16, r25; store byte 0x81
ROM:0571 E89C          ldi     r25, 0x8C ; 
ROM:0572 8B9F          std     Y+0x17, r25; store byte 0x8c
ROM:0573 E6AC          ldi     r26, 0x6C ;
ROM:0574 E0B5          ldi     r27, 5
ROM:0575 E020          ldi     r18, 0    ;  set loop counter to 0
ROM:0576
ROM:0576          loc_576:                                ; CODE XREF: sub_536+46
ROM:0576 9191          ld      r25, Z+   ;  load encoded value to r25
ROM:0577 2798          eor     r25, r24  ;  XOR with r24
ROM:0578 0F92          add     r25, r18  ;  add loop counter
ROM:0579 939D          st      X+, r25   ;  store decoded character
ROM:057A 5F2F          subi    r18, -1   ;  increment loop counter
ROM:057B 3127          cpi     r18, 0x17 ;  quit once we have processed 0x17 characters
ROM:057C F7C9          brne    loc_576
ROM:057D 9180 0576     lds     r24, 0x576;  load character from position 10 in the string (0x576-0x56c)
ROM:057F 3480          cpi     r24, 0x40 ;  make sure it is '@'
ROM:0580 F4A1          brne    loc_595
ROM:0581 E26B          ldi     r22, 0x2B ; 
ROM:0582 E075          ldi     r23, 5
ROM:0583 E88F          ldi     r24, 0x8F ;
ROM:0584 E095          ldi     r25, 5
ROM:0585 940E 0332     call    subWriteWithNewline_332 ; write Correct Pin State message
ROM:0587 E167          ldi     r22, 0x17
ROM:0588 E68C          ldi     r24, 0x6C ;  load flag address (0x56c)
ROM:0589 E095          ldi     r25, 5
ROM:058A 940E 04F0     call    sub_4F0
ROM:058C E66C          ldi     r22, 0x6C ; 
ROM:058D E075          ldi     r23, 5          
ROM:058E E88F          ldi     r24, 0x8F ;
ROM:058F E095          ldi     r25, 5
ROM:0590 940E 0332     call    subWriteWithNewline_332 ; write flag
ROM:0592 E081          ldi     r24, 1
ROM:0593 E090          ldi     r25, 0
ROM:0594 C002          rjmp    loc_597
ROM:0595          ; ---------------------------------------------------------------------------
ROM:0595
ROM:0595          loc_595:                                ; CODE XREF: sub_536+4A
ROM:0595 E080          ldi     r24, 0
ROM:0596 E090          ldi     r25, 0
ROM:0597
ROM:0597          loc_597:                                ; CODE XREF: sub_536+5E
ROM:0597 95D3          inc     r29
ROM:0598 B60F          in      r0, SREG
ROM:0599 94F8          cli
ROM:059A BFDE          out     SPH, r29  
ROM:059B BE0F          out     SREG, r0 
ROM:059C BFCD          out     SPL, r28 
ROM:059D 91DF          pop     r29
ROM:059E 91CF          pop     r28
ROM:059F 9508          ret
ROM:059F          ; End of function sub_536

In this algorithm the only unknown factor is the value of r24, but to save time we can bruteforce it.

Let us rewrite the algorithm in Python:

1
2
3
4
5
6
7
8
9
10
11
flag = [0xB5, 0xB5, 0x86, 0xB4, 0xF4, 0xB3, 0xF1, 0xB0, 0xB0, 0xF1, 0xED, 0x80, 0xBB, 0x8F, 0xBF, 0x8D, 0xC6, 0x85, 0x87, 0xC0, 0x94, 0x81, 0x8C]

for z in range(0x100):
	out = ""

	for x in range(len(flag)):
		out += chr(((flag[x] ^ z) + x) & 0xFF)
		
	if out[10] == '@':	
		print out
		break

Running the script gets us the flag:

1
2
C:\work\flareon17\remorse>\Python27\python.exe remorse_solve.py
no_r3m0rs3@flare-on.com