Trend Micro CTF 2015 Writeup #TrendCTF #TrendCTF2015

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. 1~10問目:数字と演算子(+, -, *)のみ
  2. 11~20問目:1.に加えて括弧が増える
  3. 21~30問目:2.に加えて、4桁以上の数字にカンマが入るようになる(入らない場合もある)
  4. 31~40問目:3.に加えてローマ数字での表現が増える
  5. 41~50問目:3.に加えて数字が英語で表現されるようになる
  6. 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

問題文

(ファイルを解析してフラグを探せ)

(後で書く)

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください