From 9cd0157d4685a185d1645ebfe4a4a76af1d07ef9 Mon Sep 17 00:00:00 2001 From: Marmeus Date: Tue, 20 Jan 2026 12:56:11 +0000 Subject: [PATCH] Added usage of ollvm ofuscation --- Payload_Type/cazalla/Dockerfile | 5 +- .../cazalla/agent_functions/builder.py | 193 ++++++++++++++---- README.md | 10 +- 3 files changed, 168 insertions(+), 40 deletions(-) diff --git a/Payload_Type/cazalla/Dockerfile b/Payload_Type/cazalla/Dockerfile index 78363f0..9713d69 100644 --- a/Payload_Type/cazalla/Dockerfile +++ b/Payload_Type/cazalla/Dockerfile @@ -18,9 +18,12 @@ RUN apt-get update && \ apt-get install -y --no-install-recommends \ apt-utils ca-certificates git zip make build-essential \ libssl-dev zlib1g-dev libbz2-dev xz-utils tk-dev libffi-dev \ - liblzma-dev libsqlite3-dev protobuf-compiler mingw-w64 nasm && \ + liblzma-dev libsqlite3-dev protobuf-compiler mingw-w64 nasm docker.io && \ rm -rf /var/lib/apt/lists/* +# Create the /tmp/converter directory For OLLVM +RUN mkdir -p /tmp/converter + # --- Reconfirma pip y setuptools actualizados (ya viene, pero por si acaso) --- RUN python -m pip install --upgrade pip setuptools wheel diff --git a/Payload_Type/cazalla/cazalla/agent_functions/builder.py b/Payload_Type/cazalla/cazalla/agent_functions/builder.py index a4730c1..5950d2c 100644 --- a/Payload_Type/cazalla/cazalla/agent_functions/builder.py +++ b/Payload_Type/cazalla/cazalla/agent_functions/builder.py @@ -5,9 +5,14 @@ from mythic_container.PayloadBuilder import * from mythic_container.MythicCommandBase import * from mythic_container.MythicRPC import * import json -from distutils.dir_util import copy_tree +from distutils.dir_util import copy_tree,remove_tree import asyncio +import string, random, os, subprocess + +def generate_random_string(length=100): + chars = string.ascii_letters + string.digits # a-zA-Z0-9 + return ''.join(random.choices(chars, k=length)) class CazallaAgent(PayloadType): name = "Cazalla" @@ -43,6 +48,13 @@ class CazallaAgent(PayloadType): choices=["console", "file"], default_value="console" ), + BuildParameter( + name="ollvm_compilation", + parameter_type=BuildParameterType.ChooseOne, + description="OLLVM obfuscation", + choices=["0","1","2"], + default_value="0" + ) ] agent_path = pathlib.Path(".") / "cazalla" agent_icon_path = agent_path / "agent_functions" / "cazalla.png" @@ -51,7 +63,7 @@ class CazallaAgent(PayloadType): build_steps = [ BuildStep(step_name="Gathering Files", step_description="Creating script payload"), BuildStep(step_name="Applying configuration", step_description="Updating configuration constants"), - BuildStep(step_name="Compiling", step_description="Compiling with mingw"), + BuildStep(step_name="Compiling", step_description="Compiling the code"), ] async def build(self) -> BuildResponse: @@ -192,6 +204,7 @@ class CazallaAgent(PayloadType): output_format = self.get_parameter("output") debug_level = self.get_parameter("debug_level") debug_output = self.get_parameter("debug_output") + ollvm_compilation = int(self.get_parameter("ollvm_compilation")) config_path = f"{agent_build_path.name}/agent_code/cazalla/Config.h" @@ -248,51 +261,155 @@ class CazallaAgent(PayloadType): StepSuccess=True )) - # Determine build target and filename based on output format and debug settings - if debug_level == "none": - make_target = output_format - output_filename = f"cazalla.{output_format}" - make_flags = "" - else: - make_target = f"debug_{output_format}" - output_filename = f"cazalla-debug.{output_format}" - # Pass debug level and output type to Makefile - # The Makefile will convert string values to numbers - make_flags = f"DEBUG_LEVEL={debug_level} DEBUG_OUTPUT={debug_output}" + # Local Compilation (without OLLVM) + if ollvm_compilation == 0: + # Determine build target and filename based on output format and debug settings + if debug_level == "none": + make_target = output_format + output_filename = f"cazalla.{output_format}" + make_flags = "" + else: + make_target = f"debug_{output_format}" + output_filename = f"cazalla-debug.{output_format}" + # Pass debug level and output type to Makefile + # The Makefile will convert string values to numbers + make_flags = f"DEBUG_LEVEL={debug_level} DEBUG_OUTPUT={debug_output}" - command = f"make -C {agent_build_path.name}/agent_code/cazalla {make_target} {make_flags}" - filename = f"{agent_build_path.name}/agent_code/cazalla/build/{output_filename}" + command = f"make -C {agent_build_path.name}/agent_code/cazalla {make_target} {make_flags}" + filename = f"{agent_build_path.name}/agent_code/cazalla/build/{output_filename}" - proc = await asyncio.create_subprocess_shell( - command, - stdout=asyncio.subprocess.PIPE, - stderr=asyncio.subprocess.PIPE - ) + proc = await asyncio.create_subprocess_shell( + command, + stdout=asyncio.subprocess.PIPE, + stderr=asyncio.subprocess.PIPE + ) - stdout, stderr = await proc.communicate() + stdout, stderr = await proc.communicate() - compile_output = stdout.decode() if stdout else "" - compile_errors = stderr.decode() if stderr else "" + compile_output = stdout.decode() if stdout else "" + compile_errors = stderr.decode() if stderr else "" - if proc.returncode != 0: + if proc.returncode != 0: + await SendMythicRPCPayloadUpdatebuildStep(MythicRPCPayloadUpdateBuildStepMessage( + PayloadUUID=self.uuid, + StepName="Compiling", + StepStdout=f"Compilation failed!\nSTDOUT:\n{compile_output}\n\nSTDERR:\n{compile_errors}", + StepSuccess=False + )) + resp.status = BuildStatus.Error + resp.build_message = f"Compilation failed: {compile_errors}" + return resp + + debug_info = f" (DEBUG: {debug_level}/{debug_output})" if debug_level != "none" else "" await SendMythicRPCPayloadUpdatebuildStep(MythicRPCPayloadUpdateBuildStepMessage( PayloadUUID=self.uuid, StepName="Compiling", - StepStdout=f"Compilation failed!\nSTDOUT:\n{compile_output}\n\nSTDERR:\n{compile_errors}", - StepSuccess=False + StepStdout=f"Successfully compiled cazalla{debug_info}\nCommand: {command}\nTarget: {make_target}\nFlags: {make_flags}\nOutput: {output_filename}", + StepSuccess=True )) - resp.status = BuildStatus.Error - resp.build_message = f"Compilation failed: {compile_errors}" - return resp - debug_info = f" (DEBUG: {debug_level}/{debug_output})" if debug_level != "none" else "" - await SendMythicRPCPayloadUpdatebuildStep(MythicRPCPayloadUpdateBuildStepMessage( - PayloadUUID=self.uuid, - StepName="Compiling", - StepStdout=f"Successfully compiled cazalla{debug_info}\nCommand: {command}\nTarget: {make_target}\nFlags: {make_flags}\nOutput: {output_filename}", - StepSuccess=True - )) + resp.payload = open(filename, "rb").read() + resp.build_message = f"Successfully built {output_filename}{debug_info}" - resp.payload = open(filename, "rb").read() - resp.build_message = f"Successfully built {output_filename}{debug_info}" + # OLLVM compilation in a Docker container + else: + container_name = generate_random_string(6) + docker_volume_folder = os.path.join("/", "tmp", "converter",container_name) + + # Translate debug variables to Docker container variables + # DEBUG_LEVEL: none=0, errors=1, warnings=2, info=3, all=4 + # DEBUG_OUTPUT: console=0, file=1 + debug_level_docker = debug_level.replace("none", "0") + debug_level_docker = debug_level.replace("errors", "1") + debug_level_docker = debug_level.replace("warnings", "2") + debug_level_docker = debug_level.replace("info", "3") + debug_level_docker = debug_level.replace("all", "4") + debug_output_docker = debug_output.replace("console", "0") + debug_output_docker = debug_output.replace("file", "1") + + # Ollvm parameters: + level_1_obfuscation_parameters = "-mllvm -fla -mllvm -bcf -mllvm -sub" + level_2_obfuscation_parameters = "-mllvm -sub -mllvm -sub_loop=3 -mllvm -split -mllvm -split_num=3 -mllvm -fla -mllvm -bcf -mllvm -bcf_loop=3 -mllvm -bcf_prob=40" + + if ollvm_compilation == 1: + obfuscation_parameters = level_1_obfuscation_parameters + elif ollvm_compilation == 2: + obfuscation_parameters = level_2_obfuscation_parameters + + # Compilation Command + compilation_command = f"clang -target x86_64-w64-mingw32 \ + -fuse-ld=lld \ + -DDEBUG_LEVEL={debug_level_docker} \ + -DDEBUG_OUTPUT={debug_output_docker} \ + {obfuscation_parameters} \ + -L/usr/lib/gcc/x86_64-w64-mingw32/13-posix \ + --sysroot=/usr/x86_64-w64-mingw32 \ + /tmp/cazalla/*.c \ + -o /tmp/cazalla/cazalla.exe \ + -lntdll -lgdi32 -lws2_32 -lcrypt32 -liphlpapi -lshlwapi -lole32 -luser32 -ladvapi32 \ + -lncrypt -lbcrypt -lversion -lnetapi32 -lwinhttp " + + # Create Docker Containter ollvm16-builder + create_container_command = [ + "docker", "run", + "--name", f"{container_name}", + "--volume", f"{docker_volume_folder}:/tmp/cazalla/", + "ollvm16-builder:latest", + "sh", "-c" ,compilation_command + ] + + + # Delete Docker Container + delete_container_command = [ + "docker", + f"fm {container_name}" + ] + + try: + # Move agent_build_path.name to docker_volume_folder + copy_tree(f"{agent_build_path.name}/agent_code/cazalla", docker_volume_folder) + + # Create Docker Container + result = subprocess.run(create_container_command, capture_output=True, text=True, check=True) + + if result.returncode != 0: + await SendMythicRPCPayloadUpdatebuildStep(MythicRPCPayloadUpdateBuildStepMessage( + PayloadUUID=self.uuid, + StepName="Compiling", + StepStdout=f"Error creating Docker Container: {result.stderr}", + StepSuccess=False + )) + resp.status = BuildStatus.Error + resp.build_message = f"Error creating Docker Container: {result.stderr}" + return resp + + # Get the output from the Docker Container + resp.payload = open(f"{docker_volume_folder}/cazalla.exe", "rb").read() + resp.build_message = "Successfully built!" + + await SendMythicRPCPayloadUpdatebuildStep(MythicRPCPayloadUpdateBuildStepMessage( + PayloadUUID=self.uuid, + StepName="Compiling", + StepStdout=f"Successfully built cazalla.exe", + StepSuccess=True + )) + + # Delete Docker Container + delete_container_command = await asyncio.create_subprocess_shell( + " ".join(delete_container_command), + stdout=asyncio.subprocess.PIPE, + stderr=asyncio.subprocess.PIPE + ) + remove_tree(docker_volume_folder) + remove_tree(str(self.agent_path)) + except Exception as e: + await SendMythicRPCPayloadUpdatebuildStep(MythicRPCPayloadUpdateBuildStepMessage( + PayloadUUID=self.uuid, + StepName="Compiling", + StepStdout=f"Error creating Docker Container: {e}", + StepSuccess=False + )) + resp.status = BuildStatus.Error + resp.build_message = f"Error creating Docker Container: {e}" + return resp return resp diff --git a/README.md b/README.md index 0f47542..9475e81 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,8 @@ This project was inspired by the article [How to build your own Mythic agent in ### Prerequisites 1. **Mythic Server** (v3.x or later) installed and running -2. Clone this repository +2. Build the [Docker Image ollvm](https://git.redteam/jesus.rodenas/ollvm-clang) in the Mythic server. + ### Install Cazalla on Mythic @@ -82,6 +83,13 @@ Or install from local directory: ./mythic-cli install folder /path/to/Cazalla ``` +Then, modify the Mythic `docker-compose.yaml`, adding the following volumnes in the "cazalla" service: + +``` +- /var/run/docker.sock:/var/run/docker.sock +- /tmp/converter:/tmp/converter +``` + ### Build the Agent Cazalla can be built directly from the Mythic UI: