UTCTF 2021

Lightning Round The first few web challenges were pretty trivial so I’ll do super quick, 2-sentence descriptions on how to solve them. Source it! Inspect source. You’ll find it. Oinker Make an oink with the exact same content and realize that each oink has an allocated place in the webpage’s directory. (Example - inputting alert(1); leads to oink endpoint 64). Go to \oink\2 to get the flag. Fastfox (easy way) Intended (hard) solution was escalating a JIT bug, which I will definitely research more of so expect part 2 ;) but the easy way was determining what functions were available in the scope of Bob’s jsshell. Some recon shows us that os.system() is in the scope, so os.system('cat flag.txt') gives you the flag. ...

Mar 14, 2021 · 607 words · Vie

DiceCTF 2021

Babier CSP The challenge takes after justCTF’s similarly named challenge. We’re given an index.js file: const express = require('express'); const crypto = require("crypto"); const config = require("./config.js"); const app = express() const port = process.env.port || 3000; const SECRET = config.secret; const NONCE = crypto.randomBytes(16).toString('base64'); const template = name => ` <html> ${name === '' ? '': `<h1>${name}</h1>`} <a href='#' id=elem>View Fruit</a> <script nonce=${NONCE}> elem.onclick = () => { location = "/?name=" + encodeURIComponent(["apple", "orange", "pineapple", "pear"][Math.floor(4 * Math.random())]); } </script> </html> `; app.get('/', (req, res) => { res.setHeader("Content-Security-Policy", `default-src none; script-src 'nonce-${NONCE}';`); res.send(template(req.query.name || "")); }) app.use('/' + SECRET, express.static(__dirname + "/secret")); app.listen(port, () => { console.log(`Example app listening at http://localhost:${port}`) }) The main difference between Dice’s challenge and justCatTheFish’s is the hashing of the NONCE value. When this script is executed, it sets the NONCE value once, and it doesn’t change values once this server is running. ...

Feb 7, 2021 · 2261 words · Vie

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

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

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

RedPwnCTF 2020

RedPwnCTF 2020 is a beginner to intermediate CTF that’s accessible to high school and college students. The CTF featured a range of easy to harder problems, which provided both a good introduction into CTFs and an opportunity to stretch your pre-established skills. I solved through a good portion of the web problems, and will document a few of the ones here. Let’s Begin! The problems are in no way ordered in terms of difficulty. ...

Jun 25, 2020 · 1139 words · Vie

CSAW 2019: Unagi

Back in 2019 I really got into CTFs as a matter of honing my security skills. They were fun to do and enriched my knowledge of cybersecurity - so I got into it pretty quickly. This was among the first of the challenges I did while under my team, Maple Bacon. At the time, I had plenty experience with SQL injections and XSS attacks, but not nearly enough experience with another common vulnerability: XXE attacks. CSAW 2019 sought to change that. ...

May 21, 2020 · 843 words · Vie