Skip to content

Angstrom CTF 2021: Jail Break

TL;DR

  • The challenge is a state machine driven entirely by text commands.
  • Each action mutates internal variables that gate progress.
  • You must reach a specific control-flow path by setting those variables precisely.
  • Button presses implement simple arithmetic on a hidden counter.
  • Drive the counter to 1337, then enter the final password to print the flag.

Video Walkthrough

Angstrom CTF 2021 Jail Break reverse engineering video walkthrough showing state manipulation via command sequencing

Challenge Description

Clam was arguing with kmh about whether including 20 pyjails in a ctf is really a good idea, and kmh got fed up and locked clam in a jail with a python! Can you help clam escape?

Solution

from pwn import *

def start(argv=[], *a, **kw):
    if args.GDB:  # Set GDBscript below
        return gdb.debug([exe] + argv, gdbscript=gdbscript, *a, **kw)
    elif args.REMOTE:  # ('server', 'port')
        return remote(sys.argv[1], sys.argv[2], *a, **kw)
    else:  # Run locally
        return process([exe] + argv, *a, **kw)

# Specify your GDB script here for debugging
gdbscript = '''
init-pwndbg
breakrva 0x1313
continue
'''.format(**locals())

# Set up pwntools for the correct architecture
exe = './jailbreak'
# This will automatically get context arch, bits, os etc
elf = context.binary = ELF(exe, checksec=False)
# Enable verbose logging so we can see exactly what is being sent (info/debug)
context.log_level = 'info'

# ===========================================================
#                    EXPLOIT GOES HERE
# ===========================================================

# Start program
io = start()

# Give commands in correct order so that bVar1 == false
io.sendlineafter('What would you like to do?', 'pick the snake up')
io.sendlineafter('What would you like to do?', 'throw the snake at kmh')

# Now we need iVar7 == 1
io.sendlineafter('What would you like to do?', 'pry the bars open')

# Move into desired code block
io.sendlineafter('What would you like to do?', 'look around')

# Now we can press buttons (need to make iVar7 == 1337, it currently == 1)
# Red button will do iVar7 * 2
# Green button will do iVar7 * 2 + 1
io.sendlineafter('What would you like to do?', 'press the red button')  # 1 * 2 = 2
io.sendlineafter('What would you like to do?', 'press the green button')  # 2 * 2 + 1 = 5
io.sendlineafter('What would you like to do?', 'press the red button')  # 5 * 2 = 10
io.sendlineafter('What would you like to do?', 'press the red button')  # 10 * 2 = 20
io.sendlineafter('What would you like to do?', 'press the green button')  # 20 * 2 + 1 = 41
io.sendlineafter('What would you like to do?', 'press the green button')  # 41 * 2 + 1 = 83
io.sendlineafter('What would you like to do?', 'press the green button')  # 83 * 2 + 1 = 167
io.sendlineafter('What would you like to do?', 'press the red button')  # 167 * 2 = 334
io.sendlineafter('What would you like to do?', 'press the red button')  # 334 * 2 = 668
io.sendlineafter('What would you like to do?', 'press the green button')  # 668 * 2 + 1 = 1337

# Now we need to enter the password to get flag
io.sendlineafter('What would you like to do?', 'bananarama')
io.recvlines(2)

# Get our flag!
flag = io.recvline()
success(flag)

Flag: actf{guess_kmh_still_has_unintended_solutions}