👁️

【セキュリティゲーム】SECCON Beginners CTF 2022 Writeup ~Crypto - CoughingFox~

2022/06/09に公開

はじめまして、ますみです!

株式会社Galirage(ガリレージ)という「生成AIに特化して、システム開発・アドバイザリー支援・研修支援をしているIT企業」で、代表をしております^^

自己紹介.png

先日、SECCON Beginners CTF 2022というイベント(2022/06/04~05)に4人チームで参加し、私はCryptoの問題を担当しました。

そこで、この記事では、その中のCoughingFoxというBeginner向けの問題の解説(Writeup)をします。

前提知識

CTFとは?

CTFとは、Capture The Flagの略で情報セキュリティ分野における「旗とりゲーム」です。
専門的な知識と技術を用いて、隠れされたFlag(文字列)を見つけ出します。
https://www.nri-secure.co.jp/glossary/ctf

大会によって定義は異なりますが、一般的にCTFは以下のようなジャンルに分かれます。

名前 ジャンル
Reversing (Binary) バイナリ解析
Forensics イメージファイル解析
Pwn Programの脆弱性攻撃
Web Webの脆弱性攻撃
Network ネットワークパケットなどの解析
Crpto 暗号の復号
Misc その他(様々なデータからフラグを見つける)

SECCONとは?

SECCONとは、Security Contestの略称で、情報セキュリティのコンテストイベントです。SECCONは、「CTF」と「ハッカソン」の二種類のコンテストを主催しています。
公式サイトでは、次のように定義されています。

情報セキュリティをテーマに多様な競技を開催する情報セキュリティコンテストイベントです。実践的情報セキュリティ人材の発掘・ 育成、技術の実践の場の提供を目的として設立されました。(SECCON 2021より引用)

https://kotobank.jp/word/SECCON-190656

問題内容

では、ここからSECCON Beginners CTF 2022のCrypto問題として出題されたCoughingFoxの問題を説明します。コンテストでは、下記のproblem.pyoutput.txtが渡されます。

この問題では、flagがダミーの文字列になっていますが、「flagが入力された状態で、problem.pyを実行すると、output.txtが出力されますよ。」という条件になります。

問題の中身を少しだけ解説すると、以下のような形になります。

  1. flagの文字列の中身を一文字ずつ抜き出し、fに代入する。
  2. 抜き出した文字fが「何番目の文字か」というインデックスiを足して、2乗して、もう一度iを足す。(ちなみに、文字はASCII表に従って、暗黙的にint型に変換されています。)
  3. 最後にシャッフル。

なんだか解けそうな気がしてきますよね😇

problem.py
from random import shuffle

flag = b"ctf4b{XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}"

cipher = []

for i in range(len(flag)):
    f = flag[i]
    c = (f + i)**2 + i
    cipher.append(c)

shuffle(cipher)
print("cipher =", cipher)
output.txt
cipher = [12147, 20481, 7073, 10408, 26615, 19066, 19363, 10852, 11705, 17445, 3028, 10640, 10623, 13243, 5789, 17436, 12348, 10818, 15891, 2818, 13690, 11671, 6410, 16649, 15905, 22240, 7096, 9801, 6090, 9624, 16660, 18531, 22533, 24381, 14909, 17705, 16389, 21346, 19626, 29977, 23452, 14895, 17452, 17733, 22235, 24687, 15649, 21941, 11472]
Pythonに詳しくない方は、こちらの入門書をご覧ください

回答(筆者の回答)

筆者の作成した回答(solver)は以下の通りです。

  1. まずoutput.txtの中身を取り出し、格納されている数字を一つずつi_outputでincrementして、取り出す。

  2. 次に、tryの中で暗号化された処理と逆の処理を記述して、その復号結果の妥当性を検証します。フラグのフォーマットルールとして、ctf4b{[\x20-\x7e]+}が提示されているため、この条件にマッチする検証を行いました。ここでのポイントとしては、暗号化した時の「何番目の文字か」というインデックスiの情報をi_choiceという変数用いて、総当たりしていることです。

  3. 結果的に、何文字目かという情報とその文字が何かという情報がリストとして取得できたため、最後にソートを行いました。

solver.py
flag = b"ctf4b{XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}"

output = [
    12147, 20481, 7073, 10408, 26615, 19066, 19363, 10852, 11705, 17445, 3028,
    10640, 10623, 13243, 5789, 17436, 12348, 10818, 15891, 2818, 13690, 11671,
    6410, 16649, 15905, 22240, 7096, 9801, 6090, 9624, 16660, 18531, 22533,
    24381, 14909, 17705, 16389, 21346, 19626, 29977, 23452, 14895, 17452,
    17733, 22235, 24687, 15649, 21941, 11472
]


def is_right_char(value: int):
    """is_right_char

    Args:
        value (int): integer number in ascii

    Returns:
        bool: whether it matches the flag regulation rule

    Example:
        >> print(is_right_char(50))
        True
    """
    if 32 <= value and value <= 126 and value.is_integer():
        return True
    else:
        return False


flag_len = len(flag)
index_list = []
word_list = []
for i_output in range(flag_len):
    for i_choice in range(flag_len):
        c = output[i_output] # <= 1. Extract Output Character
        try: # <= 2. Decode and Validate
            f = (c - i_choice)**(0.5) - i_choice
            if is_right_char(f):
                index_list.append(i_choice)
                word_list.append(int(f))
            f = -(c - i_choice)**(0.5) - i_choice
            if is_right_char(f):
                index_list.append(i_choice)
                word_list.append(int(f))
        except:
            continue

# 3. Sort List
print(f"index_list: {index_list} \n")
print(f"word_list: {word_list} \n")

flag_list = ['~'] * flag_len
for i in range(flag_len):
    flag_list[index_list[i]] = chr(word_list[i])
flag_answer = ''.join(flag_list)
print(f"flag_answer: {flag_answer}")

output-solver.txt
index_list: [47, 32, 17, 4, 46, 22, 42, 36, 41, 21, 3, 31, 14, 18, 13, 12, 27, 2, 15, 9, 1, 7, 10, 8, 29, 39, 40, 0, 6, 20, 19, 35, 33, 45, 25, 16, 5, 30, 26, 48, 43, 11, 28, 44, 34, 38, 24, 37, 23]

word_list: [63, 111, 67, 98, 117, 116, 97, 68, 67, 111, 52, 72, 89, 97, 63, 120, 84, 102, 111, 44, 116, 101, 70, 121, 97, 110, 44, 99, 72, 78, 110, 101, 117, 111, 97, 117, 123, 116, 114, 125, 110, 111, 104, 89, 115, 119, 101, 111, 84]

flag_answer: ctf4b{Hey,Fox?YouCanNotTearThatHouseDown,CanYou?}

以上のようにして、ctf4b{Hey,Fox?YouCanNotTearThatHouseDown,CanYou?}というflagが取得できました🎉

作問者の回答の手法

作問者の回答はもっとスマートでした😲
gmpy2.iroot(c, e)という「e乗根した時にその値(c)が整数かどうかを判定するライブラリ」を用いて解いていました。
https://qiita.com/ushigai_sub/items/1182d7f49e7ff92646e7

最後に

最後まで読んでくださり、ありがとうございました!
この記事を通して、少しでもあなたの学びに役立てば幸いです!

おまけ①:Raggle

RAGの精度改善に挑戦しませんか?

Raggleにて、「法務RAGシステムの性能改善ハッカソン」を開催中です!(10月20日に募集締切)

Raggleは、RAGの性能改善技術を競い合い、AIエンジニアのスキルアップを支援するプラットフォームです🥇

優勝者(GOLD🥇)の賞金は、なんと30万円!!!

SILVERは10万円、BRONZEでも5万円の賞金を用意しています!

また、参加賞として、大会終了後に「RAG精度改善ハンドブック」を贈呈予定なため、初学者の方もぜひ挑戦してみてください 🔰

みなさん、奮ってご参加ください🔥

※ 生成AIエンジニアの権利を守るため、投稿されたソースコードの著作権は、投稿者に帰属する規約としているため、その点もご安心ください◎

▼ エントリーはこちら ▼
https://raggle.jp/competition/29676d73-5675-4278-b1a6-d4a9fdd0a0ba

おまけ②:書籍出版のお知らせ

ついに『AIとコミュニケーションする技術(インプレス出版)』という書籍の事前予約が始まりました🎉

これからの未来において「変わらない知識」を見極めて、生成AIの業界において、読まれ続ける「バイブル」となる本をまとめ上げました。

かなり自信のある一冊なため、もしもよろしければ、ご一読いただけますと幸いです^^

▼ Amazonの事前予約はこちらから ▼
https://amzn.to/3ME8mLF

おまけ③:生成AIアカデミー

より専門的な「生成AIエンジニア人材」を目指しませんか?

そんな方々に向けて、「生成AIアカデミー(旧:生成AIエンジニア塾)」というプログラムを始めました🎉

最終的なゴールとして、『エンタープライズ向けの生成AIシステムを構築するためのスキルを習得し、大手案件で活躍できる人材』を目標とします。

また、一人一人にしっかりと向き合って、メンタリングをできるようにするため、現在メンバーの人数制限をしております。本気度やスキルレベルの高い人から、順番にご案内しております。

▼ 登録はこちらから ▼
https://bit.ly/generative_ai_engineer_school_by_zenn

おまけ④:AI Newsletter for Biz

最新のAIニュースの情報を収集しませんか?

AI Newsltter for Bizは、ビジネスパーソン向けに「AIニュース」を定期配信する完全無料のニュースレターです📩

一人でも多くの方にとって、「AI人材としてのスキルアップ」につながれば幸いです^^

また、現在、登録者限定で「明日から使える 無料AIサービス3選」のPDFを配布中です 🎁
※ ご登録完了のメールに、PDFリンクを添付いたします。

▼ 登録はこちらから ▼
https://bit.ly/ai_newsletter_for_biz_zenn

おまけ⑤:生成AIの仕事をしたい仲間を募集中 🤝

弊社Galirageでは常に、40-50件ほどの生成AI案件が走っております。

そして、ほとんどが「生成AIの案件(RAGシステム開発 / 精度改善の研究開発など)」の仕事になります!

かなり人手が不足しており、以下のポジションの仲間を募集しています💪

  • RAGエンジニア(RAG / LangChain / Python)
  • バックエンドエンジニア(Python / FastAPI)
  • フロントエンジニア(Next.js / TypeScript)
  • Azureエンジニア(AOAI / AI Search)
  • UI/UXデザイナー
  • 生成AIリサーチャー(研究開発 / 論文執筆)
  • 生成AIコンサルタント
  • PM / PMO

ご興味がある方は、下記のフォームよりお気軽にご連絡ください!

https://forms.gle/XMd19irZU4Fi7VAQ9

採用基準は下記の通りです。
  • 平日の日中に動ける方だと嬉しいですが、週8時間くらいの副業でもOKです!
  • 開始時期は、直近だと嬉しいですが、遠い未来でもOKです!まずはカジュアルに話しましょう😊
  • 年齢は不問です!現状は、平均年齢は30歳前後の会社です!
  • 「スキルセット」よりも「カルチャーマッチ・仕事への姿勢・ものづくりへのワクワク」を重視します。
    • 10月には新しく10名採用しました。
    • その内、エンジニア経験が3年未満の方は、4名いました。
    • スキルについては、ジョインした後に、必要に応じて、キャッチアップする時間を作ります。
    • 弊社は、正社員7名、業務委託80名の組織で構成されており、業務委託の仲間に支えられているため、正社員と業務委託の間にあまり差をつけていません。
    • 契約形態に関わらず、一緒に働く仲間として受け入れたその日から、大切な仲間です!
    • 新卒や転職の正社員採用もしていますが、業務委託での仕事を通して、お互いにWin-Winだと判断できた方のみを採用しています。
    • 私自身、フリーランスを5年間やっていたため、個人事業主と正社員のメリデメは両方の立場から理解しています。
  • 人手不足ではあるものの、採用基準をかなり厳しくしています。目の前の売上よりも、カルチャーのマッチする人だけを入れることにこだわっています。
  • ちなみに、弊社のリーダーを紹介したプロフィールページはこちらです!
    • Galirageに、本当に素敵な方が多いことは、保証します!

Discussion