justCTF[*] 2020 - A Collection of Web Problems

This last weekend was justCTF 2020 (delayed last year so it was held this year :P), held by justCatTheFish. Although I was focused between this and some other work, I was able to look through a few of the web challenges and will document them here. Forgotten Name I found this on a total fluke. I wasn’t paying attention to the challenge much but the description was compelling: I’m hesitant to attempt to nmap all known domains of justCatTheFish’s network, and so instead thought about the nature of their subdomains. Every other challenge that required accessing a server was suffixed with the subdomain *.jctf.pro. I decided to search through certificate transparency logs with that subdomain to see what would come up, and a certain URL caught my eye: 6a7573744354467b633372545f6c34616b735f6f3070737d.web.jctf.pro/. It had the correct beginning characters and it ended in jctf.pro, and visiting it we see a small message: “OH! You found it! Thank you <3”. ...

Jan 31, 2021 · 1330 words · Vie

DragonCTF 2020: Harmony Chat

A writeup for the first web problem, “Harmony Chat”, in DragonCTF 2020. A very fun and interesting challenge! TL;DR Application is vulnerable to RCE via insecure deserialization on the /csp-report endpoint Use FTP active mode to SSRF a post request to /csp-report that would open a reverse shell on the application’s HTTP server Cat flag for profit Let’s Begin! The Harmony Chat is a Discord-esque chat app where you can /register an account and create channels. Once registered, you’re given your UID, which you use to /login or to invite other users into a channel you create. ...

Nov 22, 2020 · 1354 words · Vie

Hack.lu 2020: Confessions

This is a writeup for “Confessions”, the first web challenge I solved. I was luckily able to finish this challenge in a couple hours, so I could focus my attention to the other super interesting web problems. Confessions was a nice dive into some simple GraphQL manipulation and baby crypto. Let’s Begin! The confessions webpage was a message-generation application that would hash (in sha-256) your message based on the title and content of it. Under the hood we see the nature of how these messages are stored: ...

Oct 25, 2020 · 582 words · Vie

Trend Micro CTF: Raimund Genes Quals 2020

Last year, before I became an active participant in Maple Bacon, the team went on to participate in and land a top 10 position in Trend Micro 2019 Qualifiers, later going on to compete in the finals of that year. When the 2020 serving came up this weekend, I wanted to keep with tradition and maintain the pattern - and so we landed a top 10 position and will be going on ahead to the 2020 finals :) ...

Oct 4, 2020 · 1686 words · Vie

VolgaCTF Finals 2020

A reflection on VolgaCTF Finals, which I participated in with my team. We were the only North American team participating in the event, and for a good portion of the CTF, we held 1st place! Unfortunately, that didn’t last for the end of the competition. ...

Sep 19, 2020 · 521 words · Vie

GoogleCTF 2020: Pasteurize

This is the first challenge I worked on. I will soon upload a post on the second one. I completed this challenge with the help of my team mentor! Let’s Begin! The challenge lets us load into the DOM whatever we want through this pastebin-esque function. When you make a note, you have an option to share it with a “TjMike” Entity. Sign of XSS/CSRF attacks? _My input, "uwu", is shoved into a javascript string variable called 'note'. Further down we see a_ ``const clean`` _variable that calls DOMpurify to sanitize our input._ Looking into the HTML, whatever content we put into the note is immediately shoved into a javascript string. However, if you try to input quotation marks in there, the DOMpurify clean function escapes it. So, if we can get an unescaped quote in there, we can do whatever we want. Let’s focus on the comment. ...

Aug 23, 2020 · 378 words · Vie

HacktivityCon CTF: Bullseye

It’s clear to see from the content of my blog that my expertise lies in web-based exploits. ...

Aug 9, 2020 · 493 words · Vie

Cryptography and P vs. NP: A Basic Outline

Comic from XKCD. I am not an expert in either cryptography nor algorithm analysis. However, ever since a very rewarding advanced algorithm analysis class, one question has always dwelled in my mind: what would “P=NP” mean for cryptography? I had heard that such a statement, “P=NP” is controversial in the world of security. Learning about algorithm complexity has certainly shed quite a bit of light on the topic. As a cybersecurity researcher, I was compelled to satisfy my curiosity and answer that question for myself. ...

Jul 14, 2020 · 2000 words · Vie

RedPwnCTF 2020, Part 3

Part 3 of my writeup series for RedPwnCTF 2020! I checked out the web challenge known as “Viper”. Let’s Begin! Snakes are my favourite animal. And now, you can easily create ASCII-text snakes with the handy services provided by RedPwn: When we create our viper, its name is its viperId, which is a UUID. The source code is available for us in this challenge as well. The main file, server.js, defines multiple endpoints - but the one that caught my eye immediately was GET /admin/create. ...

Jul 2, 2020 · 1161 words · Vie

RedPwnCTF 2020, part 2

Part 2 of my writeup series for RedPwnCTF 2020! Let’s Begin! Tux-Fanpage points: 464 Ignoring the 1990’s aesthetic of the page, observe the provided script: const express = require('express') const path = require('path') const app = express() //Don't forget to redact from published source const flag = '[REDACTED]' app.get('/', (req, res) => { res.redirect('/page?path=index.html') }) app.get('/page', (req, res) => { let path = req.query.path //Handle queryless request if(!path || !strip(path)){ res.redirect('/page?path=index.html') return } path = strip(path) path = preventTraversal(path) res.sendFile(prepare(path), (err) => { if(err){ if (! res.headersSent) { try { res.send(strip(req.query.path) + ' not found') } catch { res.end() } } } }) }) //Prevent directory traversal attack function preventTraversal(dir){ if(dir.includes('../')){ let res = dir.replace('../', '') return preventTraversal(res) } //In case people want to test locally on windows if(dir.includes('..\\')){ let res = dir.replace('..\\', '') return preventTraversal(res) } return dir } //Get absolute path from relative path function prepare(dir){ return path.resolve('./public/' + dir) } //Strip leading characters function strip(dir){ const regex = /^[a-z0-9]$/im //Remove first character if not alphanumeric if(!regex.test(dir[0])){ if(dir.length > 0){ return strip(dir.slice(1)) } return '' } return dir } app.listen(3000, () => { console.log('listening on 0.0.0.0:3000') }) From this, the functions Strip() and preventTraversal() are important: ...

Jun 28, 2020 · 1889 words · Vie