> We've burrowed ourselves deep within the facility, gaining access to the programable logic controllers (PLC) that drive their nuclear enrichment centrifuges. Kinetic damage is necessary, we need you to neutralize these machines.
> You can access this challenge at [https://wargames.ret2.systems/csaw_2018_plc_challenge](https://wargames.ret2.systems/csaw_2018_plc_challenge)
This is a pwn challenge on a custom online wargaming platform. We are provided with the assembly of what's ostensibly a programmable logic controller (PLC) for a centrifuge in a nuclear reactor. The challenge looks like it's still up, so you can take a look and follow along.
This was the first [ROP](https://en.wikipedia.org/wiki/Return-oriented_programming) (okay, spoiler, it's a ROP) I ever pulled off live during an actual CTF, which I was pretty excited about. The web platform meant I had to worry less about setup, and even though some of the tools it provided were a little lacking (no gdb shortcuts like `until`, no pwntools utilities for packing/unpacking numbers, ... no `one_gadget`), I think they ultimately made the whole thing a lot more educational for me, so kudos to the folks behind it.
The wargaming platform has a sequence of six checkpoints/achievements. The first four are simple enough once you reverse-engineer the assembly, the fifth just requires you to overflow a buffer (although it didn't tell this to you literally and I actually couldn't figure out what my goal was at first), but (as you'd expect) the sixth requires you to pop a shell and get the flag, which is ultimately the only thing that mattered for the CTF.
A summary of the steps:
- Reverse the `update_firmware` function, which reads in firmware from stdin and makes some checks that it's valid, including a fairly complicated checksum.
- Reverse the `execute_firmware` function, which lets you write firmware that overflows a buffer representing the material being enriched, giving you control of one function pointer.
- Leak `libc` first by overflowing right up to the end of the buffer, since there's a function pointer to `libc` right after it.
- Then, use your one function pointer to set up a ROP, starting with a stack pivot ROP gadget to the large buffer in the main command-reading loop to allow the chain to continue, and carrying out a typical `execve` syscall ROP using gadgets in `libc`.
Read the rest of the writeup here: https://blog.vero.site/post/plc