| 
									
										
										
										
											2024-02-12 18:18:57 +00:00
										 |  |  | from datetime import datetime | 
					
						
							|  |  |  | import yaml | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | version = \ | 
					
						
							| 
									
										
										
										
											2024-03-22 15:48:40 +00:00
										 |  |  |     """# T-Pot Service Builder v0.21
 | 
					
						
							| 
									
										
										
										
											2024-02-12 18:18:57 +00:00
										 |  |  |      | 
					
						
							| 
									
										
										
										
											2024-02-13 18:02:40 +00:00
										 |  |  |     This script is intended as a kickstarter for users who want to build a customized docker-compose.yml for use with T-Pot. | 
					
						
							| 
									
										
										
										
											2024-02-12 18:18:57 +00:00
										 |  |  |      | 
					
						
							|  |  |  |     T-Pot Service Builder will ask you for all the docker services you wish to include in your docker-compose configuration file. | 
					
						
							|  |  |  |     The configuration file will be checked for conflicting ports as some of the honeypots are meant to work on certain ports. | 
					
						
							|  |  |  |     You have to manually resolve the port conflicts or re-run the script and exclude the conflicting services / honeypots. | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     Review the resulting configuration and adjust the port settings to your needs by (un)commenting the corresponding lines in the config. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | header = \ | 
					
						
							| 
									
										
										
										
											2024-03-22 15:48:40 +00:00
										 |  |  | """# T-Pot: CUSTOM EDITION
 | 
					
						
							|  |  |  | # Generated on: {current_date} | 
					
						
							|  |  |  | """
 | 
					
						
							| 
									
										
										
										
											2024-02-12 18:18:57 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | config_filename = "tpot_services.yml" | 
					
						
							|  |  |  | service_filename = "docker-compose-custom.yml" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def load_config(filename): | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         with open(filename, 'r') as file: | 
					
						
							|  |  |  |             config = yaml.safe_load(file) | 
					
						
							|  |  |  |     except: | 
					
						
							|  |  |  |         print_color(f"Error: {filename} not found. Exiting.", "red") | 
					
						
							|  |  |  |         exit() | 
					
						
							|  |  |  |     return config | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def prompt_service_include(service_name): | 
					
						
							|  |  |  |     while True: | 
					
						
							|  |  |  |         response = input(f"Include {service_name}? (y/n): ").strip().lower() | 
					
						
							|  |  |  |         if response in ['y', 'n']: | 
					
						
							|  |  |  |             return response == 'y' | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             print("Please enter 'y' for yes or 'n' for no.") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def check_port_conflicts(selected_services): | 
					
						
							| 
									
										
										
										
											2024-02-13 18:02:40 +00:00
										 |  |  |     all_ports = {} | 
					
						
							|  |  |  |     conflict_ports = [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for service_name, config in selected_services.items(): | 
					
						
							| 
									
										
										
										
											2024-02-12 18:18:57 +00:00
										 |  |  |         ports = config.get('ports', []) | 
					
						
							|  |  |  |         for port in ports: | 
					
						
							|  |  |  |             # Split the port mapping and take only the host port part | 
					
						
							|  |  |  |             parts = port.split(':') | 
					
						
							| 
									
										
										
										
											2024-02-13 18:02:40 +00:00
										 |  |  |             host_port = parts[1] if len(parts) == 3 else (parts[0] if parts[1].isdigit() else parts[1]) | 
					
						
							| 
									
										
										
										
											2024-02-12 18:18:57 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-13 18:02:40 +00:00
										 |  |  |             # Check for port conflict and associate it with the service name | 
					
						
							| 
									
										
										
										
											2024-02-12 18:18:57 +00:00
										 |  |  |             if host_port in all_ports: | 
					
						
							| 
									
										
										
										
											2024-02-13 18:02:40 +00:00
										 |  |  |                 conflict_ports.append((service_name, host_port)) | 
					
						
							|  |  |  |                 if all_ports[host_port] not in [service for service, _ in conflict_ports]: | 
					
						
							|  |  |  |                     conflict_ports.append((all_ports[host_port], host_port)) | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 all_ports[host_port] = service_name | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if conflict_ports: | 
					
						
							|  |  |  |         print_color("Port conflict(s) detected:", "red") | 
					
						
							|  |  |  |         for service, port in conflict_ports: | 
					
						
							|  |  |  |             print_color(f"{service}: {port}", "red") | 
					
						
							|  |  |  |         return True | 
					
						
							| 
									
										
										
										
											2024-02-12 18:18:57 +00:00
										 |  |  |     return False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-13 18:02:40 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-12 18:18:57 +00:00
										 |  |  | def print_color(text, color): | 
					
						
							|  |  |  |     colors = { | 
					
						
							|  |  |  |         "red": "\033[91m", | 
					
						
							|  |  |  |         "green": "\033[92m", | 
					
						
							|  |  |  |         "end": "\033[0m", | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     print(f"{colors[color]}{text}{colors['end']}") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def enforce_dependencies(selected_services, services): | 
					
						
							|  |  |  |     # If snare or any tanner services are selected, ensure all are enabled | 
					
						
							|  |  |  |     tanner_services = {'snare', 'tanner', 'tanner_redis', 'tanner_phpox', 'tanner_api'} | 
					
						
							|  |  |  |     if tanner_services.intersection(selected_services): | 
					
						
							| 
									
										
										
										
											2024-02-13 18:02:40 +00:00
										 |  |  |         print_color("For Snare / Tanner to work all required services have been added to your configuration.", "green") | 
					
						
							| 
									
										
										
										
											2024-02-12 18:18:57 +00:00
										 |  |  |         for service in tanner_services: | 
					
						
							|  |  |  |             selected_services[service] = services[service] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # If kibana is enabled, also enable elasticsearch | 
					
						
							|  |  |  |     if 'kibana' in selected_services: | 
					
						
							|  |  |  |         selected_services['elasticsearch'] = services['elasticsearch'] | 
					
						
							| 
									
										
										
										
											2024-02-13 18:02:40 +00:00
										 |  |  |         print_color("Kibana requires Elasticsearch which has been added to your configuration.", "green") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # If spiderfoot is enabled, also enable nginx | 
					
						
							|  |  |  |     if 'spiderfoot' in selected_services: | 
					
						
							|  |  |  |         selected_services['nginx'] = services['nginx'] | 
					
						
							|  |  |  |         print_color("Spiderfoot requires Nginx which has been added to your configuration.","green") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-12 18:18:57 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # If any map services are detected, enable logstash, elasticsearch, nginx, and all map services | 
					
						
							|  |  |  |     map_services = {'map_web', 'map_redis', 'map_data'} | 
					
						
							|  |  |  |     if map_services.intersection(selected_services): | 
					
						
							| 
									
										
										
										
											2024-02-13 18:02:40 +00:00
										 |  |  |         print_color("For Map to work all required services have been added to your configuration.", "green") | 
					
						
							| 
									
										
										
										
											2024-02-12 18:18:57 +00:00
										 |  |  |         for service in map_services.union({'elasticsearch', 'nginx'}): | 
					
						
							|  |  |  |             selected_services[service] = services[service] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # honeytrap and glutton cannot be active at the same time, always vote in favor of honeytrap | 
					
						
							|  |  |  |     if 'honeytrap' in selected_services and 'glutton' in selected_services: | 
					
						
							|  |  |  |         # Remove glutton and notify | 
					
						
							|  |  |  |         del selected_services['glutton'] | 
					
						
							| 
									
										
										
										
											2024-02-13 18:02:40 +00:00
										 |  |  |         print_color("Honeytrap and Glutton cannot be active at the same time. Glutton has been removed from your configuration.","red") | 
					
						
							| 
									
										
										
										
											2024-02-12 18:18:57 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def remove_unused_networks(selected_services, services, networks): | 
					
						
							|  |  |  |     used_networks = set() | 
					
						
							|  |  |  |     # Identify networks used by selected services | 
					
						
							|  |  |  |     for service_name in selected_services: | 
					
						
							|  |  |  |         service_config = services[service_name] | 
					
						
							|  |  |  |         if 'networks' in service_config: | 
					
						
							|  |  |  |             for network in service_config['networks']: | 
					
						
							|  |  |  |                 used_networks.add(network) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Remove unused networks | 
					
						
							|  |  |  |     for network in list(networks): | 
					
						
							|  |  |  |         if network not in used_networks: | 
					
						
							|  |  |  |             del networks[network] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def main(): | 
					
						
							|  |  |  |     config = load_config(config_filename) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Separate services and networks | 
					
						
							|  |  |  |     services = config['services'] | 
					
						
							|  |  |  |     networks = config.get('networks', {}) | 
					
						
							|  |  |  |     selected_services = {'tpotinit': services['tpotinit'], | 
					
						
							|  |  |  |                          'logstash': services['logstash']}  # Always include tpotinit and logstash | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for service_name, service_config in services.items(): | 
					
						
							|  |  |  |         if service_name not in selected_services:  # Skip already included services | 
					
						
							|  |  |  |             if prompt_service_include(service_name): | 
					
						
							|  |  |  |                 selected_services[service_name] = service_config | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Enforce dependencies | 
					
						
							|  |  |  |     enforce_dependencies(selected_services, services) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Remove unused networks based on selected services | 
					
						
							|  |  |  |     remove_unused_networks(selected_services, services, networks) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     output_config = { | 
					
						
							|  |  |  |         'version': '3.9', | 
					
						
							|  |  |  |         'networks': networks, | 
					
						
							|  |  |  |         'services': selected_services, | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     current_date = datetime.now().strftime("%Y-%m-%d %H:%M:%S") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     with open(service_filename, 'w') as file: | 
					
						
							|  |  |  |         file.write(header.format(current_date=current_date)) | 
					
						
							|  |  |  |         yaml.dump(output_config, file, default_flow_style=False, sort_keys=False, indent=2) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if check_port_conflicts(selected_services): | 
					
						
							|  |  |  |         print_color(f"Adjust the conflicting ports in the {service_filename} or re-run the script and select services that do not occupy the same port(s).", | 
					
						
							|  |  |  |             "red") | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         print_color(f"Custom {service_filename} has been generated without port conflicts.", "green") | 
					
						
							|  |  |  |     print(f"Copy {service_filename} to tpotce/ and test with: docker compose -f {service_filename} up") | 
					
						
							|  |  |  |     print(f"If everything works, exit with CTRL-C and replace docker-compose.yml with the new config.") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | if __name__ == "__main__": | 
					
						
							|  |  |  |     print(version) | 
					
						
							|  |  |  |     main() |