File Browser

Components

For the file browser, there are a few capabilities that need to be present and implemented correctly. Specifically:

  • File Listing - there needs to be a command marked as is_file_browse with your payload type that sends information in the proper format.

  • File Removal - there needs to be a command marked as is_remove_file with your payload type that reports back success properly

  • File Download - there needs to be a command marked as is_file_download with your payload type

  • File Upload - there needs to be a command marked as is_file_upload with your payload type

These components together allow an operator to browse the file system, request listings of new directories, track downloaded files, upload new files, and even remove files. Let's go into each of the components and see what they need to do specifically.

File Listing

There are two components to file listing that need to be handled - what the file browser sends as initial tasking to the command marked as is_file_browse and what data is sent back to Mythic for processing.

Tasking

When doing a file listing via the file browser, the command_line for tasking will always be the following as as JSON string:

{
  "host": "hostname of computer to list",
  "path": "path to the parent folder",
  "file": "name of the file or folder you're trying to list"
}

This might be different than the normal parameters you take for the command marked as is_file_browse. Since the payload type's command handles the processing of arguments itself, we can handle this case and transform the parameters as needed. For example, the apfell payload takes a single parameter path as an argument for file listing, but that doesn't match up with what the file browser sends. So, we can modify it within the async def parse_arguments function:

async def parse_arguments(self):
    if len(self.command_line) > 0:
        if self.command_line[0] == '{':
            temp_json = json.loads(self.command_line)
            if 'host' in temp_json:
                # this means we have tasking from the file browser rather than the popup UI
                # the apfell agent doesn't currently have the ability to do _remote_ listings, so we ignore it
                self.add_arg("path", temp_json['path'] + "/" + temp_json['file'])
            else:
                self.add_arg("path", temp_json['path'])
            self.add_arg("file_browser", "true")
        else:
            self.add_arg("path", self.command_line)
            self.add_arg("file_browser", "true")

In the above example we check if we are given a JSON string or not by checking that the self.command_line length is greater than 0 and that the first character is a {. We can then parse it into a Python dictionary and check for the two cases. If we're given something with host in it, then it must come from the file browser instead of the operator normally, so we take the supplied parameters and add them to what the command normally needs. In this case, since we only have the one argument path, we take the path and file variables from the file browser dictionary and combine them for our path variable.

Agent File Browsing Responses

Now that we know how to translate file browsing file listing tasking to whatever our command needs, what kind of output do we need to send back?

We have another component to the post_response for agents.

{
    "action": "post_response",
    "responses": [
        {
            "task_id": "UUID of task",
            "user_output": "file browser issued listing",
            "file_browser": {
                "host": "hostname of computer you're listing",
                "is_file": "did you list a file or folder",
                "permissions": {json of permission values you want to present},
                "name": "name of the file or folder you're listing",
                "parent_path": "full path of the parent folder",
                "success": "boolean of if you were able to successfully list this",
                "access_time": "string of the access time for the entity",
                "modify_time": "string of the modify time for the entity",
                "size": 1345, //size of the entity
                "files": [ // if this is a folder, include data on the files within
                    {
                        "is_file": "true or false",
                        "permissions": {json of data here that you want to show},
                        "name": "name of the entity",
                        "access_time": "string of access time",
                        "modify_time": "string of modify time",
                        "size": 13567 // size of the entity
                    }
                ]
            }
        }
    ]
}

Most of this is pretty self-explanatory, but there are some nuances. Only list out the inner files for the initial folder/file listed (i.e. don't recursively do this listing). For the files array, you don't need to include host or parent_path because those are both inferred based on the info outside the files array, and the success flag won't be included since you haven't tried to actually list out the contents of any sub-folders. The permissions JSON blob allows you to include any additional information you want to show the user in the file browser. For example, with the apfell agent, this blob includes information about extended attributes, posix file permissions, and user/group information. Because this is heavily OS specific, there's no requirement here other than it being a JSON blob (not a string).

By having this information in another component within the responses array, you can display any information to the user that you want without being forced to also display this listing each time to the user. You can if you want, but it's not required. If you wanted to do that, you could simply turn all of the file_browser data into a JSON string and put it in the user_output field. In the above example, the user output is a simple message stating why the tasking was issued, but it could be anything (even left blank).

File Removal

There are two components to file listing that need to be handled - what the file browser sends as initial tasking to the command marked as is_remove_file and what data is sent back to Mythic for processing.

Tasking

This is the exact same as the is_file_browse and the File Browser section above.

Agent File Removal Responses

Ok, so we listed files and tasked one for removal. Now, how is that removed file tracked back to the file browsing to mark it as removed? Nothing too crazy, there's another field in the post_response:

{
    "action": "post_response",
    "responses": [
        {
            "task_id": "UUID of task",
            "user_output": "File successfully deleted",
            "removed_files": [
                {
                    "host": "hostname where file was removed",
                    "path": "full path to the file"
                }
            ]
        }
    ]
}

This removed_files section simply returns an array of dictionaries that spell out the host and paths of the files that were deleted. On the back-end, Mythic takes these two pieces of information and searches the file browsing data to see if there's a matching path for the specified host in the current operation that it knows about. If there is, it gets marked as deleted and in the UI you'll see a small trashcan next to it along with a strikethrough.

As a shortcut, if the file you're removing is on the same host as your callback, then you can omit the host field or set it to "" and Mythic will automatically add in your callback's host information instead.

This response isn't ONLY for when a file is removed through the file browser though. You can return this from your normal removal commands as well and if there happens to be a matching file in the browser, it'll get marked as removed. This allows you to simply type things like rm /path/to/file on the command-line and still have this information tracked in the file browser without requiring you to remove it through the file browser specifically.

File Downloading

There are two components to file listing that need to be handled - what the file browser sends as initial tasking to the command marked as is_download_file and what data is sent back to Mythic for processing.

Tasking

This is the exact same as the is_file_browse and the File Browser section above.

Agent File Download Responses

There's nothing special here outside of normal file download processes described in the Download section. When a new file is tracked within Mythic, there's a "host" field in addition to the full_path that is reported. This information is used to look up if there's any matching browser objects and if so, they're linked together.

File Uploading

Having a command marked as is_upload_file will cause that command's parameters to pop-up and allow the operator to supply in the normal file upload information. To see this information reflected in the file browser, the user will then need to issue a new file listing.

Last updated