When ancient vaults meet modern vulnerabilities - A tale of git histories, leaked credentials, and the secrets that shouldn't be shared


Challenge Overview

The ProtoVault Breach investigation involves analyzing a Flask application breach where database credentials were leaked through git history. We need to identify the source of the leak and trace the attack path through multiple phases of forensic analysis.

Evidence provided:

  • Ransom email showing database access proof
  • Flask application source code with git history
  • Database backup files

Step-by-Step Investigation Process

Question 1: Database Connection String Analysis

Challenge: Determine if the leak could have come from the application. Review the database connection string to ensure it is secure. Submit the connection string here.

Investigation Steps:

  1. Examine the Flask application source code:

    cat app.py
    
  2. Look for database configuration around line 9:

    app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://assetdba:[REDACTED]@pgsql_prod_db01.protoguard.local/pgamgt?sslmode=verify-full'
    
  3. Analyze the connection string components:

    • Username: assetdba
    • Password: [REDACTED]
    • Host: pgsql_prod_db01.protoguard.local
    • Database: pgamgt

Accepted Answer:

postgresql://assetdba:[REDACTED]@pgsql_prod_db01.protoguard.local/pgamgt?sslmode=verify-full

Question 2: Source File Analysis

Challenge: Review the other source files. Which one may have leaked the database? Provide the file name.

Investigation Steps:

  1. Examine git commit history:

    git log --pretty=format:"%H %an %ad %s" --date=short --all
    

    Output shows suspicious pattern:

    ccd589a Walter 2025-08-17 Release candidate
    1cc71b0 Walter 2025-08-14 Remove backup scripts
    ef917bb Walter 2025-08-12 Add item details and notes forms
    2304052 Walter 2025-08-07 Add data models
    9544195 Walter 2025-08-06 database migration scripts
    
  2. Examine the "Remove backup scripts" commit:

    git show 1cc71b0fcfcdbfefc7b59cecd898f13b532acc35
    

    Shows deleted files:

    diff --git a/app/util/backup_db.py b/app/util/backup_db.py
    deleted file mode 100644
    index d1c22b6..0000000
    --- a/app/util/backup_db.py
    +++ /dev/null
    
  3. Checkout the commit before removal to see deleted content:

    git checkout 1cc71b0fcfcdbfefc7b59cecd898f13b532acc35~1
    
  4. List backup-related files:

    find . -name "*backup*" -o -name "*restore*"
    ls app/util/
    

    Files found:

    ./app/util/backup_db.py
    ./app/util/restore_db.py
    
  5. Examine the backup script content:

    cat app/util/backup_db.py
    

Complete backup script reveals infrastructure secrets:

#!/usr/bin/env python3
import paramiko
import boto3
import codecs
import os
from scp import SCPClient

# ==== CONFIGURATION ====
SSH_HOST = "pgsql_prod_db01.protoguard.local"
SSH_PORT = 22
SSH_USER = "dbadmin"
SSH_KEY = "/home/walter/.ssh/pgsql_key"

DB_NAME = "pgamgt"
DB_USER = "assetdba"
BACKUP_FILENAME = "db_backup.sql"
LOCAL_BACKUP = f"/tmp/{BACKUP_FILENAME}"
ENC_BACKUP = f"/tmp/{BACKUP_FILENAME}.xyz"

S3_BUCKET = "protoguard-asset-management"
S3_KEY = "db_backup.xyz"
S3_REGION = "us-east-2"

def create_ssh_client():
    client = paramiko.SSHClient()
    client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    client.connect(SSH_HOST, port=SSH_PORT, username=SSH_USER, key_filename=SSH_KEY)
    return client

def run_backup():
    ssh = create_ssh_client()
    dump_cmd = f"pg_dump -U {DB_USER} {DB_NAME} > /tmp/{BACKUP_FILENAME}"
    stdin, stdout, stderr = ssh.exec_command(dump_cmd)
    # Copy file locally and upload to S3
    with SCPClient(ssh.get_transport()) as scp:
        scp.get(f"/tmp/{BACKUP_FILENAME}", LOCAL_BACKUP)
    
def encode():
    with open(LOCAL_BACKUP, "r", encoding="utf-8", errors="ignore") as f:
        data = f.read()
    encoded = codecs.encode(data, "rot_13")
    with open(ENC_BACKUP, "w", encoding="utf-8") as f:
        f.write(encoded)

# ... rest of upload functionality
  1. Return to current state:
    git checkout main
    

Accepted Answer:

backup_db.py