GRID_WAVE
Flag
dach2025{eada28984ece76ce258f354d1a87c140a2062347}
Summary
Reversing an AVR binary to get the flag byte by byte using GDB under QEMU.
Details
To run and debug the AVR binary, we use qemu-system-avr:
qemu-system-avr -M uno -bios GRID_WAVE_4X8_LangleyMicros.vr -nographic \
-serial tcp::5678,server=on,wait=off \
-s -S
The -s -S flags open a GDB server on port 1234. Connect with:
avr-gdb -nx -ex 'target remote :1234' GRID_WAVE_4X8_LangleyMicros.vr
The serial interface is available via telnet localhost 5678.
Getting clean disassembly from Ghidra was unreliable for AVR, so we used avr-objdump instead:
avr-objdump -D -m avr GRID_WAVE_4X8_LangleyMicros.vr > caca.asm
Running this YARA ruleset against the binary reveals it uses RIPEMD-160. This was useful context but not strictly necessary to solve it.
The key function is a comparison loop at 0x8a4:
; r24:r25 - Pointer to A (our input hash)
; r22:r23 - Pointer to B (the expected hash)
; r20:r21 - Length (20 bytes for RIPEMD-160)
8a4: fb 01 movw r30, r22
8a6: dc 01 movw r26, r24
8a8: 04 c0 rjmp .+8 ; jump to 0x8b2
8aa: 8d 91 ld r24, X+ ; load byte from our input
8ac: 01 90 ld r0, Z+ ; load byte from expected (Z++)
8ae: 80 19 sub r24, r0 ; compare
8b0: 21 f4 brne .+8 ; bail if not equal
8b2: 41 50 subi r20, 0x01 ; decrement length
8b4: 50 40 sbci r21, 0x00
8b6: c8 f7 brcc .-14 ; loop
At 0x8ac, r0 is loaded with the expected hash byte just before comparison. Setting a breakpoint here and reading $r0 after each iteration gives us the target hash one byte at a time.
Method 1 — GDB automation
(gdb) define pipi
Type commands for definition of "pipi".
End with a line saying just "end".
>ni
>printf "%x", $r0
>set $PC2=0x8ac
>end
Run pipi 20 times to get all 20 bytes of the expected RIPEMD-160 hash.
GDB and AVR process memory were out of sync when trying to read the
Zregister’s memory directly — had to read$r0after eachldinstruction instead.
Method 2 — Oracle bruteforce
Send progressively longer prefixes of the correct hash as input. Each time the comparison reaches a new byte position, $r0 will contain the next expected byte (at the moment the comparison fails).
LAUNCHCODE> eada28984ece76ce258f354d1a87c140a2062347
Success
[!] Activating GRIDWAVE...
dach2025{eada28984ece76ce258f354d1a87c140a2062347}