LoginSignup
0
0

More than 1 year has passed since last update.

SECCON CTF 2022 Domestic Finals writeup

Posted at

SECCON CTF 2022 Domestic FinalsにチームtraPで参加してきました。参加記はこちら
私が解けた問題はかなり少ないですが、そのwriteupとなります。

writeup

Jeopardy

[rev] Whisky

この問題を含め、rev、pwnの問題はすでにptr-yudai先生のwriteupが公開されています。

まず、与えられたbackdoor_plugin.soファイルをGhidraなどで開くと、特徴的な関数としてuwsgi_backdoor_request関数及びbackdoor関数が見られます。uWSGIは使用したことがなかったので、ドキュメントを見ながら解き進めます。

このプラグインは、どうやらドキュメントのThe Symcall pluginと似たような形をしているようです。uwsgi_backdoor_requestを読むと、uwsgi_backdoor_requestmysym_functionに対応しており、その引数はwsgi_request構造体であることがわかります。
backdoor関数を呼び出すには以下の3つの条件があることがわかります。

  1. HTTP_BACKDOORwsgi_requestからuwsgi_get_var関数で読み出し、値がenabledである。
  2. wsgi_requestのあるフィールドの値が16である。
  3. wsgi_requestのあるフィールドの値が0でない。

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

次に、2、3をクリアするために、wsgi_req + 0x1d8及びwsgi_req + 0xc0が表すフィールドを調べます。しばらくwsgi_request構造体の定義を探したところ、ptr-yudaiさんのwriteupにもあるように、uwsgi.hにあることがわかります。フィールドのサイズを0x1d8及び0xc0になるまでひとつひとつ足していってもよかったのですが、面倒だったので以下のようなコードを記述し、Docker上で用意した環境で走らせることでフィールドを手動二分探索(?)しました。

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;
}
# 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でエンコードした結果がヘッダーに追加されてレスポンスとなることがわかります。
よって、以下のようなコードを書くことで、フラグを得ました。

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のサンプルソースコードがずっと2位のバイナリを吐き続けました(!?)。

まとめ

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

0
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
0
0