osu!gaming CTF 2024 Writeup

# osu!gaming CTF 2024
順位は367位/984位でした。

![score.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982234/de0d64fd-61d1-9eea-0c84-765ed9246f03.png)

# 目次
- misc/discord
- misc/survey
- osu/sanity-check-1
- misc/Infiltrating the OSU! (I)
- crypto/base727
- web/mikufanpage
- crypto/ROSSAU
- osu/smoked
- pwn/betterthanu
- misc/Infiltrating the OSU! (II)
- forensics/nathan-on-osu
- まとめ

# misc/discord
チャンネル「announcements」で開始直後(2024/3/2 2:00)にsahuangさんが発言した文章の中にflagがあります。
文章がかなり長いので今回は写真省略します。

```osu{Rhy7hm_15_L1f3}```

# misc/survey
アンケートに答えるとflagが取得できます。

```osu{push_these_poochs_off_me_like_BAU}```

# osu/sanity-check-1
ビートマップ情報のタグを見るとflagが書いてあります。
![sanity-check-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982234/557f80f4-2b0c-a95f-ba35-7da506730546.png)

```osu{welc0me_2_osu!!}```

# misc/Infiltrating the OSU! (I)
この問題は以下の画像のURLを「``https://assets.ppy.sh/``」の中から探し出し送信するとflagが送信されます。
![osu-banner.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982234/07301a4b-f29a-e0d4-abdf-6639bab22d22.jpeg)

ヒントとして[hoifanrdさんのosu!プレイヤー情報](https://osu.ppy.sh/users/13336293)が提供されているのでその中から同じような画像がないか調べます。

![Infiltrating_the_OSU_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982234/7fb33167-5c71-bbc7-ed39-3d647e71042f.png)

赤い矢印で指された画像のURLを送ればよさそうです。この画像のURLは開発者ツールで見ることができます。
ちなみにここでCtrl+Shift+Cを同時押しするとその画像をクリックするだけで画像のURLがわかるのでお勧めです。

送信したらflagが出てきました。

```osu{tr1v4l_5rc_1n5p3c7_1n_webs1t3}```

# crypto/base727

カテゴリにChatGPTと書いてあったので与えられたファイルのコード(727.py)の逆の手順をたどるコードをChatGPTに依頼したらこのようなコードが返ってきました。

```python
import binascii

def decode_base_727(encoded_string):
    base = 727
    decoded_value = 0

    for char in encoded_string:
        decoded_value = decoded_value * base + ord(char)

    decoded_string = ""
    while decoded_value > 0:
        decoded_string = chr(decoded_value % 256) + decoded_string
        decoded_value //= 256

    return decoded_string

# 与えられたBase727でエンコードするコード
encoded_hex_string = b'06c3abc49dc4b443ca9d65c8b0c386c4b0c99fc798c2bdc5bccb94c68c37c296ca9ac29ac790c4af7bc585c59d'
encoded_string = binascii.unhexlify(encoded_hex_string).decode()

decoded_string = decode_base_727(encoded_string)
print(decoded_string)
```

実行するとflagが出ました。

![727.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982234/20928b18-26b0-e3ed-4e35-0b6a1b5c20e3.png)

```osu{wysiwysiwysiywsywiwywsi}```

# web/mikufanpage
ダウンロードしたファイルの中にReadme.mdがあったので開いたらflagがあったのでそのまま入力したら正解してしまった・・・
大丈夫なのかこれ。

ちなみに正攻法は
```https://mikufanpage.web.osugaming.lol/image?path=miku1.jpg./../flag.txt```のように接続するとflagが出てくるディレクトリトラバーサルの問題だったらしいです。

```osu{miku_miku_miku_miku_miku_miku_miku_miku_miku_miku_miku_miku_miku}```

# crypto/ROSSAU
これはeがかなりでかいのでwiener's attackが適用できます。
過去にwiener's attackの記事書いているみたいなのでもしよかったらどうぞ。

https://qiita.com/seiya1122_404/items/60c803199b75a7984eed

今回はdが分かればいいのでこのコードで行きます。

```python
import owiener

e = 876603837240112836821145245971528442417
n = 5912718291679762008847883587848216166109
d = owiener.attack(e, n)

if d is None:
    print("Failed")
else:
    print("d={}".format(d))
```

以下のように求まりましたがこれが答えではありません。ユーザ名を特定する必要があります。

![ROSSAU_d.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982234/3914b342-9c1f-0bfe-94e7-d16fe29336c7.png)

osu!のプレイヤー情報のURLのところを見てみると数字が入っているので[数字をdの値に変更したプレイヤー情報](https://osu.ppy.sh/users/124493)にしてアクセスすると・・・

![ROSSAU_user.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982234/423f51da-ffce-9690-17ad-ae062e5bc90e.png)

chocomintさんのプレイヤー情報になりました。したがってchocomintさんが正解です。

```osu{chocomint}```

# osu/smoked

与えられたファイルはosrファイルでosu!のゲームのリプレイファイルとなっています。

osu!アカウントを持っていなくてもこちらでできます。

https://ordr.issou.best/about

flagはリプレイしている最中にカーソルで書いているみたいです。ちなみに私はosu!をやったことないのでもしかしたらカーソルじゃなくてほかの方法でやってる可能性があります。

```osu{smoked_map_fun}```

# pwn/betterthanu

コードは以下のようになっています。

```c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>

FILE *flag_file;
char flag[100];

int main(void) {
    unsigned int pp;
    unsigned long my_pp;
    char buf[16];

    setbuf(stdin, NULL);
    setbuf(stdout, NULL);

    printf("How much pp did you get? ");
    fgets(buf, 100, stdin);
    pp = atoi(buf);

    my_pp = pp + 1;

    printf("Any last words?\n");
    fgets(buf, 100, stdin);

    if (pp <= my_pp) {
        printf("Ha! I got %d\n", my_pp);
        printf("Maybe you'll beat me next time\n");
    } else {
        printf("What??? how did you beat me??\n");
        printf("Hmm... I'll consider giving you the flag\n");

        if (pp == 727) {
            printf("Wait, you got %d pp?\n", pp);
            printf("You can't possibly be an NPC! Here, have the flag: ");

            flag_file = fopen("flag.txt", "r");
            fgets(flag, sizeof(flag), flag_file);
            printf("%s\n", flag);
        } else {
            printf("Just kidding!\n");
        }
    }

    return 0;
}

```

以下の条件を満たせばflagを取得することができます。
- pp = 727であること(最初に入力する部分)
- pp > my_pp であること(ただしmy_pp = pp + 1)

1つ目の条件を守ると2つ目は
my_pp = 728
pp = 727
なので条件を満たさなくなってしまいます。

2つ目の条件を守る(unsigned int型を利用してpp = 4294967295)と入力すると
pp = 727ではないので1つ目の条件を満たさなくなります。

ここで以下の部分に注目します。

```c
    printf("Any last words?\n");
    fgets(buf, 100, stdin);
```

この部分にたくさんの文字を入れて```if (pp <= my_pp)```を無視できるように書き換えれば2つ目の条件を回避することができます。これで1つ目の条件を守りつつ2つ目の条件を回避でflagが手に入るようになります。

![betterthanu.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982234/0c8ef883-22c3-e8db-19d8-65b492b0d5aa.png)

ちなみに私は9を16回入力して回避しました。

```osu{i_cant_believe_i_saw_it}```

実はpwnは外部CTFで初めて自力で解けました。

# misc/Infiltrating the OSU! (II)(解けなかった)
Google画像検索するとその画像があるURLを調べられます。

![Infiltrating_the_OSU_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982234/83c55ada-a050-11dd-7dcd-7f295dfa2fec.png)

その中で「i.ppy」にあり、かつ寸法が1100x280pxの画像を探してURLを送信するとflagが送信されます。

```osu{d1d_y0u_p2w???0r_d1d_y0u_f2w_by_u51ng_7h3_f0rum???}```

ちなみにWriteup書いている間に分かりました。misc/Infiltrating the OSU! (I)の影響を強く受けすぎてhoifanrdさんのosu!プレイヤー情報のサイトのなかをずっと探し回ってました。英語ちゃんと読めていれば・・・

# forensics/nathan-on-osu(解けなかった)

スクショなのでなんか加工前の画像に復元するものあるのかなと思っていたらやっぱりありました。
こちらは「aCropalypse」という脆弱性でherietさんが詳しく解説しています。

https://zenn.dev/heriet/articles/acropalypse-gif

以下のサイトで高さ1080 x 幅1920と入力して問題の写真ファイルを選択するとできるみたいです。ちなみにどうやってその高さと幅を特定するかはわかりませんでした・・・

https://acropalypse.app/

![nathan-on-osu.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982234/f7e8ae51-ccba-7651-d170-42f933bc9b2a.png)

```osu{cr0pp3d_Future_Candy<3}```

# まとめ
後もう少しで解けた問題があったのでかなり悔しいです・・・