I think I’ve gone word blind. I don’t want to stop because it took me ages to get to this point and I don’t have a way to leap back here when I spin it up again
Have you tried using alternative parentheses? Like e.g. the UTF-8 full-width characters? Maybe the filter is somewhere in front and Jinja gracefully converts them back, for you.
Have you tried using alternative parentheses? Like e.g. the UTF-8 full-width characters? Maybe the filter is somewhere in front and Jinja gracefully converts them back, for you.
Have you tried using alternative parentheses? Like e.g. the UTF-8 full-width characters? Maybe the filter is somewhere in front and Jinja gracefully converts them back, for you.
os.system(‘id’)
aka. os.system%uff08'id'%uff09
I owe you at least a small beer!
It progressed slightly - getting server errors now but that could be down to all the ■■■■ I’ve been throwing at it.
So far it looks like this bypassed at least part of the content filtering.
EDITED TO ADD
Might have been a bit too optimistic. It just generates HTTP500s even with a clean boot, I think its breaking the content filter rather than bypass. Also it s a lot of characters when I only have 45 to play with.
But I am genuinely indebted to @HomeSen for the nudge here.
So, I am still stuck, but I’ve made some progress.
I can write to the HTTP referrer string and I can call request.environ.HTTP_REFERER in the SSTI, but it still remains static.
So for example: {{os.popen.request.environ.HTTP_REFERER}} doesn’t work but {{request.environ.HTTP_REFERER}} does actually print whatever I put in the referer field.
So for example: {{os.popen.request.environ.HTTP_REFERER}} doesn’t work but {{request.environ.HTTP_REFERER}} does actually print whatever I put in the referer field.
So clearly the OS module is not wholly imported, just os.popen.request. Maybe something useful in there? Not 100% sure though without being able to look at it.
Then again that has absolutely nothing to do with the HTTP_REFERER string unless you are down a rabbit hole, it does seem like a perfect XSS opportunity only question is how to trigger it…
It could well be a rabbit hole. Right now I have no way to tell.
However it is a lab on Jinja2 exploitation so I think XSS isn’t really part of the lab builders plans.
I have space for 41 characters between the {{ and }} markers, so my options are limited.
I’d like to do an os.popen('id').read() at the very least but ( and ) are blocked so that doesn’t work. Sending a referer with variations of the (id).read() string didn’t work.
Using __getchilditem__ syntax makes some progress but quickly runs out of space.
It could well be a rabbit hole. Right now I have no way to tell.
However it is a lab on Jinja2 exploitation so I think XSS isn’t really part of the lab builders plans.
SSTI is a subset of XSS
As for the rest, the only bracket bypass I can think of uses parenthesis… somehow the backend must be using them or else would not be able to run. That means there is prefiltering prior to hitting the template… have you looked into py modules that do this?
Yeah - the content filtering happens before the data is sent through to the Jinja2 part. As far as I can tell its a custom set of filtering and it creates all kinds of issues.
For example, any attempt to submit a request with (),[],%, ,+, \, " (and a few other symbols) is rejected before it gets to the engine. It also rejects various encodings to try and sneak them past.
I figure you would have told us already if you knew (mainly a bump excuse), but were you able to narrow down what the filter is likely built on? Is it getting filtered in the web app, a modification to the backend server running Jinja2, python, etc.?
The filter is the first stage of the application, the exploit path is built on an authentication form. If you create a user who already exists, the subsequent messages are passed through the app to an SSTI-vulnerable application.
For example, if you create the first user as {{'7'*7}}@example.com, nothing happens. If you then resend a user creation request with the same email, you get a message saying 77777@example.com already exists.
What this means is that the first creation has to work, which means it has to get through the filtering in place on that stage - this largely excludes anything I’ve tried .