sec👨‍💻fortress:~#

Defensive By Offensive!.

View on GitHub

Server Side Template Injection

VulnMachines SSTI

image

After going over to the web page it shows this image

Trying to input something shows it get reflected back image

Using basic SSTI payload works image

Let’s use this SSTI check to know what template engine it uses image

First i’ll try ${7*7} but it doesn’t get evaluated image

Next we move unto the down part of what we are using to get the template engine

Now i’ll try this `` image

It gets evaluated

So we move unto ``

But doing that gives us an error image

Your nickname contains restricted characters!

To bypass this we can try using double quote instead of single quote

Doing that works image

From here we can say the template engine is either Jinja2 or Twig

But from the web server header we can then conclude it’s Jinja2 templating engine that is being used since the webserver is built on python image

The aim of this challenge is to get the flag

Checking the env works and shows the flag image

Flag: 56756c6e6d616368696e6573202d20506c61636520666f722050656e746573657273

It is in it’s hex form

I used python to decode it

#!/usr/bin/python3
# Author: Hack.You

encoded = '56756c6e6d616368696e6573202d20506c61636520666f722050656e746573657273'
decoded = bytes.fromhex(encoded)
flag = b'vnm{'+decoded+b'}'
print(f'Flag: {flag}')

Running it gives us the flag image

But how about we try get RCE

First I need to know the classes that are present and preferably the subprocess class

Reason is because it’s a python module that allows us to execute commands image

So here’s the payload:


But giving that to the web server gives an error image

Your nickname contains restricted characters!

It seems like it filters another character

To make it easier i’ll intercept one of the post request and save it in a file image image

Now i’ll use ffuf to fuzz for allowed special characters image image image

Sorry about the way my ffuf is that’s the new update 😥

But we can see the allowed characters :)

One way we can improvise in bypassing the filter is by converting the blacklisted character to hex image

Using the updated payload works image

Now we can check if the subprocess class is among it image

Cool it’s among the classes

We need to get the position of the subprocess class number

Burp intruder can help with that :) i did try scripting this but unfortunately i can’t seem to make it send as raw data without it being converted to it’s string form

I’ll just fuzz using Burp Intruder image image

After running it I got this image

We can see the request with a content length of 258

Checking it shows that it indeed works image image

And the position for the subprocess class is 286

We can then try reading the app.py file image

Here’s the result gotten from reading app.py (P.S: I exfiltrated it 🙂)

import random
from flask import Flask, render_template_string, render_template, request

app = Flask(__name__)
app.config['SECRET_KEY'] = 'Follow us on Twitter rapidsafeguard'

#Tiaonmmn don't remember to remove this part on deploy so nobody will solve that hehe
'''
def encode(line, key, key2):
    return ''.join(chr(x ^ ord(line[x]) ^ ord(key[::-1][x]) ^ ord(key2[x])) for x in range(len(line)))

app.config['flag'] = encode('', 'GQIS5EmzfZA1Ci8NslaoMxPXqrvFB7hYOkbg9y20W3', 'xwdFqMck1vA0pl7B8WO3DrGLma4sZ2Y6ouCPEHSQVT')
'''

app.config['flag'] = '56756c6e6d616368696e6573202d20506c61636520666f722050656e746573657273'
#app.config['flag']="Success fully pass SSTI"
nicknames = ['˜”*°★☆★_%s_★☆★°°*', '%s ~♡ⓛⓞⓥⓔ♡~', '%s Вêчңø в øĤлâйĤé', '♪ ♪ ♪ %s ♪ ♪ ♪ ', '[♥♥♥%s♥♥♥]', '%s, kOтO®Aя )(оТеЛ@ ©4@$tьЯ', '♔%s♔', '[♂+♂=♥]%s[♂+♂=♥]']
#nicknames=['psycho','rapidsafeguard']
@app.route('/', methods=['GET', 'POST'])
def index():
    if request.method == 'POST':
        try:
            p = request.values.get('nickname')
            id = random.randint(0, len(nicknames) - 1)
            if p != None:
                if '.' in p or '_' in p or '\'' in p:
                    return 'Your nickname contains restricted characters!'
                return render_template_string(nicknames[id] % p)

        except Exception as e:
            print(e)
            return 'Exception'

    return render_template('index.html')

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=1337)

We can also see the flag there 😅

And we’re done 👻