PakenCTF writeup
こんにちは!Ken.Sです!
先程まで行われてたPakenCTFのwriteupです!楽しいCTFでした!
今回は初心者用でしたので、m1z0r3では参加せず個人で参加しました。しかしそのm1z0r3にボコボコにされました(笑)
結果
解説
pwn
store 100pt
問題文:
「以下のコマンドからサーバープログラムに接続して、FLAGを入手して下さい。
nc 3.131.69.179 17693」
そして、store.cと実行ファイルstoreが与えられます。
store.cを見ると、所持金998244353円の状態から100円のリンゴをいくつか買ってください。その後の所持金が1000000007円以上だったらflagが出ますというもの。
現実世界だとあり得ませんが、このプログラムではint型で定義されているのでオーバーフローを起こせばいいのです。手元でリンゴをいくつ買うとオーバーフローが起きるかというプログラムを組めば、あとはそれをサーバーに送ればOKです。
pakenCTF{6ef1ne_Int_l0n9_l0ng}
forensics
amazing sound 100pt
amazing_sound.mp3 が与えられます。linux上でstringsとかやってみましたが一切分からず。聞けばいいのかと思ったが何言ってるか分からず。問題名から何かすごい音なのかな、逆再生とかできんのかなと思ったらまさかのビンゴ!
逆再生した音声は英語で数字を言っているものでした。数字と言っても1~9だけなのでなんとか聞き取れました。
pakenCTF{3426543712456783}
web
F12
問題文、ファイルなどは一切無いのでとりあえずF12キーを押します。そうしたらElementにflagがありました。
pakenCTF{deve10per_t0015}
unreadable2
u.js が与えられます。中を見ると、_0x*****という変数に文字が代入されています。Javascriptはあまり分からないのですが、CTF{}の文字があったのでおそらくflagをバラバラにしているだけと見たので、中身をコピってpythonで解きました。
pakenCTF{h0w_d0_yOu_re4d_th1s_text}
misc
Hello World 10pt
問題文:以下の提出フォームに pakenCTF{HelloWorld} と入力して提出して下さい。
終了!!
pakenCTF{HelloWorld}
kangaetenai 150pt
問題文:
「以下の文字列の偶数文字目を取り出して、pakenCTF{}で囲ったものを提出して下さい。
厳密に偶数文字目である事に気をつけて下さい。
theanswerisrandomstring」
簡単じゃんと思ったのですが、トラップが仕掛けてありました。pythonで偶数文字目だけ取ろうとしたらこんな表記になりました。
the ans w eri sra n domst rin g
よく見てみるとゼロ幅スペースと呼ばれる\u200bが入ってます。
しかも偶数文字目と言っても、一番最初は0文字目として数えられるようでした。tが1文字目だとばかり思っていたので何回もincorrect出しました。
pakenCTF{teasweisandmtrng}
Unbearable to read 250pt
問題文:
「丸止无和川加奴周利加宇奴和川加奴最毛末幾左川止宇久川仁久知分加数二十個答衣左安
カッコの内部は算用数字
pakenCTF{〇○○}」
は??????????
中国語じゃね?とgoogle翻訳にぶち込んだが意味のある文章になりません。最後に20個答えろみたいなことを言っているようです。
一晩寝かせてみたら、「加」とか「和」とか「宇」とかひらがなの原型となった漢字が多く使われているな、って思い調べてみるとほとんどがそうでした。そこから、知り合いにヒントをもらった形にはなりましたが、ひらがなの原型でない漢字を除くと「丸周最分数二十個答」となるっことが分かりました。
丸、周、分数から円周率じゃね!?とエスパーして、円周率の下20桁を提出したがincorrect。flag形式をよく見ると一番最初の〇だけ大きいことから3.14=3桁の容量で3と小数点以下19桁提出したら通りました!!
最終日に通ったのですが、自分も含めてsolve数は3でした。めちゃくちゃ嬉しい。
pakenCTF{31415926535897932384}
OSINT
ネットストーカーに向いている問題達でした。
Twitter 50pt
問題文:「パ研の公式Twitterを知っていますか?僕は知っています。」
「pakenCTF パ研 Twitter」で検索。公式アカウントがflagをツイートしてました。
pakenCTF{Y0u_are_tvv1tter_m45ter}
— 筑駒パ研@第69回筑駒文化祭『彩雲』 【Paken.flush();】 (@tk_paken) 2020年10月29日
pakenCTF{Y0u_are_tvv1tter_m45ter}
Address 100pt
問題文:「この中央の建築物の場所を答えよ フラグの形式は pakenCTF{<郵便番号(間に_)>_<丁目>_<番地>_<号>}」
これとpicture.jpgが与えられます。
どこかのクリエイトのようですが、白黒で画素も荒いためなかなか判別が難しいです。
しかし、店の壁のところに「武蔵野」や「三〇中央病院」という文字が見えました。恐らくその場所への案内なのでしょう(→が一緒にあるやつ)。武蔵野の近くにある地名で三から始まるのは三鷹でしょう。調べてみたら三鷹中央病院という病院は存在しました。その近くにあるクリエイトは3店ほどあり、あとはストリートビューで探せばOKです。
pakenCTF{181_0013_4_14_16}
kaishuu 150pt
問題文:「ハッシュタグの中身を当てて下さい。FLAGはハッシュタグの中身 ( '#' なし) をpakenCTF{}で括ったものです。」
これとimage0,1,2,3の4枚が与えられます。
(重かったので直接問題を見てください)
これはm1z0r3の人達と話しながらやってたのですが、一人が渋谷っぽいと「渋谷 落書き」とググったところ以下のサイトがヒット。
良い話なような気がするけど、落書きっていいのかな。
pakenCTF{391045428}
Station 250pt
問題文:「この駅の名称とこの線の名称をローマ字で答えよ
ただし「都営」などは不要で、地名のような固有名詞で回答せよ
回答形式は、英字はすべて小文字、ヘボン式で
pakenCTF{<駅の名前>_station_<線の名前>_line}」
これと、station.jpgが与えられます。
写真から見るに、渋谷と吉祥寺を結んでいることから京王井の頭線、吉祥寺行きと永福町方面のホームが別であるからその間の駅、2つの線路に対してホームが一つという形の駅ということが分かります。あとはgoogleビューで最後を満たす駅を探せばOKです。
すぐに駅は分かったのですが、固有名詞なので頭文字を大文字にしたり線の名前にkeioと入れていたのでincorrectが続きましたが、なんとか通りました。
pakenCTF{kugayama_station_inokashira_line}
このように、写真から簡単に場所を特定できてしまいます。皆さんSNSの投稿などには気を付けましょう。水曜日のダウンタウンに目を付けられます
kyopro
JOISS2020 70pt
問題文:「これは何でしょう?
}rerv{nTC__Vr5pehk1sVaer4nf$rTeoun8v0Fn
ただし、ここでは $ を他の文字より真に小さい末端文字として扱っています。」
8割方OSINT問題でした。
まず、これもflagを並び替えたものだろうと推測できます。アナグラムだけでは特定できない上に$が気になります。
問題名でググると以下のgithubがヒットします。どうやら作成者のものみたいです。その中のpdfファイルを読み込みます。
p23あたりに$を末端文字とするという問題文と同じ文章が出てきます。そしてBW変換というのを行って暗号化しているみたいです。
後ろn文字目(n:0~文字列の長さ)から最後までの文字列を辞書順に並べます。例えばapple$だと出来る文字列は、$,e$,le$,ple$,pple$,apple$となり辞書順に並べると
$
e$
le$
ple$
pple$
となります。
辞書順の上から順にその文字の一つ前に来る文字を暗号文とします。上記の例だと、
$ -> e
apple$ -> $
e$ -> l
le$ -> p
ple$ -> p
pple$ -> a
暗号文:e$lppa
となります。
なので、暗号文を一文字ずつを辞書順に並べることで、ある文字が何の文字の前に来るかが分かります。その結果がこんな感じです。
これをあとはしりとりの要領で繋げる…としたのですが、なかなか上手くいきません。しばらく経っても分からずtr4nsfornとVVheelみたいな文章が出てきた頃、BW変換とググると以下のサイトが…
BW変換ってこの略か、と分かりあとはleetに沿ってflagを作れば一発でした。8->Bであったり、二つの同じ文字を並べて一つの文字を作る(VV->W, vv-> w, nn-> m)というleetは初めてでした。
pakenCTF{8urr0vv5_VVhee1er_Tr4nsfornn}
Let's play Nim 150pt
問題文:「Zipファイルをダウンロード・解凍して遊んでみて下さい!
勝つとFLAGを得られます。」
これとLetsPlayNim.zipが与えられます。
遊び方がしばらく分からなかったのですが、実行ファイルということで./Gameで良かったです。
以下、問題のNimのルールです。
<Nimのルール>
2人のプレイヤーがいくつかのコインの山からコインを取り合う。ゲームの目的は、最後のコインを取ることである(コインの代わりに石や豆を使ってもよい)。
まず、コインの山を複数準備する。
各々のプレイヤーは自分の順番のとき、コインの山を1つ選んでその山から1枚以上のコインを取り去る(複数の山からコインを取ったり、コインを一枚も取らなかったりするのは反則である)。これが終わったら次のプレイヤーの手番になる。
すべての山のコインがなくなったとき、ゲームは終わりである。そして、最後のコイン(複数のときもある)を取ったときのプレイヤーが勝者である。
※入力の際に整数以外を入力した際の動作は未定義である。
※プログラムに勝利することでFLAGを得られる。
※プレイヤーが先手である。
※初期値は乱数で決定される。
※Mountainの入力の際に-1を入力することで中止できる。
つまり、最後一つの山しかない状態で自分の番が来ればいいのです。そして、1:1, 2:1の状態で来ると詰みます。一回目は案の定負けてその反省を活かしたら二回目に勝てました。ちゃんとした考察は出来ていないのですが、山を2つにして、1:2,2:2の形で相手に送ると勝ち確です。まず、二つの山だけにするよう他の山を全て無くし、あとは二つの山のコインの数が同数になるようにすればOKです。
pakenCTF{Y0v_4r3_N1m_M4s7er}
shortest 150pt
問題文:「N頂点M辺の全ての重みが1の無向グラフがあります。
define君は頂点0からの全頂点への最短経路を求めるプログラムを書きましたが、どうやらバグっているようです。
撃墜テストケースを作成して下さい。
フォーマット
N M
A_1 B_1
...
A_M B_M
ただし、N, M共に5以下である必要があります。
入力例
3 2
0 1
1 2
撃墜テストケースをnc 3.131.69.179 18293でサーバープログラムに接続、提出するとFLAGを得られます。
プログラム : WA.cpp」
とりあえずWA.cppを見てみます。最初は全然わからなかったのですが、21行目でd[u]が-1なら更新するってとこに疑問を感じ、以下のような入力を行ったらflagが出ました。
5 5
0 1
1 2
2 3
3 4
0 4
0->4はコスト1で行けるが、前の4つの命令で0->4のコストが3となり-1ではないので更新されなかったって感じです。競プロ強者曰く、stackを使っているのがいけないみたいです。
pakenCTF{d0_u_l1ke_c0de40rces}
binary 200pt
問題文:
「1以上1000以下の10000個の数字が1列に並んでいます。
1番先頭の数字は1、1番最後(つまり、先頭から10000番目)の数字は1000で、隣り合う数字の差の絶対値は1以下です。
? x を入力することで、先頭からx番目の数字を得ることができます。
この操作を高々10回行った後、500がある位置のうち1つを、その位置をxとして ! x の形で入力し、出てきたフラグを答えてください。
ただし、この問題の設定で数字の列に500が含まれていることは証明可能です。
nc 3.131.69.179 19292」
例えば1~3の数字が一列に並んだ場合、1->3に飛ぶことは出来ない(隣り合う数字の差の絶対値は1以下)ので、2は必ず登場します。この要領で考えると500という数字が必ず出てきます。
正しい解法かは分かりませんが、まず5000番目の数字が何か聞きます。500より小さかったら、5000+(500とその数字の差)番目以降にあることが分かります。500より大きかった時も同様です(5000-(その数字と500の差)以前にある)。これを繰り返すと10回以内で大抵見つかります。500に近くなったら、たとえば480とかでたらちょっと大きい数字番目を聞いて、[a,b]みたいに範囲を限定するとかなり楽でした。
pakenCTF{pvvnt0o1s_1s_usefu1}
cycle 250pt
問題文:
「N頂点M辺の重みなし有向グラフがあります。各頂点には1からNの番号が、各辺には1からMの番号が振られており、i番目の辺はAiからBiに向かって張られています。
あなたは、このグラフに閉路が出来るように、辺を0本以上追加します。
追加する辺の候補はK個あります。i番目の候補は、PiからQiに向かって新たに辺を追加するということを表し、また、その辺を追加するにはCiのコストがかかります。
閉路を作るのにかかるコストの最小値を求めてください。
ただし、辺を追加する必要がない場合は0を出力し、どのように辺を追加しても閉路が作れない場合は-1を出力してください。
入力フォーマット N M K
A_1 B_1
A_2 B_2
:
A_M B_M
P_1 Q_1 C_1
P_2 Q_2 C_2
:
P_K Q_K C_K
制約
1≦N≦1000
1≦M≦1000
1≦K≦1000
1≦A_i, B_i, P_i, Q_i≦N
1≦C_i≦10^9
グラフは連結とは限らない
この問題に対する正しい出力をAnsとすれば、FLAGはpakenCTF{Ans}です。
入力ファイル : input.txt」
まず問題文の解釈に時間がかかりました。全ての頂点を訪れる必要は無く、一つ閉路作ればいいのです。それに気付くのが遅れ-1でないのか?と思ってました。
方法としては深さ優先探索で元の頂点まで戻ってこれるか調べその時のコストを記憶します。そのコストより小さいコストで閉路が出来たら更新します。
結局調べたら閉路は一個しか作れないみたいです。
pakenCTF{751878637}
inversion 250pt
問題文:
「長さ N の 要素が1〜 N からなる順列Aで、転倒数が K であるようなものの個数を10^9+7で割った余りを求めて下さい。
ただし、数列Aの転倒数とは i < j かつ A_i > A_j であるような (i, j) の組の個数を言います。
この問題の答えを
Test1 : N=245,K=18946
Test2 : N=489,K=75634
の場合について求め、
pakenCTF{(Test1の答え)_(Test2の答え)} の形で提出して下さい。(括弧は入れない)」
この問題面白かった!!
初めはNC2 (combinationのやつ)で考えるのかと思いましたが、回数が多すぎる…。ということで、Nが小さい場合で考えていきました。
i) N=2のとき
(1,2), (2,1)の2通りなので、転倒数とその個数は[1,1](i番目に転倒数がiの時の個数と表現していきます)となります。
ii) N=3のとき
1番目に1を置いた場合、その1と転倒数になるペアは存在しません。故にこの場合は(1,2,3), (1,3,2)の[1,1]です
1番目に2を置いた場合、2,3番目どちらに1を置こうが2と転倒数になります。あとは3と転倒数になるかどうかなので(2,1,3), (2,3,1)の[0,1,1]です
1番目に3を置いた場合、2,3番目どちらに1,2を置こうが3と転倒数になります。あとは1,2と転倒数になるかどうかなので(3,1,2), (3,2,1)の[0,0,1,1]です。
全て合わせると、[1,2,2,1]となります。
ここで、(1,1)という並びが上記3つ全てあります。ここから数学的帰納法で考えます。
N=kのとき、1番目にxを置いた場合、x-1以下の数字と必ず転倒数になる。2番目以降は
N=k-1のときに求めた。と考えると、あとは足し算するだけです。
[1,2,2,1]のような配列を作ると、i番目には転倒数iの時に何通りのペアがあるかが格納されます。
実行時間は時間がかかりましたが(2分程)、正しい結果が出力されました。
pakenCTF{965917879_825627234}
3BHR 400pt
問題文:「時は2050年。自治会によって奪われた自由を取り戻すべく、我々筑駒革命軍は自治会率いる筑駒防衛軍に宣戦布告した。
決闘の場所は筑駒のグラウンドである。
グラウンドは南北にHm、東西にWmの長方形である。ここで、北西の端からx m南に、y m東に行った点を(x,y) と表現することにしよう。
グラウンドにはN人の防衛軍がおり、i 人目は(X_i,Y_i) に立っている。いずれも南北両方向または東西両方向に向かってビームを撃っており、南北方向ならp_i=0, 東西方向なら p_i=1 である。
我々は任意の回数だけ防衛軍の射程圏外の任意の場所に移動、東西または南北にビームを撃ってその方向にいる防衛軍を倒す事ができる。なお、グラウンドの外から撃つこともできるが、防衛軍のビームはグラウンド外にも貫通することに注意だ。
さて、最大で何人の防衛軍を倒す事ができるだろうか?
入力フォーマット
H W N
X_1 Y_1 p_1
...
X_N Y_N p_N
制約
H,Wは10^9以下
Nは10^5以下
0<=X_i < H
0<=Y_i < W
入力例1
5 5 2
1 1 1
1 3 0
出力例1
2
入力例2
5 5 4
1 1 1
1 3 0
3 3 1
3 1 0
出力例2
0
この問題の 入力1 , 入力2 についての正しい出力をそれぞれAns1,Ans2とすればFlagは pakenCTF{Ans1_Ans2} です。」
さすがは400点問題、めちゃくちゃてこずりました。最初は、縦横それぞれにビームの通っている座標を格納する配列を作り、ある防衛軍隊員が一方向にしかビームが通っていない座標にいたら死んだこととし、その防衛軍が出しているビームを消すという作業を繰り返し、更新されなくなったら終わる(その消えたビームによって一方向しかビームが無い座標が増えそこに隊員がいた場合は更新)というプログラムを組みましたがincorrectを連発しました。
結局、O(N^2)というクソ長いプログラムを書き、二日目の夜就寝しました。起きたら見事答えをはじき出しcorrect! 良い子は真似しないでね!
内容としては、ある隊員の放っているビームとは垂直のビームを放っていて且つそのある隊員の座標を通るビームを放つ隊員達を格納する配列を組み、その配列が空になると死ぬという感じです。
pakenCTF{55157_80517}
CTFでのプログラミング問題はオーダーめちゃくちゃでも時間かけてでも通ればいいから良い(だから成長しない)
crypto
salad 70pt
問題文:「これはなんでしょう?」
sdnhqFWI{wklv_lv_wrr_hdvb}
まあROTですね、FWIだからrot23でしょう。
pakenCTF{this_is_too_easy}
Mr.Taher 200pt
Mr-Taher.zipが与えられます。中にはcodeとpycが与えられ、codeの中にはcode1,2があります。この時点でブロック暗号か?いやだな?とか思ってました。
pycの中が分からず、見たらなんかplaintextとか書いてあって、ここからソース復元できないかなって思ったら、pycってpythonの逆コンパイルした時の拡張子なんですね、このファイルは拡張子ないですが…。
unpyclibはインストールしたんですけど、pipが3系だったので2系で書かれてるこのpycは復元できず…。途方に暮れてたら、悔しいことにtechacademyのサイトに助けられました…。
Pythonのuncompyleモジュールの使い方を現役エンジニアが解説【初心者向け】 | TechAcademyマガジン
uncompyle6 pyc.pyc(cp pyc pyc.pycを忘れずに) で復元できました!!
ElGamal暗号でした。ご丁寧に秘密鍵を書いてくれているので、あとはwikiみて復号の仕方を思い出します。c1^(-x)*c2 mod pでした。-x乗する時にc1でinverse取るのを忘れないように。
pakenCTF{7a6er_4_31GaMa1}
Easy RSA 200pt
問題文:
「RSA暗号の説明をよく読んで、復号して下さい。部誌のP45〜を読むのも良いと思います。」
これとhttps://paken2020.web.app/assets/2020_paken_bushi.pdf, RSA.txtが渡されます。
RSA.txtにp,qがあるのでちゃっちゃと復号させます。
pakenCTF{d16_y0u_un6erstand_r5a}
kazoeage 250pt
問題文:
「RSA暗号の公開鍵と暗号文から復号してください。」
これとkazoeage.txtが与えられ、中にはN, e, cがあります。kazoeageとかいうからNが素因数分解できないのかと思ったら普通に出来ました。あとは前問と同じです。
pakenCTF{k4z0e4ge_1s_4un}
Coprime Crypto 500pt
問題文:
「---Decrypt this cryptograph---
"c1ys{4_C0_ky_}_hhaFrnn75ar5!y7p3T8aep1p"
---Examples of plain texts and codes' pair---
"Tsukukoma-Paken" "ea-mkksnkPaouuT"
"kenkenken2004" "4002nekneknek"
"We_love_CTF" "oCevT_eFl_W"
"Prime_Number_Is_Still_Veiled" "lerlri__mVIees_i_NlSuetmdibP"
"Are_You_Enjoying_This_CTF?" "?FTC_sihT_gniyojnE_uoY_erA"
"abcdefghijk" "eibfjcgkdha"」
とりあえず並び替えされていて、平文の頭文字が暗号化されると一番後ろに行くことが分かります。そして中には逆から読めば平文になる暗号文もあります。Coprimeということで互いに素からエスパーします。平文を等間隔で書いたものだろう、逆読みのやつはn-1を互いに素としているのだろう、ということで復元します。pの次はa,k,e,nですから、p-a間とa-k間が等しいaを見つけて、その差分でグルグルまわして終了です。
pakenCTF{7h15_15_an_3asy_cryp708r4phy!}
Black Box X 600pt
BlackBoxX.zipだけが与えられます。この問題はその中のblackboxxファイルが実行ファイルだということに気付けば7割方OKです。何か文字入れたら16進数が出てきてencodeと同じだと気づきます。そして、aと入れたら毎回同じ出力であること、入力をa,abとしたとき前6桁が変わってないこと、入力をb,abとすると後ろ6桁は変わることが分かります。暗号の仕方がブラックボックスということでしょう。あとは、string.printableで一致するかのbruteforce確認作業です。一致したらその文字を加えてまた回しましょう。
pakenCTF{Y0u_1i8hte6_7he_dArKNe55}
解けた問題は以上になります。cryptoの150ptが解けなかったのは悔しいです。対象が初心者用ということで、普段やらないWeb, misc, pwnなどやってみましたが面白いですね!アンケートで50pt貰えるのも嬉しいですね(笑) 最近のCTFは難しすぎるのでこのくらいの難易度が丁度良くめちゃくちゃ楽しかったです!!
そして、m1z0r3に負けて悔しかったのでこれをお供えします。
solverなどは後日GitHubに掲載します!
問題やsolverはこちらです!
それでは!
See you next time!