zenet_logo

-株式会社ゼネット技術ブログ-

SECCON 2017 Online CTFに参加しました(Write-up)

こんにちは。システム事業部の松永です。
12/9~10にかけてSECCON Online CTF 2017が行われましたね。
弊社でも有志が集まって(会社としては)初参加してみました。

f:id:zenet-tech:20171212113042j:plain
(弊社会議室でSECCONの壁に苦戦している様子)

結果は300点で580位と散々でしたが、初参加を記念して恥ずかしながらもWrite-upを書いてみたいと思います。

Run me!(Programming 100)

(この問題は私ではなく、参加した社員の一人が解いてくれましたのでWrite-upも書いてもらってます。)

入社4年目大柳です。
この問題はフィボナッチ数列に関する問題で、フィボナッチ数列とは1つ前の項と2つ前の項を足していく数列です。
最初に問題のプログラムを見たときは、どんな処理を行っているのかパッとは分かりませんでした…。
しかし、他の社員がフィボナッチ数列だと手計算で解明してくれたので、すぐさまフィボナッチ数列再帰処理を使わないで求める方法を検索しました。

再帰呼び出しを用いないフィボナッチ数列の計算 - Qiita

世の中にはすごい人たちがたくさんいるものですね…すぐに出てきました(笑)

フィボナッチ数列の第n項を求めます
nをいくつにしますか? : 11011
フィボナッチ数列の第11011項の数は650761408323317176677727615418728824035834139276098998490249192132666758545760517800054917034155243927170284032856159641073239445267259027201529090078896791094491606651280986273375358475762477790432186275595009347181655230560612893072010176744437899125794062096822499169737341076562268978822309439778493884517811269755645677051823939101818750862488649336629337157213652909313926271909722579127327516034001078889493903847162940951919936666981110589496109534874704781719109928400031417346568159901873387957504386076864598280589140560720555215586103334108606666557885182543411057646507987554088958465040914897691939542285281414546306123632401776970176802858533764858159120251846344138169520194579452006975065591700295752709436626337896977143749517364692359205470520308998499747373023079909096931930849470838600436193492730120598058390332468715098569506803288748815104425904241644846838395455904535450056833234799685571736399955768131656445051569947468596781842534517197721000873495062895837282533156293369623617362342118583768869069357254102738089664559884034222599617271201387495056590015984399482556187470258510628428546129648977633092532344658489593547730850249245718744514953339799649429008307017831938762015220771469692523759803441301822573457181350382636976785308875676049259482221646051841764952498511738390807032009076345712915067307334601511409483180854512241289677598260345859220604188459466566218428522712526307485414327912984814200699366287893779866533195964875622418194229718474283906639970274067803465246049255487228512317014925146357266424154230175016287402954010234339299976926358623916935423402962510413409907048690682619724213875769975891654986212343055742766929242325603302953851160284942626779251037312496874310855130377517889541404945838665610608950717555040757378177019719117615549280661866187332498803134726445107694994290546795927294081948416543673731399120512192375688817905543314233147723782998209741461558386215456190659067634677870007289790910629423072714321397319111715970130151174669992797276293445539760861617336440030158167771970869191088140343413881822920781894388333124029339099939263144538805634147654202831717365638267529461536461367917300661565377015525846611173849663494461429041123993952629470445363197932541803303152120627201578910609457626560492171665716942761589です

長いですね…再帰処理を使った問題のプログラムでは時間がかかり過ぎて帰ってこないはずです。
で、問題ではこの結果の先頭32桁なので、

Ans. SECCON{650761408323317176677727615418728}

SHA-1 is dead(Crypto 100)

今年の2月ごろにGoogleが発表した*1SHA-1の衝突攻撃に関する問題ですね。
SHA-1ハッシュ値が同じである、2つの異なるファイルをアップロードすれば良さそうです。
実際に衝突に使われたPDFはこちらのサイトにあったので、これをそのまま使おうとしたもののファイルサイズは「2017KiB < file1, file2 < 2018KiB」という縛りがあったのでそのままは使えず…(当たり前ですが)

こちらの解説されているサイトを見ると、

先頭320バイトの部分で衝突が起きていてそれ以降が同じ値ならずっと衝突し続ける

とあるので、前述のPDFファイルを力技で以下のように加工してみました。

# ファイル1を2018Kib超えるまで結合
File.open("shattered-1.pdf", "r+b") {|s1| File.open("file1", "w+b"){|f1| f1.write(s1.read) } }
File.open("shattered-1.pdf", "r+b") {|s1| File.open("file1", "w+b"){|f1| f1.write(s1.read) } }
File.open("shattered-1.pdf", "r+b") {|s1| File.open("file1", "w+b"){|f1| f1.write(s1.read) } }
File.open("shattered-1.pdf", "r+b") {|s1| File.open("file1", "w+b"){|f1| f1.write(s1.read) } }
File.open("shattered-1.pdf", "r+b") {|s1| File.open("file1", "w+b"){|f1| f1.write(s1.read) } }

# ファイル2を2018Kib超えるまで結合(最初のファイルのみ1と異なるもの)
File.open("shattered-2.pdf", "r+b") {|s2| File.open("file2", "w+b"){|f2| f2.write(s2.read) } }
File.open("shattered-1.pdf", "r+b") {|s1| File.open("file2", "w+b"){|f2| f2.write(s1.read) } }
File.open("shattered-1.pdf", "r+b") {|s1| File.open("file2", "w+b"){|f2| f2.write(s1.read) } }
File.open("shattered-1.pdf", "r+b") {|s1| File.open("file2", "w+b"){|f2| f2.write(s1.read) } }
File.open("shattered-1.pdf", "r+b") {|s1| File.open("file2", "w+b"){|f2| f2.write(s1.read) } }

# 2017KiB < file1, file2 < 2018KiBに加工
File.truncate("file1", (2018*1024-100))
File.truncate("file2", (2018*1024-100))

Ans. SECCON{SHA-1_1995-2017?}

Thank you for playing!

ボーナス問題ですね。
Write-upに載せるのは心苦しいですが、貴重な得点ですので一応。

Ans. SECCON{We have done all the challenges. Enjoy last 12 hours. Thank you!}

参加してみて

やはりSECCONの壁は高かったです...
ですが、古典的な問題から最新の動向まで幅広く出題されるのでとても刺激的で楽しめました。

来年3月にSECCON Beginners CTFが開催されるようなので、今度はそこにチャレンジしてみたいと思います!