duckが送るBeginnersCTF2019 BitFlip(Crypto)の解説 Not初心者向け
どうもduckです。最近は仕事とctfしかしてません。ブログタイトル「CTFと共に生きる」とかにしません?
今回はCryptoのラスボスBitFlipです。いろんな方のwriteupを読ませていただきましたが、使われている数学について解説しているwriteupはないんじゃないか?
私がやるしかないな!(需要?なにそれおいしいの?)
まずはもらったコードからこれを解析すると以下の操作が行われていることがわかります。
まず最初に思いつく方法はブルートフォースです。
が、美しくないうえ、サーバーから全てのReturnの情報を得なければならないので割愛します。
(ついでに言えば途中で運営側からBitFlipのサーバーにアクセスしすぎだよ自重しろというお達しもありました。つまりはブルートフォース以外の方法があるはず)
気になる方はこちらの方のWriteupを見るとよいです。
SECCON Beginners CTF 2019 - Qiita
さてここから数学のお話。
今回私の記事の中では
(ただし1番下位のbitを0bitとします)
(サーバーから返ってくる値)
として話を進めます。
となることにも注意しておきます。(Flipが0→1のときは+、1→0のときは-)
また、書くのが面倒なのでこれ以降と書くのをやめます。適宜置き換えてください。
まず、サーバーにアクセスして
となるをゲットしましょう。よほど運が悪くなければ2回でゲットできます。
もちろんこの段階ではどのビットが反転されたのかわかりませんのでn,mは不明です。
ーーーーー
目標は、平文が線形関係であるときに用いることができるFranklin-Reiter Related Message Attackを行うことです。
と表せるとき、
の暗号文と公開鍵がわかれば、平文を求められることを使います。
まあ後でもう少しだけ解説します。
ーーーーー
1.Coppersmith’s Short Pad Attackする
でありこれをとおきます。
そうすると
...①
...②
と表せます。
このsさえ求まればFranklin-Reiter Related Message Attackが使える形になります。
ここで
の多項式を考えます。(を未知数xに置き換えただけ)
の解はを含むことは明らかです。(つまり共通解をもつ)
この性質から、sを求めるのに終結式を使います。(終結式の定義については割愛します。終結式の定義といくつかの性質 | 高校数学の美しい物語)
終結式は共通解をもつ二つの多項式に対しては0になるという性質を持ちます。
つまりから終結式を計算して、それが0になることからsを求めます。
終結式の計算にはシルベスター行列の行列式を使います。(終結式の定義といくつかの性質 | 高校数学の美しい物語)
今回の場合は以下のようになります。
こっから先は手計算では無理だ。
アホなので手計算でシルベスターの行列式計算しました。
sの大きさに注意しつつプログラムに投げましょう。後でやります。(おい)Sagemathがpythonライクでおすすめだった気がします。
mathematicaとかフリーで使えたっけ?使えるならそっちでも。
sのサイズが大きすぎるため、このままプログラムに投げるにはとしていい値が来ないと計算無理です。
何回も問題サーバーにアクセスして解けるパターンを待ってもいいですが、今回はわかってる情報からsがある程度絞り込めるのでそれを利用します。
の形なのがわかっているので、これを使い回くらい終結式を計算すればよいことがわかります。
今回はmax(n)として250くらいを取りました。
このmax(n)は実験中にサーバーサクセスを繰り返してたときに推測した値です。
これでSagemathをつかわなくともsが求まります。
以下くそコード。
N = 82212154608576254900096226483113810717974464677637469172151624370076874445177909757467220517368961706061745548693538272183076941444005809369433342423449908965735182462388415108238954782902658438063972198394192220357503336925109727386083951661191494159560430569334665763264352163167121773914831172831824145331 e = 3 #max(n) nm = 250 C1 = 19668512534871703818804721058464184088540192186216654188589585883263154008964228350399514299852538811337835790238510703474647742023573370430287373841543674974547734434937124159068497046659147350241364684829208188803795307462087810637640642350674397153687260268727800582499681256385837706667398671154929189579 C2 = 44939803625275977251911534717835431979049524856461188120868461571121976859707514547338914366715426490130522458001402249990220314314873155256383447002643583335186960138112746521599509022925369612324695641201278318699732590955718931066187237603506202339345820308234883558809220466506231185260966657450242854347 #2べきを先にリストに格納 list2 = [] t = 1 ans = 0 i = 0 while i <= nm: list2.append(t) t = t * 2 t = t % N i += 1 #sを表示する def result(s,n,m,l): print(s,n,m,l) ans = s #ブルートフォース for n in range(nm): for m in range(nm)[n+1:nm]: #2^m + 2^n or 2^m - 2^n s = (list2[m] + list2[n]) % N if solve(s): result(s,n,m,0) elif solve(-s): result(s,n,m,1) #2^m - 2^n or 2^n - 2^m s = (list2[m] - list2[n]) % N if solve(s): result(s,n,m,2) elif solve(-s): result(s,n,m,3)
solve関数が消えていますが、うえで示した終結式に代入して、=ならTrue ,ならFalseを返すだけの関数です。
結果はこちら
383123885216472214589586756787577295904680382499389440 42 178 3
今回のケースでは
FLAGの42bit目が0→1反転したものと、178bit目が1→0反転したものであることがわかりました。
まあさえ知ってれば大体OKですが。
2.Franklin-Reiter Related Message Attackする
...①
...②
のsが1で求まったとします。
です。
この時はで求まります。(雑)
もうちょっとだけ解説を加えます。
は多項式版ユークリッドの互除法をして、最大公約多項式を求めろということです。
整数のユークリッドの互除法とおんなじです。そしたら答えがわかります。(雑)
例を挙げます。
の最大公約単項式を求めてみましょう。
頑張ってユークリッドの互除法をすると以下のようになります。
ということは
となっていることを意味します。
つまり共通因数がわかったってことだ!!
これ見たらの共通解はどう見ても1やんけ!ってなわけですね。
は共通解を持つことがわかっているので、は必ず1ではない多項式です。
ほとんどの場合で、それは1次多項式でありとなりますからがわかります。
(まれにが2次式以上になりますが、それを解いてを求めるのはかなりめんどくさいのでおとなしくの選択からやり直すのをおすすめします。)
実際にやってみた結果。(Sagemathを使いました。sympyだと整数環上でしかできなかったためあきらめた。)
PRx.<x> = PolynomialRing(Zmod(N)) g1 = x^e - c1 g2 = (x+s)^e - c2 while g2: g1, g2 = g2, g1 % g2 print(g1.monic())
結果。
つまり
bit反転させるのが筋ですが、もうめんどいのでこのまま復号します。
from Crypto.Util.number import bytes_to_long, getRandomInteger, getPrime,long_to_bytes N = 82212154608576254900096226483113810717974464677637469172151624370076874445177909757467220517368961706061745548693538272183076941444005809369433342423449908965735182462388415108238954782902658438063972198394192220357503336925109727386083951661191494159560430569334665763264352163167121773914831172831824145331 m = -82212154592315489750110187598968636841905821953623851870053845076997511568524415687534405445330110037385522700226033733612223434284079949332614038131717774815337863135195292470488899872185912270098336585556230191588353421626879687269516794206695695261382777258681677254870347368455087826235419500816586773161 m = m % N print(long_to_bytes(m))
ctf4b{b1tfl1pp1ng_1s_r3lated_m3ss4ge} DUMMYDUMMYDUMMYDUMMYDUMMYDUMMYDUMMYDUMMYDUMMYDUMMYDUMMYDUMMYDUMIYDUMMYDUMMYDUMMYDUMMY\n
反転さぼった影響で赤い部分の文字が変わってますね。(気になる人は178bit目を反転させましょう)まあもうFLAG出たしいいでしょう。
お疲れさまでした。
supereggが送るBeginners CTF 2019[warmup]Ramen(Web)の解説
どうもこんにちは、supereggです。今回がBeginnersCTF2019にWebの問題である「Ramen」の解説をしたいと思います。
まずは問題のサイトにアクセスします。
https://ramen.quals.beginners.seccon.jp/
めちゃめちゃ美味しそうですね。私はラーメンが大好きなので嬉しいです。
まず以下の入力フォームとそのしたの表に注目します
名前を検索できる入力フォームがあり、その下にラーメン屋の店員の名前と一言が書いてあります。
入力フォームがあるので、まずはSQLインジェクションが使えないかチェックみようと思います。
SQLインジェクションとは・・・アプリケーションのセキュリティ上の不備を意図的に利用し、アプリケーションが想定しないSQL文を実行させることにより、データベースシステムを不正に操作する攻撃方法のこと。 また、その攻撃を可能とする脆弱性のことである。(あ(引用:wikipedia)>>https://ja.wikipedia.org/wiki/SQL%E3%82%A4%E3%83%B3%E3%82%B8%E3%82%A7%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3>>
SQLインジェクションが使えるかどうか判断する方法として典型的なものとして「'(シングルクォーテーション)を1つ入力するとエラーメッセージが表示されるというものがあります。
何故判断できるのかを簡単に説明すると入力フォームで入力されてきた値は普通すべて、特殊な意味を持たない文字列として扱うようにしなければなりません。そのため、「'」などのメタキャラクタ(特殊な意味を持つ文字)はエスケープして「'」を特殊な意味を持たない文字列として扱うようにしなければなりません。(PHPの場合は\')もし「'」をエスケープしていなかった場合、入力フォームから入力されてきた値で予期しないSQL文が実行されることになるのです。
それでは実際に入力フォームに「'」を入れてみましょう。
次にSEARCHボタンをクリック」すると・・・
何やらエラー文が出てきました。index.phpの11行目のエラーだそうです。(本来ならリリースの段階では画面にエラー表示はさせないようになっているのが常識なのですがCTFではこのようにエラーが画面に表示するように設定している場合があるそうです。エラーメッセージが画面に表示しない設定の場合は、開発者ツールでHTTPステータスコードを確認すれば内部エラーが起きたかどうか判断できます。(エラーコードは500))
何故エラーになるのかというと、
SLECT * FROM users WHERE name=''';
となり、シングルクォーテーションが1つ余計になり、SQLのシンタックスエラーになり、それがPHP側で表示されます。
これでSQLインジェクションを使えばいいというのがほぼ確定になりました。
次にどのRDBMS(データベースソフトのこと)が使われているのか判別します。
代表的なRDBMSの中には「MySQL」、「PostgreSQL」、「SQLite」があります。
この3つの書式の違いでまずあるのがコメントアウトです。
- MySQL 「#」
- PostgreSQL 「--」
- SQLite 「--」
となります。
この3つなら「#」コメントをつけることが出来たらMySQLだと決めつけることができます。
早速判断するために試してみましょう。
なんとエラーが出ませんでした。MySQLが使われているということが分かりましたね。
エラーが出ない理由は以下のように最後の「'」が#でコメントアウトされているからです
''#'
これにより、好きなSQL文を実行できるようになります。なんと恐ろしい( ゚Д゚)
RDBMSではユーザが定義する領域の他に、そのデータ領域のメタ情報(テーブルやカラムの情報)を保持する領域が作られます。
MySQLの場合はINFORMATION_SCHEMAとして定義されていて、データベースの形態をとっていて、SQL文により中身の情報を取り出すことが可能です。
次の文字列を検索フォームに入力すると、データベース名とカラム名を表示させることができます。
'union select table_name, column_name from information_schema.columns#
入力してSEARCHボタンを押すと、データベースが結合されて、たくさん値が表示されますが、下の方までスクロールすると怪しげなデータベース名とカラム名が表示されています。
これによってflagというテーブルのfragというカラムに求めるものがあると考えられます。これでなかったら逆にヤバイですよね。
上のコードの意味は、information_schemaの中のculumnsテーブルの中のtable_nameとcolumn_nameとう名前(これはinformation_schemaの中で定義されている)のカラムを画面に表示されているデータベースのにunionを使って結合させています。そして内部プログラムは以下のようになっています。
select * from users where name='' union select table_name, column_name from information_schema.columns#'
このように「'」をエスケープしていなければSQL文を実行できます。今回はunionを使っていますが、ANDやORを使って好き勝手にSQLをぶっ放すことが出来ます。例えば
select * from users where name=''OR 1=1#'
ですべて真にしたり・・・
次に
'union select flag,"hello" from flag#
を入力すると("hello"の部分はデータベースを結合させるときにカラムの数合わせにてきとうに入れた値なのでなんでもいいです)
すると・・・
イエーーーーーーーーーーーイ!!!!!!!!!!!
duckが送るBeginners CTF 2019 Go RSA(Crypto)の解説
どうもduckです。今日はGo RSAについて書くよ。
名前から見てわかる通り、公開鍵暗号の1種であるRSA暗号がわからないと解けない。
公開鍵暗号については↓を見るかググって。
公開鍵暗号方式とは?初心者でもわかる公開鍵暗号方…|Udemy メディア
まずはざっくりRSAについて数式部分を書くよ。アタックするからには理解しておきたい。
平文を,暗号文を,公開鍵,秘密鍵とする。
具体的なアルゴリズムの流れを見よう。
(1)受信側:(十分大きな素数)を選びとする。(任意)
(2)受信側:を計算する。(はオイラーのトーシェント関数と呼ばれ、定義があるが今はこの形のみ知っていれば十分)
(3)受信側:と互いに素な整数をもってくる。(任意)
(4)受信側:となるを求める。(拡張ユークリッドの互除法を用いる)
(5)受信側:公開鍵を公開。
(6)送信側:と暗号文を作成し、送り付ける。
(7)受信側:で復号でき平文をゲットできる。
通常RSAへのアタックは秘密鍵dを求め、暗号文を解読することが考えられる。
正しく運用されていれば安全であるが、以下のサイト(おすすめ)に挙げられるようなパラメータの設定ミスをすると解読されうる。
CTFではそう言った問題がでるのだろうか?(ちなみにCryptoのBitFlipではその中の脆弱性を突く問題が出た)
さて、では実際に問題を見よう。
Server: nc 133.242.17.175 1337と問題文に書かれている。
Linuxのnc(ネットキャット?)コマンドで接続しよう。
まずEncypted flag is~と書いてあるから、これを複合すればよいことがわかる。問題文でNを忘れたといっていたからNがわかれば解けそうと思っておく。
次に最後の行を見よう。The D was~と書いてある。おそらくこれが秘密鍵だろう。
真ん中部分はユーザー入力である。こちらが入れた数字に対し、謎の数字が返ってくるようだ。
Encyptedflag,D,ユーザー入力により返ってくる値は再接続のたびに変わるようだ。
つまり我々は、3回までのユーザー入力からヒントを得てNを計算すればよいのだろう。
頑張ろう。
ユーザー入力が何を返しているのかがよくわからないのでまずは実験してみる。
その結果、
(a)いつでも1に対しては1が返ってくる。
(b)同じ接続の中で同じ数字を入れると同じ値が返ってくる。
(c)1を除いた入力に対して、大体同じ桁数の値が返ってくる。
などの特徴があることが分かった。
(b)から乱数などは使われていなそうだし,(a)から何かのべき乗計算をしているのではないかと推測できる。
また(c)からmodを取っているのではという推測もたつ。
これらの推測と上で説明したRSAの式たちを見比べると
とかか?と勘繰る。
つまり
が返ってきてそうである。
この仮定の下でNを求めに行こう。
我々が入手できるのは以下の3本の式をみたすinput,rの組である。
input1,2,3:ユーザー入力、r1,r2,r3:サーバーから返ってくる値
inputを操作してNを顕現させたい。
こういう任意で入力できる問題は大体小さい数字をinputとするとか、2のべきをinputとするとかだとうまくいくことが多い。
またmodで悩んだときはを使った形に直すとうまくいくことも多い。(特に数学よくわからないという人にお勧めする)
なんともひどい誘導だが以下のようにすればNが求まる。
inputとして2,3を与える。
これは適当な整数を用いて
と書ける。を移項すると
となる。お分かりだろうか?これでNが求まるのだと。我々は勝利したのだと。
公約数を思い出してほしい。
との約数に明らかにNがある!やったぜ。
追記:
書き忘れていましたが、RSAでは一般的にが用いられることが一般的です。
それを使いましょう。
最大公約数はユークリッドの互除法というアルゴリズムで高速に求まる。
わからない人は学習指導要領が改定されて高校生でも知ってるからなんとか学んで。
一つだけ注意しておくと、場合によってはNの整数倍が出てきてしまうことだ。
具体的にはとが互いに素ではない場合である。
でてきたN で
をしてもうまくFLAGが出ないときは、違うペアで試してみるとよい。
まあ私もまだやってないんだけどな!!
おつかれさま!また明日!!!!!
追記:いままでずっとFLAG書くの忘れてた。この回のだけ残ってたので貼っておく。
ctf4b{f1nd_7he_p4ramet3rs}
コード
from Crypto.Util.number import long_to_bytes import math c=17085620552658351183335544500690226272875422158935145341165358891244918062440861767294934344129747923141668732715787177751203261627026230386846774546801758980449060209320668104704097944761232115359564279944744011306082649286738268431655969673959744882964166437946605686952999392726525064814877455046451725768410312677212123398538560508582810195854081569284454616942253143100785505524167586197713206797113052644900411469422688939261982981855377987421758621965591995651651907064794890066406751092949615529766196252331712555809200696136040227513088824530815886117265362591775970066168663851386432407675346081685681927303 r1=12308943287801278381602271020636811688003973209453971581897097872964067773128210282456593395262732270249597048332555708886509308319520920180598650511766799712167512259642431520797141790111692065487078128961600689554367757339155513577144978675218793446249701301839641500569661759646423276187542173318171335382960662774233945196912603079740368273195927210668950566249353140103271649493388077952820446391920593020564832067217333892843371485574515498385351718470670460084994536203053240439442202272531830723505883179658297522435407455008248311187789781960113589834827112974168260506676775743411648452439899496100115579052 r2=2266282824131486468448037400097649751436638343554890873042053537566051913016220134485956663087061113434331598112257987671237397919781153037511303664236178026024200716300256313054976795440759304679065940565652927875017851134819722783392228160931697899128129053901710489789174445944014043443083527638965765809070488225452982880922703011627801716957978130236512493237537609220292483693697781504935020101279551815050569381943159352285456791072657310654958418397051221153029472723065900747600963890428868830367126410421411370704517816919980344041449903545200031548407512798483005492350803089508282331827149736642020562720 d=1814452580735375349943862720618828918630139915423974587850653785462197560999774344107135368454555043491667375552314392616309506004814918478288708383302285286685970221339255810252747773103059121031264059575772453212207545840235008436247634620933941004726742219846507737410336486611203816257479343986488367114011777255284708000213494879044090517505540067938866432994071508106192379566964836729181005004378702445684759533988544066532056379172318125748705772688436663116204079306930926328994293354010739696046248305808409576809006078527713033315527061213274532299699148742370572758989921371532108833619290755313406817153 e=65537 N = math.gcd(r1-pow(2,e),r2-pow(3,e)) m = pow(c,d,N) print(long_to_bytes(m))
duckが送るBeginners CTF 2019 Party(Crypto)の解説
どうもduckです。唯一自力で解いたPartyについて解説したい。
さて、問題をDLしたらparty.tar.gzというファイルだったので、
tar -zxvf party.tar.gzコマンドで解凍する。
tarはLinuxの標準的な圧縮形式で、windowsでいうzipみたいなファイルらしい(よくわからん)。
解凍するとencrypt.pyというファイルとencryptedというファイルが出てきた。
encryptedをcatするとなんか数字がめちゃくちゃ出てくる。
encrypt.pyを読めば意味がわかるはず。
さて、ここからは大きく二つのフェイズに分けて説明しようと思う。
1.pythonファイルの解析。これによりflagを得るためにやるべきことがわかる。
2.実際にflagをゲットしてみる。(3元1次連立方程式を解くことになるんだけれどね)
頑張っていこう。
1.pythonを読む
python party
1,2行目:モジュールのimportだ。Cでいうインクルードだ。
5~9行目:関数の定義だ。関数が呼ばれた時に見ればいい。
12,13行目:変数の定義。放っておこう。
14行目からコードをしっかり見ていくことになる。
が、先に15行目について一言触れておく。assert文と呼ばれるもので、普通デバッグのときに使われる。(はず)
assert(条件式)のように書き、条件式がFalseのときにのみ処理を停止させる。
今の例だとを満たせば動くが、それ以外はプログラムが落ちる。
(一応補足。pythonではa**bでをあらわす。)
気になる方は試すべし。この先の説明では無視する。
14行目:
secret = bytes_to_long(FLAG)
2行目でimportしたCrypto.Util.numberの関数bytes_to_longを使っている。
Crypto.Util.numberを詳しく調べたわけではないが、FLAGの文字列を数字列に直してsecretに代入しているのだろう。
ちなみに数字列を文字列に直すのにはlong_to_bytesを使えばいけた。単純。
つまりsecretという数字列が求まれば
FLAG = bytes_to_long(secret)
でFLAGが求まる。
17行目:
coeff = [secret] + [getRandomInteger(N) for i in range(M-1)]
[]はpythonではリストを表す。
リストの結合は+でかける。
[2,3] + [1,1,2,4] #[2,3,1,1,2,4]
例はこんな感じ。
次に
[getRandomInteger(N) for i in range(M-1)]
がわからない方。python内包表記で調べると幸せになれる。
超簡単な例↓
リスト内包表記の活用と悪用 - Qiita
結局こうなる。
coeff = [secret,getRandomInteger(N) ,getRandomInteger(N) ]
getRandomIntegerも2行目でimportしたCrypto.Util.numberの関数。
Nまでの乱整数を取ってくるのだろう。(調べてないけど)
長い変数はうざったいので短い名前にする。getRandomIntegerは毎回結果が異なることに注意。
coeff = [s,r1,r2 ]
18行目:
party = [getRandomInteger(N) for i in range(M)]
つまり
party = [getRandomInteger(N),getRandomInteger(N),getRandomInteger(N)]
というリスト。
だるいので短い名前にする。
party = [p1,p2,p3]
20行目:
val = map(lambda x: f(x, coeff), party)
無名関数(lambdaのこと)とかmapについて説明するのは面倒になので、わからない方は
Python2,3での比較!map関数を使う方法【初心者向け】 | TechAcademyマガジン
ここら辺を参照いただきたく。
結局valはこうなる。
val = [f(party[0],coeff),f(party[1],coeff),f(party[2],coeff)]
やっと関数fが出てきたので5行目に戻ろう
5行目:
def f(x, coeff): y = 0 for i in range(len(coeff)): y += coeff[i] * pow(x, i) return y
len(list)はlistの長さを返す関数で、
pow(a,b)はを表す関数である。
よってf(x,coeff)は今、len(coeff)=3だったことに注意すると
を表す。
coeff = [s,r1,r2 ] party = [p1,p2,p3]
としていたから、結局
であり
val = [s+ r1 * p1 + r2 * (p1 ** 2),s+ r1 * p2+ r2 * (p2 ** 2),s+ r1 * p3 + r2 * (p3**2)]
である。
長いので
val = [v1,v2,v3]
としておく。
21行目:
output = list(zip(party, val))
これがencryptedの中身である(続く22行目でoutputで出力されているから)。結局encryptedにはpartyとvalが格納されていることが分かった。
つまりp1,p2,p3,v1,v2,v3が与えられたということだ。
partyとvalからsecret(=sとおいていた)を復元しよう。
val = [s+ r1 * p1 + r2 * (p1 ** 2),s+ r1 * p2+ r2 * (p2 ** 2),s+ r1 * p3 + r2 * (p3**2)]
なのだから
となる。
v1,v2,v3,p1,p2,p3はencryptedに書いてある。残りはs(secret),r1,r2だけだ。
未知数3個。式3つ。中学生でも解ける連立方程式だ。
2.flagをゲットする
詰まったところだけ書く。
・numpy(数学ライブラリ、有名)をつかって解いてみる
v1,v2,v3,p1,p2,p3が大きすぎて解けない。おそらく中でCコードが動いてるからかと予想。
・自力で解く
連立方程式を解くと以下のようになる。
それをpythonに(四則演算のみ、もはや電卓として使う)解かせる。コードを書くのはsupereggに任せる。
python慣れも兼ねて頑張って。
python2だと問題なくとけるが、python3の場合は
Python3の割り算は切り捨てではない - Qiita
のため解けない。
計算途中で小数に変換されることによる誤差のせい。
/じゃなく//を使えば3でも解ける。r2をわざわざ通分した表示にしているのもそのためである。
出てきた答えを
FLAG = bytes_to_long(s)
とすればFLAGが求まる。
supereggが送るBeginners CTF 2019 [warmup]So Tired(Crypto)の解説
まずダウンロードしてきた「7e9eb0636de2cad98b1eee3b667aea6c_so_tired.tar.gz」
をtar -xzvfコマンドで解凍するとencrypted.txtがゲットできます。
ますfileコマンドでチェックすると
拡張子が.txtであることから、catコマンドで中身を見てみることにしましょう。
文字が多くてきもいです。ここで最後に注目します。
==とあることからBase64でエンコードされたものと予想できます。
(Base64変換では4文字ずつ変換していき、4文字に満たない分は=記号を追加して4文字にする仕様があります)
base64でデコードを行います。$ base64 encrypted.txt -d > result.txt(-dでデコード)
catコマンドで中身を見てみます。
何なんだこれは!?(頭が痛い・・・(>_<))
よくわからないので取り合えずfileコマンドを使って見ましょう。
なにやらzlibによって圧縮されてるようです。
zlib・・・データの圧縮および伸張を行うためのフリーのライブラリ
ちなみに、今はKali Linuxを使っているが、centos環境でfileコマンドで見てみると次のように表示された。
なんと、zlibの文字がどこにも見えない・・・ なぜ???
チームメンバーのduckはこれに悩まされていた。かわいそうに(´;ω;`)
次にzlib(ライブラリ)を使って圧縮されているファイルを伸張することを考える。
このプログラムを実行するとresult2.txtにencrypted.txtの中身がbase64デコードされたものをzlibで伸張された文字列がresult2に格納される。
さっそくcatコマンドで中身を見てみよう。
何やらまたbase64エンコードされたような文字列が出てきた。
ここで、もしかして問題ファイルのencrypted.txtの中身は何度もbase64エンコードとzlibで圧縮されているのではと予想できます。つまり、エンコードされていない元の文字列がFlagなのではないか・・・・・・・(^▽^)/。
よって次のプログラムを実行してみる。
デコードできなくなったときにエラーを発することを利用する。つまり、上の図のコードの場合だとエラーがでたときのdataの中身をresult2.txtに書き込むようにしている。
このプログラムを実行した後にresult2.txtを見てみると・・・
Flagゲットだぜーーーーーーーーーーーーーーーーー
チームfalcon 初陣!SECCON Beginners CTF2019 71位!!
チーム falconのduckです。
昨日、今日はSECCON Beginners CTF2019 の開催日でしたね。
我々チーム falconも健闘してまいりました。
初参加ながらも、666チーム中71位でした。何とも言えない。
Write up は後程書くこととしまして、メンバー紹介させていただきます。
1.superegg(score 0)
今回は0点だったが何かの間違いだ。孵化すればこっちのもんだ。楽しみにしておけ。
2.duck(score 324)
たのしかった。
3.phoenix(score 909)
チームfalconの救世主
4.secret()
ここから伝説は始まる!!!!!!!!