picoMini 2022 Write Up

2022年1月に開催されたpicoMini 2022のWrite Upです。

実際に使ったコードは[GitHub](https://github.com/FullteaOfEEIC/picoMini2022)に置いてあります。CTFの解答なので、可読性は皆無です。気になるところがあったら気軽に訪ねていただければと思います。

#runme.py

```runme.py``` というファイルが配布されます。

```
python runme.py
```
として実行したところ、flagが表示されました。

#ncme

問題文に ```nc saturn.picoctf.net 50959```と書かれていたので、実行するとflagが表示されました。

#convertme.py

```convertme.py``` というファイルが配布されます。
実行したところ、

```
If 50 is in decimal base, what is it in binary base?
Answer:
```
(10進数における50は2進数でどうなりますか?)ときかれたので、110010と入力するとflagが出力されました。50の部分はランダムのようです。

#Codebook

```code.py``` と ```codebook.txt```が配布されます。
code.pyを実行するとflagが入手できました。

#fixme1.py

```fixme1.py``` が配布されます。
そのまま実行すると、

```
File "/Path/to/fixme1.py", line 20
    print('That is correct! Here\'s your flag: ' + flag)
IndentationError: unexpected indent
```

と表示されました。どうやら20行目にエラーがあり、インデントがおかしいようです。テキストエディタでファイルを開くと、20行目の行頭に不要なスペースが入っているのでこれを削除して再度実行するとflagが得られます。

#fixme2.py
```fixme2.py``` が配布されます。
こちらも実行すると、

```
  File "/Path/to/fixme2.py", line 22
    if flag = "":
            ^
SyntaxError: invalid syntax
```

というエラーが表示されます。22行目において、```==```と書くべきところを```=```としたのが原因です。修正して再度実行すればflagが得られます。

#PW Crack 1

```level1.py``` と ```level1.flag.txt.enc``` が配布されます。level1.pyを実行するとパスワードの入力を求められました。
テキストエディタでファイルの中身を見ると、

```level1.py
user_pw = input("Please enter correct password for flag: ")
if( user_pw == "1e1a"):
    print("Welcome back... your flag, user:")
    decryption = str_xor(flag_enc.decode(), user_pw)
    print(decryption)
```

 という処理が見えるので、パスワードとして```1e1a```を入力すればflagが入手できそうです。
実際に実行すればflagが入手できます。

#Glitch Cat
問題文で指定されたサーバーに接続すると
```picoCTF{gl17ch_m3_n07_' + chr(0x63) + chr(0x35) + chr(0x36) + chr(0x35) + chr(0x37) + chr(0x66) + chr(0x66) + chr(0x33) + '}'```という応答が返ってきました。
見るからにpythonの文字列なので、

```glitchcat.py
print('picoCTF{gl17ch_m3_n07_' + chr(0x63) + chr(0x35) + chr(0x36) + chr(0x35) + chr(0x37) + chr(0x66) + chr(0x66) + chr(0x33) + '}')
```
とすることでflagが入手できます。

#PW Crack 2
```level2.py``` と ```level2.flag.txt.enc``` が配布されます。level2.pyを実行すると、再びパスワードの入力を求められました。
level2.pyの中を見ると、

```level2.py
if( user_pw == chr(0x32) + chr(0x65) + chr(0x30) + chr(0x65) ):
    print("Welcome back... your flag, user:")
    decryption = str_xor(flag_enc.decode(), user_pw)
    print(decryption)
```
という処理が見えます。
```chr(0x32) + chr(0x65) + chr(0x30) + chr(0x65)```は ```2e0e```なので、これを入力すればflagが表示されます。

#HashingJobApp
接続すると、 

```
Please md5 hash the text between quotes, excluding the quotes: 'a full moon'
Answer:
```
(''で囲まれた単語のmd5値を入力してください)と表示されました。
文字列のmd5値は

```hash.py
import hashlib
print(hashlib.md5(b'a full moon').hexdigest())
```

で取得できます。md5値を入力すると別の単語で同じ質問をされるので、3会くり返せばflagが表示されます。

#Serpentine
配布された```serpentine.py``` を実行すると

```と表示されます。
a) Print encouragement
b) Print flag
c) Quit
```
ここでbを選択すると、```Oops! I must have misplaced the print_flag function! Check my source code!```と言われました。
```print_flag```なる関数が存在するようなので、外から関数を呼び出してやります。

```serpentine_solve.py
from serpentine import print_flag

print_flag()
```
あとはこのファイルを実行すればflagが入手できます。

#PW Crack 3
配布された```level3.py``` を実行すると、またしてもパスワードを要求されました。level3.pyの末尾には

```level3.py
# The strings below are 7 possibilities for the correct password. 
#   (Only 1 is correct)
pos_pw_list = ["f09e", "4dcf", "87ab", "dba8", "752e", "3961", "f159"]
```
と記載されています。どうやらこの7つのどれかが正しいパスワードのようです。
これ以上考えるのが面倒くさいので、7通り全部試せばOKです。7つしか候補が無いほうが悪い。

#PW Crack 4
PW Crack 3とほぼ同じ問題ですが、パスワードの候補が100個に増えました。根性で手入力してもいいのですが、流石にだるいので総当りするスクリプトを書きます。

```crack_level4.py
from level4 import pos_pw_list, hash_pw, correct_pw_hash

for pos in pos_pw_list:
    pos_hash = hash_pw(pos)
    if pos_hash==correct_pw_hash:
        print(pos)
```

パスワードが```eacc```であることがわかるので、これをlevel4.pyに入力すればflagが入手できます。

#PW Crack 5
PW Crack3, PW Crack 4とほぼ同じですが、今回は```dictionary.txt```のどれかがパスワードのようです。

PW Crack 4の時と同じように、スクリプトを書いて総当りを行います。

```crack_level5.py
from level5 import hash_pw, correct_pw_hash

with open("dictionary.txt", "r") as fp:
    for pos in fp:
        pos = pos.strip() # 行末の改行を削除
        pos_hash = hash_pw(pos)
        if pos_hash==correct_pw_hash:
            print(pos)
```

パスワードが判明したので、あとはlevel5.pyを実行して入力すればflagが出力されます。