This is an Arduino (AVR) challenge. You can read the full official solution from FireEye, here I just want to show how we can just find use “grep” to quickly find the decryption function to get the flag.
At first, I was going to try to understand what this binary does, but before going too deep, I had an idea: this binary is so small, what if I can just find the flag string without looking at the program’s logic. Looking at the strings present in the binary, it is obvious The flag is not in cleartext, so it must be encrypted somehow.
Most encryption algorithm will involve the use of XOR (eor
in AVR). Looking at the disassembly, all EORs are just to clear a register (e.g: eor r1, r1
). There is only one eor
in 0xaee
that is not clearing a register (eor r25, r24
), which is the last one in this grep
output.
$ avr-objdump -m avr -D remorse.ino.hex |grep eor c4: 11 24 eor r1, r1 1ec: 99 27 eor r25, r25 2e6: 99 27 eor r25, r25 340: 11 27 eor r17, r17 59e: 88 27 eor r24, r24 742: 11 24 eor r1, r1 78e: 11 24 eor r1, r1 7f2: 11 24 eor r1, r1 904: 11 24 eor r1, r1 a16: 11 24 eor r1, r1 aee: 98 27 eor r25, r24
Looking at the code around it: it is a single loop, with eor
and subi
. This must be the decrypt loop.
ae6: ldi r26, 0x6C ; 108 ae8: ldi r27, 0x05 ; 5 aea: ldi r18, 0x00 ; 0 decrypt: aec: ld r25, Z+ aee: eor r25, r24 af0: add r25, r18 af2: st X+, r25 af4: subi r18, 0xFF ; 255 af6: cpi r18, 0x17 ; 23 af8: brne .-14 ; 0xaec
We just need to find the encrypted data pointed by Z (which is a pair of R31:R30), and r24 (the xor key). Looking a bit up, we found the code that fills in the encrypted data. It sets Z with the value of Y (pair of R29:R28), clears the memory, and fill it with some bytes.
a80: movw r30, r28 ; Z = Y a82: adiw r30, 0x01 ; Z++ a84: movw r26, r30 ; X = Z a86: ldi r25, 0xFF ; a88: add r25, r30 ; clear: a8a: st X+, r1 a8c: cpse r25, r26 a8e: rjmp .-6 ; 0xa8a a90: ldi r25, 0xB5 a92: std Y+1, r25 a94: std Y+2, r25 a96: ldi r25, 0x86 a98: std Y+3, r25 a9a: ldi r25, 0xB4 a9c: std Y+4, r25 a9e: ldi r25, 0xF4 aa0: std Y+5, r25 aa2: ldi r25, 0xB3 aa4: std Y+6, r25 aa6: ldi r25, 0xF1 aa8: std Y+7, r25 aaa: ldi r18, 0xB0 aac: std Y+8, r18 aae: std Y+9, r18 ab0: std Y+10, r25 ab2: ldi r25, 0xED ab4: std Y+11, r25 ab6: ldi r25, 0x80 ab8: std Y+12, r25 aba: ldi r25, 0xBB abc: std Y+13, r25 abe: ldi r25, 0x8F ac0: std Y+14, r25 ac2: ldi r25, 0xBF ac4: std Y+15, r25 ac6: ldi r25, 0x8D ac8: std Y+16, r25 aca: ldi r25, 0xC6 acc: std Y+17, r25 ace: ldi r25, 0x85 ad0: std Y+18, r25 ad2: ldi r25, 0x87 ad4: std Y+19, r25 ad6: ldi r25, 0xC0 ad8: std Y+20, r25 ada: ldi r25, 0x94 adc: std Y+21, r25 ade: ldi r25, 0x81 ae0: std Y+22, r25 ae2: ldi r25, 0x8C ae4: std Y+23, r25
Going a bit up again, we found a ret
(return), which means its the end of another function/subroutine. It seems that r24
is filled somewhere else by the caller of this decrypt function.
It doesn’t matter, r24
is just an 8 bit register (256 possible values). Translating this to python, with a brute force loop:
a = "b5b586b4f4b3f1b0b0f1ed80bb8fbf8dc68587c094818c".decode("hex") for key in range(0, 256): s = '' for i,c in enumerate(a): m = ((ord(c)^key) + i)&0xff s = s + chr(m) print key, hex(key), s
And since all flags always have a flare-on.com suffix, we can just add a grep:
$ python brute.py|strings|grep flare 219 0xdb no_r3m0rs3@flare-on.com
So the flag is no_r3m0rs3@flare-on.com
and the key is 219 decimal (0xdb).