|
|
|
@@ -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}\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
|
|
|
|
|