-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
199ed67
commit 8de7c97
Showing
5 changed files
with
13 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
--- | ||
layout: post | ||
current: post | ||
cover: assets/squ1rrel/nisala/personal-website/cover.png | ||
cover: assets/squ1rrel/nisala/personal-website/cover.webp | ||
navigation: True | ||
title: "Personal Website" | ||
date: 2024-05-06 10:00:00 | ||
|
@@ -11,25 +11,27 @@ subclass: 'post' | |
author: nisala | ||
--- | ||
|
||
challenge description | ||
Check out my personal website! I have a blog! | ||
|
||
This was the hardest web challenge in the CTF, with only two solves. My favorite part about this challenge is that it kinda "punishes" you for thinking like a CTF player. This challenge doesn't respond well to throwing tools at the problem. Instead, you have to really understand the technology and its shortcomings, and take a methodical approach that's specific to the challenge itself. | ||
|
||
## Step 1: Getting our bearings | ||
|
||
This challenge has no source, so all we have to go off of is the website, https://blog.squ1rrel.dev. | ||
|
||
TODO INSERT PHOTO OF SITE | ||
![Image of the challenge website](/assets/squ1rrel/nisala/personal-website/challenge-site.png) | ||
|
||
Let's start by identifying its technologies. Using the chrome extension Wappalyzer, we can see that the site is hosted on Firebase. I'm not entirely sure how this extension is figuring this out, but there are a number of possibilities, from the IP it's connecting to (the primary Firebase load balancer), to the fact that blog.squ1rrel.dev has a CNAME record to a web.app URL (Firebase Hosting's subdomain). | ||
Let's start by identifying its technologies. Using the Chrome extension Wappalyzer, we can see that the site is hosted on Firebase. I'm not entirely sure how the extension is figuring this out, but there are a number of possibilities, from the IP it's connecting to (an easily-identifiable Firebase load balancer), to the fact that blog.squ1rrel.dev has a CNAME record to a web.app URL (Firebase Hosting's subdomain). | ||
|
||
We can also see that the challenge very clearly wants us to look at cloud storage. The blog post only has one image, and it's being loaded in from Firebase storage. The blog post also says they have "more in storage". So, let's do that. | ||
|
||
TODO INSERT IMAGE | ||
![Storage link in HTML](/assets/squ1rrel/nisala/personal-website/storage.png) | ||
|
||
## Step 2: Authentication | ||
|
||
There are two layers of authentication in this challenge -- authentication with Firebase as a web app, and authentication with Firebase as a user. Let's start with app authentication. | ||
|
||
In order for Firebase to know what app we're referencing, we need to pass it a config, which contains an API key and various access URLs. Thankfully, because this site is hosted on Firebase, that's easy to get. It's always at https://blog.squ1rrel.dev/__/firebase/init.json (among other places in these reserved URLs). | ||
In order for Firebase to know what app we're referencing, we need to pass it a config, which contains an API key and various access URLs. Thankfully, because this site is hosted on Firebase, that's easy to get. It's always at `https://blog.squ1rrel.dev/__/firebase/init.json` (among other places in these reserved URLs). | ||
|
||
```js | ||
const firebaseConfig = { | ||
|
@@ -51,9 +53,11 @@ const auth = getAuth(); | |
await createUserWithEmailAndPassword(auth, "[email protected]", "password"); | ||
``` | ||
|
||
And we're authenticated! | ||
|
||
## Step 3: Storage | ||
|
||
And we're fully authenticated! Now, it's time to get our files. Firebase Storage does technically have a way to stop users from enumerating the files in a storage bucket, but most people don't configure it. Instead, they just mark the bucket as "read-only", not realizing that "read" permissions also for some reason include "list" permissions. Thus, we can list the files in this bucket. | ||
Now, it's time to get our files. Firebase Storage does technically have a way to stop users from enumerating the files in a storage bucket, but most people don't configure it. Instead, they just mark the bucket as "read-only", not realizing that "read" permissions also for some reason include "list" permissions. Thus, we can list the files in this bucket. | ||
|
||
```js | ||
const storage = getStorage(app); | ||
|
@@ -95,4 +99,4 @@ for (let i = 0; i < flag.length; ++i) { | |
|
||
If the `set` fails, that means we guessed the wrong letter and need to try again. But if it succeeds, the letter is correct and we can move onto the next one. | ||
|
||
And with that, we have the flag! | ||
And with that, we have the flag! `squ1rrel{fIrebas3_hAs_s0me_interesting_qu1rks}` |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.