Pwn2Win CTF 2018 Writeup

この大会は2018/12/1 0:37(JST)~2018/12/3 0:37(JST)に開催されました。
今回もチームで参戦。結果は 530点で163チーム中44位でした。
自分で解けた問題をWriteupとして書いておきます。

A Segregated New World [Read first] (Story)

長文の中にフラグが書いてある。

CTF-BR{I_know_about_th3_r1sks!}

g00d b0y (Bonus)

ルールのページ(https://pwn2win.party/rules/?lang=br)の最下部にフラグが書いてある。

CTF-BR{RTFM_1s_4_g00d_3xpr3ss10n_v4.0}

Sum [Hello World Platform] (PPC-M, Platform)

SSL接続するサンプルプログラムがついているので、実行してみる。

received: 5 7 3 5 6 3 6 1 5 3 9 2 0
sent: 55
received: 2 2 5 3 8 0
sent: 20
received: 9 6 9 3 4 2 4 0
sent: 37
received: 3 4 1 7 3 9 3 3 7 8 9 2 8 8 6 6 2 8 0
sent: 97
received: 5 3 4 2 1 5 5 0
sent: 25
received: 2 4 8 3 4 6 2 4 9 8 0
sent: 50
received: 3 9 9 4 7 3 4 8 0
sent: 47
received: 5 4 2 9 8 9 4 1 5 6 3 4 8 9 5 7 8 0
sent: 97
received: 4 8 4 8 1 3 4 2 2 6 3 2 3 7 0
sent: 57
received: 6 8 2 9 7 8 4 9 8 5 5 7 3 6 3 3 7 0
sent: 100
received: 2 7 5 6 9 3 6 0
sent: 38
received: 4 5 7 1 9 1 6 4 1 3 7 5 1 3 5 0
sent: 62
received: 6 5 3 3 7 4 9 0
sent: 37
received: 3 1 8 6 1 1 1 6 4 7 5 7 0
sent: 50
received: 6 2 2 5 9 2 3 5 3 0
sent: 37
received: 6 4 7 6 8 1 8 1 8 6 2 8 3 3 0
sent: 71
received: 3 6 9 5 9 4 1 5 6 2 9 6 4 6 8 7 1 6 0
sent: 97
received: 7 6 5 1 7 9 6 8 0
sent: 49
received: 9 3 5 1 6 1 5 7 5 5 0
sent: 47
received: 6 3 7 7 1 8 7 9 2 5 9 3 7 1 8 8 5 0
sent: 96
received: CTF-BR{Congrats!_you_know_how_to_sum!}
CTF-BR{Congrats!_you_know_how_to_sum!}

The Bavarian Hierarchy (PPC-M, Platform)

最初の1行はNとMを表している。Nは上司、部下の関係みたいな組み合わせの数。Mはある2名の従業員番号の情報の数。
次のN行が上記の組み合わせ。次のM行が上記2名で問題となっている。

N行は左が最も上位で、右の番号に別のデータの左の番号を連結させていくと階層になる。問題となっている2名で共通の上司の数を求める問題になっていることを考慮して、コードを書く。テンプレートは与えられているので、solve関数の中だけ追記すればよい。

def solve(N,M,edges,queries):
    # Solution here, ans = array of answers to each of the queries
    trees = []
    for edge in edges:
        found = False
        for i in range(len(trees)):
            if trees[i][-1] == edge[0]:
                found = True
                trees[i].append(edge[1])
                break
            elif edge[0] in trees[i]:
                found = True
                idx = trees[i].index(edge[0])
                new_tree = [trees[i][j] for j in range(idx + 1)]
                new_tree.append(edge[1])
                trees.append(new_tree)
                break
        if not found:
            trees.append(list(edge))

    ans = []
    for query in queries:
        q = list(query)
        paths = []
        found1 = False
        found2 = False
        for i in range(len(trees)):
            if found1 == False and q[0] in trees[i]:
                found1 = True
                paths.append(trees[i])
            if found2 == False and q[1] in trees[i]:
                found2 = True
                paths.append(trees[i])

        if len(paths[0]) < len(paths[1]):
            min_path = len(paths[0])
        else:
            min_path = len(paths[1])

        count = 0
        for i in range(min_path):
            if paths[0][i] == paths[1][i]:
                count += 1
            else:
                break
        ans.append(count)

    return '\n'.join(map(str,ans)).strip()

    
import ssl, socket

class Connect(object):
    def __init__(self, host, port):
        self.context = ssl.create_default_context()
        self.conn = self.context.wrap_socket(
            socket.socket(socket.AF_INET),
            server_hostname=host)
        self.conn.connect((host, port))
        self.f = self.conn.makefile('rwb', 0)
    def __enter__(self):
        return self.f
    def __exit__(self, type, value, traceback):
        self.f.close()

with Connect('programming.pwn2.win', 9003) as f:
    inew,M = 0,0
    edges = list()
    queries = list()
    for il,line in enumerate(f):
        line = line.strip()
        print('received line %d: %s' % (il,line))
        
        if b'CTF-BR{' in line or b'WRONG' in line: break
            
        if il==inew:
            N,M = map(int,line.split())
            edges = list()
            queries = list()
        elif il<=inew+N:
            a,b = line.split()
            edges.append((a.strip(),b.strip()))
        elif il<=inew+N+M:
            a,b = line.split()
            queries.append((a.strip(),b.strip()))
        
        if il==inew+N+M:
            ans = solve(N,M,edges,queries)

            f.write((ans+'\n').encode('utf-8'))
            print(ans)  # for debugging purposes
            
            inew = il+1

実行すると、15ラウンドほどでフラグが表示された。

CTF-BR{L0w357_C0mMoN_4ncE57Or_1s_u53fu1l_f0r_8i3r4rch13S}