MHSCTF 2022 Writeup

この大会は2022/2/18 21:00(JST)~2022/2/25 21:00(JST)に開催されました。
今回もチームで参戦。結果は満点の1105点で8位でした。
自分で解けた問題をWriteupとして書いておきます。

Transposer (General 15)

100×100のランダムな文字が敷き詰められている。
"{"で検索すると1箇所見つかり、縦にフラグが書いてある。

flag{lott4_t3xt_t0_r34d!}

Hello CTF (Programming 5)

Programmingの問題では機能仕様が提示されているので、その処理をするコードをサブミットする必要がある。
この問題は指定文字列を出力するだけ。

def main():
    print('flag{Hello_mhsCTF2022}')

main()

Jet's Pizza (Programming 20)

ピザの標準価格は15ドル。あとはトッピングで加算され、20ドルを超える場合は、5%引きという計算をする。
あとは以下に気を付けプログラミングする。

・該当しない文字は無視する。
・重複する文字は2回目以降は加算しない。
・小数第2位まで必ず出力する。
import sys

def main():
    i = 0
    prices = []
    for topping in sys.stdin:
        topping = ''.join(set(topping))
        price = 15.0
        for t in topping:
            if t == 'T':
                price += 1.50
            elif t == 'O':
                price += 1.25
            elif t == 'P':
                price += 3.50
            elif t == 'M':
                price += 3.75
            elif t == 'A':
                price += 0.40
        if price > 20.0:
            price = price * 0.95
        price = round(price, 2)
        prices.append(price)
        i += 1
        if i == 7:
            break

    for p in prices:
        print('{:.2f}'.format(p))

main()

Euler's Method (Programming 35)

オイラー法を元にサンプルの計算を確認してみる。

[Sample1]
2 + 0.8 * (5^2 - 6*2^2) = 2 + 0.8 * 1 = 2.8

[Sample2]
2 + 0.9 * (5^2 - 6*2^2) = 2 + 0.9 * 1 = 2.9
2.9 + 0.9 * (5.9^2 - 6*2.9^2) = 2.9 + 0.9 * -15.65 = -11.185
-11.185 + 0.9 * (6.8^2 - 6*-11.185^2) = -11.185 + 0.9 * -704.385 = -645.1

計算方法は合っていそう。あとは以下に気を付けプログラミングする。

・例外が発生するような計算の場合は出力なしとする。
・小数第1位まで必ず出力する。
import sys

def main():
    init = True
    ys = []
    for params in sys.stdin:
        params = params.rstrip()
        if init:
            count = int(params)
            init = False
        else:
            try:
                step = float(params.split(' ')[0])
                max_x = float(params.split(' ')[1])
                r = round((max_x - 5.0) / step)
                x = 5.0
                y = 2.0
                for i in range(r):
                    y += step * (x**2 - 6*y**2)
                    x += step
                y = round(y, 1)
                ys.append(y)
            except:
                ys.append('')
            count -= 1
        if count == 0:
            break

    for y in ys:
        print(y)

main()

Cloudy w/ a Chance of Rain (Programming 45)

6時間の各時間の雨の確率から、6時間のどこから雨が降る確率を出力する必要がある。各時間で雨が降らない確率を求め、積算する。それを100%から引けば、答えになる。

import sys
import math

def main():
    init = True
    ans_probs = []
    for probs in sys.stdin:
        probs = probs.rstrip()
        if init:
            count = int(probs)
            init = False
        else:
            probs = probs.split(' ')
            ans_prob = 1
            for p in probs:
                ans_prob *= (1 - float(p) / 100)
            ans_probs.append(ans_prob)
            count -= 1
        if count == 0:
            break

    for p in ans_probs:
        print(math.floor((1 - p) * 100))

main()

Mysterious (Reverse Engineering 55)

問題のファイルにはこう書かれている。

>~~~~~~~~~~~~~7-055+p95+-119+p94867++++-274+1-p778351137+++++++++v              
                                    v194--1-4-8-6+++3539p-2+393  <              
v16++74p+555+++++++++++99485271536p+<                                           
>9+pv                                                                           
    >41-92++-745+3-4+p72-888++-7591+++++8924++5-p555541-++++v                   
v                                                           <                   
>+45+7724+++5-5-p79+45+-52+-+3115+++67+3-p66+-114++7+2-4442-++pv                
                                                                                
                     @p-1+56+++++++++++111111111111-+++++567734<                
                                                                                
v+L^0k@%~~a`F★出力

Befungeという言語で書かれていると推測する。
https://ja.wikipedia.org/wiki/Befungeを参考に見ていく。
入力は13文字なので、それを算出する必要がある。
いろいろ試しながら入力(inp)の条件を見る。
このとき以下のスクリプトで調整・検証しながら、条件を割り出した。

stack = [102, 108, 97, 103, 123, 51, 53, 48, 49, 52, 110, 57, 125]
stack.append(7)
y = stack.pop(); x = stack.pop(); stack.append(x - y)
stack.append(0)
stack.append(5)
stack.append(5)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); v = stack.pop()
print('(%d, %d): %s' % (y, x, chr(v)))
stack.append(9)
stack.append(5)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x - y)
stack.append(1)
stack.append(1)
stack.append(9)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); v = stack.pop()
print('(%d, %d): %s' % (y, x, chr(v)))
stack.append(9)
stack.append(4)
stack.append(8)
stack.append(6)
stack.append(7)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x - y)
stack.append(2)
stack.append(7)
stack.append(4)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
stack.append(1)
y = stack.pop(); x = stack.pop(); stack.append(x - y)
y = stack.pop(); x = stack.pop(); v = stack.pop()
print('(%d, %d): %s' % (y, x, chr(v)))
stack.append(7)
stack.append(7)
stack.append(8)
stack.append(3)
stack.append(5)
stack.append(1)
stack.append(1)
stack.append(3)
stack.append(7)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
stack.append(3)
stack.append(9)
stack.append(3)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
stack.append(2)
y = stack.pop(); x = stack.pop(); stack.append(x - y)
y = stack.pop(); x = stack.pop(); v = stack.pop()
print('(%d, %d): %s' % (y, x, chr(v)))
stack.append(9)
stack.append(3)
stack.append(5)
stack.append(3)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
stack.append(6)
y = stack.pop(); x = stack.pop(); stack.append(x - y)
stack.append(8)
y = stack.pop(); x = stack.pop(); stack.append(x - y)
stack.append(4)
y = stack.pop(); x = stack.pop(); stack.append(x - y)
stack.append(1)
y = stack.pop(); x = stack.pop(); stack.append(x - y)
y = stack.pop(); x = stack.pop(); stack.append(x - y)
stack.append(4)
stack.append(9)
stack.append(1)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); v = stack.pop()
print('(%d, %d): %s' % (y, x, chr(v)))
stack.append(6)
stack.append(3)
stack.append(5)
stack.append(1)
stack.append(7)
stack.append(2)
stack.append(5)
stack.append(8)
stack.append(4)
stack.append(9)
stack.append(9)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
stack.append(5)
stack.append(5)
stack.append(5)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); v = stack.pop()
print('(%d, %d): %s' % (y, x, chr(v)))
stack.append(4)
stack.append(7)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
stack.append(6)
stack.append(1)
stack.append(9)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); v = stack.pop()
print('(%d, %d): %s' % (y, x, chr(v)))
stack.append(4)
stack.append(1)
y = stack.pop(); x = stack.pop(); stack.append(x - y)
stack.append(9)
stack.append(2)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x - y)
stack.append(7)
stack.append(4)
stack.append(5)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
stack.append(3)
y = stack.pop(); x = stack.pop(); stack.append(x - y)
stack.append(4)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); v = stack.pop()
print('(%d, %d): %s' % (y, x, chr(v)))
stack.append(7)
stack.append(2)
y = stack.pop(); x = stack.pop(); stack.append(x - y)
stack.append(8)
stack.append(8)
stack.append(8)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x - y)
stack.append(7)
stack.append(5)
stack.append(9)
stack.append(1)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
stack.append(8)
stack.append(9)
stack.append(2)
stack.append(4)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
stack.append(5)
y = stack.pop(); x = stack.pop(); stack.append(x - y)
y = stack.pop(); x = stack.pop(); v = stack.pop()
print('(%d, %d): %s' % (y, x, chr(v)))
stack.append(5)
stack.append(5)
stack.append(5)
stack.append(5)
stack.append(4)
stack.append(1)
y = stack.pop(); x = stack.pop(); stack.append(x - y)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
stack.append(4)
stack.append(5)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
stack.append(7)
stack.append(7)
stack.append(2)
stack.append(4)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
stack.append(5)
y = stack.pop(); x = stack.pop(); stack.append(x - y)
stack.append(5)
y = stack.pop(); x = stack.pop(); stack.append(x - y)
y = stack.pop(); x = stack.pop(); v = stack.pop()
print('(%d, %d): %s' % (y, x, chr(v)))
stack.append(7)
stack.append(9)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
stack.append(4)
stack.append(5)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x - y)
stack.append(5)
stack.append(2)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x - y)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
stack.append(3)
stack.append(1)
stack.append(1)
stack.append(5)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
stack.append(6)
stack.append(7)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
stack.append(3)
y = stack.pop(); x = stack.pop(); stack.append(x - y)
y = stack.pop(); x = stack.pop(); v = stack.pop()
print('(%d, %d): %s' % (y, x, chr(v)))
stack.append(6)
stack.append(6)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x - y)
stack.append(1)
stack.append(1)
stack.append(4)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
stack.append(7)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
stack.append(2)
y = stack.pop(); x = stack.pop(); stack.append(x - y)
stack.append(4)
stack.append(4)
stack.append(4)
stack.append(2)
y = stack.pop(); x = stack.pop(); stack.append(x - y)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); v = stack.pop()
print('(%d, %d): %s' % (y, x, chr(v)))
stack.append(4)
stack.append(3)
stack.append(7)
stack.append(7)
stack.append(6)
stack.append(5)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x - y)
stack.append(1)
stack.append(1)
stack.append(1)
stack.append(1)
stack.append(1)
stack.append(1)
stack.append(1)
stack.append(1)
stack.append(1)
stack.append(1)
stack.append(1)
stack.append(1)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
stack.append(6)
stack.append(5)
y = stack.pop(); x = stack.pop(); stack.append(x + y)
stack.append(1)
y = stack.pop(); x = stack.pop(); stack.append(x - y)
y = stack.pop(); x = stack.pop(); v = stack.pop()
print('(%d, %d): %s' % (y, x, chr(v)))

検証した結果、条件は以下の通り。

・inp[12] - 7 = ord('v')
・inp[11] - 9 - 5 = ord('+')
・inp[10] - 9 - 4 - 8 - 6 - 7 = ord('L')
・inp[9] + 7 + 7 + 8 + 3 + 5 + 1 + 1 + 3 + 7 = ord('^')
・inp[8] - 9 - 3 - 5 - 3 + 6 + 8 + 4 + 1 = ord('0')
・inp[7] + 6 + 3 + 5 + 1 + 7 + 2 + 5 + 8 + 4 + 9 + 9 = ord('k')
・inp[6] + 4 + 7 = ord('@')
・inp[5] - 4 + 1 - 9 - 2 = ord('%')
・inp[4] + 7 - 2 - 8 - 8 - 8 + 7 + 5 + 9 + 1 = ord('~')
・inp[3] + 5 + 5 + 5 + 5 + 4 - 1 = ord('~')
・inp[2] + 7 + 9 - 4 - 5 - 5 - 2 = ord('a')
・inp[1] - 6 - 6 = ord('`')
・inp[0] - 4 - 3 - 7 - 7 - 6 - 5 = ord('F')

以上の条件を元に、フラグを割り出す。

#!/usr/bin/env python3
inp = [32] * 13

inp[12] = ord('v') + 7
inp[11] = ord('+') + 9 + 5
inp[10] = ord('L') + 9 + 4 + 8 + 6 +7
inp[9] = ord('^') - 7 - 7 - 8 - 3 - 5 - 1 - 1 - 3 - 7
inp[8] = ord('0') + 9 + 3 + 5 + 3 - 6 - 8 - 4 - 1
inp[7] = ord('k') - 6 - 3 - 5 - 1 - 7 - 2 - 5 - 8 - 4 - 9 - 9
inp[6] = ord('@') - 4 - 7
inp[5] = ord('%') + 4 - 1 + 9 + 2
inp[4] = ord('~') - 7 + 2 + 8 + 8 + 8 - 7 - 5 - 9 - 1
inp[3] = ord('~') - 5 - 5 - 5 - 5 - 4 + 1
inp[2] = ord('a') - 7 - 9 + 4 + 5 + 5 + 2
inp[1] = ord('`') + 6 + 6
inp[0] = ord('F') + 4 + 3 + 7 + 7 + 6 + 5

flag = ''.join([chr(i) for i in inp])
print(flag)
flag{35014n9}

James Harold Japp (Web Exploit 10)

HTMLソースを見ると、こう書いてある。

    <script>
      function validatepwd() {
        var x = document.getElementById("pwd").value;
        if (x == "this_is_a_really_secure_password") {
          window.open("/weirdpage.php?pwd=doublepassword")
        }
      }
    </script>

このコードからthis_is_a_really_secure_passwordを入力すればよいことがわかる。
入力してみると、https://mhsctf-jamesharoldjapp.0xmmalik.repl.co/weirdpage.php?pwd=doublepasswordに飛ぶが、Not Found.となる。
このページのHTMLソースを見ると、コメントにフラグが書いてあった。

<!--lol gottem here's the flag: flag{1n$p3ct0r_g3n3r@l}-->
flag{1n$p3ct0r_g3n3r@l}

new site who dis? (Web Exploit 20)

Cookieを見ると、userキーに"basic"が設定されている。この値を"admin"にして、https://mhsctf-newsitewhodis.0xmmalik.repl.co/flagへのリンクをクリックしてみると、フラグが表示された。

flag{1t$-@_m3_Mari0}

Bend (Web Exploit 25)

リンクをクリックすると、リダイレクトしてYouTubeのページに移動する。
curlでリダイレクトさせずにアクセスする。

$ curl https://mhsctf-bend.0xmmalik.repl.co/flag
<a href="/flag/">Found</a>.

$ curl https://mhsctf-bend.0xmmalik.repl.co/flag/
<meta http-equiv = "refresh" content = "0; url = https://www.youtube.com/watch?v=dQw4w9WgXcQ" />

<!-- flag{g3t_cur1ed} -->
flag{g3t_cur1ed}

Et tu, Brute? (Web Exploit 45)

好きな数字の1番目と2番目を当てる必要があるが、1と100の間なので、ブルートフォースする。

#!/usr/bin/env python3
import requests

url = 'https://mhsctf-ettubrute.0xmmalik.repl.co/status.php'

found = False
for f1 in range(1, 101):
    for f2 in range(1, 101):
        payload = {"number": f1, "number2": f2}
        r = requests.post(url, data=payload)
        if 'Sorry, you\'re clearly not my friend' not in r.text:
            found = True
            print('favorite number 1: ', f1)
            print('favorite number 2: ', f2)
            print(r.text)
            break
    if found:
        break

実行結果は以下の通り。

favorite number 1:  77
favorite number 2:  97
Wow! You must really be my friend if you know my favorite and second favorite numbers! Here's a flag for you: flag{pur3_s7r3ngth}
flag{pur3_s7r3ngth}

Significant Other (Forensics 30)

LSBを取り出すと、データの中にフラグが入っていた。

#!/usr/bin/env python3
import wave

with wave.open('a5e72d6b8755dc997599d1580d40c98c.wav', 'rb') as audio:
    frame_bytes = bytearray(list(audio.readframes(audio.getnframes())))

extracted = [frame_bytes[i] & 1 for i in range(len(frame_bytes))]
data = ''.join(chr(int(''.join(map(str, extracted[i:i+8])), 2)) for i in range(0, len(extracted), 8))
assert 'flag{' in data

begin = data.index('flag{')
end = data.index('}', begin)
flag = data[begin:end + 1]
print(flag)
flag{ilY_<3}

What's Cooking? (Cryptography 10)

以下の順にデコードする。

・8進数
・16進数
・base64
#!/usr/bin/env python3
import base64

enc = '65 141 40 66 144 40 67 70 40 66 70 40 65 141 40 63 63 40 67 64 40 67 64 40 66 62 40 65 67 40 63 61 40 66 66 40 66 63 40 64 65 40 64 61 40 66 142 40 66 64 40 64 67 40 64 66 40 63 71'
enc = enc.split(' ')

dec = ''
for c in enc:
    dec += chr(int(c, 8))
print(dec)

dec = dec.split(' ')
msg = ''
for c in dec:
    msg += chr(int(c, 16))
print(msg)

flag = base64.b64decode(msg).decode()
print(flag)

実行結果は以下の通り。

5a 6d 78 68 5a 33 74 74 62 57 31 66 63 45 41 6b 64 47 46 39
ZmxhZ3ttbW1fcEAkdGF9
flag{mmm_p@$ta}
flag{mmm_p@$ta}

Peanuts (Cryptography 10)

Pigpen cipher。https://en.wikipedia.org/wiki/Pigpen_cipherを参考に復号する。

goodgriefcharliebrown
flag{goodgriefcharliebrown}

What's Cooking? 2 (Cryptography 10)

以下の順にデコードする。

・base32デコード
・base64デコード
・morse信号への変換
・morse信号デコード
・8進数デコード
#!/usr/bin/env python3
import base64

morse = {
    '.----': '1',
    '..---': '2',
    '...--': '3',
    '....-': '4',
    '.....': '5',
    '-....': '6',
    '--...': '7',
    '---..': '8',
    '----.': '9',
    '-----': '0'
}

with open('7732348dab3df4cf51cc5f6443aa6e38.txt', 'r') as f:
    enc = f.read()

enc = base64.b32decode(enc).decode()
print(enc)

enc = base64.b64decode(enc).decode()
print(enc)

sep = enc[5]
enc = enc.replace(enc[0], '.')
enc = enc.replace(enc[1], '-')
print(enc)

enc = enc.split('\n')
codes = ''
for c in enc:
    code = ''
    for m in c.split(sep):
        code += morse[m]
    codes += code + ' '
codes = codes[:-1]
print(codes)

codes = codes.split(' ')
flag = ''
for c in codes:
    flag += chr(int(c, 8))
print(flag)

実行結果は以下の通り。

4qCo4qCk4qCk4qCk4qCk4qCA4qCo4qCo4qCo4qCo4qCk4qCA4qCk4qCo4qCo4qCo4qCoCuKgqOKgpOKgpOKgpOKgpOKggOKgqOKgqOKgqOKgqOKgqOKggOKgqOKgqOKgqOKgqOKgpArioKjioKTioKTioKTioKTioIDioKjioKjioKjioKjioKTioIDioKjioKTioKTioKTioKQK4qCo4qCk4qCk4qCk4qCk4qCA4qCo4qCo4qCo4qCo4qCk4qCA4qCk4qCk4qCo4qCo4qCoCuKgqOKgpOKgpOKgpOKgpOKggOKgpOKgpOKgqOKgqOKgqOKggOKgqOKgqOKgqOKgpOKgpArioKjioKTioKTioKTioKTioIDioKjioKjioKjioKjioKjioIDioKjioKjioKjioKjioKgK4qCk4qCo4qCo4qCo4qCo4qCA4qCo4qCo4qCo4qCk4qCkCuKgqOKgqOKgqOKgqOKgpOKggOKgqOKgqOKgqOKgqOKgpArioKjioKTioKTioKTioKTioIDioKTioKjioKjioKjioKjioIDioKjioKjioKjioKTioKQK4qCo4qCk4qCk4qCk4qCk4qCA4qCk4qCk4qCo4qCo4qCo4qCA4qCo4qCk4qCk4qCk4qCkCuKgqOKgpOKgpOKgpOKgpOKggOKgpOKgpOKgqOKgqOKgqOKggOKgqOKgqOKgqOKgqOKgqA==
⠨⠤⠤⠤⠤⠀⠨⠨⠨⠨⠤⠀⠤⠨⠨⠨⠨
⠨⠤⠤⠤⠤⠀⠨⠨⠨⠨⠨⠀⠨⠨⠨⠨⠤
⠨⠤⠤⠤⠤⠀⠨⠨⠨⠨⠤⠀⠨⠤⠤⠤⠤
⠨⠤⠤⠤⠤⠀⠨⠨⠨⠨⠤⠀⠤⠤⠨⠨⠨
⠨⠤⠤⠤⠤⠀⠤⠤⠨⠨⠨⠀⠨⠨⠨⠤⠤
⠨⠤⠤⠤⠤⠀⠨⠨⠨⠨⠨⠀⠨⠨⠨⠨⠨
⠤⠨⠨⠨⠨⠀⠨⠨⠨⠤⠤
⠨⠨⠨⠨⠤⠀⠨⠨⠨⠨⠤
⠨⠤⠤⠤⠤⠀⠤⠨⠨⠨⠨⠀⠨⠨⠨⠤⠤
⠨⠤⠤⠤⠤⠀⠤⠤⠨⠨⠨⠀⠨⠤⠤⠤⠤
⠨⠤⠤⠤⠤⠀⠤⠤⠨⠨⠨⠀⠨⠨⠨⠨⠨
.----⠀....-⠀-....
.----⠀.....⠀....-
.----⠀....-⠀.----
.----⠀....-⠀--...
.----⠀--...⠀...--
.----⠀.....⠀.....
-....⠀...--
....-⠀....-
.----⠀-....⠀...--
.----⠀--...⠀.----
.----⠀--...⠀.....
146 154 141 147 173 155 63 44 163 171 175
flag{m3$sy}
flag{m3$sy}

Weird Music (Cryptography 25)

曲はベートーベンの運命のようだが、リズムが違う。モールス信号のリズムか。

-... . . .--. ..--.- -... --- - --- .--. -..

これを元にフラグを投入する。

flag{BEEP_BOTOPT}×
flag{beep_botopt}×

推測しながら、調整する。

flag{beep_boop}

Green (Cryptography 30)

RGBの緑の値を文字にしていくと、base32文字列のようになる。文字列長が合わないので、"="でパディングし、デコードするとまたbase32文字列になる。あとは何回かbase32デコードすると、フラグになった。

from PIL import Image
import base64

img = Image.open('6e7ee269ddfdddc28304a10b36991812.png').convert('RGB')
w, h = img.size

assert(h == 1)

msg = ''
for x in range(w):
    _, g, _ = img.getpixel((x, 0))
    msg += chr(g)

while True:
    if len(msg) % 8 == 0:
        break
    msg += '='

while True:
    try:
        msg = base64.b32decode(msg)
    except:
        break

print(msg)
flag{d075_4nd_d0ts}

Green 2 (Cryptography 35)

緑色の数値をalphabetのインデックスとして文字にする。

hellotheremhsctf

Vigenere暗号と推測し、https://cryptii.com/pipes/vigenere-cipherで復号する。

s0kple4lmekm}y4ie_}b

推測は外れたようだ。他の暗号をいろいろ探してみると、Hill暗号が試せそう。
Hill暗号として復号してみると、復号できた。

#!/usr/bin/sage
from PIL import Image

def decrypt(K, ct, alphabet):
    ct = [[alphabet.index(c)] for c in ct]
    C = matrix(Zmod(n), ct)
    P = K.inverse() * C
    pt = ''.join([alphabet[P[i][0]] for i in range(P.nrows())])
    return pt

img = Image.open('d67cee647f8282218af8dca1c56a20da.png').convert('RGB')
w, h = img.size

keys = []
for y in range(78, h, 156):
    key = []
    for x in range(78, w, 156):
        r, g, b = img.getpixel((x, y))
        key.append(g)
    keys.append(key)

alphabet = 'vxotbj9a8yqp7n5mh1rzwcd6gfiks3uel240{}_'
ciphertext = 'jkwb44pg26teiu}78uu{'

n = len(alphabet)
K = matrix(Zmod(n), keys)

flag = ''
for i in range(0, len(ciphertext), 4):
    ct = ciphertext[i:i+4]
    pt = decrypt(K, ct, alphabet)
    flag += pt
print(flag)
flag{j4ck_4nd_ji11}}

最後"}"が2文字重なっているので、1文字はずす。

flag{j4ck_4nd_ji11}