8
8
import asyncio
9
9
import platform
10
10
11
- if platform .system () == 'Windows' :
11
+ if platform .system () == 'Windows' :
12
12
RUNOF_HOST_PATH = "C:\\ Mythic\\ Apollo\\ srv\\ RunOF.dll"
13
13
else :
14
14
RUNOF_HOST_PATH = "/srv/RunOF.dll"
@@ -34,6 +34,17 @@ def __init__(self, command_line, **kwargs):
34
34
ui_position = 1
35
35
)
36
36
]),
37
+ CommandParameter (
38
+ name = "bof_file" ,
39
+ display_name = "New Bof" ,
40
+ type = ParameterType .File ,
41
+ description = "A new bof to execute. After uploading once, you can just supply the coff_name parameter" ,
42
+ parameter_group_info = [
43
+ ParameterGroupInfo (
44
+ required = True , group_name = "New" , ui_position = 1 ,
45
+ )
46
+ ]
47
+ ),
37
48
CommandParameter (
38
49
name = "function_name" ,
39
50
cli_name = "Function" ,
@@ -47,6 +58,11 @@ def __init__(self, command_line, **kwargs):
47
58
group_name = "Default" ,
48
59
ui_position = 2
49
60
),
61
+ ParameterGroupInfo (
62
+ required = False ,
63
+ group_name = "New" ,
64
+ ui_position = 2
65
+ ),
50
66
]),
51
67
CommandParameter (
52
68
name = "timeout" ,
@@ -61,6 +77,11 @@ def __init__(self, command_line, **kwargs):
61
77
group_name = "Default" ,
62
78
ui_position = 3
63
79
),
80
+ ParameterGroupInfo (
81
+ required = False ,
82
+ group_name = "New" ,
83
+ ui_position = 3
84
+ ),
64
85
]),
65
86
CommandParameter (
66
87
name = "coff_arguments" ,
@@ -82,11 +103,15 @@ def __init__(self, command_line, **kwargs):
82
103
group_name = "Default" ,
83
104
ui_position = 4
84
105
),
106
+ ParameterGroupInfo (
107
+ required = False ,
108
+ group_name = "New" ,
109
+ ui_position = 4
110
+ ),
85
111
]),
86
112
]
87
113
88
114
async def get_arguments (self , arguments : PTRPCTypedArrayParseFunctionMessage ) -> PTRPCTypedArrayParseFunctionMessageResponse :
89
- argumentResponse = PTRPCTypedArrayParseFunctionMessageResponse (Success = True )
90
115
argumentSplitArray = []
91
116
for argValue in arguments .InputArray :
92
117
argSplitResult = argValue .split (" " )
@@ -98,18 +123,19 @@ async def get_arguments(self, arguments: PTRPCTypedArrayParseFunctionMessage) ->
98
123
value = value .strip ("\' " ).strip ("\" " )
99
124
if argType == "" :
100
125
pass
101
- elif argType == "int16" or argType == "-s" :
126
+ elif argType == "int16" or argType == "-s" or argType == "s" :
102
127
coff_arguments .append (["int16" ,int (value )])
103
- elif argType == "int32" or argType == "-i" :
128
+ elif argType == "int32" or argType == "-i" or argType == "i" :
104
129
coff_arguments .append (["int32" ,int (value )])
105
- elif argType == "string" or argType == "-z" :
130
+ elif argType == "string" or argType == "-z" or argType == "z" :
106
131
coff_arguments .append (["string" ,value ])
107
- elif argType == "wchar" or argType == "-Z" :
132
+ elif argType == "wchar" or argType == "-Z" or argType == "Z" :
108
133
coff_arguments .append (["wchar" ,value ])
109
- elif argType == "base64" or argType == "-b" :
134
+ elif argType == "base64" or argType == "-b" or argType == "b" :
110
135
coff_arguments .append (["base64" ,value ])
111
136
else :
112
- return PTRPCTypedArrayParseFunctionMessageResponse (Success = False , Error = f"Failed to parse argument: { argument } : Unknown value type." )
137
+ return PTRPCTypedArrayParseFunctionMessageResponse (Success = False ,
138
+ Error = f"Failed to parse argument: { argument } : Unknown value type." )
113
139
114
140
argumentResponse = PTRPCTypedArrayParseFunctionMessageResponse (Success = True , TypedArray = coff_arguments )
115
141
return argumentResponse
@@ -177,7 +203,7 @@ async def registered_runof(self, taskData: PTTaskMessageAllData) -> str:
177
203
fileSearch = await SendMythicRPCFileSearch (MythicRPCFileSearchMessage (
178
204
TaskID = taskData .Task .ID ,
179
205
Filename = "RunOF.dll" ,
180
- LimitByCallback = True ,
206
+ LimitByCallback = False ,
181
207
MaxResults = 1
182
208
))
183
209
if not fileSearch .Success :
@@ -190,7 +216,7 @@ async def registered_runof(self, taskData: PTTaskMessageAllData) -> str:
190
216
Filename = "RunOF.dll" ,
191
217
IsScreenshot = False ,
192
218
IsDownloadFromAgent = False ,
193
- Comment = f"Shared RunOF.dll for all execute_coff tasks within Callback { taskData . Callback . DisplayID } "
219
+ Comment = f"Shared RunOF.dll for all execute_coff tasks within apollo "
194
220
))
195
221
if fileRegister .Success :
196
222
return fileRegister .AgentFileId
@@ -199,33 +225,84 @@ async def registered_runof(self, taskData: PTTaskMessageAllData) -> str:
199
225
200
226
async def create_go_tasking (self , taskData : PTTaskMessageAllData ) -> PTTaskCreateTaskingMessageResponse :
201
227
response = PTTaskCreateTaskingMessageResponse ( TaskID = taskData .Task .ID , Success = True )
228
+ originalGroupNameIsDefault = taskData .args .get_parameter_group_name () == "Default"
229
+ if taskData .args .get_parameter_group_name () == "New" :
230
+ fileSearchResp = await SendMythicRPCFileSearch (MythicRPCFileSearchMessage (
231
+ TaskID = taskData .Task .ID ,
232
+ AgentFileID = taskData .args .get_arg ("bof_file" )
233
+ ))
234
+ if not fileSearchResp .Success :
235
+ raise Exception (f"Failed to find uploaded file: { fileSearchResp .Error } " )
236
+ if len (fileSearchResp .Files ) == 0 :
237
+ raise Exception (f"Failed to find matching file, was it deleted?" )
238
+ searchedTaskResp = await SendMythicRPCTaskSearch (MythicRPCTaskSearchMessage (
239
+ TaskID = taskData .Task .ID ,
240
+ SearchCallbackID = taskData .Callback .ID ,
241
+ SearchCommandNames = ["register_file" ],
242
+ SearchParams = taskData .args .get_arg ("bof_file" )
243
+ ))
244
+ if not searchedTaskResp .Success :
245
+ raise Exception (f"Failed to search for matching tasks: { searchedTaskResp .Error } " )
246
+ if len (searchedTaskResp .Tasks ) == 0 :
247
+ # we need to register this file with apollo first
248
+ subtaskCreationResp = await SendMythicRPCTaskCreateSubtask (MythicRPCTaskCreateSubtaskMessage (
249
+ TaskID = taskData .Task .ID ,
250
+ CommandName = "register_coff" ,
251
+ Params = json .dumps ({"file" : taskData .args .get_arg ("bof_file" )})
252
+ ))
253
+ if not subtaskCreationResp .Success :
254
+ raise Exception (f"Failed to create register_file subtask: { subtaskCreationResp .Error } " )
255
+
256
+ taskData .args .add_arg ("coff_name" , fileSearchResp .Files [0 ].Filename )
257
+ taskData .args .add_arg ("loader_stub_id" , taskData .args .get_arg ("bof_file" ))
258
+ taskData .args .remove_arg ("bof_file" )
259
+ else :
260
+ file_resp = await SendMythicRPCFileSearch (MythicRPCFileSearchMessage (TaskID = taskData .Task .ID , Filename = taskData .args .get_arg ("coff_name" )))
261
+ if file_resp .Success and len (file_resp .Files ) > 0 :
262
+ taskData .args .add_arg ("loader_stub_id" , file_resp .Files [0 ].AgentFileId )
263
+ else :
264
+ raise Exception ("Failed to fetch uploaded file from Mythic (ID: {})" .format (taskData .args .get_arg ("coff_name" )))
202
265
registered_runof_id = await self .registered_runof (taskData )
203
266
taskData .args .add_arg ("runof_id" , registered_runof_id )
204
- file_resp = await SendMythicRPCFileSearch (MythicRPCFileSearchMessage (TaskID = taskData .Task .ID , Filename = taskData .args .get_arg ("coff_name" )))
205
- if file_resp .Success and len (file_resp .Files ) > 0 :
206
- taskData .args .add_arg ("loader_stub_id" , file_resp .Files [0 ].AgentFileId )
207
- else :
208
- raise Exception ("Failed to fetch uploaded file from Mythic (ID: {})" .format (taskData .args .get_arg ("coff_name" )))
209
-
210
267
timeout = taskData .args .get_arg ("timeout" )
211
268
if timeout is None or timeout == "" :
212
269
taskData .args .set_arg ("timeout" , "30" )
213
270
214
271
taskargs = taskData .args .get_arg ("coff_arguments" )
215
- if taskargs == "" or taskargs is None :
216
- response .DisplayParams = "-Coff {} -Function {} -Timeout {}" .format (
217
- taskData .args .get_arg ("coff_name" ),
218
- taskData .args .get_arg ("function_name" ),
219
- taskData .args .get_arg ("timeout" )
220
- )
221
- else :
222
- response .DisplayParams = "-Coff {} -Function {} -Timeout {} -Arguments {}" .format (
223
- taskData .args .get_arg ("coff_name" ),
224
- taskData .args .get_arg ("function_name" ),
225
- taskData .args .get_arg ("timeout" ),
226
- taskargs
227
- )
272
+ if originalGroupNameIsDefault :
273
+ if taskargs == "" or taskargs is None :
274
+ response .DisplayParams = "-Coff {} -Function {} -Timeout {}" .format (
275
+ taskData .args .get_arg ("coff_name" ),
276
+ taskData .args .get_arg ("function_name" ),
277
+ taskData .args .get_arg ("timeout" )
278
+ )
279
+ else :
280
+ argsString = ""
281
+ normalizedArgs = []
282
+ for argEntry in taskargs :
283
+ if argEntry [0 ] in ['s' , 'int16' ]:
284
+ argsString += f"-Arguments { argEntry [0 ]} :{ argEntry [1 ]} "
285
+ normalizedArgs .append (['s' , argEntry [1 ]])
286
+ elif argEntry [0 ] in ['i' , 'int32' ]:
287
+ argsString += f"-Arguments { argEntry [0 ]} :{ argEntry [1 ]} "
288
+ normalizedArgs .append (['i' , argEntry [1 ]])
289
+ elif argEntry [0 ] in ['z' , 'string' ]:
290
+ argsString += f"-Arguments { argEntry [0 ]} :\" { argEntry [1 ]} \" "
291
+ normalizedArgs .append (['z' , argEntry [1 ]])
292
+ elif argEntry [0 ] in ['Z' , 'wchar' ]:
293
+ argsString += f"-Arguments { argEntry [0 ]} :\" { argEntry [1 ]} \" "
294
+ normalizedArgs .append (['Z' , argEntry [1 ]])
295
+ else :
296
+ argsString += f"-Arguments { argEntry [0 ]} :\" { argEntry [1 ]} \" "
297
+ normalizedArgs .append (['b' , argEntry [1 ]])
298
+ taskData .args .set_arg ("coff_arguments" , normalizedArgs )
228
299
300
+ response .DisplayParams = "-Coff {} -Function {} -Timeout {} {}" .format (
301
+ taskData .args .get_arg ("coff_name" ),
302
+ taskData .args .get_arg ("function_name" ),
303
+ taskData .args .get_arg ("timeout" ),
304
+ argsString
305
+ )
229
306
return response
230
307
231
308
async def process_response (self , task : PTTaskMessageAllData , response : any ) -> PTTaskProcessResponseMessageResponse :
0 commit comments