SECCON Beginners CTF 2020 Writeup

# 解けた問題
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496507/a3fadbd5-13b0-2d60-f9b2-1e1675111e48.png)

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

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

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

```python
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でデコードできるとのこと。
そこで以下のプログラムを書きました：

```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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496507/ac18e2be-f436-b7f9-fb1b-6d817bfa6db2.png)

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

```java
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問題をあと一個でも頑張って通そうと思って取り組んだのがこれです。

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

```python
        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処理に時間がかかるはずっ！**

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

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

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

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