Trend Micro CTF Asia Pacific & Japan 2015に参加した。
チームとしては1400点獲得。
自分は200点問題を3問解いたので書いていく。
(問題文等の確保をしてなかったのでその辺は適当。後ほどアップデートできればする)
Programming 200
問題文
(サーバに接続して計算しろ、みたいな感じ)指定されたサーバに接続すると、数式が送られてくるのでその計算結果を答えればよい。
合っていると次の問題が送られてきて、間違っていると終了する。以下のような数式が送られてくる。
3 + 2 = 84 * 2 - 6 = 475 - 70 + 68 - 998 = 2 + 31 * 5963 + 1 - 3 = 7 + 3 * 83 - 4644 * 4 + 955 = 3 + 65 - 1 * 84 - 50 * 382 + 58 = 864654 + 418931 - 1183 * 80 - 139 + 43880 * 3565349 - 8 = 56530727 + 2 * 43742511 - 62 + 9519096 * 4448117 - 695 * 9101222 + 30650349 = 89030 + 753588 - 385686849 * 78763 - 4994684 * 929289070 - 4 + 27825 * 884073534 + 4942 = 8 + 4506226779 - 0 + 566 * 613603 + 820264 * 690 - 2 * 7 - 75996 + 6029293421 =10問で1セットになっているようで、10問正答するたびに表現が豊かになっていく。
- 1~10問目:数字と演算子(+, -, *)のみ
- 11~20問目:1.に加えて括弧が増える
- 21~30問目:2.に加えて、4桁以上の数字にカンマが入るようになる(入らない場合もある)
- 31~40問目:3.に加えてローマ数字での表現が増える
- 41~50問目:3.に加えて数字が英語で表現されるようになる
- 51問目~:全部入り
こんな感じ。
1: 2 + 31 * 5963 + 1 - 3 = 2: 350262 * 7 - 255439 * ( 86 - 3 ) + 30536 - 1984619 * 381 = 3: 2 - 42,296 + 7 * ( 43,919 - 91,057 ) + 1,913 = 4: ( 71904 + XC ) * LXVII + 5680 - 6089 + CMLXXIX = 5: 83,025 + 8,604 - sixty one thousand, five hundred forty one * ( four - 4 ) + one = 6: ( LXIV + 6014 ) * ( 268 - 9042 ) * five hundred forty seven + 817 =基本方針:bcに丸投げ
Linuxにはbcという便利なコマンドがあって、複雑な数式でもちゃんと解釈して答えを出してくれる。
さすがにローマ数字や英語表現には対応してないので、その辺は事前に自分で処理してやる必要がある。
ローマ数字については、pythonにromanというそのものズバリなパッケージがあったのでそれを活用。
英語についてはしょうがないので自分でパースした。
以下ソース。#!/usr/bin/python # -*- coding:utf-8 -*- import socket, struct, telnetlib import subprocess import roman import re # --- common funcs --- def sock(remoteip, remoteport):     s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)     s.connect((remoteip, remoteport))     return s, s.makefile('rw', bufsize=0) def read_until(f, delim='\n'):     data = ''     while not data.endswith(delim):         c = f.read(1)         if len(c) == 0:             break         data += c     return data def shell(s):     t = telnetlib.Telnet()     t.sock = s     t.interact() def p(a): return struct.pack("<I",a) def u(a): return struct.unpack("<I",a)[0] # --- main --- dic = {     "zero": "0",     "one": "+1",     "two": "+2",     "three": "+3",     "four": "+4",     "five": "+5",     "six": "+6",     "seven": "+7",     "eight": "+8",     "nine": "+9",     "ten": "+10",     "eleven": "+11",     "twelve": "+12",     "thirteen": "+13",     "fourteen": "+14",     "fifteen": "+15",     "sixteen": "+16",     "seventeen": "+17",     "eighteen": "+18",     "nineteen": "+19",     "twenty": "+20",     "thirty": "+30",     "forty": "+40",     "fifty": "+50",     "sixty": "+60",     "seventy": "+70",     "eighty": "+80",     "ninety": "+90",     "hundred": "*100",     "thousand": "*1000",     "million": "*1000000",     "billion": "*1000000000",     "trillion": "*1000000000000" } s, f = sock("ctfquest.trendmicro.co.jp", 51740)    # 接続 p = subprocess.Popen("bc", stdin = subprocess.PIPE, stdout = subprocess.PIPE) while True:     q = read_until(f, '=')     print q     if q.find("=") == -1:         break     q_bc = q     q_bc = q_bc.replace("=", "")     q_bc = q_bc.replace(",", "")     delim = r'([\\*()+-/])'     t = re.split(delim, q_bc)     for i in range(len(t)):         t[i] = t[i].strip()         if t[i] == "":             continue         # operator         if re.match(delim, t[i]) is not None:             continue         # roman         if roman.romanNumeralPattern.match(t[i]):             t[i] = str(roman.fromRoman(t[i]))             continue         # digit         if t[i].isdigit():             continue         # else         delim2 = r"(thousand|million|billion|trillion)"         t2 = re.split(delim2, t[i])         for j in range(len(t2)):             if re.match(delim2, t2[j]) is not None:                 continue             t3 = t2[j].split(" ")             for k in range(len(t3)):                 if t3[k] in dic.keys():                     t3[k] = dic[t3[k]]             t2[j] = "".join(t3)             t2[j] = t2[j].lstrip("+")             t2[j] = "+(" + t2[j] + ")"         for j in range(len(t2)):             if t2[j] in dic.keys():                 t2[j] = dic[t2[j]]         t[i] = "".join(t2)         t[i] = t[i].lstrip("+")         t[i] = "(" + t[i] + ")"     q_bc = "".join(t)     print "  q to bc: %s" % q_bc     p.stdin.write("%s\n" % q_bc)     a = read_until(p.stdout)     f.write(a)無事100問正答するとフラグが送られてくる。
Congratulations! The flag is TMCTF{U D1D 17!}Crypto 200
問題文
(一部が隠されたプログラムとその実行結果から使われているAESのIVを求めよ)(後で書く)
Analysis Defensive 200
問題文
(ファイルを解析してフラグを探せ)(後で書く)