def delete_container_task(container_vul, user_info, request_ip): """ 删除漏洞容器 :param container_vul: container vul :param user_info: user info :param request_ip: request ip :return: """ user_id = user_info.id task_id = create_delete_container_task(container_vul=container_vul, user_info=user_info) if user_info.is_superuser or user_id == container_vul.user_id: operation_args = ContainerVulSerializer(container_vul).data sys_log = SysLog(user_id=user_id, operation_type="容器", operation_name="删除", ip=request_ip, operation_value=operation_args["vul_name"], operation_args=json.dumps(operation_args)) sys_log.save() # 下发停止容器任务 delete_container.delay(task_id) else: task_info = TaskInfo.objects.filter(task_id=task_id).first() task_info.task_msg = json.dumps(R.build(msg="权限不足")) task_info.task_status = 3 task_info.update_date = timezone.now() task_info.save() return task_id
def delete_image(self, request, pk=None): user = request.user if not pk or pk == "undefined": return JsonResponse(R.build(msg="环境不存在")) if not user.is_superuser: return JsonResponse(R.build(msg="权限不足")) try: layout = Layout.objects.filter(layout_id=pk).first() if not layout: return JsonResponse(R.build(msg="环境不存在")) layout_name = layout.layout_name layout_id = str(layout.layout_id) layout_path = os.path.join(DOCKER_COMPOSE, layout_id) with transaction.atomic(): _tmp_file_path = "docker-compose" + layout_path.replace( DOCKER_COMPOSE, "") layout_data = LayoutData.objects.filter( layout_id=layout, file_path=_tmp_file_path).first() if layout_data and layout_data.status == 'running': return JsonResponse(R.build(msg="环境正在运行中,请首先停止运行")) # 删除分数 LayoutServiceContainerScore.objects.filter( layout_id=layout).delete() # 删除容器 if layout_data: LayoutServiceContainer.objects.filter( layout_user_id=layout_data) # 删除服务网卡 service_list = LayoutService.objects.filter(layout_id=layout) if len(service_list) > 0: for service in service_list: # service_id = service.service_id LayoutServiceNetwork.objects.filter( service_id=service).delete() # 删除服务 LayoutService.objects.filter(layout_id=layout).delete() # 删除内容 layout.delete() # 删除文件和文件夹 shutil.rmtree(layout_path) request_ip = get_request_ip(request) sys_log = SysLog(user_id=user.id, operation_type="编排环境", operation_name="删除", operation_value=layout_name, operation_args=json.dumps( LayoutSerializer(layout).data), ip=request_ip) sys_log.save() except Exception as e: traceback.print_exc() return JsonResponse(R.err()) return JsonResponse(R.ok())
def flag_layout(self, request, pk=None): if not pk or pk == "undefined": return JsonResponse(R.build(msg="环境不存在")) user = request.user layout_info = Layout.objects.filter(layout_id=pk, is_release=True).first() if not layout_info: return JsonResponse(R.build(msg="环境不存在或未发布")) flag = str(request.GET.get("flag", "")) if not flag: return JsonResponse(R.build(msg="Flag 不能为空")) if not flag.startswith("flag-{bmh"): return JsonResponse(R.build(msg="Flag 格式不正确")) layout_path = os.path.join(DOCKER_COMPOSE, str(layout_info.layout_id)) layout_data = LayoutData.objects.filter( layout_id=layout_info, file_path="docker-compose" + layout_path.replace(DOCKER_COMPOSE, ""), ).first() service_container = LayoutServiceContainer.objects.filter( layout_user_id=layout_data, container_flag=flag).first() if not service_container: return JsonResponse(R.build(msg="Flag 不正确")) service_container_score = LayoutServiceContainerScore.objects.filter( user_id=user.id, flag=flag, service_container_id=service_container).first() if not service_container_score: service_info = service_container.service_id image_info = service_container.image_id service_container_score = LayoutServiceContainerScore( layout_service_container_score_id=uuid.uuid4(), user_id=user.id, layout_id=layout_info, layout_data_id=layout_data, service_id=service_info, image_id=image_info, create_date=timezone.now(), service_container_id=service_container, flag=flag, update_date=timezone.now()) service_container_score.save() request_ip = get_request_ip(request) sys_log = SysLog(user_id=user.id, operation_type="编排环境", operation_name="提交Flag", operation_value=layout_info.layout_name, operation_args=json.dumps({"flag": flag}), ip=request_ip) sys_log.save() return JsonResponse(R.ok())
def share_image_task(image_info, user_info, request_ip): """ 共享镜像 :param image_info: 镜像信息 :param user_info: 用户信息 :param request_ip: 请求 IP :return: """ task_id = create_share_image_task(image_info=image_info, user_info=user_info) operation_args = ImageInfoSerializer(image_info).data sys_log = SysLog(user_id=user_info.id, operation_type="镜像", operation_name="分享", ip=request_ip, operation_value=operation_args["image_vul_name"], operation_args=json.dumps(operation_args)) sys_log.save() share_image.delay(task_id) return task_id
def create_container_task(container_vul, user_info, request_ip): """ 创建漏洞容器 :param container_vul: container vul :param user_info: user info :param request_ip: request ip :return: """ image_info = container_vul.image_id user_id = user_info.id task_id = create_run_container_task(container_vul, user_info) if user_info.is_superuser or user_id == container_vul.user_id: operation_args = ImageInfoSerializer(image_info).data sys_log = SysLog(user_id=user_id, operation_type="容器", operation_name="启动", ip=request_ip, operation_value=operation_args["image_vul_name"], operation_args=json.dumps(operation_args)) sys_log.save() setting_config = get_setting_config() try: countdown = int(setting_config["time"]) except: countdown = int(DEFAULT_CONFIG["time"]) if countdown == 0: run_container.delay(container_vul.container_id, user_id, task_id, countdown) elif countdown != 0 and countdown > 60: # run_container(container_vul.container_id, user_id, task_id, countdown) setting_config = get_setting_config() if 'del_container' in setting_config: del_container = setting_config['del_container'] if not del_container or del_container == 0 or del_container == '0': add_chain_sig = chain(run_container.s(container_vul.container_id, user_id, task_id, countdown) | stop_container.s().set(countdown=countdown)) else: add_chain_sig = chain(run_container.s(container_vul.container_id, user_id, task_id, countdown) | delete_container.s().set(countdown=countdown)) add_chain_sig.apply_async() else: task_info = TaskInfo.objects.filter(task_id=task_id).first() task_info.task_msg = json.dumps(R.build(msg="停止时间最小为 1 分钟")) task_info.task_status = 4 task_info.update_date = timezone.now() task_info.save() else: task_info = TaskInfo.objects.filter(task_id=task_id).first() task_info.task_msg = json.dumps(R.build(msg="权限不足")) task_info.task_status = 3 task_info.update_date = timezone.now() task_info.save() return task_id
def stop_layout(self, request, pk=None): if not pk or pk == "undefined": return JsonResponse(R.build(msg="环境不存在")) user = request.user if not user.is_superuser: return JsonResponse(R.build(msg="权限不足")) layout_info = Layout.objects.filter(layout_id=pk, is_release=True).first() if not layout_info: return JsonResponse(R.build(msg="环境不存在或未发布")) layout_id = str(layout_info.layout_id) layout_path = os.path.join(DOCKER_COMPOSE, layout_id) layout_data = LayoutData.objects.filter( layout_id=layout_info, file_path="docker-compose" + layout_path.replace(DOCKER_COMPOSE, ""), ).first() if not layout_data: return JsonResponse(R.build(msg="环境未启动,无法停止")) if not os.path.exists(layout_path): return JsonResponse(R.ok()) if layout_data.status == "stop": return JsonResponse(R.ok()) try: with transaction.atomic(): container_list = get_project(layout_path).stop() if container_list: for container in container_list: container_id = container.id LayoutServiceContainer.objects.filter(docker_container_id=container_id) \ .update(container_status="stop") LayoutServiceContainer.objects.filter( layout_user_id=layout_data).update(container_status="stop") layout_data.status = "stop" layout_data.save() except Exception as e: return JsonResponse(R.err()) request_ip = get_request_ip(request) sys_log = SysLog(user_id=user.id, operation_type="编排环境", operation_name="停止", operation_value=layout_info.layout_name, operation_args=json.dumps( LayoutSerializer(layout_info).data), ip=request_ip) sys_log.save() return JsonResponse(R.ok())
def create_image_task(image_info, user_info, request_ip, image_file=None): """ 创建镜像任务 """ user_id = user_info.id task_id = create_create_image_task(image_info=image_info, user_info=user_info) if user_info.is_superuser: image_name = image_info.image_name image_desc = image_info.image_desc image_vul_name = image_info.image_vul_name image_rank = image_info.rank task_info = TaskInfo.objects.filter(task_id=task_id).first() if image_file: task_msg = {} try: file_info = image_file.read() images = client.images.load(file_info) image = images[0] repo_tags = image.attrs["RepoTags"] if len(repo_tags) == 0: # 移除本地镜像 try: client.images.remove(image.id) except Exception as e: pass task_msg = R.build(msg="文件镜像 Tag 不能为空") else: config = image.attrs["ContainerConfig"] port_list = [] if "ExposedPorts" in config: port_list = config["ExposedPorts"] ports = [] for port in port_list: port = port.replace("/", "").replace("tcp", "").replace("udp", "") ports.append(port) image_name = repo_tags[0] image_port = ",".join(ports) image_info = ImageInfo.objects.filter(image_name=image_name).first() if not image_info: image_info = ImageInfo() image_info.image_name = image_name image_info.image_port = image_port # image_vul_name image_info.image_vul_name = image_name.replace("vulfocus/","") if not image_vul_name else image_vul_name # image_desc image_info.image_desc = image_name.replace("vulfocus/","") if not image_desc else image_desc # rank image_info.rank = 2.5 if image_rank > 5 or image_rank < 0.5 else image_rank image_info.is_ok = True image_info.save() task_info.task_name = "拉取镜像:"+image_name task_info.task_status = 3 task_msg = R.ok(data="%s 添加成功" % (image_name, )) except Exception as e: traceback.print_exc() task_msg = R.err() try: image_info.delete() except: pass task_info.task_status = 4 finally: task_info.task_msg = json.dumps(task_msg) task_info.update_date = timezone.now() task_info.save() elif image_name: # 创建任务 # create_image(task_id=task_id) create_image.delay(task_id) else: R.build(msg="镜像文件或镜像名称不能为空") operation_args = ImageInfoSerializer(image_info).data sys_log = SysLog(user_id=user_id, operation_type="镜像", operation_name="创建", ip=request_ip, operation_value=operation_args["image_vul_name"], operation_args=json.dumps(operation_args)) sys_log.save() else: task_info = TaskInfo.objects.filter(task_id=task_id).first() task_info.task_msg = json.dumps(R.build(msg="权限不足")) task_info.task_status = 3 task_info.update_date = timezone.now() task_info.save() return task_id
def create(self, request, *args, **kwargs): """ 创建编排环境信息 """ user = request.user if user.is_superuser: data = request.POST.get("data", "") id = request.POST.get("id", "") name = request.POST.get("name", "") if not name: return JsonResponse(R.build(msg="名称不能为空")) desc = request.POST.get("desc", "") img = request.POST.get("img", "") if not data: return JsonResponse(R.build(msg="参数不能为空")) topo_data = json.loads(data) if topo_data == {}: return JsonResponse(R.build(msg="编排环境不能为空")) nodes = topo_data["nodes"] if not nodes or len(nodes) == 0: return JsonResponse(R.build(msg="节点不能为空")) connectors = topo_data["connectors"] check_open = False container_list = [] network_dict = {} check_network_name_list = [] for node in nodes: node_id = node["id"] node_type = node["type"] node_attrs = node["attrs"] if len(node_attrs) == 0: return JsonResponse(R.build(msg="节点属性不能为空")) if node_type == "Container": node_open = node_attrs["open"] node_port = node_attrs["port"] if node_open and node_port: check_open = True container_list.append(node) elif node_type == "Network": network_name = node_attrs["name"] if not network_name: return JsonResponse(R.build(msg="网卡不能为空")) if network_name in check_network_name_list: return JsonResponse(R.build(msg="不能重复设置网卡")) check_network_name_list.append(network_name) network_dict[node_id] = node if node_attrs == {}: return JsonResponse(R.build(msg="网卡或容器属性不能为空")) if not check_open: return JsonResponse(R.build(msg="请开放可访问入口")) if len(container_list) == 0: return JsonResponse(R.build(msg="容器环境不能为空")) if len(network_dict) == 0: for container in container_list: if not container["attrs"]["open"]: return JsonResponse( R.build(msg="在不配置网卡段情况下请保证所有的环境开放访问权限")) else: if not connectors or len(connectors) == 0: return JsonResponse(R.build(msg="在配置网卡的情况下连接点不能为空")) try: yml_content = build_yml(container_list=container_list, network_dict=network_dict, connector_list=connectors) yml_data = yml_content["content"] env_data = yml_content["env"] env_content = "" if len(env_data) > 0: env_content = "\n".join(env_data) with transaction.atomic(): operation_name = "创建" if id: layout = Layout.objects.filter(layout_id=id).first() operation_name = "修改" else: layout = Layout(layout_id=uuid.uuid4(), create_date=timezone.now(), update_date=timezone.now()) layout_data = LayoutData.objects.filter( layout_id=layout).first() if layout_data and layout_data.status == 'running': return JsonResponse(R.build(msg="环境正在运行中,请首先停止运行")) layout.layout_name = name layout.layout_desc = desc layout.create_user_id = user.id layout.image_name = img layout.raw_content = json.dumps(topo_data, ensure_ascii=False) layout.yml_content = yaml.dump(yml_content["content"]) layout.env_content = env_content # 保存到数据库中 layout.save() # 删除相关原有的服务数据 layout_service_list = list( LayoutService.objects.filter( layout_id=layout).values("service_id")) # 删除网卡相关数据 services = yml_data["services"] for service_name in services: service = services[service_name] image = service["image"] image_info = ImageInfo.objects.filter( image_name=image).first() if not image_info: return JsonResponse( R.build(msg="%s 镜像不存在" % (image, ))) is_exposed = False ports = "" if "ports" in service and len(service["ports"]) > 0: is_exposed = True if image_info.image_port: ports = ",".join( str(image_info.image_port).split(",")) layout_service = LayoutService.objects.filter( layout_id=layout, service_name=service_name).first() if not layout_service: layout_service = LayoutService( service_id=uuid.uuid4(), layout_id=layout, service_name=service_name, create_date=timezone.now(), update_date=timezone.now()) if { "service_id": layout_service.service_id } in layout_service_list: layout_service_list.remove( {"service_id": layout_service.service_id}) layout_service.image_id = image_info layout_service.service_name = service_name layout_service.is_exposed = is_exposed layout_service.exposed_source_port = ports layout_service.save() if "networks" not in service: continue networks = service["networks"] service_network_list = list( LayoutServiceNetwork.objects.filter( service_id=layout_service).values( 'layout_service_network_id')) for network in networks: network_info = NetWorkInfo.objects.filter( net_work_name=network).first() if not network_info: return JsonResponse( R.build(msg="%s 网卡不存在" % (network, ))) service_network = LayoutServiceNetwork.objects.filter( service_id=layout_service, network_id=network_info, ).first() if not service_network: service_network = LayoutServiceNetwork( layout_service_network_id=uuid.uuid4(), service_id=layout_service, network_id=network_info, create_date=timezone.now(), update_date=timezone.now()) if { "layout_service_network_id": service_network.layout_service_network_id } in service_network_list: service_network_list.remove({ "layout_service_network_id": service_network.layout_service_network_id }) service_network.save() # 删除已经不存在的网卡 if len(service_network_list) > 0: for service_network in service_network_list: LayoutServiceNetwork.objects.filter( layout_service_network_id=service_network[ 'layout_service_network_id']).delete() # 删除服务数据 for layout_service in layout_service_list: service_id = layout_service['service_id'] # 删除服务数据 LayoutService.objects.filter( service_id=service_id, layout_id=layout).delete() if layout_data: # 删除启动容器 LayoutServiceContainer.objects.filter(service_id=service_id, layout_user_id=layout_data). \ delete() # 删除分数 LayoutServiceContainerScore.objects.filter( layout_id=layout, layout_data_id=layout_data, service_id=service_id).delete() else: # 删除启动容器 LayoutServiceContainer.objects.filter( service_id=service_id).delete() # 删除分数 LayoutServiceContainerScore.objects.filter( layout_id=layout, service_id=service_id).delete() request_ip = get_request_ip(request) sys_log = SysLog(user_id=user.id, operation_type="编排环境", operation_name=operation_name, operation_value=name, operation_args=json.dumps( LayoutSerializer(layout).data), ip=request_ip) sys_log.save() except Exception as e: return JsonResponse(R.err(msg="服务器内部错误,请联系管理员")) return JsonResponse(R.ok()) else: return JsonResponse(R.build(msg="权限不足"))
def run_layout(self, request, pk=None): if not pk or pk == "undefined": return JsonResponse(R.build(msg="环境不存在")) """ 运行环境 """ user = request.user if not user.is_superuser: return JsonResponse(R.build(msg="权限不足")) layout_info = Layout.objects.filter(layout_id=pk, is_release=True).first() if not layout_info: return JsonResponse(R.build(msg="环境不存在或未发布")) yml_content = layout_info.yml_content env_content = layout_info.env_content layout_id = str(layout_info.layout_id) layout_path = os.path.join(DOCKER_COMPOSE, layout_id) try: env_content = get_random_port(env_content) except Exception as e: return JsonResponse(R.build(msg=str(e))) open_host_list = [] raw_con = json.loads(layout_info.raw_content) network_list = client.networks.list() net_list = [] network_names = [ item['attrs']['name'] for item in raw_con['nodes'] if item['name'] == "Network" ] for i in network_list: net_list.append(i.attrs['Name']) for network_name in network_names: if network_name in net_list: pass else: try: network_det = NetWorkInfo.objects.filter( net_work_name=network_name).first() ipam_pool = docker.types.IPAMPool( subnet=network_det.net_work_subnet, gateway=network_det.net_work_gateway) ipam_config = docker.types.IPAMConfig( pool_configs=[ipam_pool]) net_work = client.networks.create( network_det.net_work_name, driver=network_det.net_work_driver, ipam=ipam_config, scope=network_det.net_work_scope) net_work_client_id = str(net_work.id) if not network_det.net_work_gateway: net_work_gateway = net_work.attrs['IPAM']['Config'][ 'Gateway'] network_det.net_work_gateway = net_work_gateway network_det.net_work_client_id = net_work_client_id network_det.save() except Exception as e: return JsonResponse(R.build(msg=str(e))) try: with transaction.atomic(): _tmp_file_path = "docker-compose" + layout_path.replace( DOCKER_COMPOSE, "") layout_data = LayoutData.objects.filter( layout_id=layout_info, file_path=_tmp_file_path).first() if not layout_data: layout_data = LayoutData( layout_user_id=uuid.uuid4(), create_user_id=user.id, layout_id=layout_info, status="running", file_path="docker-compose" + layout_path.replace(DOCKER_COMPOSE, ""), create_date=timezone.now(), update_date=timezone.now()) else: layout_data.status = "running" if not os.path.exists(layout_path): os.makedirs(layout_path) docker_compose_file = os.path.join(layout_path, "docker-compose.yml") with open(docker_compose_file, "w", encoding="utf-8") as f: f.write(yml_content) env_file = os.path.join(layout_path, ".env") with open(env_file, "w", encoding="utf-8") as f: f.write("\n".join(env_content)) # 启动 container_list = get_project(layout_path).up() # 保存 layout_data.save() for container in container_list: docker_container_id = container.id service_id = container.service container_host = "" container_port = "" container_flag = "flag-{bmh%s}" % (uuid.uuid4(), ) docker_container = client.containers.get(container.id) service_info = LayoutService.objects.filter( service_name=service_id, layout_id=layout_info).first() if not service_info: raise Exception("环境服务不存在") image_info = service_info.image_id service_container = LayoutServiceContainer.objects.filter( service_id=service_info, user_id=user.id, layout_user_id=layout_data, image_id=image_info).first() if not service_container: service_container = LayoutServiceContainer( service_container_id=uuid.uuid4(), user_id=user.id, service_id=service_info, layout_user_id=layout_data, image_id=image_info, container_flag=container_flag, create_date=timezone.now()) else: container_flag = service_container.container_flag """ 写入 flag """ command = 'touch /tmp/%s' % (container_flag, ) execute_result = tasks.docker_container_run( docker_container, command) if execute_result["status"] == 500: raise Exception(execute_result["msg"]) container_ports = container.ports if len(container_ports) == 0: try: container_ports = docker_container.attrs[ "NetworkSettings"]["Ports"] except Exception as e: pass vul_host_list = [] if service_info.is_exposed: vul_ip = tasks.get_local_ip() else: vul_ip = "127.0.0.1" port_dict = {} if len(container_ports) > 0: for _tmp_port in container_ports: source_port = str(_tmp_port).replace( "/", "").replace("tcp", "").replace("udp", "") if container_ports[_tmp_port]: target_port = container_ports[_tmp_port][0][ "HostPort"] else: target_port = source_port port_dict[source_port] = target_port vul_host_list.append(vul_ip + ":" + target_port) if len(vul_host_list) > 0: container_host = ",".join(vul_host_list) if service_info.is_exposed: open_host_list.extend(vul_host_list) if len(port_dict) > 0: container_port = json.dumps(port_dict, ensure_ascii=False) # 连接 host service_container.container_host = container_host # 连接 端口 service_container.container_port = container_port container_status = execute_result["data"]["status"] service_container.docker_container_id = docker_container_id service_container.container_status = container_status service_container.update_date = timezone.now() service_container.save() except Exception as e: traceback.print_exc() return JsonResponse(R.build(msg=str(e))) result_data = { "layout": { "name": layout_info.layout_name, "desc": layout_info.layout_desc, }, "open": open_host_list } request_ip = get_request_ip(request) sys_log = SysLog(user_id=user.id, operation_type="编排环境", operation_name="启动", operation_value=layout_info.layout_name, operation_args=json.dumps( LayoutSerializer(layout_info).data), ip=request_ip) sys_log.save() return JsonResponse(R.ok(data=result_data))