5
2

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 2021 Writeup (Web)

Last updated at Posted at 2021-05-24

はじめに

初めてのQiita記事です。
SECCON Beginners CTF 2021 に参加したので Writeup というものを書いてみます。
常設ではないCTFは去年の SECCON Beginners CTF 以来2回目、今回もチームは組まずソロ参加でした。
簡単なWeb問題だけでも解けたらいいなと思って参加してみましたが、Web4問・Misc3問・Crypto1問・Reversing2問が解けて結果は862点 943チーム中の191位でした。思ったよりできたので嬉しいです。

追記:Web以外を別記事に書きました。 https://qiita.com/tm741_/items/bace80869d5cee8c393f

Web問題Writeup

osoba

美味しいお蕎麦を食べたいですね。フラグはサーバの /flag にあります!
https://osoba.quals.beginners.seccon.jp/
想定難易度: Beginner

適当にリンクを踏むとクエリ変数にパスらしいものが出てきます。
https://osoba.quals.beginners.seccon.jp/?page=public/kikin.html

配布ファイルからflagファイルがあるのが分かるのでパストラバーサルでアクセスします。
https://osoba.quals.beginners.seccon.jp/?page=../flag

ctf4b{omisoshiru_oishi_keredomo_tsukuruno_taihen}

Werewolf

I wish I could play as a werewolf...
https://werewolf.quals.beginners.seccon.jp/
想定難易度: Easy

player.role == 'WEREWOLF'になっていたらflagが出力されるのに、ランダムで選ばれるroleの値のリストにはWEREWOLFが入っていません。
下のようにリクエストの変数を全部読み込んでしまう実装なので正しい変数名で送信すればいいのは分かりましたが、とりあえず __role=WEREWOLF とか role=WEREWOLFを送ってみてもうまくいかない。

app.py
    if request.method == 'POST':
        player = Player()

        for k, v in request.form.items():
            player.__dict__[k] = v

配布ソースの通りPlayerクラスのオブジェクトを作って__dict__を表示させることで、正しい変数名は_Player__roleであることがわかりました。

import random

class Player:
    def __init__(self):
        self.name = None
        self.color = None
        self.__role = random.choice(['VILLAGER', 'FORTUNE_TELLER', 'PSYCHIC', 'KNIGHT', 'MADMAN'])

testplayer = Player()
print(testplayer.__dict__) # {'name': None, 'color': None, '_Player__role': 'VILLAGER'}

Bodyを_Player__role=WEREWOLFとしたPOSTリクエストを送るとflagが返されます。
ctf4b{there_are_so_many_hackers_among_us}

mass assignment脆弱性というそうですが日本語訳の定訳を知りたいです。

check_url

Have you ever used curl ?
https://check-url.quals.beginners.seccon.jp/
想定難易度: Easy

惜しいところまで行っていたようですが正答できませんでした。

$_SERVER["REMOTE_ADDR"]が127.0.0.1になればflagが取得できるようです。

index.php
if ($_SERVER["REMOTE_ADDR"] === "127.0.0.1"){
  echo "Hi, Admin or SSSSRFer<br>";
  echo "********************FLAG********************";
}

$_SERVER["REMOTE_ADDR"]はネットワーク層のIPアドレスが入っていてHTTPリクエストからは改変できないようなので、

SSRFって書いてあるのもヒントに、問題サーバのcurlを使って自身へのHTTPアクセスを試みます。
ただ、localhostはブロックされ、127.0.0.1はピリオドがSuper sanitizing👻されてしまうので渡せません。

index.php
if ($url !== "https://www.example.com"){
  $url = preg_replace("/[^a-zA-Z0-9\/:]+/u", "👻", $url); //Super sanitizing
}
if(stripos($url,"localhost") !== false || stripos($url,"apache") !== false){
  die("do not hack me!");
}

IPアドレスの10進数表記があったことを思い出し、変換してみた2130706433では400 Bad Request
ほかに調べていてピリオドを使わない8進数表記017700000001を見つけたもののこれも400 Bad Requestというところで挫折。

この記事に辿り着けなかったのが残念です。

作問者様Writeupより、正解は16進数表記の0x7F000001だったそうです。
https://check-url.quals.beginners.seccon.jp/?url=https://0x7F000001/
ctf4b{5555rf_15_53rv3r_51d3_5up3r_54n171z3d_r3qu357_f0r63ry}

json

外部公開されている社内システムを見つけました。このシステムからFlagを取り出してください。
https://json.quals.beginners.seccon.jp/
想定難易度: Medium

ローカルネットワーク(192.168.111.0/24)内から閲覧する必要があるそうです。
bff\main.goClientIP()のIPアドレスを見て制限をかけているようですが、go のClientIP()は特に設定していないとHTTPリクエストのX-Forwarded-Forヘッダで偽装できるのが分かりました。

リクエストにX-Forwarded-For: 192.168.111.1ヘッダを追加して内部ページが表示されました。

Submitを押すとJSONをPOSTしますが、Flagを選択したときの{"id":2}は禁止されています。
bffとapiでJSONに同じキーが2個あるときの解釈が違っているのを予想し(apiのソースは読んでなかった) {"id":2,"id":1}を送信してみると正解。
{"result":"ctf4b{j50n_is_v4ry_u5efu1_bu7_s0metim3s_it_bi7es_b4ck}"}

cant_use_db

Can't use DB.
I have so little money that I can't even buy the ingredients for ramen.
🍜
https://cant-use-db.quals.beginners.seccon.jp/

深夜に見るラーメン画像、なんと攻撃力の高いことか…。

DBではなくuser_id別に作られるファイルでユーザーデータが保存されています。
普通に購入していくとbalanceが足りなくなりますが、ユーザーデータを読み込んでからファイルに書き込むまでの間はロックされていないのでデータ競合の問題があります。

1つリクエストを出したときのtime.sleep(random.uniform(-0.2, 0.2) + 1.0)の間に残り2つのリクエストが出されるように、buy_noodlesを2回とbuy_soupのリクエストを出せばいいことがわかります。
1秒前後も待ってくれるので特にコードを書かなくてもBuyボタンを続けて順番に押すだけで倍盛りラーメンを食べることに成功。
ctf4b{r4m3n_15_4n_3553n714l_d15h_f0r_h4ck1n6}

magic

トリックを見破れますか?
https://magic.quals.beginners.seccon.jp/
想定難易度: Hard

magic linkを上手く使ってcrawlerにXSSを踏ませる問題っぽいのは分かりましたが、CSPヘッダにscript-src 'self'があるので普通にインラインスクリプトではダメというところから進まず解けませんでした。

5
2
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
5
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?