🤖

tsukuctf(2025-05-03)

に公開

OSINT

Casca

画像を検索すると熱海市のジャカランダ遊歩道がヒットする。
「ジャカランダ遊歩道 式典」で検索して式典の開催日を検索したらOK。
TsukuCTF25{2014/06/06}

curve

曲がったエスカレーターの画像で検索すると横浜ランドマークタワーがヒットする。
Webサイトのドメインを解答。

schnee

写真検索でスイスのグリンデルワルトという土地がヒット。
緯度と経度を出す必要があるのでGoogleMapで絞り込む。

ChatGPTに画像を投げたところ、グリンデルワルトのSKISETという店がヒット。
画像内のSKISETという単語でググれば良かったっぽい。
ChatGPTが返してきたサイトの緯度経度を渡したら通った。
https://www.pic2map.com/ojwvqa.html

buildings

品川シーズンテラス前の写真だったのでリアル知識で突破。

power

写真の中に展示があるのでそれを解読していく。
下の文章の頭「とーきょーと してい きゅーせき まさかどづか」
地図の上の部分「ちどりい」
地図の茶色い部分「じゅもく」
上の特徴的な部分「せきひ いしどーろー」
地図は下が南で書かれている

どうやら将門塚の案内板の写真だったらしい。

GoogleMapから写真の位置を推測して答えてみたところ正解。

rider

OTI FRIED CHICKENという店の看板が写っているが、これはインドネシアに展開する店らしい。

インドネシアの当該店舗を一つずつGoogle Mapで確認したところ、Salatigaの店舗で取られた写真であると分かった。
手前のパンダの写真と奥のKINGと書かれた看板、大木があるので多分間違いない。

GoogleMapで店の緯度と経度を出したら正解だった。

destroyed

telegramの文章を翻訳したところ、ザポリージャ州のStepneのギムナジウムの写真であることを確認。
GoogleMapで確認したが、Stepneの範囲に学校はヒットせず。

次の特徴を持つ建物を探したところ、郵便局の西側にL字の建物を発見。

  • 二階建て
  • L字の部分の内側に遊具を置いている
  • 塀で囲まれている
  • 三角屋根
    建物の座標を解答したら通った。

crypto

a8tsukuctf

Autokey Vigenere暗号を使用している。
最初に短い鍵を使って暗号化を行い、それ以降は直前までの暗号文を鍵として使用する実装となっている。
例えば鍵が3文字の場合、4文字目の暗号化では暗号文の3文字目を鍵として使用する。

暗号文中の一部がtsukuctfという既知の平文になっていることを利用して最初の部分の鍵を計算し、それを用いて全体を復号するという順番で解く事ができる。

暗号文は次のようになっている。
ayb wpg uujmz pwom jaaaaaa aa tsukuctf
平文は次のようになっている。
xxx xxx xxxxx xxxxxxx xx tsukuctf

このときtsukuctfの部分の暗号化には直前のaaaaaaaaが使用されている(拡張鍵部分で暗号化を行っている)と考えることができる。
つまりtsukuctf以降の部分はtsukuctfをベース暗号鍵として復号していくことができる。

  • tsukuctfの次の8文字をkey:tsukuctfとして解く
  • さらに次の8文字は直前の8文字の暗号文をkeyとして解く
  • ...

これを繰り返すと次の文章が得られる。
...... tsukuctf or both the flag is concatenate the seventh word in the first sentence the third word in the second sentence and fun with underscores

PQC0

耐量子暗号アルゴリズムのKEMに触れる問題。

OpenSSL 3.5.0が必要なのでとりあえず公式サイトからインストール。
https://openssl-library.org/source/
インストール後はちゃんとパスを通す。

まずoutput.txtから秘密鍵部分を抜き出してpriv-ml-kem-768.pemに保存する。
また、ciphertext部分をrecovered_shared.datに保存する。
ciphertextはhexの文字列で渡されているのでbytes.fromhex()を用いてバイト列に変換する。
ciphertextは秘密鍵を用いて共通鍵をカプセル化したものである。

次にprivate_keyを用いてciphertext.datを復号し共通鍵を取得する。
このとき復号にはKEMアルゴリズムを使用するため最新版のopensslが必要。

openssl pkeyutl -decap -inkey priv-ml-kem-768.pem -in ciphertext.dat -secret recovered_shared.dat

最後にrecovered_shared.datに出力した共通鍵を用いてencrypted_flagを復号する。
今回はAESのECBモードを使用。

ちなみに.datファイル(data)は中身の形式が決まっていないバイナリ/テキストデータに使用される拡張子らしい。

Web

len_len

フラグ出力部は以下の通り。ただしsanitized.length<10だと事前に弾かれる。
array.length < 0という通常ではありえないチェックをしており怪しい。

const array = JSON.parse(sanitized);
if (array.length < 0) 
	return FLAG;

sanitizedの中身がオブジェクトであり、length要素の値が-1のような値であればFLAGが出力される。
ということでarray={"length":-1}という文字列を送る。

$ curl -X POST -d 'array={"length":-1}' http://challs.tsukuctf.org:28888
TsukuCTF25{l4n_l1n_lun_l4n_l0n}

型チェックって大事ですね。

JSON, JSON.parseについて

JSONは次のような形のテキストフォーマット。

{
  "name": "Alice",
  "age": 25,
  "skills": ["JavaScript", "Python"]
}

JSON.parse()を使用することでJSON形式の文字列を受取りJavascriptのオブジェクトに変換できる。

flash

Gemini先生2。

seed値から生成される10個の数字の和を計算する問題。
フラッシュ暗算みたいな感じで画面に数字が出てくるが全部の数字は出ないので正攻法では解けない。

与えられたコードを見ると、seed.txtの値とsession_idから線形合同法という手段で10個の数字を生成していることが分かる。
公開設定の不備によりパスを指定することでseed.txtへのアクセスが出来たのでまずはこれを確保。
また、開発者ツールからcookieの値を持ってきてBAE64でデコードすることでsession_idも確保。

あとはseed, session_idから手元で10この数字を生成、その合計を問題サーバに入力するとフラグが表示される。

Discussion