It’s been some months since our 0.1 release in December ‘21 and the development team have been working hard on new features, research and development, alongside bug fixes and further testing. Our preference is to make fewer releases, with a focus on stability obtained through both QA testing and testing in the field from our Adversary Operations team; customers can expect to see in the region of three major releases every 12 months. We’re very opposed to a “push to prod” mentality which may have overriding impacts on the operator experience.
The team are also working hard performing research and development that will have an overall benefit to Nighthawk as we look to integrate new techniques in to the beacon over time. Of course we’re still enthusiastic about engaging with the wider community and have released some of this research in to the public, including:
Nighthawk customers can expect to benefit from this cutting edge R&D including both public and private techniques that we discover.
We’re also very happy to welcome @x86matthew to the team, who’s already began working on new features that we hope to integrate in to Nighthawk by 0.3.
The 0.2 release is fairly significant and encompasses over five months of work from the team and includes a number of powerful features unique to Nighthawk as we continue to lead innovation in the space.
Raising the bar in operational security was one of the key drivers behind building Nighthawk and within our own red team’s tradecraft we rely heavily on the concept of keying to protect our payloads and we have typically performed this from the loader. However, we wanted to remove this burden from our customers and have brought the concept of payload keying to the Nighthawk payload generator.
Our 0.2 release offers a number of flexible options to key the Nighthawk reflective DLL against both local or remote resources. The keying code is available for all offered payload types and comes in the form of PIC shellcode which is called prior to the reflective loader.
We now offer the option to recover a decryption key from the following resources:
Remote:
Local:
The new payload generator looks as follows:
The generator additionally will also provide you with decryption stub exports for both C# and C such that the payloads can be easily integrated with existing loaders.
Finally, we also offer the option to bootstrap a block of PIC shellcode that will leverage our unhooking routines to remove any user mode EDR hooks from process prior to the keying or loading code being executed. This strategy offers configurability to leverage our APIs for dynamic syscall resolution, indirect execution and disabling of unhooking detection routines.
The reflective loader can be a bit of a choke point for many implants; if the loader isn’t sufficiently safely and securely implemented then your implant may immediately be detected, or worse still not even run. In the 0.2 release we invested a significant amount of time in rewriting our loading strategies, making them more customisable and further increasing operational security.
Included within this, we now offer multiple profile driven strategies for allocating memory in the loader, loading dependencies indirectly, resolving API calls, performing syscall execution, performing unhooking and performing heap allocations. We also ensured that these options were ported across to our x86 loader.
In our first release we provided beacon object file execution through our execute-bof command. The object files did not need to be recompiled, adjusted or modified in any way and provided full support for the Cobalt Strike API, allowing operators to reuse existing private and community tools. While this worked nicely, one thing didn’t sit well with us was that if the operator executed a BOF that performed execution through some heavily monitored API call such CreateRemoteThread, it may lead to inadvertent indicators of compromise being generated.
With this in mind, we decided to bring our OpSec execution strategies to BOFs. As such, if you execute a BOF file inside Nighthawk, our BOF loader will rewrite the import table for the BOF and translate its imports to leverage our equivalent APIs that leverage dynamic syscall execution. The following supported APIs that we translate are as follows:
OpenProcess, TerminateProcess, CreateThread, CreateRemoteThread, OpenThread, SuspendThread, ResumeThread, SetThreadContext, GetThreadContext, QueueUserAPC, TerminateThread, VirtualAlloc, VirtualAllocEx, VirtualProtect, VirtualProtectEx, VirtualFree, VirtualFreeEx, WriteProcessMemory, ReadProcessMemory, MapViewOfFile, MapViewOfFileEx, UnmapViewOfFile, CloseHandle, WriteFile, CreateFileA, CreateFileW
As noted in our 0.1 release post, we offer the operator full control over each step of the injection chain for the commands that support remote process injection. In the 0.2 release we enhanced all of our support execution strategies, offering an option to perform indirect execution of threads. This is configurable via the *Indirect flag for each of the “ExecuteMemory” options and will cause Nighthawk to identify a gadget in a loaded DLL in the remote process and direct execution through it. This provides the added benefit of confusing telemetry that may be collected through an EDRs kernel driver and used to identify thread execution originating from virtual memory. These strategies are supported for x86, x64 and cross architecture.
Nighthawk allows the operator to place various hooks within the process to circumvent defences or apply additional OpSec to the process. In the 0.1 release, the hooks were applied by modifying memory; this had the inadvertent effect of leaving certain indicators of compromise in the process. For 0.2, we completely rewrote our hooking libraries and now offer an alternate hooking implementation that leverages hardware breakpoints. This strategy does not modify memory and offers significant benefits over our previous implementation. Currently, our hardware breakpoint hooking library supports hooking for the following operations within Nighthawk, as defined by the use-hwbp-for profile option:
implant+zero
– process heap encryption,inproc-console
– console capture routines,block-dlls
– loadlibrary hooks used to prevent DLL loads,patch-etw-event
– patching of ETW related events,patch-etw-control
– further patching associated with ETW,patch-amsi
– hooks that are applied to patch AMSI.Let’s take a look at how the HWBP can be used to avoid detections when applying patches. In this example we use it to patch ETW and as demonstrated, NTDLL remains unmodified (CLR warnings can be ignored):
Allowing the beacon to sleep and encrypt while waiting for tasking is an essential tactic for hiding it from memory scanning and threat hunting tools. Nighthawk offers multiple strategies for performing this sleep and encrypt tactic, the majority of which avoid leaving common IoCs such as deploying hooks or modifying the working set, meaning they are able to evade many common threat hunting tools. In our 0.2 release, we further expanded on these self encryption strategies, making further alternate, newer techniques available.
Additionally, our 0.2 release brings further techniques for delaying execution and putting the beacon to sleep. Many beacons commonly rely on the SleepEx Windows API call to achieve this and when combined with other detection metrics, it remains somewhat of an anomaly on endpoints, creating a detection point for hunting tools such as Hunt-Sleeping-Beacons by @thefLinkk. In Nighthawk 0.2, we now offer five alternate techniques for sleeping the beacon, some of which leverage our dynamic syscall execution strategies, allowing the operator to adjust their tradecraft accordingly. The sleep modes can be defined through the “sleep-mode” profile configuration option.
Let’s take a look at some excellent community threat hunting tools being run over Nighthawk:
In our 0.1 release, we offered two modes for heap encryption, “process” and “implant”. The former brought a lot of OpSec benefits in terms of avoiding insecure allocations from Windows libraries. To achieve this, it would place hooks across a number of heap allocation APIs and force all threads to be suspended when the beacon was sleeping to avoid any potential corruption. However, it was noted to be incompatible with some of our other more exotic configuration options and combined with the all threads suspended IoC, we made the decision to drop support for it in our 0.2 release.
Instead, we now offer an alternate heap encryption mode, “implant+zero”. When operating in this mode, the implant will continue to use the Nighthawk heap encryption routines for all its threads and we additionally place a hook on RtlFreeHeap which when called will force the memory to be zeroed. The hooks for this operating mode are supported by our hardware breakpoint hooking libraries and as such avoid modifying memory in any way. Practical assessment of this technique reveals it offers almost identical benefits to the retired “process” heap encryption but brings additional stability and compatibility with other configurations.
In the following video, we demonstrate a beacon operating in implant+zero mode which shows no C2 URIs leaked to the heap through indirect allocations. In this mode the beacon will hook RtlFreeHeap using hardware breakpoints. The beacons configuration is then updated in memory to revert to a less secure mode of “implant”, which protects only allocations originating from Nighthawk threads and not indirect ones, causing the C2 URIs to be exposed on the heap:
In our 0.1 release, the user interface remained a little rough around the edges and was a key focus for improvement in 0.2. This release brings the following user interface improvements:
Nighthawk user’s can now expect a much improved UI that may look something like the following:
Let’s have a look at the 0.2 UI in action:
Aside from some of the cherry picked big ticket improvements for 0.2, there are also a number of miscellaneous improvements and bug fixes which bring more maturity to the product:
One of the biggest drawbacks in using a new C2 framework is getting to grips with functionality unique to that framework. While a lot of thought went in to our Custom C2 design such that it is sufficiently elegant to avoid the indicators associated with connectors and named pipes found in other implementations, one of the missing ingredients was more practical examples. With that in mind, we have increased the number of sample implementations available to customers by offering a “Support Tools” pack inside the Nighthawk build.
Included within this pack, we’ve included the following supporting tools:
This blog post provides a high-level overview of just some of the work performed by the Nighthawk development team over the past 5 months. Much of the work for our 0.2.1 release has also already been performed but our release schedule lacked sufficient time to integrated it in to this release. However, we have a number of new and unique features in the pipeline that we hope to offer to customers over the coming months.
Happy hacking!