InterKosenCTF Writeup
InterKosenCTFにチーム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}
感想
初心者向けと聞かされてほいほいと参加してしまいましたが,普通に難しい問題が多くて苦戦しました. 勉強になる問題がたくさんあったので復習させていただきたいと思います. 最後に,運営の皆様お疲れさまでした.
ISITDTU CTF 2019 Quals Writeup
6月29日から6月30にかけて行われたISTDTU CTF 2019 Qualsにチームzer0ptsとして参加しました. チームは7655点を獲得して10位でした. 私は2つの問題を解いて404点入れました.
Programing
balls
There are 12 balls, all of equal size, but only 11 are of equal weight, one fake ball is either lighter or heavier. Can you find the fake ball by using a balance scale only 3 times?
nc 34.68.81.63 6666
12個あるボールの中から1つだけ重さの違うボールを天秤を3回使って見つけてねという問題 似た問題がないかグーグル先生に聞いてみると見つかりました.
これをそのまま実装すればよさそうなのでコードを書きます
# -*- coding: utf-8 -*- from pwn import * host, port = "34.68.81.63", 6666 context.clear() context.log_level='error' cn= remote(host,port) for i in range (50): cn.clean() print cn.recvuntil("Weighting 1:") cn.sendline ("1,2,3,4 5,6,7,8") ans=cn.recvline() print ans if (ans.find("Both are equally heavy")!=-1): cn.recvuntil("Weighting 2:") cn.sendline("1,2 9,10") ans=cn.recvline() print ans if (ans.find("Both are equally heavy")!=-1): cn.recvuntil("Weighting 3:") cn.sendline("1 11") ans=cn.recvline() print ans if (ans.find("Both are equally heavy")!=-1): cn.recvuntil("The fake ball is :") cn.sendline("12") print("12") continue else: cn.recvuntil("The fake ball is :") cn.sendline("11") print("11") continue else: cn.recvuntil("Weighting 3:") cn.sendline("1 9") ans=cn.recvline() print ans if (ans.find("Both are equally heavy")!=-1): cn.recvuntil("The fake ball is :") cn.sendline("10") print("10") continue else: cn.recvuntil("The fake ball is :") cn.sendline("9") print("9") continue if (ans.find("The left is heavier than the right")!=-1): cn.recvuntil("Weighting 2:") cn.sendline("1,2,5 3,4,6") ans=cn.recvline() print ans if (ans.find("Both are equally heavy")!=-1): cn.recvuntil("Weighting 3:") cn.sendline("1 7") ans=cn.recvline() print ans if (ans.find("Both are equally heavy")!=-1): cn.recvuntil("The fake ball is :") cn.sendline("8") print("8") continue else: cn.recvuntil("The fake ball is :") cn.sendline("7") print("7") continue if(ans.find("The left is heavier than the right")!=-1): cn.recvuntil("Weighting 3:") cn.sendline("1 2") ans=cn.recvline() print ans if (ans.find("Both are equally heavy")!=-1): cn.recvuntil("The fake ball is :") cn.sendline("6") print("6") continue if (ans.find("The left is heavier than the right")!=-1): cn.recvuntil("The fake ball is :") cn.sendline("1") print("1") continue else: cn.recvuntil("The fake ball is :") cn.sendline("2") print("2") continue if (ans.find("The left is lighter than the right")!=-1): cn.recvuntil("Weighting 3:") cn.sendline("3 4") ans=cn.recvline() print ans if (ans.find("Both are equally heavy")!=-1): cn.recvuntil("The fake ball is :") cn.sendline("5") print("5") continue if (ans.find("The left is heavier than the right")!=-1): cn.recvuntil("The fake ball is :") cn.sendline("3") print("3") continue else: cn.recvuntil("The fake ball is :") cn.sendline("4") print("4") continue if (ans.find("The left is lighter than the right")!=-1): cn.recvuntil("Weighting 2:") cn.sendline("1,2,5 3,4,6") ans=cn.recvline() print ans if (ans.find("Both are equally heavy")!=-1): cn.recvuntil("Weighting 3:") cn.sendline("10 7") ans=cn.recvline() print ans if (ans.find("Both are equally heavy")!=-1): cn.recvuntil("The fake ball is :") cn.sendline("8") print("8") continue else: cn.recvuntil("The fake ball is :") cn.sendline("7") print("7") continue if(ans.find("The left is lighter than the right")!=-1): cn.recvuntil("Weighting 3:") cn.sendline("1 2") ans=cn.recvline() print ans if (ans.find("Both are equally heavy")!=-1): cn.recvuntil("The fake ball is :") cn.sendline("6") print("6") continue if (ans.find("The left is lighter than the right")!=-1): cn.recvuntil("The fake ball is :") cn.sendline("1") print("1") continue else: cn.recvuntil("The fake ball is :") cn.sendline("2") print("2") print cn.recvline() print cn.recvline() continue if (ans.find("The left is heavier than the right")!=-1): cn.recvuntil("Weighting 3:") cn.sendline("3 4") ans=cn.recvline() print ans if (ans.find("Both are equally heavy")!=-1): cn.recvuntil("The fake ball is :") cn.sendline("5") print("5") continue else: if (ans.find("The left is lighter than the right")!=-1): cn.recvuntil("The fake ball is :") cn.sendline("3") print("3") print cn.recvline() print cn.recvline() continue else: cn.recvuntil("The fake ball is :") cn.sendline("4") print("4") continue print cn.recvrepeat() cn.close()
ISITDTU{y0u_hav3_200iq!!!!}
コードの汚さは点数に反映されないので無視します
Cryptography
Chaos
Could you help me solve this case? I have a tool but do not understand how it works. nc 104.154.120.223 8085
とりあえずサーバーにつないでみます
$ nc 104.154.120.223 8085 Your cipher key: Here is your cipher: 99/yy/II/LL 66/mm/%%/oo 22/cc/%%/pp 33/qq/TT/!!/## 11/zz/VV/PP 88/ll/&&/rr 33/nn/**/ww 44/rr/@@/gg 33/ll/??/mm 55/cc/PP/))/&& 33/ee/RR/VV 77/vv/VV/FF 77/dd/GG/__/,, 55/00/qq 99/ll/**/ee 33/qq/||/aa 22/ll/BB/$$/&& 11/ee/II/VV 88/hh/BB/,,/== 22/xx/EE/UU 99/qq/YY/**/,, 88/mm/&&/ww 33/ii/LL/$$/&& 99/xx/++/hh 11/11/zz 44/ee/##/bb 99/mm/YY/~~/>> 44/uu/KK/==/__ 99/hh/VV/II 11/zz/KK/>>/^^ 77/vv/TT/@@/++ 00/tt/SS/--/@@ 88/ii/LL/<</`` 33/ff/VV/VV 77/vv/``/yy 55/mm/VV/UU 44/uu/~~/oo 55/33/ee 88/gg/))/dd 99/ee/GG/EE 55/oo/JJ/**/?? 22/nn/__/gg 66/ff/,,/ii 22/ll/PP/YY 88/bb/QQ/TT 55/kk/VV/../++ 22/dd/KK/))/)) 44/gg/++/qq 00/bb/``/ww 33/zz/VV/++/~~ 44/ll/!!/ii 11/aa/VV/YY 77/88/qq 11/66/ll 77/oo/,,/qq 55/77/vv 88/ss/LL/UU 99/tt/HH/~~/%% 44/oo/../rr 99/vv/DD/--/!! 22/ss/--/bb 00/77/cc 11/yy/YY/||/== 11/kk/``/ff WELCOME TO CHAOS TOOL: Description: This is a tool which helps you hide the content of the message Notes: - Message cannot contain whitespace characters - Message can use all characters including punctuation marks and number - Decrypt the above key to get the flag, len(key) = 64 - All punctuation marks use in plain key: ~`!@#$%^&*()_-+=<,>.?| - Key is not a meaningful sentence - Find the rule in this tool **FEATURES** <1> Encrypt message <2> Get the flag Your choice:
1を選ぶと任意の文字列をEncryptしたものを返してくれるので,いろいろ試していると半角スペースで1文字が区切られていることがわかりました さらに, 数字は 00/::/:: (0の場合) 小文字のアルファベットは ::/aa/??/:: (aの場合,??は記号列) 大文字のアルファベットは ::/xx/AA/:: (Aの場合,xxは小文字のアルファベット) その他の記号は ::/::/::/::/?? (?の場合)
のように1文字ずつ暗号化されているようです.
となれば,これを復号化するような処理を書いてあげれば終わりです
from pwn import * host,port="104.154.120.223", 8085 context.clear() context.log_level='error' cn=remote(host,port) key1=cn.recvuntil("WELCOME TO CHAOS TOOL:") key=key1[17:key1.find("WELCOME TO CHAOS TOOL:")].split(" ") text="" for i in range(len(key)): key[i]=key[i].strip() print key[i] if (len(key[i])==14): text+=key[i][12] continue if (len(key[i])==11): if (ord(key[i][6])>=65 and ord(key[i][6])<=90): text+=key[i][6] continue else: text+=key[i][4] continue if (len(key[i])==8): text+=key[i][1] continue print ("???") print cn.recvuntil("Your choice:") cn.sendline("2") print cn.recvuntil("Please enter the key to get flag:") cn.sendline(text) print text print cn.recvrepeat() cn.close()
ISITDTU{Hav3_y0u_had_a_h3adach3??_Forgive_me!^^}
感想
CTF初参加と言っても過言ではないような状態で,初心者向けだからと唆されて参加しましたが,解ける問題もあってよかったとおもいます. 後半はmatrixとずっと戦っていたのですが最後まで何がなんやらわからずに終わってしまったので悔しいです. あと,これは経験がない故の愚痴なので聞き流してもらいたいのですが,すごくスコアサーバーが不安定で大変でした CTFはこんなものなんですか知りませんが
易しい問題を作ってくださった運営の方々に感謝ですありがとうございました
感謝
チームのみなさんに問題を残しておいてと泣きついたためになんとか2つのフラグを通すことができました. 完全に足を引っ張ってしまいましたが,CTFを初めて数か月の超ビギナーな私を快く迎え入れてくれたzer0ptsのみなさんありがとうございました.
この文章は寝ながら書いたので無茶苦茶です.気が向いたら修正します