This hardware challenge was very interesting to us. We weren't able to solve it during the CTF, be we got it the day after!
All we had was an hex dump of asm code of a bootloader for the microprocessor PIC18F452 (8 MHz clock). After a lot of time spent studying the architecture and IS of the PIC18F model and reversing the bootloader, we've grasped that:
* First of all, the PIC would execute a function that prints "g" unless it recieves an "r". This "r" means that the PIC is ready to receive bytes.* After this was done, the PIC was answering (in a cycle) "cyx" after every 3 letters sent to it. We've later discovered the meaning of this:    * The "c" stands for "command". Sending an "R" after the "c" would cause the PIC to run our code    * The "x" and "y" were used to pass in input bytes. These bytes were then stored in memory (in blocks of 64, which means we MUST write at least 64 bytes to have our bytes written to memory).
With all of this said, we hunched that we had to dump the memory of the program! We did this using the following script:```python#!/usr/bin/env python
from pwn import *
HOST, PORT = 'localhost', 8686
context.log_level = 'debug'io = remote(HOST, PORT)
io.sendafter('g', 'r')
BLOCK = 64
# PRINT A FOREVER (just a little poc that we were executing code)# code  = "\x41\x0E"              # MOVLW 'A'# code += "\x5E\x6E"              # MOVWF DATA_0x5e # code += "\x52\xEC\x3F\xF0"      # CALL SEND_OUT_BYTE()# code += "\xFD\xD7"              # BRA -3
# DUMP RAM
code  = "\x00\x0E"                          # MOVLW \x00code += "\xf6\x6E"                          # MOVWF TBLPTR_Lcode += "\xf7\x6E"                          # MOVWF TBLPTR_Hcode += "\xf8\x6E"                          # MOVWF TBLPTR_Ucode += "\x09\x00"                          # TBLRD*+     <-------------code += "\xF5\xCF\x5E\xF0"                  # MOVFF TABLAT, REG_OUT     |code += "\x52\xEC\x3F\xF0"                  # CALL SEND_OUT_BYTE()      |code += "\xFA\xD7"                          # BRA -6  ------------------>
code += "\x00\x00" * ((BLOCK - len(code)) // 2) # pad to 64 bytesassert len(code) % BLOCK == 0
# Send the codefor i in range(0, len(code), 2):    io.sendafter('c', '.')    io.sendafter('y', code[i])    io.sendafter('x', code[i+1])
# Run the code we sentio.sendafter('c', 'R')
context.log_level = "info"
# Receive the dumpbuff = b""p = log.progress("Bytes dumped")try:    while True:        buff += io.recv()        p.status(str(len(buff)))except:    passfinally:    with open('memdump.bin', 'wb+') as f:        f.write(buff)
    print("DONE!")```
We can then execute `strings` on the dump to find the flag!```strings memdump.binSnTn9n:n?=n>n5AnBn+EnFn9n:n=n>nAnBnEnFn9n:n=n>nAnBnEnFn9n:n]=n>nSAnBnIEnFnonpjlAero{Y0u_c4N_dmp_1t}XjYjZj[j\j]jXP@["\"]"c\"]"yX*XPanbn```
FLAG: **Aero{Y0u_c4N_dmp_1t}**