最終順位は235/803位でした
beginner – pyjail
与えられたプログラムについて
exec(code, {})でユーザー入力を実行- 入力は小文字と空白のみ、最大15文字
- 実行結果の標準出力が500文字を超えると
FLAGを表示 - グローバルに空辞書を渡しているが、通常の組み込みは利用可能
- 記号・数字・アンダースコア不可 →
__import__やprint('x'*500)などの書き方が使えない
解法
import this
これで len(result) > 500 が真になり FLAG が表示されます
import this について
Python の「イースターエッグ」コマンドで、実行すると 「The Zen of Python」 という短い文章(Python の設計哲学)を表示するモジュールを読み込みます
(読み込むだけで文字が表示されます)
是非一度試してみてください
実行結果
== proof-of-work: disabled ==
Enter your solution: import this
b'infobahn{Y0u_3Sc4p3D_Th3_J@1lll_4359849084894}\n'
Answer : infobahn{Y0u_3Sc4p3D_Th3_J@1lll_4359849084894}
beginner – Linearity
行列構造を使ったXOR暗号で、線形再利用を利用して復号する問題でした
1.構造の分析
V = [v0, v1, v2, v3, v4]は固定M[i][j] = V[i] * r_ij(ただしr_ijは 0〜100 の整数)C[k] = M[k//5 % 5][k % 5] ^ ord(FLAG[k])
フラグ文字 FLAG[k] は対応する行列要素 M[row][col] とのXOR
2.ポイント
row = (i // 5) % 5
col = i % 5
この部分より、フラグが 25 文字を超える場合、M の要素が再利用される
(つまり同じ M[row][col] が複数箇所に使われる)
→ これが解析のカギ
3.同じ M を共有するペアを利用
たとえば (row=0,col=0) の箇所はi = 0, 25, 50, ...
で出現する
ここで同じ M[0][0] が使われている
それぞれに対して
C[i] ^ ord(FLAG[i]) = M[row][col]
C[j] ^ ord(FLAG[j]) = M[row][col]
なので、差分を取ると
C[i] ^ ord(FLAG[i]) = C[j] ^ ord(FLAG[j])
↓
ord(FLAG[i]) ^ ord(FLAG[j]) = C[i] ^ C[j]
これで FLAG のペアの文字の XOR 関係が求まる
つまり M の実際の値を知らなくても、文字間の関係が得られる
4. フラグ形式から推測
infobahn{ は固定なので、先頭 9 文字分の ord() が確定している
そこから上の関係式を使うと、同じ M を共有するブロックの文字をすべて順に確定できる
5. M 値の復元
M[row][col] = C[i] ^ ord(FLAG[i]) なので、FLAG[i] が確定したブロックの M は直接求まる
他のブロックでも同じ M が使われていれば、そこからさらにフラグ文字を導ける
この連鎖で全体のフラグを順に解く
from hashlib import sha256
V = [14, 38, 56, 76, 51]
C = [1357, 2854, 1102, 1723, 4416, 283, 344, 4566, 5023, 1798, 477, 3833, 1839, 5416, 4017, 1066, 161, 415, 5637, 1696, 1058, 3025, 5286, 5141, 3818, 1373, 2839, 1102, 1764, 4432, 313, 322, 4545, 5012, 1835, 477, 3825]
flag = list("infobahn{" + "?" * (len(C) - 9))
M = [[None]*5 for _ in range(5)]
# 求まる M を確定
for i in range(9):
r = (i // 5) % 5
c = i % 5
M[r][c] = C[i] ^ ord(flag[i])
# 既知の M で残りの文字を埋める
for i in range(9, len(C)):
r = (i // 5) % 5
c = i % 5
if M[r][c] is not None:
flag[i] = chr(C[i] ^ M[r][c])
flag = "".join(flag)
print(flag)
print(sha256(flag.encode()).hexdigest())
Answer : infobahn{You_HAVE_Aff1niTy_f0rCrypto}
misc – Sanity Check
Discordサーバーのsponsorsチャンネルのチャンネルトピックに書かれていました
Answer : infobahn{G00d_LucK_th1s_1S_Th3_54n17y_2435343!}
misc – Sponsors
https://2025.infobahnc.tf/sponsorsの下の方に書かれていました
Answer : infobahn{thanks_to_GoogleCloud_OffSec_OtterSec_RET2_Cybersharing_RapidRiskRadar_for_sponsoring!}
misc – Feedback
CTF終了1時間前に公開された問題です
フォームに回答するとフラグを入手できます
Answer : infobahn{s33_y0u_n3xt_ye4r_1n_InfobahnCTF_2026!}
web – PatchNotes CMS
シンプルなパストラバーサルの問題です
インスタンス起動→ページにアクセス後、Fileに以下の文字列を入力
../../../flag.txt
その後、Viewをクリックするとフラグが出てきます
Answer : infobahnctf{0c788146e222f9ac774da77108d8b643}
脆弱なコードについて/app/admin/api/preview/route.ts に
const fullPath = path.join(BASE_DIR, file);
と書かれている部分があります
ここで file はユーザー入力ですが、path.join() は 相対パスを解決してしまう ため、../../../flag.txt のようなパスが渡されると、ディレクトリを脱出できてしまいます。


コメント