pomoの掃きだめ

色々な感情をとりあえず文字に起こす場所. Twitter→@mhskmq

InterKosenCTF Writeup

f:id:pomo_mhskmq:20190813110847p:plainInterKosenCTFにチームterpomoとして参加しました.一人チームです. 結果は36位でした. ぼちぼちですね

Kurukuru Shuffle

フラグをクルクル~っと混ぜたものと,まぜまぜするためのコードが渡されます.

from secret import flag
from random import randrange


def is_prime(N):
    if N % 2 == 0:
        return False
    i = 3
    while i * i < N:
        if N % i == 0:
            return False
        i += 2
    return True


L = len(flag)
assert is_prime(L)

encrypted = list(flag)
k = randrange(1, L)
while True:
    a = randrange(0, L)
    b = randrange(0, L)

    if a != b:
        break

i = k
for _ in range(L):
    s = (i + a) % L
    t = (i + b) % L
    encrypted[s], encrypted[t] = encrypted[t], encrypted[s]
    i = (i + k) % L

encrypted = "".join(encrypted)
print(encrypted)

暗号化のための鍵として3つのランダムな値が使われていますが,大きな数字ではないので愚直に全探索して,フラグっぽい文字列を探してあげます.

KosenCTF{us4m1m1_m4sk_s3np41_1s_r34lly_cut3_38769915}

Hugtto!

フラグを埋め込んだ画像ファイル(steg_emiru.png)と埋め込みに使ったコードが渡されます.

from PIL import Image
from secret import flag
from datetime import datetime
import tarfile
import sys

import random

random.seed(int(datetime.now().timestamp()))

bin_flag = []
for c in flag:
    for i in range(8):
        bin_flag.append((ord(c) >> i) & 1)

img = Image.open("./emiru.png")
new_img = Image.new("RGB", img.size)

w, h = img.size

i = 0
for x in range(w):
    for y in range(h):
        r, g, b = img.getpixel((x, y))
        rnd = random.randint(0, 2)
        if rnd == 0:
            r = (r & 0xFE) | bin_flag[i % len(bin_flag)]
            new_img.putpixel((x, y), (r, g, b))
        elif rnd == 1:
            g = (g & 0xFE) | bin_flag[i % len(bin_flag)]
            new_img.putpixel((x, y), (r, g, b))
        elif rnd == 2:
            b = (b & 0xFE) | bin_flag[i % len(bin_flag)]
            new_img.putpixel((x, y), (r, g, b))
        i += 1

new_img.save("./steg_emiru.png")
with tarfile.open("stegano.tar.gz", "w:gz") as tar:
    tar.add("./steg_emiru.png")
    tar.add(sys.argv[0])

どうやらフラグを1bitずつ画像のr,g,bの最終1bitのどれかに入れているらしいです. フラグの形式が分かっているのでフラグ長を調べて~と思いましたが,この問題のジャンルはforensicsなのです!(なのです!) フラグの1bitがrgbのどれに入るかは乱数によって決定されており,乱数のseedにはdatetime.now()が使われています. ということで,exiftoolでsteg_emiru.pngの最終編集時間を調べます.

File Modification Date/Time     : 2019:08:06 11:44:18+09:00

この時刻をseedに使えば解けると思いましたが解けなかったので結局この付近の時刻を全探索して解きました. 探すべき時間がこれではないのか,そもそも想定解ではないのかはルールーに聞いてほしいのです

import sys
from PIL import Image
import datetime
import random

bin_flag =0
bin_r =""
bin_g =""
bin_b =""

img = Image.open("./steg_emiru.png")
new_img = Image.new("RGB", img.size)

w, h = img.size


i=0
bin_flag=0
rev_flag=0
b_flag=0
st=[]
for d in range (1,7):
    for ho in range (24):
        for m in range (60):
            for s in range (60):
                print(d,ho,m,s)
                bin_r=""
                i=0
                bin_flag=0
                rev_flag=0
                b_flag=0
                dt_jst = datetime.datetime(2019,8, d,ho, m, s, 0,tzinfo=datetime.timezone(datetime.timedelta(hours=9)))
                random.seed(int(dt_jst.timestamp()))
                for x in range(w):
                    for y in range(h):
                        rnd = random.randint(0, 2)
                        r, g, b = img.getpixel((x, y))
                        rb=(r & 1)
                        gb=(g & 1)
                        bb=(b & 1)
                        if (rnd==0):
                            bin_flag=bin_flag<<1 | rb
                        if (rnd==1):
                            bin_flag=bin_flag<<1 | gb
                        if (rnd==2):
                            bin_flag=bin_flag<<1 | bb
                        if (i%8==7 and i!=0):
                            for z in range (8):
                                rev_flag=((rev_flag<<1) |((bin_flag>>z) & 1))
                            bin_r+=(chr(rev_flag))
                            bin_flag=0
                            rev_flag=0
                            if (i==7 and bin_r[0]!="K"):
                                b_flag=1
                                break
                            if (i == 15 and bin_r[1]!="o"):
                                b_flag=1
                                break
                            if (i == 23 and bin_r[2]!="s"):
                                b_flag=1
                                break
                            elif i==23:
                                print ("Perfect!!!!!!!!!!!!!!!!!!")
                        i += 1
                        if (i==800):
                            b_flag=1
                            break
                    if (b_flag==1):
                        b_flag=0
                        break

                if (bin_r[0]=="K" and bin_r[1]=="o" and bin_r[2]=="s" and bin_r[3]=="e"):
                    st.append(bin_r)
                    a1,a2,a3,a4=d,ho,m,s

print(st)
print(d,ho,m,s)

KosenCTF{Her_name_is_EMIRU_AISAKI_who_is_appeared_in_Hugtto!PreCure}

ちなみに私のアイコンもえみるちゃんです.愛らしいですね. 私はキュアマジカル/十六夜リコが好きです(イケメンなので)

basic crackme

ELFが渡されます. 引数に入っている文字列がフラグと前方一致しているとYES!と返してくれます(途中で途切れているフラグでも可). ちゃんとassemblyを読めと声が聞こえた気がしたのでIDAを使って読んでみます. まとめると,引数の文字のn文字目を左4bitシフトしたものと右4bitシフトしたものをorして(n-1)を足してあげます. これがマジックナンバーと一致すればOKということみたいです. 挙動をpythonで再現し,全探索してあげたものがこちらになります.

import sys

li    =[0xb4,0xf7,0x39,0x59,0xea,0x39,0x4B,0x6B,0xbf,0x80,0x3d,0xd1,0x42,0x10,0xe4,0x42,0x105,0x58,0x15,0x108,0xab,0x18,0xe8,0xcd,0x1b,0xeb,0x51,0x1e,0x111,0x44,0x51,0x86,0x53,0x48,0x59,0x36,0x10A,0x9b,0xfd]
flag=[0xb4,0xf7,0x39,0x59,0xea,0x39,0x4B,0x6B,0xbf,0x80,0x3d,0xd1,0x42,0x10,0xe4,0x42,0x105,0x58,0x15,0x108,0xab,0x18,0xe8,0xcd,0x1b,0xeb,0x51,0x1e,0x111,0x44,0x51,0x86,0x53,0x48,0x59,0x36,0x10A,0x9b,0xfd]

for i in range(len(li)):
    for j in range(3,125):
        k=(j<<4)&0xFF
        l=(j>>4)
        m=k|l
        m+=i
        if (m==(li[i])):
            flag[i]=(chr(j))
            break
            
print(flag)

KosenCTF{w3lc0m3_t0_y0-k0-s0_r3v3rs1ng}

lost world

Can you restore my root user? I don't remember the password. Try running dmesg | grep KosenCTF after logging in.

パスワードを忘れたらしいので再設定します. うっかり者の先人たちの知恵を借りながらやりました.

起動したらSHIFTキー連打でRecovery modeに入ります. eキーを押してシングルユーザーモードにしてなんやかんやでパスワードを再設定できればOKです. rootでログインできたら問題文にあるとおりdmesg | grep KosenCTFを実行するとフラグが現われます. 何を参考にして解いたのか記憶がないのでざっくりになってしまいました. 反省します.

KosenCTF{u_c4n_r3s3t_r00t_p4ssw0rd_1n_VM}

感想

初心者向けと聞かされてほいほいと参加してしまいましたが,普通に難しい問題が多くて苦戦しました. 勉強になる問題がたくさんあったので復習させていただきたいと思います. 最後に,運営の皆様お疲れさまでした.