I played the DefCamp CTF 2020 with 0x90r00t as an invited guest and we got first place. (2048€ cash prize + an additional 137€ out of pure luck thanks to a raffle they organized LOL)
I wrote these writeups for a few challenges I solved because they were required to be able to claim prizes, and I thought I might as well publish them here even though they're not very well-written and explained.
dumb-discord (misc)
In this challenge, we were given a .pyc file of a Discord Bot, i.e. a Python script compiled into Python bytecode.
Use uncompyle to get the source code. Some strings were obfuscated with a simple XOR; here's the deofbuscated script:
from discord.ext import commandsimport discord, jsonfrom discord.utils import getdefobfuscate(byt): mask =b'ctf{tryharderdontstring}' lmask =len(mask)returnbytes(c ^ mask[(i % lmask)] for i, c inenumerate(byt))deftest(s): data =obfuscate(s.encode())return dataintents = discord.Intents.default()intents.members =Truecfg =open('config.json', 'r')tmpconfig = cfg.read()cfg.close()config = json.loads(tmpconfig)token = config['token']client = commands.Bot(command_prefix='/')@client.eventasyncdefon_ready():print('Connected to bot: {}'.format(client.user.name))print('Bot ID: {}'.format(client.user.id))@client.command()asyncdefgetflag(ctx):await ctx.send('pongg')@client.eventasyncdefon_message(message):await client.process_commands(message)if'!ping'in message.content.lower():await message.channel.send("pongg")if"/getflag"in message.content.lower():if message.author.id ==783473293554352141: role = discord.utils.get((message.author.guild.roles), name=("dctf2020.cyberedu.ro")) member = discord.utils.get((message.author.guild.members), id=(message.author.id))if role in member.roles:await message.channel.send(test(config['flag']))if'/help'in message.content.lower():await message.channel.send("Try harder!")if'/s基ay'in message.content.lower():await message.channel.send(message.content.replace('/s基ay', '').replace("/getflag", ''))client.run(token)
We see that we can get the flag if the account with userid 783473293554352141 has the role dctf2020.cyberedu.ro and has /getflag in their message.
Let's see if we can invite this user by using a discord bot invite link :
Great, it works! Let's invite it to our own server, create a dctf2020.cyberedu.ro role and add it to the bot. Now we need to make it send /getflag on a public channel so that it receives its own message and prints the flag. The interesting part of the script is:
The challenge description says we have to look for coordinates. Let's check out the files (volatility -f spyagency3.bin --profile=Win7SP1x64 filescan). We can see interesting occurences, like:
Unzipping it reveals an interesting file: res/drawable/coordinates_can_be_found_here.jpg.
The flag is supposed to be ctf{sha256(location of the coordinates)}. We try a few answers as for the location, without success. Eventually, we look inside the file and discover what we were looking for:
The coordinates lead to a Pizza Hut in Romania. Flag is ctf{sha256(pizzahut)} !
cross me (web)
We were given a link to a web application, where can either login or sign up.
Register an account. There's a feature on the website that allows us to post messages, with a title and a description.
Let's try a basic XSS:
Okay, so we have to satisfy a certain regexp in our payload. But as soon as we manage to pass through it, another one comes up. In total, there are four regexps that need to be bypassed:
We are greeted with a PHPSESSID but... no flag on the admin page. We also try to exfiltrate the local storage or check out headers, but still nothing.
This must mean the admin can see things only they can see locally. Let's try to craft a payload which allows us to exfiltrate the content of a page of the site, as seen by the admin:
Good, we are able to retrieve the contents of the admin page, but... still no flag. It took us longer than expected, but we eventually understood we had to exfiltrate the blog post that had the id 1:
...which contains the flag! CTF{3B3E64A81963B5E3FAC7DE0CE63966F03559DAF4B61753AADBFBA76855DB5E5A}
syntax check (web)
In this challenge, we were given a web application and we were told The flag is in /var/www/html/flag.
The website only consists of a "Parse" button, which redirects to /parse?<foo>hi%21<%2Ffoo>=&_token=40rzOC3O8ZiBDeNKTGIcgRtxT5uBgMJb0jpBMdq8, and which only outputs "Empty string supplied as input.". Checking out the source of the page, we understand this is a Laravel error dump.
This is a weird way to pass XML content, though. Let's try sending it in the HTTP body rather than in the URL:
Okay, so we don't exactly know what's going on but our XML is parsed and "rendered". We immediately think of XXE injection:
<?xml version="1.0"?><!DOCTYPE root [<!ENTITY test SYSTEM 'file:///etc/passwd'>]>
<foo>&test;</foo>
This payload does leak /etc/passwd!
But once we want to exfiltrate the file of interest:
Some kind of filter prevents us from getting its contents...
Let's try a classic PHP filter and some path obfuscation: