feature image

2021年4月29日 | ブログ記事

CPCTF2021作問者write up(?) by nambatsu

はじめに

こんにちは18Bのnambatsuです。普段は音ゲーとバイトばかりしている大学生です。2020年度はICTSCという大会に出る以外でtraPの活動をしていませんでした。しかし2021年度は(こそは?)活動したい! という気持ちでいて、早速CPCTFの作問に参加しました。

実際に4/25にCPCTFが開催され多くの人々が参加してくださいました!非常に感謝です!

僕は全部で14問の問題を出題しました。以下で僕が作った問題を取り上げてコメントしていこうかと思います。

write upとは書いて有りますが、解法はCTFページのヒント3まで開ければ見えるので簡単にしかしません・・・ ヒント3まで見た人への想定の解法や、問題コメントがほとんどだと思ってください・・・

nambatsu作問題

以下の問題を作問いたしました。

Newbie/Do you know Julius Caesar ? (正解者:65 ヒントなし:58 ヒントあり:7)

この問題は言わずもがなの問題でした。Cryptoの勉強を始めるときに一番最初に知るであろう古典暗号のシーザー暗号ですね。Cryptoの初心者向けといったらこれだろう、といった気持ちで作りました。

ちなみにFLAGのAlea jacta estはJulius Caesarの名言で、和訳すると賽は投げられたという意味になります。

Newbie/EasyRSA1 (正解者:43 ヒントなし:24 ヒントあり:19)

この問題は初心者には難しかったかもしれないです・・・ CryptoジャンルでよくあるRSA暗号の超入門という感じで作りました。ただRSA暗号の仕組みが初見だと難しいだろうなと思っていました。オイラーのトーシェント関数や、eの逆元がdになるとか数学的知識を少し必要となるので・・・
ですが、n e cをできるだけ小さくすることで手計算でも計算できるくらいのRSAを作ったので解けてくれーと思っていたら、意外にも解けている人が多くて安心しました。

RSA暗号は基本手計算なんかしないんですけども、ツールとか知らないという人でも解けるというのを意識して作問しました。ちなみにこの問題は数字を変えてCPCTF2019でも出題していました。

Newbie/Number to String (正解者:57 ヒントなし:33 ヒントあり:24)

これはLong to bytesの問題です。Cryptoを勉強している人やRSA暗号を解いたことがある人にとってはあったりまえじゃないかというような問題です。しかし、初心者に「RSAって数字を計算しているのに何で文章が暗号化されるんだろう・・・」という疑問が生まれるんじゃないだろうかというのを、僕が(勝手に)想定したためにできた問題です。

文字列を数値化することでRSA暗号の計算ができるようになるというわけですね。

Newbie/EasyRSA2 (正解者:32 ヒントなし:20 ヒントあり:12)

この問題はEasyRSA1とNumber to Stringの続きというか合わせた感じの問題ですね。これもEasyRSA1が難しいかなあと思っていたから、更に正答率下がるかなあと思ったら案の定って感じでした。ただCrypto問のレベル1に入れるにはあまりにもレベルが低いのでNewbieに置いたといった感じです。

一応Newbieということで、素数の一つは13という小さ目なものを選んだので素因数分解は簡単にできると思います。しかしこの辺になるとツールやスクリプトを書かないと計算が厳しいです。

Crypto/Encrypt code 200(正解者:52 ヒントなし:50 ヒント1:0 ヒント2:0 ヒント3:2)

この問題の解法はヒントを全部見てあげるとすぐにわかります。一応フラグの形式がFLAGから始まることを使って既知平文攻撃ができます。ただ、pとqの組み合わせが高々250通りしかないので総当たりでも解けます。

以下に想定解法のpythonコードを載せます。ここではp=24,q=8がわかったという前提でのコードです。

#decrypt.py

def _de(c, p):
    if 'A' <= c and c <= 'Z':
        return chr((ord(c) - ord('A') - p) % 26 + ord('A'))

    if 'a' <= c and c <= 'z':
        return chr((ord(c) - ord('a') - p) % 26 + ord('a'))

    return c

def de(s):
    p = 24
    q = 8
    flag = ''
    for c in s:
        flag += _de(c, p)
        p += q
    return flag

def main():
    c = "DROC{DupNgM_HMz_ew_XkpX1kK1z_PS_lGKv}"
    print(de(c))

if __name__ == '__main__':
    main()

これによりFLAG{RanDoM_ROt_is_DifF1cU1t_TO_rEAd}が得られます。

この問題はCrypto問にありがちな、プログラムのコードを読んで暗号を解く問題で、初心者でも解けるくらい簡単なやつを作ろうと思って作りました。難易度を1か2にするか悩んだのですがPPCジャンルの難易度1よりも複雑なことをしてるなあと思って難易度を2にしました。でも本当にこんなに解かれたのはとても意外です・・・ なんだかんだでNewbieのRSAより解かれているし、Newbieでよかったかなあ・・・

Crypto/RSA Power 200(正解者:22 ヒントなし:18 ヒント1:1 ヒント2:3 ヒント3:0)

この問題は問題名通り、ごり押し素因数分解をするという問題です。高々78桁の数字は5分もあればツールで素因数分解できます。素因数分解するツールは何でもいいのですがヒントではmsieveを勧めています。

しかしこの問題には別解が存在していて、factordbという素因数分解の結果をまとめているサイトにに素因数分解の結果が載っています! (http://factordb.com/index.php?query=416038843466729568664457170884180706836080953065458775761738081921119943105627)
なのでfactordbを使えばマシンパワーを使わずとも労力0で素因数が手に入ったわけですね・・・

この問題の製作途中でwebshellで素因数分解されるとやばいということに気づいて問題文面で禁止というのを追加しました。

Crypto/Nooooooo ! 300(正解者:6 ヒントなし:4 ヒント1:0 ヒント2:0 ヒント3:2)

この問題はおそらく今大会で一番コスパ悪い問題じゃないかなあと思っています。QRコードは、言うても白黒パターンだから人の手でも読めるよねということを伝えたかった問題です。ただめちゃくちゃめんどくさい・・・ できるだけ手間を減らすためにFLAGを無理やり短くしました・・・ QRコードを人力で読むのはこの辺のサイトが参考になります。

手間がかかりすぎるので本当は400点問題にするつもりだったのですが、strong-qr-decoderの存在のせい?で300点問題に下げました。strong-qr-decoderを使うと一瞬で読まれてしまいます。以下にstrong-qr-decoderの出力結果を記します。

$ ./sqrd.py -v 1-a.txt
型番:   1 (21 x 21)

[ OK ] 位置検出パターン
[ OK ] 分離パターン
[ OK ] タイミングパターン
[ OK ] 位置合わせパターン

[ OK ] 常暗モジュール
形式情報(横):                   110100101110110
形式情報(縦):                   1???????1??????
[ OK ] 縦横の形式情報の整合性
形式情報(合成):         110100101110110
形式情報(マスク解除):   011110101100100
[ OK ] 誤り訂正
形式情報(誤り訂正後):   011110101100100

誤り訂正レベル: 01      (L)
マスクパターン: 7       [ ((x * y) mod 3 + (x + y) mod 2) mod 2 = 0 ]

総コード語数: 26
データブロック: ['01000000', '11010101', '10010011', '00000111', '01010110', '00110100', '00010110', '11100111', '00100110', '01010011', '01000110', '01000110', '00010101', '00010111', '00100000', '1110????', '????????', '????????', '????????', '????0010', '01111?1?', '1?0?0010', '??00?1?0', '01??????', '??????01', '10??????']
RSブロック数:   1
RSブロック分割後:
['10??????', '??????01', '01??????', '??00?1?0', '1?0?0010', '01111?1?', '????0010', '????????', '????????', '????????', '1110????', '00100000', '00010111', '00010101', '01000110', '01000110', '01010011', '00100110', '11100111', '00010110', '00110100', '01010110', '00000111', '10010011', '11010101', '01000000']
各RSブロック中の不明データコード数: [11]

(最大)誤り訂正数: 2

RSブロック 0
不明モジュールを含むブロック数が(最大)誤り訂正数を超えています

最終的なデータバイト列: ['0x40', '0xd5', '0x93', '0x7', '0x56', '0x34', '0x16', '0xe7', '0x26', '0x53', '0x46', '0x46', '0x15', '0x17', '0x20', '0xe0', '0x0', '0x0', '0x0'] (19バイト)
最終的なデータビット列: 01000000110101011001001100000111010101100011010000010110111001110010011001010011010001100100011000010101000101110010000011100000000000000000000000000000

モード指示子:   0100 (8ビットバイト)
文字数: 13
デコードされたデータ: ['0x59', '0x30', '0x75', '0x63', '0x41', '0x6e', '0x72', '0x65', '0x34', '0x64', '0x61', '0x51', '0x72']
残りのビット列: 000011100000000000000000000000000000
デコード済み文字列: Y0ucAnre4daQr

モード指示子:   0000 (終端パターン)

Y0ucAnre4daQr

1-a.txtは以下のような感じです。

?????????????????????
?????????????????????
?????????????????????
?????????????????????
?????????????????????
1????????????????0001
11111110??????1111111
000000001??1100000000
11010011???0001110110
00111101???1000111001
??????10???0101100111
??????011100111111001
?????????000110011000
0????????010110000010
11???????100100110110
10000?????10000110000
10111?????10110110000
101???????11001110011
1?????????11101111001
1????????110010010000
11????101001101011110

すっご~い! ただQRをテキストファイルにするのも意外と大変です・・・

Forensics/Ramen ! 100(正解者:69 ヒントなし:54 ヒント1:15 ヒント2:0 ヒント3:0)

こんなに解かれるとは・・・ 今大会で3番目に解かれた問題です・・・ 想定解は画像のexif情報にGPS情報が載っているのでそこからGooglemapで検索しましょうという問題でした。
----------2021-04-28-022645

ただ、ラーメンの画像がはっきり写っているので、そのまま画像検索をするとお店の名前が出てきます。つまりOSINT問みたいな解き方もできた問題でした・・・ でもこのラーメン屋は複数店舗を出しているお店なので、どの店舗かは特定できないのではないでしょうか? なのでおそらく検索で解いた人はいろんな電話番号をFLAGとして提出したんじゃないかなと思っています。

余談ですがここのラーメン屋さんめちゃくちゃおいしいので、ぜひ食べに行ってみてください!

Forensics/Animation 300(正解者:23 ヒントなし:17 ヒント1:2 ヒント2:2 ヒント3:2)

この問題はもともと一枚のFLAGが載った画像を2ピクセルずつに切断してそれをgifアニメーションにしたよっていう問題です。なのでこれと逆の操作をしてあげると元に戻ります。ImageMagicを使うとすぐにできます。以下に結合したあとの画像を載せます。flag

ImageMagicを使う問題を作りたいなーと思って作りました。

Forensics/Uhhhh, what's this ? 300(正解者:13 ヒントなし:9 ヒント1:0 ヒント2:0 ヒント3:4)

この問題は一昨年にtraPのCTF班が行ったForensics講習会で使用した問題を改変したものです。なのでその時の僕の講習会を受けてた人は余裕で解けたに違いありません。

実際にはfileコマンド便利だよねってことを伝えたい問題です。まずファイルをダウンロードすると拡張子のついていないunknownというファイルが手に入ります。これはfileコマンドを使って調べるとgzファイルだということがわかります。なのでgzファイルを解凍するとtarファイルが出てきます。そしたらまたtarファイルを解凍しましょう。するとgzファイルが手に入ります。そしたらまたgzファイルを展開しましょう。するとzipファイルが手に入ります。そしたらzipファイルを展開しましょう。するとテキストデータが出てきます。

テキストデータを中身をみてみるとアルファベットの大文字小文字数字+/の64種類の文字で表現されているデータがみられます。これはbase64という形式でエンコードされたデータです。なのでデコードすれば良いですね!デコードすると以下の画像が現れます。

banana

ここにはFLAGがないのでこの画像を解析していきましょう。binwalkというtoolを使えばzipファイルが中に埋め込まれているのがわかります。

binwalk -e a.png

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             PNG image, 800 x 595, 8-bit/color RGBA, non-interlaced
210           0xD2            Zlib compressed data, default compression
335030        0x51CB6         Zip archive data, encrypted at least v2.0 to extract, compressed size: 101, uncompressed size: 93, name: flag.txt
335291        0x51DBB         End of Zip archive, footer length: 22

ここから

binwalk -e a.png

としてもいいですし、unzipコマンドは先頭にpngのようなゴミデータがついていてもきれいに解凍してくれます。優秀ですね。

unzipコマンド叩くとpasswordを求められます。passwordは実は画像のexif情報に載っていました。

exiftool a.png 
ExifTool Version Number         : 12.16
File Name                       : a.png
Directory                       : .
File Size                       : 327 KiB
File Modification Date/Time     : 2021:04:28 16:44:51+09:00
File Access Date/Time           : 2021:04:28 16:48:01+09:00
File Inode Change Date/Time     : 2021:04:28 16:47:20+09:00
File Permissions                : rw-r--r--
File Type                       : PNG
File Type Extension             : png
MIME Type                       : image/png
Image Width                     : 800
Image Height                    : 595
Bit Depth                       : 8
Color Type                      : RGB with Alpha
Compression                     : Deflate/Inflate
Filter                          : Adaptive
Interlace                       : Noninterlaced
Significant Bits                : 8 8 8 8
Exif Byte Order                 : Little-endian (Intel, II)
Software                        : Google
Title                           : zip pass is P_GyD2]$X7lhHWkp
Warning                         : [minor] Trailer data after PNG IEND chunk
Image Size                      : 800x595
Megapixels                      : 0.476

Title部にzip pass is P_GyD2]$X7lhHWkpとありますので、これがパスワードということになります。

この問題は出てきたファイルが何かを判別して、そのあとそれぞれに対して処理していけばいいだけなので簡単めになっちゃったかなあ、と思っていたのですが300点問題でちょうどよかったですね。安心しました。

Misc/Cpctf3301 100(正解者:44 ヒントなし:26 ヒント1:6 ヒント2:0 ヒント3:12)

この問題は昔インターネット上で話題になった事柄についての問題です。想定解法はHello. We are looking for highly intelligent individuals. To find them, we have devised a test.を検索することで何の話なのかがわかるといった問題です。

ところで、Cicada3301は結局なんの組織だったんでしょうね・・・

Misc/Please wear a mask 100(正解者:11 ヒントなし:1 ヒント1:7 ヒント2:2 ヒント3:1)

この問題も昔よく使われていたCPマスクというモザイクのお話です。この問題はヒント1を開けて解く問題と言われてしまっていたのですが、ヒント無しで解けている人は本当に凄いと思います。

しかし、モザイク、マスク、コードとかで検索をかけると何とかたどり着けるんじゃないかと思います。実際昔の人たちはモザイクパターンをみてマスクの種類を特定してたとも聞きました(多分)・・・

CPマスクを外すツールはG-MASKとかを使うのがいいです。こんな感じできれいに外れます。
----------2021-04-29-031252-1

OSINT/Where was I ? 200(正解者:34 ヒントなし:13 ヒント1:1 ヒント2:8 ヒント3:12)

この問題は私なんばつがいた場所を当てるという、ネトスト問題です。Twitterでなんばつと検索をかけると複数アカウントが出てきますので、それぞれに対してfrom:{id} since:2020-08-13 until:2020-08-14とやると@na_X_niが一件の画像ツイートしていることがわかります。

なんばつ @na_X_ni

たのし
efrujqiueaacggu
https://twitter.com/na_X_ni/status/1293751959732670464?s=20

これはSOUND VOLTEXというゲームセンターのゲームなのですが、この画像をよく見ると左下に東京都ASO:VIVA!という文字が見えます。これは調べればわかるのですがこのゲーム機が置いてあるゲームセンターの名前を表しています。よってASO:VIVA!というゲームセンターを検索すれば日比谷線恵比寿駅の近くにあるのがわかります。

音楽ゲームは楽しい!

OSINT/Let's go to a Disco 300(正解者:24 ヒントなし:10 ヒント1:4 ヒント2:4 ヒント3:6)

この問題はCPCTFのCPちゃんのツイッターアカウントを見つけ、Discordの招待リンクを探し、flagのロールをもらい、CPちゃんのプロフィール画像を手に入れる問題です。

CPちゃんのtwitterアカウントはこちらです。CPちゃん

このツイッターアカウントのツイートを見ると、

あれ、Discordサーバーの招待リンクのツイート消えてる?間違って削除しちゃったかな・・・

とありますので前に一回ツイートしたと考えられます。なのでツイートを保存するサービスにないかどうかを見てみましょう。twilogを確認するとツイートが残っているのがわかります。

discord.gg/rV3rg7e99B がDiscordサーバー招待リンクです。このサーバーにはいったら権限昇格をしないとflagチャンネルに入れません。なのでRobotがツイートしているリアクションを選択して権限を昇格しましょう。、実はリアクションの正解は、CPちゃんがツイートしている絵文字と同じものを選ぶと正解でした。

flagチャンネルに入ると、

おめでとうございます! よくここまで来ました!
FLAGは、実は私のDiscordプロフィール画像に書いてあります!

とあります。CPちゃんのプロフィール画像を手に入れる必要があります。Chromeならば開発者ツールを開くことで元画像のURLを手に入れることができます。

----------2021-04-29-034248-2

そのまま飛ぶとめちゃくちゃ小さい画像が出てきて、解像度が悪いので何も読めません。なのでURLの最後のクエリを例えば?size=1024としてやると、大きい画像が出てきてはっきりフラグを読むことができます。
d4f24f59e4e18e29c66480c8d2cc9821

この問題は、Discordの画像ファイルの入手や、リアクションロールを使った問題を作りたいと思って作成したのですが、結果的にリアクションロールが蛇足感満載の問題になってしまいました・・・
次があるときはまた何か考えよう・・・

おわりに

いろいろと拙い部分もあった問題たちですが、みなさん解いてくださってありがとうございました! 僕が作った問題は全問題ヒントなしで一人以上解けたようでよかったです。また次の機会があればまた作問をしようと思います。

ほかの作問者のwrite up

CPCTF2021 作問者writeup by xxpoxx
CPCTF2021 作問者writeup by hukuda222
CPCTF2021 作問者writeup by zassou
CPCTF2021 作問者writeup by sappi_red

nambatsu icon
この記事を書いた人
nambatsu

こんにちは馬です

この記事をシェア

このエントリーをはてなブックマークに追加
共有

関連する記事

2021年8月12日
CPCTFを支えたWebshell
mazrean icon mazrean
2021年5月19日
CPCTF2021を実現させたスコアサーバー
xxpoxx icon xxpoxx 他
2021年5月16日
CPCTFを支えたインフラ
mazrean icon mazrean 他
2019年4月22日
アセンブリを読んでみよう【新歓ブログリレー2019 45日目】
eiya icon eiya
2025年12月21日
MacでもPwnしたい!
akimo icon akimo
2023年4月29日
CPCTF2023 PPC作問陣 Writeup
noya2 icon noya2 他
記事一覧 タグ一覧 Google アナリティクスについて 特定商取引法に基づく表記