Tale of Hosting .NET in unmanaged code Part 0x3: HavocFramework

recap

We are wrapping up the \”Tale of Hosting .Net\” series by covering the implementation details of InlineAssembly-Execute feature in Havoc Framework- A very recent open source C2 framework developed by C5pider. Here in this post we are reiterating everything we saw in the earlier posts part-1 and part-2, so make sure you read it because going forward we do not go in depth rather we are going to barely scratch the surface.

Havoc Assembly Execution

The command CommandAssemblyInlineExecute in Havoc framework can execute user provided .NET assembly via a native agent of Havoc, by default the agent is called Demon. Below image shows the implementation of the said command. Only difference in the implementation of the feature when compared to our vanilla implementation is Havoc has added extra features like output redirection via named pipes, AMSI patching and execution of the assembly in the user created AppDomain. In the initialization code shown below readers should pay attention to wAppDomainName and pipePath variables.

\"\"

The output of the .NET assembly is redirected back to the operator via named pipes. The feature creates a named via CreateNamedPipe and CreateFileW for read and write operations as shown in the image below.

\"\"

The CLR hosting logic is contained in W32CreateClrInstance function as shown below. This function sets up the CLR before loading and executing the assembly.

\"\"

The implementation of the W32CreateClrInstance is shown below, all of the required COM interfaces are accessed via respective interface ids or IIDs.

\"\"

The rest of the code logic to initiate the CLR is similar to what we have seen in this blog series. The CLR initiation is shown below

\"\"

After starting the CLR, the agent will bypass the AMSI by calling the BypassPatchAMSI function. The patching of AMSI is shown below

\"\"

After patching the AMSI, the agent will enumerate the CLR version. It seems like in the future the agent will be capable of selecting a specific CLR supported by the operator provided assembly. Currently the agent will only fetches the CLR version info as shown below.

\"\"

Unlike what we have implemented in previous posts, here we can see the assembly is run inside a custom user provided AppDomain instead of DefaultAppDomain. A new domain is created using CreateDomain api as shown below.

\"\"

The assembly is loaded into user created domain and fetches the entrypoint as shown below.

\"\"

The assembly is now ready to be executed with set of arguments provided by the operator by calling Invoke_3 COM method.

\"\"

The buffer for output from the assembly is allocated as shown below.

\"\"

Standard output handle is set to previously created named pipe.

\"\"

Finally the output from the executed assembly is read through pipes by calling ReadFile api.

\"\"

Conclusion

As we can see the implementation of the CLR hosting and assembly execution techniques do not deviate much from what we have already seen in previous posts. Hope you guys enjoyed the series until next time CHEERIOS! 🙂

Leave a Reply

Your email address will not be published. Required fields are marked *