Cobalt Strike 4.9: Take Me To Your Loader


Cobalt Strike 4.9 is now available. This release sees an overhaul to Cobalt Strike’s post exploitation capabilities to support user defined reflective loaders (UDRLs), the ability to export Beacon without a reflective loader which adds official support for prepend-style UDRLs, support for callbacks in a number of built-in functions, a new in-Beacon data store and more.  

We intend to publish a few follow-up blog posts over the next couple of weeks to provide more detail on some of the changes in this release, so please keep your eye on the blog for those updates. If you haven’t subscribed to the technical mailing list for blog updates, it is worth considering doing that as well so that you don’t miss anything!  

Post-Exploitation Overhaul

Cobalt Strike’s post-exploitation capabilities have been given an overhaul, with support for prepend-style User Defined Reflective Loaders being added to the following post-exploitation DLLs: 

  • browserpivot 
  • hashdump 
  • invokeassembly 
  • keylogger 
  • mimikatz 
  • netview 
  • portscan 
  • powershell 
  • screenshot 
  • sshagent 

A new Aggressor Script hook, POSTEX_RDLL_GENERATE, has been added in order to implement this change, and replace the default reflective loader with a UDRL. Full details on this new hook and how it is used can be found in the documentation.  

It is important to note that UDRLs for Beacon payloads and post-exploitation payloads are very similar but have some subtle differences. Information on those differences, that relate to the loader entry function, the DLL’s entry point, the RDATA_SECTION pointer argument and the obfuscation start offset can be found in the documentation and should be carefully reviewed prior to making your own changes in this area. 

You can find an example implementation of a post-exploitation loader in the UDRL-VS kit in the Cobalt Strike Arsenal Kit. 

A new Malleable C2 option, post-ex.cleanup, has been added to specify whether or not to clean up the post-exploitation reflective loader memory when the DLL is loaded. We have also added the post-ex.transform-x64 and post-ex.transform-x86 blocks to the post-ex Malleable C2 block. Both new blocks support the strrep option, which replaces a string in all post-exploitation DLLs, and strrepex which replaces a string within a specific post-exploitation DLL. Valid DLL names are BrowserPivot, ExecuteAssembly, Hashdump, Keylogger, Mimikatz, NetView, PortScanner, PowerPick, Screenshot, and SSHAgent. For example:  

post-ex { 
    # cleanup the post-ex UDRL memory when the post-ex DLL is loaded  
    set cleanup "true"; 
    transform-x64 { 
        # replace a string in the port scanner dll 
        strrepex "PortScanner" "Scanner module is complete" "Scan is complete"; 

        # replace a string in all post exploitation dlls 
        strrep "is alive." "is up."; 

    transform-x86 { 
        # replace a string in the port scanner dll 
        strrepex "PortScanner" "Scanner module is complete" "Scan is complete"; 

        # replace a string in all post exploitation dlls 
        strrep "is alive." "is up."; 

You can find more information on this change in the documentation. 

Export Beacon Without A Reflective Loader 

Beacon can now be used without the exported reflective loader function when using UDRLs. This change also improves support for prepend-style UDRLs.  

The BEACON_RDLL_SIZE Aggressor Script hook is called when Beacon is being prepared and can now be used to remove the entire reflective loader space from the Beacon DLL. By returning a value of “0”, a Beacon without the reflective loader is passed to the BEACON_RDLL_GENERATE and BEACON_RDLL_GENERATE_LOCAL hooks. For example: 

# ------------------------------------ 
# $1 = DLLfilename 
# $2 = arch 
# ------------------------------------ 

    warn("Running 'BEACON_RDLL_SIZE' for DLL " .$1. " with architecture " .$2);    

As a result of this change, the default BEACON_RDLL_SIZE return value has been changed from 0 to 5.  

Callback Support

We have had a number of requests from our users to make it easier to process the results of certain function calls. This is challenging due to the asynchronous nature of Cobalt Strike’s communications, but this has been addressed in this release by the addition of callbacks for a number of built-in functions. Callbacks are triggered following a response to a command by Beacon, and also when dealing with custom dialogs via dialog input and action button clicks.  

Support for callbacks has been added to the following Aggressor Script functions: 

  • bnet 
  • beacon_inline_execute 
  • binline_execute 
  • bdllspawn 
  • bexecute_assembly 
  • bhashdump 
  • bmimikatz 
  • bmimikatz_small 
  • bportscan 
  • bpowerpick 
  • bpowershell 
  • bpsinject 

In general, there are three types of techniques that can be used to deal with callbacks – anonymous closure, named closure, and lambda closure. 

An anonymous closure is useful when you want to keep a small amount of code inline with the caller. For example, logging output from a BOF to the Beacon console would look like this: 

alias cs_example { 
    # User setup code removed for brevity      
    beacon_inline_execute($bid, $data, "go", $args, { blog($1, $2); }); 

A named closure is useful when you have a lot of code that you may want to reuse. In this example, we create a closure named “bof_cb”, which is executed when data is returned by the BOF: 

 $1 - bid, $2 - result, $3 - info map 
sub bof_cb { 
    # User defined code removed for brevity 

alias cs_example { 
    local('$bid $data $args'); 
    # User setup code removed for brevity 
    beacon_inline_execute($bid, $data, "go", $args, &bof_cb); 

A lambda closure is useful when you want to pass variables that would not be in scope using the previous examples. This example demonstrates how you are able to access the $test_num variable, which is in the scope of the cs_example alias: 

# $1 - bid, $2 – result, $3 - infomap, $4 - test_num 
sub bof_cb{ 
    # User defined code removed for brevity 

alias cs_example { 
    local('$bid $file $test_num'); 
    # User setup code removed for brevity  
    binline_execute($bid, $file, $test_num, lambda({ bof_cb($1, $2, $3, $test_num); }, \$test_num); 

Examples can also be found in a public Cobalt Strike GitHub repository, found here

Beacon Data Store

Along similar lines to the token store in the 4.8 release, we have added a Beacon Data Store that allows you to store BOFs and .NET assemblies in Beacon’s memory, allowing the stored items to be executed multiple times without having to resend the item. The Cobalt Strike client will automatically detect whether an object to be executed is already in the data store so there is nothing additional that you need to do on your part once an object is stored. Stored entries are masked by default, only becoming unmasked when used. It is also possible to store generic files in the data store which will be available for BOFs to use.  

The default data store size is 16 entries, although this can be modified by configuring the stage.data_store_size option within your Malleable C2 profile.  

data-store load [bof|dotnet|file] <name> [path] stores an item in the store. 
data-store unload [index] removes a stored item.
data-store list lists all items available in the data store. 

A number of BOF API functions have also been added to allow you to access and protect items that are stored in the Beacon Data Store:  

BeaconDataStoreGetItem(size_t index) returns a pointer to the specified item. The function will return NULL if no entry exists at the specified index. 
BeaconDataStoreProtectItem(size_t index) obfuscates a specific item in the Beacon Data Store. 
BeaconDataStoreUnprotectItem(size_t index) deobfuscates a specific item in the  Beacon Data Store. 
BeaconDataStoreMaxEntries() returns the maximum size of the Beacon Data Store. 

Beacon User Data 

Beacon User Data is a C structure that allows Reflective Loaders to pass additional data to Beacons. It is passed as a pointer to Beacon by calling Beacon’s DllMain function with a custom reasoning known as DLL_BEACON_USER_DATA (0x0d). This must be passed to Beacon before the standard DLL_PROCESS_ATTACH reason is invoked. It is not required to keep the structure in memory after the DLL_BEACON_USER_DATA call because Beacon copies necessary values from it during the call.  

A version number is contained in the structure to ensure backward compatibility between different versions of Beacons and Reflective Loaders. Newer Beacons will therefore be able to handle and utilize older Beacon User Data structures without crashing.  

Beacon User Data also allows a Reflective Loader to resolve and pass system call information to Beacon, overriding Beacon’s default system call resolver. The SYSCALL_API_ENTRY structure is used for each supported system call. The SYSCALL_API structure holds these entries. Each entry contains information on the jump address (depending on system architecture), the system call number and the address of the corresponding Nt* function. The jump address and system call number are required for indirect system calls, whilst the function address is required for direct system calls. If values are not specified, Beacon will fall back to the corresponding WinAPI call. If the system calls fields in the USER_DATA structure points to NULL, then the system call information is skipped.  

Beacon User Data also allows a Reflective Loader to pass a small (32 bytes) data buffer to Beacon, allowing users to specify and pass their own custom data. BOFs can retrieve a pointer to this data with the BeaconGetCustomUserData function.  

You can download beacon_user_data.h here and you can find a usage example in the UDRL-VS, which can be found in the Arsenal Kit.  

WinHTTP Support

Up until now, Beacon’s HTTP(S) listener has used the WinInet library by default. Based on feedback from a number of users, support for the WinHTTP library has been added.  

A new Malleable C2 group, .http-beacon, has been created. Additionally, a .http-beacon.library option has been added to allow you to set the default library used when creating a new HTTP(S) listener. Valid values are wininet and winhttp. If the new Malleable C2 profile option is not specified, new HTTP(S) listeners will continue to default to WinInet.  

The new http-beacon Malleable C2 profile group also supports variants, which can then be assigned to listeners. For example:  

http-beacon { 
    set library "winhttp"; 

http-beacon "httplib-wininet" { 
    set library "wininet"; 

http-beacon "httplib-winhttp" { 
    set library "winhttp"; 

The default value in the Malleable C2 profile can be overridden via the new HTTP library option in the stageless payload generator, generate all payloads, and windows executable dialogs. For example:  

Support has also been added in a number of Aggressor Script functions, which have been updated to add support for the new optional library parameter. When the parameter is not specified, the default library value is resolved from the listener definition. When specified, the value must be either an empty string, $null, wininet or winhttp. The following functions have been updated to support this additional parameter: 

  • payload 
  • payload_local 
  • artifact_payload 
  • all_payloads 

Host Profile Support for HTTP(S) Listeners 

Cobalt Strike’s HTTP(S) processing has limitations. Whilst we will be reviewing this and plan to make other, impactful changes in a future release, we have identified and addressed a couple of limitations in the scope of this release. Specifically, up to now, callback host names are assigned to a single URI when the Beacon payload is generated, and HTTP(S) parameters and headers are defined at a profile or variant level. This means that all HTTP(S) traffic to that host looks very similar.  

We have addressed these limitations by adding a new Malleable C2 profile group – http-host-profiles. This allows you to define HTTP characteristics (URI, headers and parameters) that will be used for HTTP(S) communications for a specific host name. Dynamic (randomly selected) values are supported. Variants are used to define host profiles for multiple host names.

Dynamic data is surrounded by square brackets and supports a list of values (up to 32) separated by a pipe character. A single value will be randomly selected from the list of dynamic data values, per request. It can also be embedded in static data, randomising part of the string.

The host-name field is a fixed string that links the host profile to the matching HTTP Hosts field on the HTTP(S) listener dialog. 

Up to 10 values are supported for the parameter and header values in a single host profile get/post definition. Both options support dynamic data syntax. Parameters and headers defined in a host profile are added in addition to any parameters and headers defined in the applicable default or variant profile.  

Beacons support up to 8 host profile definitions per listener. A generated Beacon has space for 1024 bytes of host profile data in total. If multiple hosts are defined then they must all fit within 1024 bytes. 

You can find a Malleable C2 profile with an example http-host-profiles block here.

Inter-Client Communications 

This release sees the addition of Aggressor Script support for sending and receiving data between Cobalt Strike clients. Up until this point, the only way to share data between clients was via Cobalt Strike’s Event Log – for example, @Octoberfest73’s MemFiles uses this approach to share data between clients and this is an excellent example use case for this new feature.  

Three new Aggressor Script functions have been added to facilitate the firing and consumption of custom events:  

custom_event is used to broadcast a custom event to all Cobalt Strike clients.
Arguments are:  
$1 – the topic name 
$2 – the event data 

custom_event_private is used to send a custom event to a single, specific Cobalt Strike client.
Arguments are:
$1 – who to send the custom event to 
$2 – the topic name 
$3 – the event data 

custom_event_<topic-name> is fired when a client receives a custom event from another client.
Arguments are:
$1 – who sent the custom event 
$2 – the event data 
$3 – the time the event was sent 

BOF Updates 

A feature that we’ve had on our backlog for quite some time is to add a key/value store to Beacon, which is intended to be used as a persistent store between BOF executions. As we have had recent customer requests along those lines, we figured that now would be a good time to address this.  

Three new APIs have been added to Beacon to support this key/value store:  
BeaconAddValue(const char * key, void * ptr) allows you to add a memory address to a key. 
BeaconGetValue(const char * key) allows you to retrieve the memory address associated with a key. 
BeaconRemoveValue(const char * key) allows you to remove the key. Note that this will not do any memory clean-up; in order to prevent memory leaks, this clean-up should be handled by the BOF. 

We have also added a new API that can be used by BOFs to get information on Beacon such as the Beacon address, sections to mask, heap records to mask, the mask, sleep mask address and sleep mask size information: 
BeaconInformation(BEACON_INFO * pBeaconInfo) 

This API is particularly useful for the Sleep Mask BOF as it uses it to populate the BEACON_INFO data structure, and this information can then be passed to the evasive sleep implementation to provide size information that is required to hide the sleep mask BOF. The sleep mask kit in the Arsenal kit has been updated with these changes.  

Examples of these changes have been added to the bof_template project in the public Cobalt Strike GitHub

Whilst not part of the main product release, another relevant update that we recently released is the ability to debug and test BOFs without having to spawn a Beacon. The BOF-VS template was created and a blog post authored during the current release cycle, and I’m including a reference here to highlight that work. Following user feedback and questions around how the BOF-VS is licensed and how they can publish their own work, we have decided to move the BOF-VS out of the Arsenal kit and publish it in the public Cobalt-Strike GitHub to address those issues. 

Sleep Mask Update 

The sleep mask processing has been updated to mask the sleep mask code that is patched into Beacon.  

System Call Updates 

An update has been made to the system call support that was added in the 4.8 release. Support for direct and indirect system calls has been added for the following functions:  

  • DuplicateHandle 
  • ReadProcessMemory 
  • WriteProcessMemory 

Product Security Updates

A change has been made to authorization files so that they are no longer backwards compatible with older versions of Cobalt Strike. This means that the authorization file generated when you update to or install the 4.9 release will not work with any 4.8 versions that you may also need to use. Whilst this change should not affect the majority of our users, we do know that some users test newer versions before using them in engagements and could be impacted by this change.  

Licensed users that need an old (pre-4.9) authorization file can generate one here: 

Backwards Compatibility

While we are on the subject of backwards compatibility of the authorization files, I feel that this is a good opportunity to reaffirm that Cobalt Strike itself is not backwards compatible with previous versions. This is a subject that comes up frequently after each new release.  

If you want to put Cobalt Strike into play in an existing engagement, you need to stand up a new team server and new Beacons need to be started. Ideally, users would wait until new engagements are about to be started before switching to the latest release rather than attempting this in the middle of an existing engagement. This is, of course, up to you – but please be aware of the issues that may arise when doing this.

Other Updates

We have made a few other, smaller changes in this release. 

The listeners listed in the Listener Chooser are now listed by name, instead of presented in a random order. 

The about box has been given an update so that it’s more responsive when it is expanded. 

We have added support for spawning processes under the impersonated user security context.  

A new Malleable C2 option, sleep, has been added to match the sleep command syntax added in the 4.8 release. The new setting accepts both seconds/jitter values or using the new d/h/m/s/j syntax. For example: 

sleep 20 25 
sleep 1d 3h 15m 30s 50j 

Note that if the sleep value is set, the existing sleeptime and jitter values cannot be used. The settings are mutually exclusive. 

Java Support

Whilst we haven’t made any changes in this release, we just wanted to give our users advanced notice that we are planning to update the minimum supported Java version from Java 8 to Java 11 in the next release. Hopefully, this won’t negatively impact any of our users but this should give you enough time to factor this in, if you need to make changes to your environment.  

To see a full list of what’s new in Cobalt Strike 4.9, please check out the release notes. Licensed users can run the update program to get the latest version, or download version 4.9 from the website. To purchase Cobalt Strike or learn more, please contact us

Cobalt Strike 2023 Roadmap and Strategy Update


I blogged about the Cobalt Strike roadmap in March last year and while the fundamental tenets of our approach to R&D remain unaltered, a lot has changed behind the scenes over the past year or so. I try to engage with our customers on various platforms and over the past few months, I’ve been asked a lot of questions about our roadmap. My hope is that this blog post will help to answer some of those questions. As we have some major changes planned for the next 12-18 months, I’d like to spend a little time providing some insights into the current state of Cobalt Strike R&D as well as offering some transparency about our plans for 2023 and beyond.  

Cobalt Strike R&D Team

I mentioned in the roadmap update last year that we were planning on expanding the size of the R&D team. Over the past 12 months we have more than doubled the size of the team. We have added experienced software engineers to the core development team and built a research team that is dedicated to driving the product forward.

One of our more recent hires, William Burgess, is leading our research team. He will be playing a key role in shaping the future direction of the product, bringing his extensive experience in developing security tools to bear. A key part of his role is to provide technical guidance and help to define priorities for both research activities and main product releases. In addition to this, he will also be conducting his own research activities. He recently released a blog post on spoofing call stacks dynamically with timers and already has others in the pipeline.

Henri Nurmi is another recent hire and he brings both extensive red teaming and software engineering experience to the team. Henri was behind the token store change in the 4.8 release (which was an update on the version that he submitted to the Community Kit a while ago!). In addition to his work on the core product, Henri has also been working on several other items that we’ll eventually be releasing into the Arsenal Kit and blogging about. Jean-François Maes has been a team member for quite some time and while he is currently focussing on updating and improving our training material (as a certified SANS instructor, this is definitely in his wheelhouse) he is also continuing to perform research activities.

Several other new (and older) team members prefer to keep a lower public profile but are nonetheless helping to drive development of the core product, contribute to research, update product security and more. A recent example of this was the first post in a series revisiting the User-Defined Reflective Loader (UDRL) that accompanied a new addition to the Arsenal Kit.

It has taken a while to hire the team that we were looking for and build up some momentum on associated R&D tasks, but I feel that we’re in a really good place now. We are cognisant of the fact that we have customers with a wide range of expertise and skill levels and I feel we are now better able to cater to the needs of our customers. Things were relatively quiet while that was playing out but you can now expect to see more output on the blog, more tools in the Arsenal Kit, and more cutting-edge features in the main product releases. Fortra continues to invest in Cobalt Strike and I’m grateful for the support from our leadership team.


The Cobalt Strike R&D team is part of a wider team that we are actively collaborating with on multiple fronts. Fortra acquired Outflank in September last year and the two teams are working closely together, collaborating on research topics and looking at ways in which we can improve the interoperability between Cobalt Strike and Outflank’s OST. Users can benefit from the new Cobalt Strike/OST bundle and leverage tools within OST to help with their engagements.

We also work closely on research topics with the Core Security team. Some members of the Core Impact research team also work on Cobalt Strike research items and both teams look at ways to improve the interoperability between the products. We are also lucky enough to work alongside and collaborate closely with other members of the wider Core Security team such as Santiago Pecin, as well as exploit writers and other red teams and penetration testing teams across Fortra.

There is a huge array of talent right across the Offensive Security department within Fortra and we are all pulling in the same direction. It has taken a while to get this all ramped up but you will now start to see the benefits of this work – especially customers that own other offensive security products from Fortra (OST/Core Impact) in addition to Cobalt Strike.

Flexibility And Stability

The recent customer survey (thank you to everyone that responded) affirmed our belief that stability and flexibility are key features of the product and are very much something that our users value. They are the core tenets of our development philosophy and play a key role in our releases.

Cobalt Strike’s strategy around evasion has always been “evasion through flexibility” meaning that we want to provide you with tools that you can use to modify default behaviours. This approach was something that Raphael Mudge pioneered with the Artifact and Resource kits and is something that we continue to support via the Arsenal Kit. It is important for us to address the concerns of our customers and we are aware that “evasion through flexibility” only works when there is enough documentation and example code to simplify modifications to the tools that we provide. This was one of the reasons behind the UDRL-VS that we recently released into the Arsenal Kit. In addition to this, we will also continue to update the tools available in the Arsenal Kit – for example, the evasive changes made to the Sleep Mask Kit in the 4.8 release.

We are also acutely aware that Cobalt Strike’s Beacon has been widely signatured in recent years. We have a blog post coming out in the next week or two which will help address some of these concerns and we will continue to review this in future. Ultimately, I have every confidence that our research team will continue to ease the burden on our users with these efforts.

The focus on flexibility is also a key reason for the infrequent releases. As I mentioned, our users have told us that they want fewer releases to give them more time to test the product before putting it into service – due at least in part to the fact that we give them the ability to bring their own tooling to bear. 


It’s fair to say that we have a very ambitious roadmap for the next 9-12 months. I’m not going to go into a huge amount of detail, partly because I don’t want to risk over-promising and under-delivering (I’m being pragmatic, as our priorities may change), and partly because we do still like to keep our cards close to our chest to some degree at least. I would like to offer some degree of transparency into both our roadmap and strategy though. 

There are essentially three strands to our R&D activities over the coming months, all of which are underpinned by the varied research activities carried out by our research team. Main product releases are of course the focus, with the 4.9 release already being scoped out and features for subsequent releases already being planned as well. Secondly, we will be tackling some technical debt which will allow the product to gracefully evolve (i.e. it will allow us to bring in some ground-breaking changes without fundamentally changing what the product has grown to be). Thirdly, we are aiming to overhaul our update infrastructure which will allow us to make improvements to product security, as well as add some really impactful features later on down the line.

We have a lot of key updates on our backlog that we will start to address once we have completed the infrastructure migration. The migration will open up a number of different possibilities to evolve the product and offer our users some amazing new features. There is a lot more to come from us towards the end of this year and into 2024.

Main Product Releases

The 4.9 release is shaping up to be quite significant and while we’re still working on fleshing out the scope, a late Summer release is what we’re working towards at the moment.  We’re also currently planning a further release towards the end of the year. This release should also start to provide greater interoperability between Cobalt Strike and Outflank’s OST, which will be an ongoing development focus. 

Features requested and pain points expressed by our users all feed into our roadmap. Your feedback is paramount when considering the scope of each release. 

Technical Debt

There is a need for us to address some technical debt. This will provide a platform to evolve the product while we stay true to the fundamentals of the incredible product created by Raphael Mudge. We want to do the product justice and improve upon it, not tear apart Raphael’s legacy. This is always at the forefront of any change that we make. Tackling technical debt is a necessary part of the development process for any professionally maintained product, but not something that we talk about in the release blogs.

Addressing technical debt will allow us to evolve our product security measures. The changes that we have made over the last few releases have had a very real, demonstrable impact on malicious use of the software, but we need to continue to make improvements in this area. It will also allow us to address some pain points and feature suggestions that can’t currently be addressed. An example that I know will be popular is to “do something about Sleep”. We’re limited in what we can do right now but adding support for other scripting languages is definitely something that we can consider once we have made the necessary changes under the covers.

Update Infrastructure Migration

The migration of the Cobalt Strike update infrastructure is a huge undertaking and we will be collaborating with other teams within Fortra to roll this change out. One of the main drivers for the change is that it will allow us to make several key product security changes, although it does also provide us with a platform that we can use to evolve the product and bring several significant benefits to users as well. I will follow up in a separate blog post to go into those additional benefits in more detail when we are a lot further along as the migration will be an iterative process – but there will be a number of useful features that we are looking to include right from the off.

The first change of note is that we ultimately intend to deprecate the current download site and migrate to a new platform that will pull everything that users need into one place. This should eventually include software downloads, documentation, training material, a feature suggestion portal, the ability to submit technical support tickets and more. Ultimately, we have a raft of features that we intend build into the platform, giving users unprecedented levels of flexibility. As I said, more to come on that topic further on down the line. We have a lot of work to do before we get to those really innovative items. 

Another part of the migration is the deprecation of the current update process. We will be aiming to tighten up product security in a number of different ways as well as make it easier for users to provision their red teaming infrastructure. One change that we are planning to make in this area is the addition of API support to make the process of provisioning red teaming infrastructure via scripting much more straightforward and more secure.

We are also looking to make changes to how the product is licensed and how license keys feed into the update process. We’ve actually had some timely customer requests in this area (again, thanks to the customer survey) and we’ll be taking that into account.

We are carefully considering how to roll these changes out so that we don’t negatively impact users that are used to working in specific ways. These changes, along with others that we will be making to the new platform, will be positively impactful for users that choose to take advantage of them but won’t negatively impact users that can’t or don’t want to.  


Before wrapping up this post, I wanted to mention our user community. We continue to add flexibility to the product and our users continue to take advantage of that to mould it into something that works for them. The real power of Cobalt Strike, and something that Raphael Mudge was passionate about, is the flexibility that allows our users to customise, extend and use their own tools as well as share them with other community members. This is where our incredible user community really shines and has helped shape the product into what it is today. We do not take our users for granted and it is your feedback and feature suggestions that continue to shape the direction of the product. Thank you for your support.  

One of the ways that we try to recognise the contributions of our user community is the Cobalt Strike Community Kit. There are hundreds of tools written by our user community that are scattered all over GitHub and the Community Kit was created to cultivate a number of those projects into one easy-to-reference area. There are over 100 projects listed, with more being added regularly. If you have a tool that you would like to submit, there is a submission link on the site that can be used for that.  

Feature requests can be submitted to [email protected] and we are always happy to talk to users on social media, Slack and Discord. 

Thank you again for your continued support.

Cobalt Strike 4.8: (System) Call Me Maybe


Cobalt Strike 4.8 is now available. This release sees support for system calls, options to specify payload guardrails, a new token store, and more.  

We had originally planned to get this release out late in 2022 but progress was stymied due to the 4.7.1 and 4.7.2 patch releases that we had to put out to fix vulnerabilities that were reported in the 4.7 release. We spent a few development cycles performing a security review of the code and working on some technical debt, and then it was the holiday season. It’s here now though, and better late than never!  

Before getting into the details of this release, I just wanted to mention that you should now start to see much more content from us to supplement main product releases. William Burgess recently released his first blog post since joining the Cobalt Strike team and he will be playing a key role in providing technical guidance on the future direction of the product. We have more blog posts and tooling coming over the next few weeks and months, starting with a series on UDRL development (the first of which should drop next week). Coming later in the year are some huge changes to Cobalt Strike itself. More details on that will come in a follow-up blog post soon. We know that our users are struggling with evasion and have reported other pain points. As I mentioned in my roadmap update last year, we have been aggressively building out our R&D team and while it’s taken a while to do that and get all of our ducks in a row, you’ll now really start to see the benefits of those behind-the-scenes changes. Now, back to the 4.8 release. 

System Calls Support

This release sees the addition of support for direct and indirect system calls. We have added support for a number of system calls, specifically:  

  • CloseHandle
  • CreateFileMapping
  • CreateRemoteThread
  • CreateThread
  • GetThreadContext
  • MapViewOfFile
  • OpenProcess
  • OpenThread
  • ResumeThread
  • SetThreadContext
  • UnmapViewOfFile
  • VirtualAlloc
  • VirtualAllocEx
  • VirtualFree
  • VirtualProtect
  • VirtualProtectEx
  • VirtualQuery

The stageless Beacon payload generation dialog has been updated to allow you to specify the system call method to be used at execution time. The available options are:  

None: Use the standard Windows API function
Direct: Use the Nt* version of the function
Indirect: Jump to the appropriate instruction within the Nt* version of the function

It is important to note that there are some commands and workflows that inject or spawn a new Beacon that do not allow you to set the initial system call method. Those commands/workflows are:

  • elevate 
  • inject 
  • jump 
  • spawn 
  • spawnas 
  • spawnu 
  • teamserver responding to a stageless payload request 
  • teamserver responding to an External C2 payload request 

The stage.syscall_method in the MalleableC2 profile controls the method used at execution time, and you can use the syscall-method [method] command to modify the method that will be used for subsequent commands. Additionally, syscall-method without any arguments will query and return the current method.  

System call support is something that we intend to continue to update and enhance in future releases. Your feedback on this is welcomed.  

Generate Payloads With Built-In Guardrails 

Support has been added for payload guardrails, which can be set at the listener level and then, if required, overridden when generating a payload.  

Guardrails can be set based on the following criteria: 

  • IP address: This can be a single IP address or a range using a wildcard to replace the rightmost octet(s). For example,, 123.123.123.*, 123.123.*.* and 123.*.*.* are all valid inputs. 123.*.123.* is not. 
  • Username: This can be a specific user name, or you can prefix/suffix a wildcard (i.e. *user or user*). The username field is case insensitive.  
  • Server name: Again, this can be a specific server name, or you can prefix/suffix a wildcard (i.e. *server or server*). The server name field is case insensitive. 
  • Domain: As with username and server name, the domain field can either be a specific domain or you can prefix/suffix a wildcard (i.e. *domain or domain*). The domain name field is also case insensitive.

The listener dialog has a new “Guardrails” option at the bottom of the screen that allows you to set and update guardrails for that listener.  

When generating a payload, the guardrails value from the associated listener is used as a default value.  

You can use the default values or override them to set specific values for the payload being created. Setting specific values here does not change the default values set at the listener level.

Multi-Byte Support For Obfuscating Beacon’s Reflective DLL’s Import Table

We have made a change to the obfuscation routine used for the stage.obfuscate MalleableC2 option which relates to how Beacon’s Reflective DLL’s import table is obfuscated.

Part of this process involved moving from a fixed, single byte XOR key to a randomly generated multi-byte XOR key. The single byte XOR mask was easily signatured and caught by tools such as YARA. Moving to a randomly generated multi-byte XOR key should help address those issues. 

Sleep Mask Updates

A number of updates have been made to the Sleep Mask. The main change is that the Sleep Mask size limit has been increased from 8192 to 16384 bytes. Other changes include: 

  • Support for the use of system calls with the MASK_TEXT_SECTION capability
  • The addition of define tags for the Windows API functions to remove the need for LIBRARY$Function syntax
  • The implementation of evasive sleep via stack spoofing (x64 only). Related changes include the addition of a bypass for Control Flow Guard (CFG), as well as the addition of a helper utility (getFunctionOffset)

Token Store

One change that we’ve had on the backlog for a while was the addition of a token store, to facilitate the hot swapping of access tokens. Windows tokens are process specific; hence each Beacon has its own token store with its own tokens. Please be aware that those tokens are therefore only available to be used by that specific Beacon.

The token store is based around the new token-store command. The command supports a number of options that perform specific functions (all supported by tab completion). Available functions are as follows:

token-store steal [pid,…] <OpenProcessToken access mask>
This steals the token(s) from the specificed PID(s). Use commas to separate each PID. This command will steal the token and put it into the token store, but will not impersonate straight away. The steal-and-use command should be used for that purpose (although it should be noted that steal-and-use only supports a single PID). This command supports the optional OpenProcessToken access mask like the existing steal_token command. 

token-store use [id]
This tasks Beacon to use the token with the specified ID from the token store.  

token-store steal-and-use [pid] <OpenProcessToken access mask>
This allows you to steal the token from the specified PID, add it to the token store and immediately use it. This command supports the optional OpenProcessToken access mask like the existing steal_token command. 

token-store show 
This displays the tokens in the token store. 

token-store remove [id,…]
This allows you to remove the token(s) corresponding to the specific ID(s) from the token store. Use commas to specify multiple IDs.  

token-store remove-all 
This removes all tokens from the token store. 

One additional point is that tokens can also be stolen via the process list in the GUI. Steal a token in the usual way (i.e. Explore -> Process List, select one or more PIDs and click on Steal Token) and then make sure the “store token in the token store” checkbox is checked before stealing the token. You are also able to select multiple Beacons at once before opening the process list.  

Finally, we have also implemented corresponding aggressor functions to the options described above, i.e.:  

  • btoken_store_remove 
  • btoken_store_show 
  • btoken_store_steal_and_use 
  • btoken_store_steal 
  • btoken_store_remove_all 
  • btoken_store_use 

ETW Blinding 

This release also sees the addition of support for ETW blinding via patching for the execute-assembly and powerpick commands. While there is limited support in this release, this is something that we will look to build on in future releases.  

The execute-assembly and powerpick commands now have an optional PATCHES parameter, specified as follows: 

execute-assembly “[PATCHES: [patch-rule] [patch-rule] [patch-rule] [patch-rule]]” [/path/to/file.exe] [arguments] 


powerpick “[PATCHES: [patch-rule] [patch-rule] [patch-rule] [patch-rule]]” [commandlet] [arguments] 

The optional PATCHES parameter can modify functions in memory for the process. Up to four patch-rule rules can be specified (delimited by spaces), with each patch-rule being made up of a library, function, offset and hex patch value, for example: [library],[function],[offset],[hex-patch-value], where:

  • library can be 1 – 260 characters  
  • function can be 1-256 characters 
  • offset is the offset from the start of the executable function and can be 0 – 65535 
  • hex-patch-value can be 2 – 200 hex characters (0 – 9, A – F) and the length must be and even number (hex pairs)

Further information on the patch-rule syntax can be found in the documentation.  

Sync Data At Teamserver Startup 

There has been a long-standing issue within Cobalt Strike whereby any data retrieved from a target (for example, screenshots, keylog data etc.) is unavailable in the client after the teamserver is restarted. This issue has been addressed, and data that was previously “lost” to the UI is now persisted between restarts.  

We have also added a new script, clearteamserverdata, that can be used to delete all data after an engagement has completed. 

Change How License Expiration Date Is Processed 

A key update related to product security is a change to how the license expiration date is processed. Previously, the expiration date was checked at teamserver startup and if it was valid, the teamserver was able to start. No further checks were performed and the teamserver was able to run until shut down by the operator.

We have tightened this processing up so that the license expiration date is checked on a daily basis. The reasoning behind the previous behaviour was that it wasn’t always convenient or logistically possible to run an update in the middle of an engagement (to grab a new authorization file with an updated expiration date). Nor was it convenient under those circumstances to restart the teamserver following an update. We have added mitigations for those scenarios in the new processing, meaning that there will be no impact on operations while refreshing your authorization file. If you need to update your license while an engagement is running, please consult the documentation for information on how you can do this. We do recommend, however, that you consider your license expiration date before starting a new engagement and avoid this situation occurring, if at all possible.

To make sure that you don’t get caught out by an expiring license, we have added a couple of new banners to the client UI.  

Starting 45 days before your license is due to expire, a warning banner will appear in the client, informing you that your license is expiring and when it is due to expire. This warning message can be dismissed but will reappear each day when the expiration date is checked. This should provide sufficient time to renew your license key if this has not already been taken care of:

If you fail to renew your license before it expires, you will have a 14-day grace period in which to do so. For the duration of that grace period, you will see an error banner that cannot be dismissed:

After the grace period has ended, if your license has not been renewed and the authorization file refreshed, the teamserver will shut down and you will be unable to restart it until you have renewed your license.  

Quality Of Life Changes 

In addition to the features already mentioned, we have also added a number of smaller changes, mainly requested by our users, as follows:

Added Flexibility To Specifying Sleep Time

A small change requested by a user was to make the sleep time easier to set. Rather than only being able to specify the sleep time in seconds, you can now also specify days, hours and minutes by suffixing those values with “d”, “h” and “m” respectively.  

A usage example is sleep 2d 13h 45m 8s 30j which translates to “sleep for 2 days, 13 hours, 45 minutes, 8 seconds with 30% jitter”. 

We have also added a new aggressor function, bsleepu that works in the same way.  

Display Current Token In The UI

Another user request was to display the current token in the client UI. This gelled nicely with the new token store and you are now able to see the current token the table view and status bar in brackets alongside the user name.  

Related to this change, we also addressed the issue whereby make_token would report the wrong user name (i.e. the user name of the current Beacon process) due to a Windows API limitation. This has been addressed and the correct username appears in brackets.   

Copy/Paste From The Beacon Output Pane 

We have added support for copying and pasting commands from the Beacon output pane.  

CTRL+C copies and CTRL+X cuts the selected text from either the output pane or the command line. Text can only be selected in the output pane or command line, not both. CTRL+V pastes text from the clipboard onto the command line. This works for any console window (for example, the Beacon console, SSH console, script console, event log and web log).  

Chain Multiple Commands In A Single Mimikatz Call 

The mimikatz command has been updated to support chaining multiple commands in a single operation. This also applies to the bmimikatz and bmimikazt_small aggressor functions (although bmimikatz_small is limited to lsadump::dcsync, sekurlsa::logonpasswords and sekurlsa::pth).  

Commands can be chained by adding a semicolon as a delimiter between commands, for example:
mimikatz standard::coffee;standard::coffee  

Note that the semicolon can still be escaped if it is required in a command (i.e. “\;”). Also, the command length is limited to 511 characters to ensure that the final character in the string is EOS (\0).  

Specify Exit Function On Stageless Windows Executable Dialog

A change was made in the 4.7 release to allow you to specify the exit option (either “thread” or “process”) on the Stageless Payload Generator dialog.  A similar change has now been made to the Stageless Windows Executable dialog that also allows you to specify the exit option (“thread” or “process”).  

Arsenal Kit Checksum

One final change to mention, again requested by a user, was to add a checksum for the Arsenal Kit. This has been done and it can be found at .

To see a full list of what’s new in Cobalt Strike 4.8, please check out the release notes. While licensed users can run the update program to get the latest version, we recommend that you download version 4.8 from scratch from the website to get the new update application. This is because the TLS certificates on and will be updated soon, and the existing updater will report errors if it isn’t updated. To purchase Cobalt Strike or learn more, please contact us

Read the latest release blog:

Out Of Band Update: Cobalt Strike 4.7.1


Cobalt Strike 4.7.1 is now available. This is an out of band update to fix an issue discovered in the 4.7 release that was reported to be impacting users, and for which there was no workaround. We also took the opportunity to address a vulnerability that was reported shortly after the 4.7 release, along with mitigations for potential denial-of-service attacks.

Sleep Mask Issue

An issue was reported whereby when stage.sleep_mask is not set (i.e. set to false), Beacon will still allocate space for the sleep mask BOF in memory. This issue has now been fixed.


An independent researcher identified as “Beichendream” reached out to inform us about an XSS vulnerability that they discovered in the teamserver. This would allow an attacker to set a malformed username in the Beacon configuration, allowing them to remotely execute code. We created a CVE for this issue which has been fixed.

As part of this fix, a new property has been added to the TeamServer.prop file (located in the home folder of the teamserver):

limits.beacons_xssvalidated specifies whether XSS validation is performed on selected Beacon metadata. By default, this is set to true.

Denial-of-Service Mitigations

We were also made aware of the potential to conduct a denial-of-service attack against the teamserver itself. While this can be mitigated by good OPSEC (using a redirector, turning staging off and so on), we have made updates to mitigate this type of attack.

A number of new properties have been added to the TeamServer.prop file as part of the mitigations:

limits.beacons_max sets a limit on the total number of Beacons that the teamserver will support. The default is 500. To turn this off (support an unlimited number of Beacons), use 0.

Three additional settings allow you to set a threshold rate for adding new Beacons (how many new Beacons can be added in a specific time period):

limits.beacon_rate_period specifies the time period (in milliseconds) during which the number of Beacons added is monitored and limited.

limits.beacon_rate_maxperperiod specifies how many new Beacons can be added in the specified time period.

limits.beacon_rate_disableduration specifies how long the teamserver will ignore additional new Beacons for if the number of new Beacons exceeds the limit in the given time period.


limits.beacon_rate_period is set to 3000, limits.beacon_rate_maxperperiod is set to 50 and limits.beacon_rate_disableduration is set to 600000. If more than 50 new Beacons are added in a 3 second (3000ms) time period, any additional new Beacons added in the next 10 minutes (600000ms) will be ignored.

We apologise for any problems that these issues may have caused. If you notice any other issues with Cobalt Strike, please refer to the online support page, or report them to our support email address. Licensed users can run the update program to get this version, or download version 4.7.1 from scratch from the website. We recommend taking a copy of your existing Cobalt Strike folder before upgrading in case you need to revert to the previous version. To purchase Cobalt Strike or learn more, please contact us.

Cobalt Strike 4.7: The 10th Anniversary Edition


Cobalt Strike 4.7 is now available. This release sees support for SOCKS5, new options to provide flexibility around how BOFs live in memory, updates to how Beacon sleeps and a number of other changes that have been requested by our users. We’ve also given the user interface a bit of a refresh (including support for the much-requested dark mode!).

In recognition of Cobalt Strike’s 10th anniversary, I’d like to say a sincere thanks to all of our users for your continued support over the years – from the very first version created by Raphael Mudge, through the acquisition by Fortra (the new face of HelpSystems) and up to today and beyond. When I first met Raphael, he impressed upon me how unique and special Cobalt Strike’s user community is, and I’m reminded of that every day – from interactions on social media, to submissions to the Community Kit and all of the great (and to be honest, sometimes not so great!) feedback that we receive. Cobalt Strike wouldn’t be where it is today without your support and constant feedback, so thank you. Here’s to the next 10 years!

A Word About Evasion

Before getting into the details of the 4.7 release, I’d like to spend a little time talking about what isn’t in the release. We’ve had a lot of feedback over the last few months that Cobalt Strike is being aggressively fingerprinted, and this is making it difficult to bypass AV and EDR tools. This is making things particularly difficult for teams that don’t have the time to develop their own tools, and you may have been expecting changes in the 4.7 release to push back on this. However, as I mentioned in a blog post about our roadmap back in March, we aren’t going to be adding any out of the box evasive measures to the core Cobalt Strike product (and just to avoid repeating myself, please do read the blog post as it goes into depth about why that’s the case). That isn’t to say that we aren’t doing anything at all–of course we take this seriously, and of course we are focussing our efforts on making improvements. Our main product releases will continue to add flexibility, make changes to the product requested by our users, and keep things stable. Meanwhile, our growing research team will focus on adding new and updating existing evasive tools to the Arsenal Kit outside of the main release cycle, keeping things moving without affecting or making you wait for main product releases. This should work out much better for you, our users, in the long term. Rather than waiting for main product releases, you should start to see regular releases of, and updates to, the evasive tooling that you need in the Arsenal Kit.

Fortra continues to invest in both the development team and the research team. We recently released a Thread Stack Spoofing tool into the Cobalt Strike Arsenal Kit and we have a number of other tools currently in development that we are expecting to release over the next few weeks, filling in the gap between now and the 4.8 release at the end of the year. The reason for this aside is to reassure you all that we are acutely aware of the issues that you’re facing and while the 4.7 release itself doesn’t contain a raft of tools to address issues around evasion, we are taking this seriously and already working on this in the background. Thank you all for your patience as our research team finds their feet and research efforts ramp up.

Now, back to the details of the 4.7 release. That’s what you’re here for, after all.

SOCKS5 Proxy Server Support

This release sees the implementation of a popular feature request – support for SOCKS5. Rather than replacing SOCKS4a altogether, you can choose whether to use SOCKS4a or SOCKS5 when starting SOCKS. A number of changes have been made, including an update to the “Start SOCKS” dialog to enable you to choose between SOCKS4a and SOCKS5 (as well as enter required parameters if SOCKS5 is selected), an update to the Proxy Pivots table to display whether SOCKS4a or SOCKS5 is being used, updates to the commands to start and stop SOCKS in the Beacon console, and an update to the bsocks Aggressor Script command. For details on the new command line options, run help socks within a Beacon console. For general details of the changes, please refer to the documentation.

It is important to note that these changes currently only add support for DNS resolution and UDP. We have not added support for IPv6 or GSSAPI authentication in this release, because the feedback that we got from you is that those features aren’t critical. We will, of course, continue to monitor feedback and will add support for those features if and when you indicate that they are important to add. We also intend to make other changes in future releases, including decoupling SOCKS5 from Beacon which should improve both speed and reliability. That is a bigger change though, and our priority for this release was to add this initial support.

Adding Flexibility Around How BOFs Live In Memory

Beacon Object Files are a key feature for Cobalt Strike. We have added more malleability around how Beacon Object Files live in memory, which should make them more difficult to fingerprint. To facilitate this, two new Malleable C2 profile settings have been added:

bof_allocator controls how you allocate memory for your BOF. Supported settings are VirtualAlloc, MapViewOfFile and HeapAlloc.

bof_reuse_memory determines whether or not memory is released. If this setting is “true”, memory is cleared and then reused for the next BOF execution; if this setting is “false”, memory is released and the appropriate memory free function is used, based on the bof_allocator setting.

Memory permissions (RWX/RX or RW/RX) are set according to the values set in the new Malleable C2 profile settings above. The exception is HeapAlloc, which is always RWX.

Review Of BOF Usage Of VirtualAlloc RWX/RX Memory

Adding flexibility around how BOFs live in memory provided us with the means to address another item that we had on our backlog. We have added support for additional relocation types for BOFs, specifically the .xdata, .pdata, and .bss sections. This change firstly means that an issue has been resolved whereby BOFs sometimes wouldn’t run because the address offset was greater than 4GB. Secondly, the number of available dynamic functions has been increased from 32 to 64.

Sleep Updates

Changes have been made to the Sleep Mask Kit and around sleep in general.

The main change is that you are now able to override the method called when Beacon goes to sleep. From 4.4 through 4.6, Beacon would call the sleep mask function that was patched into the .text section. This had some drawbacks as you were limited on how the code could be written in the sleep_mask.c files used for writing BOFs, and there was also an issue related to size constraints. In this release, Beacon has been reworked to add support for all of the things that you can do in a BOF when it comes to sleeping. Not only do you now have the ability to use your own sleep function, but you are also now able to call dynamic functions (LIBRARY$function) and Beacon API functions (when the Beacon code isn’t masked).

There are two other benefits of this change worth highlighting:

Executable code is now no longer located within Beacon’s .text section and has instead been moved to a different memory region.

The sleep mask BOF size limit has been increased from 769 bytes to 8192 bytes.

Related to this, while the Arsenal Kit still supports the older versions of the sleep mask, this release adds support for implementing the sleep mask as a true BOF. You will need to pull the updated Arsenal Kit to be able to use this feature.

Steal Token Update

The steal_token function has been updated to enable it to steal tokens from processes that it previously couldn’t get to. A user reported that as Beacon used OpenProcessToken to request TOKEN_ALL_ACCESS, in some cases this returned an access denied error. Manually tweaking the permissions in Beacon when it called OpenProcessToken was enough for them to get steal_token to succeed.

We took this feedback on board and you are now able to customize the access mask when steal_token is invoked. A number of changes have been made to facilitate this:

A steal_token_access_mask option has been added to the Malleable C2 profile. This is optional and allows you to set a default access mask used for steal_token and bsteal_token.

Support has been added to allow you to set the access mask (and override the default value) when invoking steal_token and bsteal_token from the command line.

The Steal Token dialog has been updated to allow you to set the access mask (and override the default value). This applies when both a single process and multiple processes are selected before opening the dialog.

Note that if no default value for the access mask is provided (either via the new Malleable C2 profile option, dialog option, or command line options), steal_token will default to the current access mask of TOKEN_ALL_ACCESS.

Module Stomping Update

Based on user feedback, a small change has been made to module stomping. In some cases, although the module was loaded, the actual stomping failed because Beacon remained in virtual memory. This was because unless the exported function had an ordinal value between 1 and 15, Beacon would default to using VirtualAlloc. This limitation has now been addressed by adding optional syntax to the setting to specify the starting ordinal when searching for exported functions.

Clipboard Stealer

You are now able to steal the contents of the Windows clipboard on the target system via a command (clipboard) or an Aggressor Script command (bclipboard), with a caveat: this feature is only useful when the clipboard contains text (for example, credential material). This is a quick change and the intended use case is for those occasions where a target is observed using a password manager (or similar) to grab a password; you would then be able to copy that password (or other relevant material) from the clipboard for use. If there is text on the clipboard, this will be returned and displayed; if not, an error will be displayed informing you that the clipboard contents are not text based. The exception to this is that if the clipboard contents exceed 204800 bytes, an error will be returned instead.

While this is a quick change with limited scope, we will likely enhance this feature in a future release. There are a number of interesting directions that we could go with this and we’d be interested to hear your feedback.

User Interface/Default Aggressor Script Updates

This release brings a refresh to the look and feel of the client UI (although not the complete overhaul that we’re still considering for a future release), along with a number of changes to the default aggressor script that introduce some usability improvements. You may recognise some of the default Aggressor Script changes, as some of those changes were inspired by mgeeky’s “cobalt-arsenal” Aggressor Scripts (which incidentally can be found within the Cobalt Strike Community Kit). While we have also added our own changes and implemented some things in our own way, we would just like to say a huge thank you to mgeeky for permission to bring some of that functionality into Cobalt Strike itself.

We have made a number of changes in this area. Here are a few highlights:

Dark Mode

The most eye-catching change (and one of the most requested) is the addition of dark mode. This can be toggled via a new menu option.

Sleep Time Tracking

Sleep time tracking works by recording the sleep time for each Beacon and displaying it in a new column in the Beacon table view. This information is persisted between teamserver restarts so it should always be available.

Beacon Health Tracking

Linked to the sleep time tracking is a new Beacon Health tracking feature. This feature uses the sleep time and cross references this with the last check-in time to determine whether the Beacon is active, disconnected, or dead. This information is displayed in the Beacon table view and reflected in the Beacon’s icon. This feature can be enabled or disabled via a new option on the preferences dialog.

Icon Updates

Speaking of icons, we have updated the icons that are used on the pivot graph and in the Beacon table view to represent Beacon status and OS type.

Toolbar And Menu Updates

We have also updated the icons on the toolbar in the client and have removed toolbar buttons for some of the less popular functions. Related to this change, the main menu has been reorganised, flattening the menus and moving some of the options around into more useful and intuitive locations.

Bulk Payload Generation

Related to the menu reorganisation, we have added a new menu item to allow you to generate x86 and x64 stageless payloads for all available payload variants at once. A new Sleep function, all_payloads, has also been added to allow you to do this from the command line.

Stageless Payload Generator With Exit Option

We have added a stageless payload generator dialog that allows you to set either “thread” or “process” as the exit option.

Windows Error Code Resolution

Windows error codes are now automatically parsed and resolved, so you no longer need to memorise every single Windows error code or go and look it up when Beacon just returns the error code. The relevant error message is now displayed alongside the error code. We have also added a new Beacon console command (windows_error_code) and an Aggressor Script function (windows_error_code) that can be used to convert an error code to a message on demand.

Process List Display Updates

The output of the ps command has been enhanced to resolve parent/child relationships and display the process list as a treeview instead of the old, flat version. The Beacon process is displayed in yellow. We have plans to enhance this with more colour coding in a future release, too.

There are a number of other UI changes that have been implemented, including displaying more information in the Beacon and event status bars, displaying timestamps, making it easier to interact with Beacons, a new “import credentials” option, and much more.

To see a full list of what’s new in Cobalt Strike 4.7, please check out the release notes. Licensed users can run the update program to get the latest version, or download version 4.7 from scratch from the website. To purchase Cobalt Strike or learn more, please contact us.

Arsenal Kit Update: Thread Stack Spoofing


As I mentioned in the recent Roadmap Update blog post, we are in the process of expanding the Cobalt Strike development team and ramping up our research activities so that we can release more tools outside of the core product release schedule. We’re also acutely aware of Cobalt Strike’s limitations when it comes to EDR and AV evasion, and our research efforts at the moment aim to make improvements in that area. In that vein, a new tool is now available in the Cobalt Strike Arsenal that adds thread stack spoofing capabilities.

AV and EDR detection mechanisms have been improving over the years and one specific technique that is used is thread stack inspection. This technique determines the legitimacy of a process that is calling a function or an API.

Thread stack spoofing is not a new technique and there are several good examples of this technique that are already available. The research team would like to highlight mgeeky’s thread stack spoofer, which works well and was the catalyst for the team to look into their own implementation. To avoid confusion here, it’s worth pointing out that the research team used new concepts and techniques resulting from their own research activities to develop their own unique take on this technique, rather than using mgeeky’s implementation.

Full details on our implementation are included in the readme that accompanies the tool in the Cobalt Strike Arsenal. This information and the tool itself are only available to licensed customers. The Cobalt Strike Arsenal is accessed via a link in Cobalt Strike, or directly here.

Out Of Band Update: Cobalt Strike 4.6.1


Cobalt Strike 4.6.1 is now available. This is an out of band update to fix a few issues that were discovered in the 4.6 release that were reported to be impacting users and for which there was no workaround. This does not affect the 4.7 release, which is still on track to ship this summer.

Website Cloning

Two issues related to website cloning were addressed. An issue was introduced with the 4.6 release that caused all website cloning to fail, and we had a separate backlog issue that caused an error when cloning https websites. Both of these issues have been fixed.

Error When Using rportfwd_local

An issue was reported whereby when using rportfwd_local, any connection that entered the forwarded port caused the Cobalt Strike client to disconnect and reconnect with the teamserver. This issue has been fixed.

Workaround: glibc Dependency Issue

Some users have reported an issue when running on certain (mainly older) Linux distributions that causes the teamserver to fail to start due to a glibc dependency. We are currently looking into ways to update our build process to minimise the impact of this in the 4.7 release. While there is no fix available at the moment, we have documented a workaround. If you are affected by this issue, please refer to the steps in the Cobalt Strike documentation.

We apologise for any problems that these issues may have caused. If you notice any other issues with Cobalt Strike, please refer to the online support page, or report them to our support email address. Licensed users can download version 4.6.1 from the website. To purchase Cobalt Strike or learn more, please contact us.

Cobalt Strike 4.6: The Line In The Sand


Cobalt Strike 4.6 is now available. As I mentioned in the recent Roadmap Update blog post, this isn’t a regular release, as it mostly focuses on security updates. There are also a couple of useful updates for users. A major release is planned for this summer, so this release lays the groundwork for the changes that are coming at that point.

Execute-assembly 1MB Limit Increase

A number of users have been asking for this for quite some time, and the change that we made affect not only execute-assembly, but other tasks (eg. dllinject) as well. We have added three new settings to the Malleable C2 profile (tasks_max_size, tasks_proxy_max_size and tasks_dns_proxy_max_size) that can be used to control maximum size limits. Note that these settings need to be set prior to team server startup. If the size is increased at a later time, old artifacts will still use the previous size settings and tasks that are too large will be rejected.

Comprehensive information on the new settings can be found in the Cobalt Strike documentation.

Arsenal Kit

We have combined the individual kits in the Cobalt Strike arsenal into a single kit, appropriately known as the Arsenal Kit. Building this kit yields a single aggressor script that can be loaded instead of loading all of the separate kits individually. The kit is controlled by the arsenal_kit_config file which is used to configure the kits that are built with the script.

The Arsenal Kit can be downloaded by licensed users from the Cobalt Strike arsenal.

Security Updates

This is the main focus of the Cobalt Strike 4.6 release. It is a necessary step as it lays the groundwork for our future development efforts.

Product security is nothing new. There has always been anti-proliferation processing in the software and, as discussed in this blog post (published by Raphael Mudge in 2019), we do our due diligence when it comes to screening potential customers and working with law enforcement. I think it is worth pointing out that the processes described by Raphael in that blog post are still processes that are followed at Fortra (the new face of HelpSystems) today–specifically:

From time to time, we receive informal requests for technical assistance or records from private entities. Our policy is not to perform analysis for, provide deconfliction services to, or disclose our records to private entities upon informal request.

If we have information relevant to a law enforcement investigation, we comply with valid legal process.

This stance is to avoid frivolous requests and to protect our customer’s information.

We also investigate tips. We can’t usually share information back, but we look into things brought to our attention.

We are also proactive when it comes to searching for Cobalt Strike teamservers out in the wild. This work is carried out by our own, dedicated threat intelligence team and it helps us to improve our product controls. That team also issues takedown requests if cracked copies are found.

Over the past few releases, we have made enhancements to Cobalt Strike’s product security. We intentionally haven’t described product security changes in much detail, but we do take it very seriously. Product security has been and will continue to be a key feature on our roadmap.

The 4.5 release in December 2021 saw changes to product licensing and improvements on the watermarking in the software. Those changes made it significantly more difficult to tamper with the authorization ID and locate the ever-changing hidden watermarks, therefore making it easier for us to trace stolen copies of Cobalt Strike back to specific customers. We have yet to see any credible reports of cracked copies of the 4.5 release being used because of these changes. We have seen what are claimed to be cracked copies of 4.5 being sold, but those have all turned out to be older versions badged as 4.5. By design, if the watermarks in the 4.5 release are tampered with, it will simply no longer work.

The 4.6 release brings a change to how the teamserver is deployed. Rather than a Java .jar archive, the teamserver has been built as a native binary. The client is still shipped as a .jar archive but we also plan to change that at some point as well. You shouldn’t notice anything different about the update process itself, but it is important to note that “cobaltstrike.jar” is now just a container for the team server (“TeamServerImage”) and client (“cobaltstrike-client.jar”), both of which will automatically be extracted during the update process. One thing to bear in mind though is that due to the changes in how Cobalt Strike 4.6 is installed and how it runs, coupled with changes to the download infrastructure to facilitate those changes, any scripts that you might have to automate the update process will likely no longer work and will need to be changed.

What does this mean? For you, moving forward, there is no real change. You can still download, update and use Cobalt Strike in the same way–however, please be aware that in this instance, you will need to download 4.6 directly from the website as the version 4.5 updater is incompatible with this release and will not recognize that an update is available. For us, building the software in this way is another step forward in terms of product security.

This is a line in the sand for us. We needed to make these necessary security enhancements so that we can forge ahead with our new development strategy and deliver more of what matters to our users. Normal service will be resumed with the 4.7 release this summer. Cobalt Strike will be 10 years old then so we’re hoping to do that release justice to mark the occasion properly.

To see a full list of what’s new in Cobalt Strike 4.6, please check out the release notes. Licensed users can download version 4.6 from the website. To purchase Cobalt Strike or learn more, please contact us.

Cobalt Strike Roadmap Update


Historically, Raphael Mudge, the creator of Cobalt Strike, didn’t typically talk about the Cobalt Strike roadmap publicly. He preferred to play his cards close to his chest and only revealed the details about each release when it went live (and he didn’t give much warning about the release date, either). That was his way of building excitement for each release. For the most part we’ve continued that tradition, but I’d like to spend a little time being a bit more transparent about our future development plans, before dropping back into the shadows.

I spent about a year working closely with Raphael after HelpSystems acquired Strategic Cyber, amongst other things being educated on what makes Cobalt Strike so special. One of the many things that he instilled in me is that the fundamental principles of Cobalt Strike are stability and flexibility. He was excited to see a team of experienced, professional software engineers being built around the product to provide the stability and we’ve continued to add flexibility over the past few releases – for example, with the recent sleep mask kit and user defined reflective loader kit. That’s our mantra: Stability and Flexibility.

Raphael also cautioned against adding cutting edge, out of the box evasion techniques to Cobalt Strike. The obvious danger is that once they’re inevitably fingerprinted, we’d get stuck in an endless loop of fixing those issues rather than working on new features. Cobalt Strike’s defaults are easily fingerprinted and that’s by design. The idea is that you bring your own tools and techniques to Cobalt Strike and use those. That’s what makes it unique.

We spend a lot of time engaging with our user community on social media, Slack and Discord, sometimes engaging directly in those threads and sometimes via DM, email or on video calls. I love that aspect of my role. It’s great to get the opportunity to interact directly with people that are using Cobalt Strike and see first-hand what’s working and what isn’t.

We’ve had a lot of feedback recently that some users just don’t have the time to work on their own tools because they’re so busy on engagements. We created the Cobalt Strike Community Kit to act as a central repository of extensions written by our users to make it easier to find useful tools but obviously there are cases where specific tools just don’t exist and you don’t have time to write them yourselves. We don’t want to abandon our core philosophy and start adding out of the box evasion to the core product, but we are making some changes.

Firstly, we are expanding the development team to provide additional capacity. Secondly, and more importantly, we are changing our development cycle so that we can give you your cake AND let you eat it.

Up until now, we have aimed to get at least three releases out per year. We are moving to a model where we will release updates to core Cobalt Strike (Stability and Flexibility) twice per year. One release will be in the Summer, and another in the Winter. You’re confused. I can sense it. “How does reducing the number of releases help?” Well, the second part of the new release schedule is to ramp up research activities and start releasing more tools outside the regular release schedule. What does this mean? The plan is that essentially, in between those core releases (which should contain more features due to the extended development time between them), we’ll be releasing a steady stream of tools into the Community Kit and/or into the Cobalt Strike arsenal. The location of each tool pretty much depends on the type of tool being released and whether we’re releasing the source as well.

There is a caveat to this, though. There is a little short-term pain while we pivot to this new release model. There will be a small, intermediate Cobalt Strike release this Spring (late March or early April) that doesn’t really have a lot of flashy new features for you, our users, but sets the foundation for future releases. We have a much bigger release planned that should ship around July/August to mark Cobalt Strike’s 10-year anniversary.

The future is bright. HelpSystems continues to invest in Cobalt Strike and expand the team around it. We will continue to listen to our users and give you the product and features that you need.

Feature requests can be submitted to [email protected] and I’m always happy to talk to users on social media, Slack and Discord.

Cobalt Strike 4.5: Fork&Run - you're "history"


Cobalt Strike 4.5 is now available. This release sees new options for process injection, updates to the sleep mask and UDRL kits, evasion improvements and a command history update along with other, smaller changes.

Security Updates

Before getting into the details of the release, I just wanted to impress upon you how seriously we take product security. We dedicated a significant portion of this release to improving controls around product licensing. We are fully committed to improving the security of the product and will continue to make product security enhancements a priority in future releases.

Process Injection

Until now, Cobalt Strike’s only process injection option was the built-in fork&run technique. While this is good for stability, it limits OPSEC options. We have added two new Aggressor Script hooks (PROCESS_INJECT_SPAWN and PROCESS_INJECT_EXPLICIT) to allow you to define how the fork&run and explicit injection techniques are implemented when executing post exploitation commands. A new BOF along with an Aggressor Script function implements both of these new techniques. You will now have the option of using the built-in fork&run technique or creating your own process injection technique.

Example: The keylogger using a custom process injection technique written by @ajpc500

Command History

Since adding the reconnect button in the 4.4 release, the new number one change request relates to issues with command history. There was an outstanding issue whereby scrolling back through your command history and then running a new command would insert that command in the wrong place in the command history. Not only did we fix that, we also overhauled command history to make it much more usable.

We have added a “history” command that displays your command history. You can choose to display all commands in the command history (“history all”) or specify how many commands that you want to display (for example, “history 10”). Is that all? No! We’ve also made working with command history more Unix-like by adding support for bang (!) characters.

history command

“Max Retry” Processing

This release also sees the addition of a complementary strategy to the existing Host Rotation Strategy. The “max retry” strategy is available for HTTP, HTTPS and DNS Beacons and it allows you to tell a Beacon to exit after a specified failure count. As failure count crosses a threshold, the sleep time is adjusted to a specified value.

The strategy comes with a number of default values for exit and sleep thresholds but you will be able to add custom values with a new Aggressor hook (LISTENER_MAX_RETRY_STRATEGIES).

Max Retry Strategy

Sleep Mask Kit Updates

The Sleep Mask kit was introduced in Cobalt Strike 4.4. There are two changes to the sleep mask kit in this release. Firstly, following user feedback, we have increased available space from 289 to 769 bytes. Secondly, we have added support to the kit for masking heap memory.

User Defined Reflective Loader Kit Update

Like the Sleep Mask kit, the User Defined Reflective Loader kit was introduced in Cobalt Strike 4.4. Following user feedback, we have increased the reserved size in Beacon for a larger User Defined Reflective Loader. A new Aggressor hook (BEACON_DLL_SIZE) allows you to specify whether to reserve 5k (the current threshold) or 100k for your custom loader.

Other Changes

One final, small update to mention is that to save you a click, the x64 checkbox is now checked by default on all payload generation dialogs. Please be aware of this change so that you don’t rely on muscle memory when working with those dialogs and accidentally uncheck that checkbox!

x64 checked by default

Documentation Changes

Unrelated to this release, but still relevant, is a change to the documentation. Earlier this month we made some changes to the Cobalt Strike infrastructure. One of those changes was an overhaul of the Cobalt Strike website, and the manual is now searchable:

Please note that you may need to refresh your browser cache to see the new documentation.

The support manual is now searchable

We will be publishing follow-up blog posts that provide much more detail on most of these changes in the next few days, so please keep your eye on the blog for those updates.

To see a full list of what’s new in Cobalt Strike 4.5, please check out the release notes. Licensed users can run the version 4.4 update program to get version 4.5. If you have not yet updated to version 4.4, you will need download from the website. To purchase Cobalt Strike or ask about evaluation options, please contact us for more information.