Skip to content
Merged
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
66 changes: 66 additions & 0 deletions Payload_Type/rango/rango/agent_code/src/commands.zig
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ pub const CommandExecutor = struct {
return try self.executeDownload(task);
} else if (std.mem.eql(u8, task.command, "upload")) {
return try self.executeUpload(task);
} else if (std.mem.eql(u8, task.command, "deletefile")) {
return try self.deleteFile(task);
} else if (std.mem.eql(u8, task.command, "deletedirectory")) {
return try self.deleteDirectory(task);
} else {
return MythicResponse{
.task_id = task.id,
Expand Down Expand Up @@ -248,4 +252,66 @@ pub const CommandExecutor = struct {
.status = "completed",
};
}

fn deleteFile(self: *CommandExecutor, task: MythicTask) !MythicResponse {
const Parameters = struct {
path: []const u8,
};
const parsed = try json.parseFromSlice(Parameters, self.allocator, task.parameters, .{});
defer parsed.deinit();
const path = parsed.value.path;
if (path.len == 0) {
return MythicResponse{
.task_id = task.id,
.user_output = "No path provided",
.completed = true,
.status = "error",
};
}
std.fs.deleteFileAbsolute(path) catch |err| {
return MythicResponse{
.task_id = task.id,
.user_output = try std.fmt.allocPrint(self.allocator, "Failed to delete file: {}", .{err}),
.completed = true,
.status = "error",
};
};
return MythicResponse{
.task_id = task.id,
.user_output = try std.fmt.allocPrint(self.allocator, "Deleted file: {s}", .{path}),
.completed = true,
.status = "completed",
};
}

fn deleteDirectory(self: *CommandExecutor, task: MythicTask) !MythicResponse {
const Parameters = struct {
path: []const u8,
};
const parsed = try json.parseFromSlice(Parameters, self.allocator, task.parameters, .{});
defer parsed.deinit();
const path = parsed.value.path;
if (path.len == 0) {
return MythicResponse{
.task_id = task.id,
.user_output = "No path provided",
.completed = true,
.status = "error",
};
}
std.fs.deleteTreeAbsolute(path) catch |err| {
return MythicResponse{
.task_id = task.id,
.user_output = try std.fmt.allocPrint(self.allocator, "Failed to delete directory: {}", .{err}),
.completed = true,
.status = "error",
};
};
return MythicResponse{
.task_id = task.id,
.user_output = try std.fmt.allocPrint(self.allocator, "Deleted directory: {s}", .{path}),
.completed = true,
.status = "completed",
};
}
};
75 changes: 75 additions & 0 deletions Payload_Type/rango/rango/agent_functions/delete_directory.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
from mythic_container.MythicCommandBase import *
from mythic_container.MythicRPC import *
from mythic_container.MythicGoRPC import *

class DeleteDirectoryArguments(TaskArguments):
def __init__(self, command_line, **kwargs):
super().__init__(command_line, **kwargs)
self.args = [
CommandParameter(name="path", display_name="Delete directory", type=ParameterType.String,
description="Path of the directory to delete"),
]
async def parse_arguments(self):
if len(self.command_line) == 0:
raise ValueError("Must supply a path to run")
self.add_arg("command", self.command_line)

async def parse_dictionary(self, dictionary_arguments):
self.load_args_from_dictionary(dictionary_arguments)

class DeleteDirectoryCommand(CommandBase):
cmd = "deletedirectory"
needs_admin = False
help_cmd = "delete_directory /path/to/directory"
description = """This deletes the specified directory"""
version = 1
author = "@pop-ecx"
attackmapping = ["T1070"]
argument_class = DeleteDirectoryArguments
attributes = CommandAttributes(
suggested_command=True
)

async def opsec_pre(self, taskData: PTTaskMessageAllData) -> PTTTaskOPSECPreTaskMessageResponse:
response = PTTTaskOPSECPreTaskMessageResponse(
TaskID=taskData.Task.ID,
Success=True,
OpsecPreBlocked=False,
OpsecPreBypassRole="other_operator",
OpsecPreMessage="Delete file command allowed to execute.",
)
return response
async def opsec_post(self, taskData: PTTaskMessageAllData) -> PTTTaskOPSECPostTaskMessageResponse:
response = PTTTaskOPSECPostTaskMessageResponse(
TaskID=taskData.Task.ID,
Success=True,
OpsecPostBlocked=False,
OpsecPostBypassRole="other_operator",
OpsecPostMessage="Delete file command post-processing allowed.",
)
return response
async def create_go_tasking(self, taskData: MythicCommandBase.PTTaskMessageAllData) -> MythicCommandBase.PTTaskCreateTaskingMessageResponse:
response = MythicCommandBase.PTTaskCreateTaskingMessageResponse(
TaskID=taskData.Task.ID,
Success=True,
Parameters=taskData.args.get_arg("path"),
)
await SendMythicRPCArtifactCreate(MythicRPCArtifactCreateMessage(
TaskID=taskData.Task.ID, ArtifactMessage="{}".format(taskData.args.get_arg("path")),
BaseArtifactType="Process Create"
))
response.DisplayParams = taskData.args.get_arg("path")
return response
async def process_response(self, task: PTTaskMessageAllData, response: any) -> PTTaskProcessResponseMessageResponse:
resp = PTTaskProcessResponseMessageResponse(TaskID=task.Task.ID, Success=True)
if isinstance(response, dict) and "user_output" in response:
resp.Output = response["user_output"]
if "status" in response and response["status"] == "error":
resp.Success = False
elif isinstance(response, str):
resp.Output = response
else:
resp.Output = "Unexpected response format: " + str(response)

resp.completed = True
return resp
78 changes: 78 additions & 0 deletions Payload_Type/rango/rango/agent_functions/delete_file.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
from mythic_container.MythicCommandBase import *
from mythic_container.MythicRPC import *
from mythic_container.MythicGoRPC import *

class DeleteFileArguments(TaskArguments):
def __init__(self, command_line, **kwargs):
super().__init__(command_line, **kwargs)
self.args = [
CommandParameter(name="path", display_name="Delete file", type=ParameterType.String,
description="Path of the file to delete"),
]

async def parse_arguments(self):
if len(self.command_line) == 0:
raise ValueError("Must supply a path to run")
self.add_arg("command", self.command_line)

async def parse_dictionary(self, dictionary_arguments):
self.load_args_from_dictionary(dictionary_arguments)

class DeleteFileCommand(CommandBase):
cmd = "deletefile"
needs_admin = False
help_cmd = "deletefile /path/to/file"
description = """This deletes the specified file"""
version = 1
author = "@pop-ecx"
attackmapping = ["T1070"]
argument_class = DeleteFileArguments
attributes = CommandAttributes(
suggested_command=True
)

async def opsec_pre(self, taskData: PTTaskMessageAllData) -> PTTTaskOPSECPreTaskMessageResponse:
response = PTTTaskOPSECPreTaskMessageResponse(
TaskID=taskData.Task.ID,
Success=True,
OpsecPreBlocked=False,
OpsecPreBypassRole="other_operator",
OpsecPreMessage="Delete file command allowed to execute.",
)
return response
async def opsec_post(self, taskData: PTTaskMessageAllData) -> PTTTaskOPSECPostTaskMessageResponse:
response = PTTTaskOPSECPostTaskMessageResponse(
TaskID=taskData.Task.ID,
Success=True,
OpsecPostBlocked=False,
OpsecPostBypassRole="other_operator",
OpsecPostMessage="Delete file command post-processing allowed.",
)
return response
async def create_go_tasking(self, taskData: MythicCommandBase.PTTaskMessageAllData) -> MythicCommandBase.PTTaskCreateTaskingMessageResponse:
response = MythicCommandBase.PTTaskCreateTaskingMessageResponse(
TaskID=taskData.Task.ID,
Success=True,
Parameters=taskData.args.get_arg("path"),
)
await SendMythicRPCArtifactCreate(MythicRPCArtifactCreateMessage(
TaskID=taskData.Task.ID, ArtifactMessage="{}".format(taskData.args.get_arg("path")),
BaseArtifactType="Process Create"
))

response.DisplayParams = taskData.args.get_arg("path")
return response

async def process_response(self, task: PTTaskMessageAllData, response: any) -> PTTaskProcessResponseMessageResponse:
resp = PTTaskProcessResponseMessageResponse(TaskID=task.Task.ID, Success=True)
if isinstance(response, dict) and "user_output" in response:
resp.Output = response["user_output"]
if "status" in response and response["status"] == "error":
resp.Success = False
elif isinstance(response, str):
resp.Output = response
else:
resp.Output = "Unexpected response format: " + str(response)

resp.completed = True
return resp
20 changes: 20 additions & 0 deletions documentation-payload/rango/commands/deletedirectory.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
## Description
deletedirectory is used to delete a specified directory from the file system.

## Usage

```
deleledirectory </path/to/directory>
```

### Examples

```
> for linux
deletedirectory /home/user/important
```

```
> for windows
deletedirectory C:\Users\user\important
```
20 changes: 20 additions & 0 deletions documentation-payload/rango/commands/deletefile.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
## Description
deletefile is used to delete a specified file from the file system.

## Usage

```
deletefile </path/to/filename>
```

### Examples

```
> for linux
deletefile /home/user/important.txt
```

```
> for windows
deletefile C:\Users\user\important.txt
```