1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

SECCON Beginners CTF 2020 Writeup

Posted at

解けた問題

image.png

はじめに

タイトルの通りSECCON Beginners CTF 2020に参加しました。結果は惨敗だったわけですが、一応解けたのを共有します。

Welcome

チュートリアルですので割愛します。

R&B

まずfileコマンドでテキストファイルだとわかりました。
で、プログラム見ると、

from os import getenv


FLAG = getenv("FLAG")
FORMAT = getenv("FORMAT")


def rot13(s):
    # snipped


def base64(s):
    # snipped


for t in FORMAT:
    if t == "R":
        FLAG = "R" + rot13(FLAG)
    if t == "B":
        FLAG = "B" + base64(FLAG)

print(FLAG)

まず**rot13,base64って何?**という初歩的なことが分かってなかったので検索すると、pythonでデコードできるとのこと。
そこで以下のプログラムを書きました:

def rot13Reverse(arg):
    import codecs
    return codecs.decode(arg, 'rot13')

def base64Reverse(arg):
    import base64
    return str(base64.b64decode(bytes(arg, 'utf-8')))

s = "___" #テキストファイルの中身

while(True):
    print(s)
    if(s[0] == 'R'):
        s = rot13Reverse(s[1:])
    elif(s[0] == 'B'):
        s = base64Reverse(s[1:])
    else:
        break
    
print(s)

お察しの通りこれ上手く動きませんでした。 base64Reverseはbyte配列を返すんですね。
ですからコンソールに出てきたものをひたすらコピペして何とか答えにたどり着きました。

emoemoencode

かわいい

少し悩み、バイナリエディタで開くと、
image.png

F09F???? という並びが4回ずつ繰り返していることに気付いた僕は、デコードしたらctf4bから始まるだろうと仮定して以下の様なプログラムを書きました。

import java.util.List;

public class Main{
    public static void main(String[] args){
        List<Integer> list = List.of(0xF09F8DA3,0xF09F8DB4,0xF09F8DA6,0xF09F8CB4,
            0xF09F8DA2,0xF09F8DBB,0xF09F8DB3,0xF09F8DB4,0xF09F8DA5,0xF09F8DA7,
            0xF09F8DA1,0xF09F8DAE,0xF09F8CB0,0xF09F8DA7,0xF09F8DB2,0xF09F8DA1,
            0xF09F8DB0,0xF09F8DA8,0xF09F8DB9,0xF09F8D9F,0xF09F8DA2,0xF09F8DB9,
            0xF09F8D9F,0xF09F8DA5,0xF09F8DAD,0xF09F8CB0,0xF09F8CB0,0xF09F8CB0,
            0xF09F8CB0,0xF09F8CB0,0xF09F8CB0,0xF09F8DAA,0xF09F8DA9,0xF09F8DBD);

            list.stream().map(
                i -> {
                    if(i > 0xF09F8D60){
                        return i-0xF09F8D60;
                    }else{
                        return i-0xF09F8C80;
                    }
                }).forEach(i->System.out.print((char)i.shortValue()));
    }
}

頭が悪い
最初ifで分岐しなかったら文字化けがひどかったのでctf4bを参考にして最初がそうなるように分岐を作りました。

結果は

CTF4B[STEGAN0GRAPHY?BY?EM000000JI]

あとはエスパーでアルファベットを小文字にし、「[」を「{」にし、「?」を「_」にしたら通りました。
想定解じゃないでしょうけども。

Spy

Beginner問題をあと一個でも頑張って通そうと思って取り組んだのがこれです。

サーバー側プログラムの重要な部分:

        if not exists:
            return render_template("index.html", message="Login failed, try again.", sec="{:.7f}".format(time.perf_counter()-t))

        # auth.calc_password_hash(salt, password) adds salt and performs stretching so many times.
        # You know, it's really secure... isn't it? :-)
        hashed_password = auth.calc_password_hash(app.SALT, password)
        if hashed_password != account.password:
            return render_template("index.html", message="Login failed, try again.", sec="{:.7f}".format(time.perf_counter()-t))

最初はSQLインジェクションとかして強制的にログインするのかなとか思っていろいろやってましたが、二つのrender_templateが何が違うかを穴が開くほど見つめてようやく気付きました。

hash処理に時間がかかるはずっ!

パスワードを意図的に長くして全てのユーザーに対し総当たりして、ロード時間が不自然に長いものをピックしていったら正解しました。

ログインしなくてよかったのか...

終わりに

まだまだ自分が勉強不足であることを改めて思い知らされたので、これからも精進していこうと思います。

運営の皆様ありがとうございました。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?