download file.txt
-1
total chunks, then Mythic will expect at some point for the agent to return a total chunk count so that Mythic knows the transfer is over. This can be helpful when the agent isn’t able to seek the file length ahead of time.full_path
of the file and determine how many chunks it’ll take to transfer the file. It then creates the following structure:
host
field allows us to track if you’re downloading files on the current host or remotely. If you leave this out or leave it blank (""
), then it’ll automatically be populated with the callback’s hostname. Because you can use this same process for downloading files and downloading screenshots from the remote endpoint in a chunked fashion, the is_screenshot
flag allows this distinction. This helps the UI track whether something should be shown in the screenshot pages or in the files pages. If this information is omitted, then the Mythic server assumes it’s a file (i.e. is_screenshot
is assumed to be false
). This message is what’s sent as an Action: post_response message.
What if you don’t know the total number of chunks ahead of time? No worries - register as normal but for the total_chunks
field put a negative value. Later on, when you’re sending chunks, you can add in your total_chunks
and Mythic will simply update it on the fly.
The full_path
can be reported in any of the chunks and is an optional value. For example, if you collected a screenshot into memory and want to “download” it to Mythic, then there is no full_path
to report back. In cases like this, you can specify a filename
value that might make more sense (ex: screenshot 1
, monitor 2
, lsass memory dump
, etc).
Mythic will respond with a file_id:
chunk_num
field is 1-based. So, the first chunk you send is "chunk_num": 1
.chunk_num
1 based”, you might be wondering. It’s a legacy situation from Mythic 1.0 where everything was written in Python without proper struct tracking. This meant Mythic was having to do a lot of guess work for if keys weren’t there or if agents were simply supplying “empty” or null fields that they weren’t using as part of a message. This made it tricky to determine if an agent was referring to chunk 0
or if they were simply setting that value to 0
because it wasn’t being used (especially if a user tried to download a file that was 0 bytes in size). Starting real chunk data at 1
made it much easier to determine the scenario.
Since then, Mythic was rewritten in Golang with stronger type checking, structs, and a slightly modified struct structure to help with all of this. Now it’s a legacy thing so that everybody’s agents don’t have a breaking change.
total_chunks
field is set to null
, otherwise Mythic will think you’re trying to transfer another file.chunk_size
first. The chunk_size
allows Mythic to seek the right spot in the file on disk before writing that chunk’s data. chunk_size
is not the size of the current chunk, Mythic can determine that much, but rather the size of every chunk the agent will try to read at a time. The last chunk is most likely not going to be the same size as the other chunks; because of this, Mythic needs to know the size of chunks in general in case it gets the last chunk first.