Tags: pic18f pic18f452 

Rating: 5.0

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 \x00
code += "\xf6\x6E" # MOVWF TBLPTR_L
code += "\xf7\x6E" # MOVWF TBLPTR_H
code += "\xf8\x6E" # MOVWF TBLPTR_U
code += "\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 bytes
assert len(code) % BLOCK == 0

# Send the code
for 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 sent
io.sendafter('c', 'R')

context.log_level = "info"

# Receive the dump
buff = b""
p = log.progress("Bytes dumped")
try:
while True:
buff += io.recv()
p.status(str(len(buff)))
except:
pass
finally:
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.bin
SnTn
9n:n?
=n>n5
AnBn+
EnFn
9n:n
=n>n
AnBn
EnFn
9n:n
=n>n
AnBn
EnFn
9n:n]
=n>nS
AnBnI
EnFn
onpjl
Aero
{Y0u_c4N_dmp_1t}
XjYjZj[j\j]jXP@
["\"]"c
\"]"y
X*XP
anbn
```

FLAG: **Aero{Y0u_c4N_dmp_1t}**