平成31年4月30日(火)23:00(JST)~令和元年5月1日(水)02:00 (JST)に開催されていたSECCON 令和CTFのWriteupです。

着手した問題は3問、うち解けた問題は3問でした。


フラグの例は?(Misc Point:10)

CTFでよくあるフラグのフォーマットを確認する問題です。

問題文

平成最後の最後、令和最初のSECCON CTFにようこそ。 フラグはSECCON{reiwa}です。

Flag

SECCON{reiwa}

零は?(Misc Point:100)

問題文

nc zerois-o-reiwa.seccon.jp 23615

解説

問題文の通り、netcatを使ってアクセスを行うと方程式の解が0となるように?に数値を埋める問題が100問出題されます。?= の後一定時間入力待ちがあるため、その間に計算して?に入る値を入力していくと100問解いた後にフラグが出力されるというもの。

[1/100]
0=?-58
?=58
[2/100]
...

初めは適当に書いたbashスクリプトで手入力で回答を行っていましたが、計算速度の問題や手入力のための遅延でタイムアウトしてしまうためpythonを使うように方針変更。

#!/bin/bash

PLANE_FORMULA=$1

for A in {0..10000}; do
  FORMULA=$(echo $PLANE_FORMULA | sed "s/?/$A/")
  if [ $((FORMULA)) -eq 0 ]; then
    echo $A
    exit 0
  fi
done

pythonでsocketを使うプログラムを書き慣れていなかったので、以下のwriteupを参考に簡単に自動化。

import socket
import re

class Netcat:
    """ Python 'netcat like' module """
    def __init__(self, ip, port):
        self.buff = ""
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.socket.connect((ip, port))

    def read(self, length = 1024):
        """ Read 1024 bytes off the socket """
        return self.socket.recv(length)

    def read_until(self, data):
        """ Read data into the buffer until we have data """
        while not data in self.buff:
            self.buff += self.socket.recv(1024)
        pos = self.buff.find(data)
        rval = self.buff[:pos + len(data)]
        self.buff = self.buff[pos + len(data):]
        return rval

    def write(self, data):
        self.socket.send(data)
        
    def close(self):
        self.socket.close()

# メイン処理
nc = Netcat('153.120.18.15', 23615)
for i in range(1, 101):
    print(nc.read_until(str(i)+'/100]'))
    resp = nc.read_until('\n')
    print(resp)
    resp = nc.read_until('\n')
    print(resp)
    resp = resp.strip()
    formula = resp.split('=')[1]
    for j in range(10000000):
        if eval(formula.replace('?',str(j))) == 0:
            nc.write(str(j) + '\n')
            break
    print("next")
print(nc.read()) # 最後に何が出力されるかわからなかったので適当にprint
print(nc.read())
print(nc.read())
print(nc.read())

雑な自動化をしてしまったため、問題の途中で ?=10000000 のようなとても計算時間がかかるような値が含まれている事がいくつかあるようでタイムアウトしてしまうので、複数の窓で並列に実行。うちどれか1つでも100問解ければ良いかなと思ってtryしていた所無事解けたようでフラグをゲットする事ができました。

Flag

SECCON{REIWA_is_not_ZERO_IS}

bREInWAck(Misc Point:100)

問題文

元号が変わる。記号も変わる。
参考: https://ja.wikipedia.org/wiki/Brainfuck

  • 添付ファイル
    flag.bw
令和和和和和和和和和和和和和和和和「令和
和和和和令和和和和令和和和和和和和令和和
和和和和令和和平平平平平成」令和和和。令
和和和和和。成成。。平成成成成。成。令令
和和和和和和和和和和和。令和和。平平平和
和和和。令和和。和和和和。令令和和和和和
和和和和和和和。平平平和和和和和和和和和
和和和和。成成成成成成成成。令成成成成成
成成成。令令。成成成成成。成成成成成成。
令和。平平和和。令令令和和和和和和和和和
和。

解説

参考記事を見ると、どうやらBrainfuckで記述されたプログラムが 「令和平成。」 に置き換わっている事が何となく想像ついたので、それぞれをBrainfuckの言語仕様の対応する文字へエディタの機能を使って置換していった。ソースコードをよく見るといくつかの文字の対応はすぐに分かったので以下の文字は決め打ちで残りの文字を置換した。

「  = [
 」 = ]
 。 = .

実行環境はWebのインタプリタでも良かったのですが、今回はInsaneBFというアプリを利用しました。

何パターンか思考していると無事Flagの文字列が出力されるパターンを発見。

>++++++++++++++++[>+
++++>++++>+++++++>++
++++>++<<<<<-]>+++.>
+++++.--..<----.-.>>
+++++++++++.>++.<<<+
+++.>++.++++.>>+++++
+++++++.<<<+++++++++
++++.--------.>-----
---.>>.-----.------.
>+.<<++.>>>+++++++++
+.

Flag

SECCON{bREIn_WAnic!}

まとめ

1年半ぶりぐらいのCTFでしたがとりあえず数問は解けて良かったです。

参考文献