curl as a service 2

https://alpacahack.com/daily/challenges/curl-as-a-service-2

コードから

/frontend/app.py

@app.post("/curl")
def curl():
    url = request.form.get("url", "")
    completed_process = subprocess.run(
        [
            "curl",
            "--silent",
            "--show-error",
            url,
        ],
        capture_output=True,
        text=True,
    )
    return {
        "output": completed_process.stderr or completed_process.stdout,
    }

POST /curlurl パラメータに任意の文字列を渡せることがわかる。ただし curl への引数としては1つだけ

secret/app.py (1337 番ポートに接続があったとき実行されると律儀に教えてくれている)

# This program is executed when there is a connection to 1337/tcp by socat
answer = input("What is your wish?").strip()
print(f"Your wish: {answer}")
if answer == "Give me a flag":
    print("Sure! Here is the flag!")
    with open("flag.txt") as f:
        print(f.read().strip())
else:
    print("Sorry, I can't do that...")

標準入力に Give me a flag と入力すればいいらしい。

secret/Dockerfile

# 中略

CMD ["socat", "-T1", "tcp-listen:1337,fork,reuseaddr", "exec:'python app.py'"]

...というプログラムが secret:1337 で実行されていることがわかる。

考え方

curl の仕様を読むと良い https://curl.se/docs/manpage.html#--telnet-option

すると何やら大量のプロトコルがサポートされていることがわかる。いろいろ目をつけてもいいが、今回は CTF 関連でよく使われる Gopher プロトコルの仕様を読む。

https://datatracker.ietf.org/doc/html/rfc4266 (自動で日本語訳されたもの) https://tex2e.github.io/rfc-translater/html/rfc4266.html

このプロトコルは以下のURLを受け取る。

gopher://<host>:<port>/<gopher-path>

<gopher-path> は以下の形式のいずれか。

<gophertype><selector>
<gophertype><selector>%09<search>
<gophertype><selector>%09<search>%09<gopher+_string>