For Plantly, we get access to an online plant store. We’re given two sets of default/example user credentials to login initially and you’re able to register more accounts if needed (which I did because I killed the server more than once, oops).
Register yourself an account or sign in with the provided credentials. Heading over to “Browse Our Plans” we see some plants to add to cart, as well as a “Custom Order” field to type into.
If we add this stuff to our cart and proceed to checkout, we’ll see a summary of our order and an option to view a receipt.
Viewing the receipt shows our “Custom Request” text reflected on the receipt. Hm.
We have access to the source code for this app, so we can see whats happening. In store.py we can see in the receipt our custom request is being rendered as a template by Flask:
We know that we can control this input, so lets test. Go back to the store and place a custom order. For your custom order, enter “{{7*7}}”
.
Add this to your cart, proceed to checkout, and view your receipt. You should notice your new “Custom Request” actually shows the result of calculating 7x7!
This demonstrates that the web application is vulnerable to Server Side Template Injection (SSTI). You can read more about SSTI in Jinja2 here or here. Now that we know the app is vulnerable to this, we can craft a simple payload to get the flag:
{{ self.__init__.__globals__.__builtins__.__import__('os').popen('cat flag.txt').read() }}
Go back to the store, insert the above payload as your “Custom Order”, proceed to checkout and view your receipt, you should see your flag displayed as your last “Custom Request”!