はじめに
あけましておめでとうございます。
新年から気を引き締めるためにオンラインCTF(TetCTF)に参加してきましたので、参加記録と雑感を書きます。
TetCTF2023 とは
TetCTFはベトナムの新年の祝日(Tet)に新年が皆様にとって良い年でありますようにと願いを込めて、開催されています。
https://ctf.hackemall.live/
難易度は正直わかりません。CTFTimes(https://ctftime.org/)で新年からできるCTFを探し、見かけたのでやってみた、というところが正直なところです。
問題にいくつか着手したのでどこまで考えて何を考えたかを書きます。
Welcome
よくあるWelcome問題。
RulesページにFlagが記載されていたので送信して得点ゲット。
NewYearBot
Web問題。指定されたURLにアクセスするとBotが準備されており、入力によって回答を返す。
Fileにサーバサイドのコードがあるので、中身を確認できる。
重要そうなコード部分を確認する。
1.Botに回答させるキーワード群。FL4Gをいうオブジェクトにflagを読み込んでいるので、最終的にこのオブジェクトを読む。
app = Flask(__name__)
FL4G = os.environ.get(‘secret_flag’)
fail = “???<br><img src=’https://i.imgur.com/mUfnGmL.png’ width=’20%’ />”
NewYearCategoryList = [“NewYearCommonList”, “NewYearHealthList”, “NewYearFamilyList”, “NewYearWealthList”]
NewYearCommonList = [“Chúc Mừng Năm Mới!”, “Happy New Year!”, “Cheers to a new year and another chance for us to get it right!”, “Let’s make 2023 our best year yet.”, “Năm mới Vui Vẻ”, “New year! New Me!”]
NewYearHealthList = [“Sức Khoẻ Dồi Dào!”, “Wishing you and yours health and prosperity in the new year”, “May the new year bring you peace”, “Joy, and happiness!”, “Tết An Lành”]
NewYearFamilyList = [“Gia Đình Hạnh Phúc!”, “Hoping that the new year will bring you and your family a year full of joy and serenity”, “Together! Forever!”, “Best wishes for your family”]
NewYearWealthList = [“Năm Mới Phát Tài!”, “Have a sparkling New Year!”, “Here’s hoping you make the most of 2023!”, “May the new year bless you with health, wealth, and happiness.”, “An Khang Thịnh Vượng”]
2.BotValidatorと呼ばれる、ユーザからの入力を検証する処理。NewYearCategoryList 内の最長のリストのインデックス以上ははじく。(この場合、6)
def botValidator(s):
# Number only!
for c in s:
if (57 < ord(c) < 123):
return False
# The number should only within length of greeting list.
n = “”.join(x for x in re.findall(r’\d+’, s))
if n.isnumeric():
ev = “max(“
for gl in NewYearCategoryList:
ev += “len(%s),” % gl
l = eval(ev[:-1]+”)”)
if int(n) > (l-1):
return False
return True
3.ユーザからの入力を受けて出力を処理する箇所。
try:
debug = request.args.get(“debug”)
if request.method == ‘POST’:
greetType = request.form[“type”]
greetNumber = request.form[“number”]
if greetType == “greeting_all”:
greeting = random_greet(random.choice(NewYearCategoryList))
else:
try:
if greetType != None and greetNumber != None:
greetNumber = re.sub(r’\s+’, ”, greetNumber)
if greetType.isidentifier() == True and botValidator(greetNumber) == True:
if len(“%s[%s]” % (greetType, greetNumber)) > 20:
greeting = fail
else:
greeting = eval(“%s[%s]” % (greetType, greetNumber))
try:
if greeting != fail and debug != None:
greeting += “<br>You’re choosing %s, it has %s quotes”%(greetType, len(eval(greetType)))
except:
pass
else:
greeting = fail
else:
greeting = random_greet(random.choice(NewYearCategoryList))
except:
greeting = fail
pass
else:
greeting = random_greet(random.choice(NewYearCategoryList))
if fail not in greeting:
bot_list = [“( ´ ∀ `)ノ~ ♡”, “(✿◕ᴗ◕)つ━━✫・*。”, “(๑˘ᵕ˘)”]
else:
bot_list = [“(≖ ︿ ≖ ✿)”, “ᕙ(⇀‸↼‶)ᕗ”, “(≖ ︿ ≖ ✿)ꐦꐦ”, “┌( ಠ_ಠ )┘”]
bot = random.choice(bot_list)
except:
pass
return “%s<div class=’centered’>%s<strong><font color=’red’>%s<br>NewYearBot >> </font></strong>%s</div>”%(css, front, bot, greeting)
以下のコードがキモ。greetType = FL4G, greetNumberを調整することでフラグを読み取れる。
greeting = eval(“%s[%s]” % (greetType, greetNumber))
greetType=FL4G, greetNumber=0でフラグの一文字目を出力できた。
BotValidatorの検証の結果、6以上の数はエラーとして返されてしまう。
CMSがFlaskであったので、debugモードで起動してみると、Flag文字列は24文字であることがわかる。
greetType=FL4G, greetNumber=-1でフラグの最後の一文字目を出力できた。
同じようにgreetType=FL4G, greetNumber=-5までは文字列を取得できました。
間の13文字がどうしても取得できず時間切れとなりました。
Writeupを確認しての回答
pythonのNot演算子「~」を利用することで6文字目から13文字目まで取得できるとのこと。
-~0-~4 -> 6
-~0-~5 -> 7
flag自体は本記事では記載いたしません。
まとめ
TetCTFに参加し、着手した問題をどう考えたか記載しました。
問題自体は解けませんでしたが、pythonの言語使用について深く調べるいい機会となりました。
定期的にオンラインCTFに参加して、自分自身の力をつけていきます。
The following two tabs change content below.