SECCON CTF 2022 Domestic Finals writeup

SECCON CTF 2022 Domestic FinalsにチームtraPで参加してきました。参加記は[こちら](https://trap.jp/post/1769/)。
私が解けた問題はかなり少ないですが、そのwriteupとなります。
## writeup
### Jeopardy

#### [rev] Whisky
この問題を含め、rev、pwnの問題はすでにptr-yudai先生の[writeup](https://ptr-yudai.hatenablog.com/entry/2023/02/14/033354#Reversing-Whisky)が公開されています。

まず、与えられた`backdoor_plugin.so`ファイルをGhidraなどで開くと、特徴的な関数として`uwsgi_backdoor_request`関数及び`backdoor`関数が見られます。uWSGIは使用したことがなかったので、[ドキュメント](https://uwsgi-docs.readthedocs.io/en/latest/)を見ながら解き進めます。

このプラグインは、どうやらドキュメントの[The Symcall plugin](https://uwsgi-docs.readthedocs.io/en/latest/Symcall.html?highlight=wsgi_request)と似たような形をしているようです。`uwsgi_backdoor_request`を読むと、`uwsgi_backdoor_request`が`mysym_function`に対応しており、その引数は`wsgi_request`構造体であることがわかります。
`backdoor`関数を呼び出すには以下の3つの条件があることがわかります。
1. `HTTP_BACKDOOR`を`wsgi_request`から`uwsgi_get_var`関数で読み出し、値が`enabled`である。
1. `wsgi_request`のあるフィールドの値が16である。
1. `wsgi_request`のあるフィールドの値が0でない。

まず、1をクリアするために、`uwsgi_get_var`関数の挙動を調べます。すると、どうやらCGI環境変数を読みだしていることがわかり、これに`HTTP_BACKDOOR`を追加して`GET`リクエストを送ると良いことがわかります。ここで、CGI環境変数を変えることはできないのでは...？と思い、時間を溶かしましたが、[この説明](https://www6.uniovi.es/~antonio/ncsa_httpd/cgi/env.html)にあるように、ヘッダーの名前に`HTTP_`というprefixをつけたものが自動で設定されるため、keyが`Backdoor`、valueが`enabled`であるヘッダーを追加してリクエストを送ればよいことがわかりました。

次に、2、3をクリアするために、`wsgi_req + 0x1d8`及び`wsgi_req + 0xc0`が表すフィールドを調べます。しばらく`wsgi_request`構造体の定義を探したところ、ptr-yudaiさんのwriteupにもあるように、[uwsgi.h](https://github.com/unbit/uwsgi/blob/master/uwsgi.h#L1379)にあることがわかります。フィールドのサイズを`0x1d8`及び`0xc0`になるまでひとつひとつ足していってもよかったのですが、面倒だったので以下のようなコードを記述し、Docker上で用意した環境で走らせることでフィールドを手動二分探索(?)しました。
```c
int mysym(struct wsgi_request *wsgi_req) {
        // read request variables
        if (uwsgi_parse_vars(wsgi_req)) {
                return -1;
        }

        // get HTTP_BACKDOOR
        uint16_t vlen = 0;
        char *v = uwsgi_get_var(wsgi_req, "HTTP_BACKDOOR", 13, &vlen);

        // send status
        if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) return -1;
        // send content_type
        if (uwsgi_response_add_content_type(wsgi_req, "text/plain", 10)) return -1;
        // uri_lenをフィールド名に変更する
        int a = offsetof(struct wsgi_request, uri_len);
        char ret[32] = {};
        itoa(a, ret, 10);
        
        // send the body
        if (uwsgi_response_write_body_do(wsgi_req, ret, strlen(ret))) return -1;

        return UWSGI_OK;
}
```
```dockerfile
# create gcc env
FROM gcc:latest
# copy source code
COPY mysym.c ./mysym.c
COPY uwsgi.h ./uwsgi.h
# build mysym.c
RUN gcc -fPIC -shared -o mysym.so `uwsgi --cflags` mysym.c
# use uwsgi
FROM python:3.7
# copy mysym.so
COPY --from=0 /mysym.so /mysym.so
# install uwsgi
RUN pip install uwsgi
ENTRYPOINT ["uwsgi", "--dlopen", "/mysym.so", "--symcall", "mysym", "--http-socket", ":9090", "--http-socket-modifier1", "18"]
```
これにより、フィールドがそれぞれ`authorization_len`及び`uri`であることがわかりました。この情報を用いると、`Authorization`ヘッダーの長さが16であり、`URI`が設定されており、ヘッダーに`Backdoor: enabled`が設定されている際に`backdoor`関数が呼び出され、`URI`の位置のファイルを`Authorization`の内容をキーにして`AES128-cbc`でエンコードした結果がヘッダーに追加されてレスポンスとなることがわかります。
よって、以下のようなコードを書くことで、フラグを得ました。
```python
from Crypto.Cipher import AES
from Crypto.Util.number import long_to_bytes

key = b'abcdeabcdeabcdez'

print(key)

enc = long_to_bytes(0x761a7bb2cead118aa222cbfcdc2671dae5bd34f196064cad31d1a30404ec231127e6b9be073515395fdbd07f4934e3cbe3865e7f958acbd860a9c181a0d28b10)


cipher = AES.new(key, AES.MODE_ECB)
print(cipher.decrypt(enc))
print(cipher.decrypt(enc).decode('utf-8'))
```

### KoH

#### Heptarchy

与えられたバイナリとdiffの少ないバイナリを吐くソースコードを提出し、そのdiffの少なさを競うKoHです。
私は最初に適当なソースコードを提出するだけのお仕事で、ほとんど取り組んでおらず、チームメンバーのImperiがずっといい感じの点数を取ってくれていたのですが、wasmだけ私の提出した[emccのサンプルソースコード](https://emscripten.org/docs/getting_started/Tutorial.html?highlight=emcc#generating-html)がずっと2位のバイナリを吐き続けました(!?)。

## まとめ

私はずっと他のrev2問とにらめっこしており、全然問題を解くことができなかったので、もっと精進して他2問も解けるように頑張りたいと思いました。ほかの問題に関しては後々チームメンバーがwriteupを出すと思います。
運営の皆さん、ありがとうございました。