Blog: Red Teaming

Securing your red team kit with Uncomplicated Firewall

Neil Lines 29 May 2019

After reading Identifying Cobalt Strike team servers in the wild I started thinking, why are people not firewalling off their kit? If you read the above post and I suggest you do, you will see under section “Scanning and Results” that the research concluded that 7718 unique Cobalt Strike (CS) team servers were observed in the wild between 2015 to 2019.

The CS team servers were enumerated in a genius way, hats off to Fox-IT for the identification that the NanoHTTPD servers bundled with CS add a surplus whitespace in all HTTP responses. Now while Raphael the creator of CS has addressed the above in the release of Cobalt Strike version 3.13 the discovery of 7718 team servers in the wild does still raise a question, why are these instances not using a firewall (FW) to restrict access to their infrastructure?

UFW could be the simple answer

UFW – Uncomplicated Firewall is the default firewall for Ubuntu, it was created to help ease iptables configuration, and let’s be honest iptables never felt like an intuitive FW solution, I am wondering if the complexity of iptables configuration is one of the reasons why 7718 instances of CS were freely enumerated.

While this post is around configuring UFW with CS, you can use it for restricting access to any service.

UFW install and run

UFW should come installed with Ubuntu, to verify if it has been installed simply run.

[email protected]:~/Desktop # sudo ufw status numbered

If UFW is installed, you should see the following response.

Status: inactive

If you see no response, as will be the case if you are using Kali, your simply need to install UFW.

sudo apt-get install ufw

If you get an error from the above, try updating your package list by running the following.

sudo apt-get update

And then retry

sudo apt-get install ufw

So, with UFW installed and ready to go, it’s now time to quickly go over the basics.

UFW the basics

As is the case with all FW’s the second you enable one, all services inbound unless strictly configured will be blocked. This means, that if you’re working remotely with a VPS and you enable UFW without the correct attention you’re going to lock yourself out!

To stop yourself from been blocked, think to yourself, how do I access the device? For this example, we will use SSH TCP port 22, which is the typical management service used to configure a virtual private server (VPS).

Adding the following UFW syntax, will enable accessing to your device over SSH.

sudo ufw allow from Add-Your-External-IP-Address to any port 22

To demonstrate the above command, please see directly below, were I have replaced the use of an external IP address with an internal IP address used for lab purposes.

[email protected]:~/Desktop/cobaltstrike# sudo ufw allow from 192.168.1.53 to any port 22
Rule added

If you are unsure of your external IP simply google “my IP address”. There are circumstances where you may wish to not restrict access to a single IP address, requiring that you open access to a whole subnet, or even allow unrestricted access to SSH. Home provider ISP’s, which commonly don’t offer static IP address allocation is one such example.

The following syntax will enable access to a whole /24 subnet in one command.

[email protected]:~/Desktop/cobaltstrike# sudo ufw allow from 192.168.1.0/24 to any port 22

Or alternatively you can enable SSH access from any IP address source by running the following syntax.

[email protected]:~/Desktop/cobaltstrike# sudo ufw allow 22/tcp
Rule added
Rule added (v6)

Now your ready to enable your FW to do this simply type sudo ufw enable followed by pressing enter.

[email protected]:~/Desktop/cobaltstrike# sudo ufw enable
Firewall is active and enabled on system startup

Following the FW going into active mode you can view all active FW rules, simply typing

sudo ufw status numbered
[email protected]:~/Desktop/cobaltstrike# sudo ufw status numbered
Status: active

     To                         Action      From
     --                         ------      ----
[ 1] 50050                 ALLOW IN    192.168.1.18
[ 2] 443                   ALLOW IN    192.168.1.20
[ 3] 443                   ALLOW IN    192.168.1.53
[ 4] 22                    ALLOW IN    192.168.1.53
[ 5] 22                    ALLOW IN    192.168.1.0/24
[ 6] 22/tcp                ALLOW IN    Anywhere
[ 7] 22/tcp (v6)           ALLOW IN    Anywhere (v6)

Worth noting you don’t have to include the numbered switch after the status command, but it is a helpful addition, as the referenced numbers makes it easier when deleting rules.

To delete any rules you no longer need, simply define which line number you wish to delete and type
sudo ufw delete Add-Number.

[email protected]:~/Desktop/cobaltstrike# sudo ufw delete 6
Deleting:
allow 22/tcp
Proceed with operation (y|n)? y
Rule deleted (v6)

Reviewing the UFW status once more shows that the FW line 6 rule has been removed.

[email protected]:~/Desktop/cobaltstrike# sudo ufw status numbered
Status: active

To                 Action      From
--                 ------      ----
[ 1] 50050         ALLOW IN    192.168.1.18
[ 2] 443           ALLOW IN    192.168.1.20
[ 3] 443           ALLOW IN    192.168.1.53
[ 4] 22            ALLOW IN    192.168.1.53
[ 5] 22            ALLOW IN    192.168.1.0/24

And the final command to get you going is how to disable the FW if you ever wish to, again this is simple and requires only one line, which is sudo ufw disable.

[email protected]:~/Desktop/cobaltstrike# sudo ufw disable
Firewall stopped and disabled on system startup

Take me to the lab

The following section details how you can use UFW with typical red team infrastructure, the demonstration was based on a lab environment, but could just as easily be used in the wild.

For lab demonstration the following diagram documents the infrastructure setup used to test UFW with CS, the firewall was installed on the CS team server, some will notice the omission of a redirector, for initial lab purposes the addition of a redirector was not included.

Figure 1: High level overview of the initial lab

The second diagram details a more typical offensive infrastructure environment which includes a redirector, again the firewall was installed on the CS team server, this topology is detailed more towards the end of the blog post.

Figure 2: High level overview of the final lab used for testing

Some reading this will be thinking you could just use the redirector apache mod rules to restrict flows, and while this is correct, it is a more complex solution compared to a typical FW configuration.

For demonstration purposes a CS team server configured to listen on IP address 192.168.1.23 was started.

Figure 3: Starting up Cobalt Server in the LAB

[email protected]:~/Desktop/cobaltstrike# ./teamserver 192.168.1.23 password

[*] Will use existing X509 certificate and keystore (for SSL)
[!] This is a trial version of Cobalt Strike. You have 8 days left of your trial. If you purchased Cobalt Strike. Run the Update program and enter your license.
[$] WARNING! This trial is *built* to get caught by standard defenses. The licensed product does not have these restrictions. See: http://blog.cobaltstrike.com/2015/10/14/the-cobalt-strike-trials-evil-bit/ [This is a trial version limitation]
[$] Added EICAR string to Malleable C2 profile. [This is a trial version limitation]
[+] Team server is up on 50050
[*] SHA256 hash of SSL cert is: 35c1d30da7a0b256679fbcf242d340a25186fb5d6369e8c6d066e3a0bd48b2dc
[$] WARNING! Beacon will not encrypt tasks or responses! [This is a trial version limitation]
[!] Web Server will use default SSL certificate (you don't want this).
    Use a valid SSL certificate with Cobalt Strike: https://www.cobaltstrike.com/help-malleable-c2#validssl
[$] Disabled x86 payload stage encoding. [This is a trial version limitation]
[$] Disabled x64 payload stage encoding. [This is a trial version limitation]
[+] Listener: http (windows/beacon_https/reverse_https) on port 443 started!
[!] Trapped java.io.EOFException during client (192.168.1.18) read [Manage: neo]: null

Access to the team server using the CS client was initiated from host IP 192.168.1.18 and while no UFW instance was presently running on the team server it was confirmed that access from the client to the server was successful.

Figure 4: Connecting a Cobalt client to the cobalt server

Figure 5: Verification that the client could connect to the server

Following the verification that the CS client could communicate with the server UFW was enabled on the CS team server.

[email protected]:~/Desktop/cobaltstrike# ufw enable

Figure 6: Enabling UFW on the Cobalt server

Repeating the above connectivity after enabling the FW on the cobalt server IP address 192.168.1.23 verified that the cobalt client from IP address 192.168.1.18 was now blocked from access.

Figure 7: Attempting to access the Cobalt server from the Cobalt client machine

Figure 8: Connection attempt as expected timing out due to the FW been enabled

Historically FW come with the ability to view all denied connections, and UFW is no different. To view the logs in real time, open another tab and copy and paste the following line in.

[email protected]:~/Desktop/cobaltstrike# tail -f /var/log/ufw.log

Note – It would be worth having the logs running in a monitor full time during the start of any engagement, just to verify your not blocking any expected connections.

The log file as can be seen in the extract directly below, details that host IP 192.168.1.18 was blocked from accessing the team server on IP address 192.168.1.23 over the TCP port of 50050.

Apr 12 04:52:36 kali kernel: [  922.272762] [UFW BLOCK] IN=eth0 OUT= MAC=00:50:56:2d:08:53:00:50:56:24:e1:b7:08:00 SRC=192.168.1.18 DST=192.168.1.23 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=65326 DF PROTO=TCP SPT=60190 DPT=50050 WINDOW=29200 RES=0x00 SYN URGP=0

Now to get uber geeky, you can even enumerate the OS that attempted to access the team server by the time to live (TTL) response in the logs, TTL=64 equals FreeBSD/Linux.

Directly below details several common TTL to their correlating OS flavour.

  • Operating System (OS) Initial TTL
  • Linux (kernel 2.4 and 2.6) – TTL=64
  • Google’s customized Linux – TTL=64
  • FreeBSD – TTL=64
  • Windows XP – TTL=128
  • Windows 7, Vista and Server 2008 – TTL=128
  • Cisco Router (IOS 12.4) – TTL=255

To enable access from the 192.168.1.18 cobalt client host, the following configuration was added to the FW on the CS team server.

[email protected]:~/Desktop/cobaltstrike# sudo ufw allow from 192.168.1.18 to any port 50050

Followed by running run ufw status numbered to verify that the line was active.

To physically verify access from host 192.168.1.18 to the Cobalt server, another connection attempt was initiated.

Figure 9: Access is granted from the Cobalt host to the Cobalt server

As a final step to verify that UFW was working as expected, an attempted connection was made from host IP 192.168.1.20 to the Cobalt server on port 50050, which timed out.

The following log, see directly below, confirmed that the access attempt from host 192.168.1.20 was denied and then dropped by the FW.

Apr 12 05:05:48 kali kernel: [ 1803.070294] [UFW BLOCK] IN=eth0 OUT= MAC=00:50:56:2d:08:53:00:0c:29:db:c9:4f:08:00 SRC=192.168.1.20 DST=192.168.1.23 LEN=48 TOS=0x00 PREC=0x00 TTL=128 ID=15044 DF PROTO=TCP SPT=49327 DPT=50050 WINDOW=65535 RES=0x00 SYN URGP=0

As is always the case with life, we should double check our findings and as such, a port scan from host 192.168.1.18 set to verify if port 50050 was open was conducted.

[email protected]:~/Desktop/cobaltstrike# nmap -sS -v --open -p 50050 192.168.1.23
Starting Nmap 7.70 ( https://nmap.org ) at 2019-03-12 01:04 BST
Initiating ARP Ping Scan at 11:55
Scanning 192.168.1.23 [1 port]
Completed ARP Ping Scan at 11:55, 0.04s elapsed (1 total hosts)
Initiating Parallel DNS resolution of 1 host. at 11:55
Completed Parallel DNS resolution of 1 host. at 11:55, 0.01s elapsed
Initiating SYN Stealth Scan at 11:55
Scanning 192.168.1.23 [1 port]
Discovered open port 50050/tcp on 192.168.1.23
Completed SYN Stealth Scan at 11:55, 0.03s elapsed (1 total ports)
Nmap scan report for 192.168.1.23
Host is up (0.00048s latency).

PORT      STATE SERVICE
50050/tcp open  unknown
MAC Address: 00:50:56:2D:08:53 (VMware)

Read data files from: /usr/bin/../share/nmap
Nmap done: 1 IP address (1 host up) scanned in 0.23 seconds
           Raw packets sent: 2 (72B) | Rcvd: 2 (72B)

The port scan was then repeated but this time from host IP address 192.1681.20 and the results as can be seen below show that port 50050 state is identified as filtered, and not open as was the case while scanning from the allowed host.

C:\Program Files (x86)\Nmap>nmap -sS -v -p 50050 192.168.1.23
Starting Nmap 7.70 ( https://nmap.org ) at 2019-03-12 01:09 GMT Daylight Time
Initiating ARP Ping Scan at 12:09
Scanning 192.168.1.23 [1 port]
Completed ARP Ping Scan at 12:09, 1.00s elapsed (1 total hosts)
Initiating Parallel DNS resolution of 1 host. at 12:09
Completed Parallel DNS resolution of 1 host. at 12:09, 0.01s elapsed
Initiating SYN Stealth Scan at 12:09
Scanning 192.168.1.23 [1 port]
Completed SYN Stealth Scan at 12:09, 0.27s elapsed (1 total ports)
Nmap scan report for 192.168.1.23
Host is up (0.00s latency).

PORT      STATE    SERVICE
50050/tcp filtered unknown
MAC Address: 00:50:56:2D:08:53 (VMware)

Read data files from: C:\Program Files (x86)\Nmap
Nmap done: 1 IP address (1 host up) scanned in 3.05 seconds
           Raw packets sent: 3 (116B) | Rcvd: 1 (28B)

Being able to granularly restrict access in a trivial way is great, as it means you can explicitly enable access to targets and drop any traffic which maybe initiated by other entities to enumerate services associated to the cobalt team server, before we all high five, there is a large problem with the above config, the targets beacon which is typically sent over TCP/80 HTTP or TCP/443 HTTPs will now also be blocked.

To enable access from your target to the team server, you only require the following one line.

sudo ufw allow from Add-IP-range-of-your-target to any port 443

To demonstrate this a CS PS payload was created using the following process.

Attacks / Packages / Payload Generator

Figure 10: Selecting payload generator

The listener was set as HTTP and the output set as PowerShell Command.

Figure 11: Listener and output settings

An extract of the generated payload can be seen directly below.

Figure 12: Extract of the created payload

And then finally to test, the above payload was pasted into a CMD session on host IP 192.168.1.20

Which resulted in the attempted connection from the host to the CS team server over TCP port 443 been made. Which was blocked by the FW as can be seen in the tailing log files, which show that BLOCK was triggered.

Apr 12 05:09:49 kali kernel: [ 2070.461637] [UFW BLOCK] IN=eth0 OUT= MAC=00:50:56:2d:08:53:00:0c:29:db:c9:4f:08:00 SRC=192.168.1.20 DST=192.168.1.23 LEN=52 TOS=0x00 PREC=0x00 TTL=128 ID=15073 DF PROTO=TCP SPT=49328 DPT=443 WINDOW=8192 RES=0x00 SYN URGP=0

To enable access the following rule was added to the FW.

[email protected]:~/Desktop/cobaltstrike# ufw allow from 192.168.1.20 to any port 443
Rule added
[email protected]:~/Desktop/cobaltstrike# ufw status numbered
Status: active

     To              Action      From
     --              ------      ----
[ 1] 50050      ALLOW IN    192.168.1.18
[ 2] 443        ALLOW IN    192.168.1.20

Note – During an active test it would be advised to enumrate the targets external IP ranges and then add a rule to the FW to allow acces from thoes ranges before sending in any potential payloads.

Repeating the process of pasting in the payload on the host IP address 192.168.1.20 resulted in the connection now been allowed inbound through the FW.

Figure 13: Access inbound is now allowed

Once more to verify, a port scan was conducted from host 192.168.1.20 and 192.168.1.18, as expected host 192.168.1.20 could see that TCP port 443 was open.

C:\Program Files (x86)\Nmap>nmap -sS -v -p 443 192.168.1.23
Starting Nmap 7.70 ( https://nmap.org ) at 2019-03-12 02:22 GMT Daylight Time
Initiating ARP Ping Scan at 12:22
Scanning 192.168.1.23 [1 port]
Completed ARP Ping Scan at 12:22, 0.22s elapsed (1 total hosts)
Initiating Parallel DNS resolution of 1 host. at 12:22
Completed Parallel DNS resolution of 1 host. at 12:22, 0.01s elapsed
Initiating SYN Stealth Scan at 12:22
Scanning 192.168.1.23 [1 port]
Discovered open port 443/tcp on 192.168.1.23
Completed SYN Stealth Scan at 12:22, 0.00s elapsed (1 total ports)
Nmap scan report for 192.168.1.23
Host is up (0.00s latency).

PORT    STATE SERVICE
443/tcp open  https
MAC Address: 00:50:56:2D:08:53 (VMware)

Read data files from: C:\Program Files (x86)\Nmap
Nmap done: 1 IP address (1 host up) scanned in 0.86 seconds
           Raw packets sent: 2 (72B) | Rcvd: 2 (72B)

Where the host IP 192.168.1.18 could not verify the service as open.

[email protected]:~/Desktop/cobaltstrike# nmap -sS -v  -p 443 192.168.1.23
Starting Nmap 7.70 ( https://nmap.org ) at 2019-03-12 02:22 BST
Initiating ARP Ping Scan at 12:22
Scanning 192.168.1.23 [1 port]
Completed ARP Ping Scan at 12:22, 0.03s elapsed (1 total hosts)
Initiating Parallel DNS resolution of 1 host. at 12:22
Completed Parallel DNS resolution of 1 host. at 12:22, 0.02s elapsed
Initiating SYN Stealth Scan at 12:22
Scanning 192.168.1.23 [1 port]
Completed SYN Stealth Scan at 12:22, 0.24s elapsed (1 total ports)
Nmap scan report for 192.168.1.23
Host is up (0.00054s latency).

PORT    STATE    SERVICE
443/tcp filtered https
MAC Address: 00:50:56:2D:08:53 (VMware)

Read data files from: /usr/bin/../share/nmap
Nmap done: 1 IP address (1 host up) scanned in 0.41 seconds
           Raw packets sent: 3 (116B) | Rcvd: 1 (28B)

Typical Red Team Infrastructure Lab

The following has been included to demonstrate how to simulate a typical red team infrastructure deployment in a VR lab environment.

Figure 14: Typical red team infrastructure lab

The above infrastructure was made using three virtual machines, which were all configured to be on the same virtual network to simplify for lab testing.

The Target PC consisted of a window’s 7 VM and the Redirector and CS Team Server consisted of a Kali Linux VM each.

The UFW Firewall’s were installed on each of the Kali boxes.

The following configurations were applied on the Kali host IP 192.168.1.18 (Redirector).

Socat proxy was used to forward all traffic received on port TCP/443 HTTPS to the CS Team Server on host IP address 192.168.1.23.

socat TCP4-LISTEN:443,fork TCP4:192.168.1.23:443

The FW rule was configured to allow traffic from any host in the 192.168.1.0/24 network but drop all other ports.

ufw allow from 192.168.1.0/24 to any port 443

The team server FW was configured to allow the defined host access to connect via the CS client (In this example to reduce the number of virtual machines the CS client is housed on the redirector host, you would not do this in the wild) and finally all TCP/443 traffic originating from the redirector is allowed in bound resulting in all other traffic been dropped by default.

Configuration on the team server 192.168.1.23

ufw allow from 192.168.1.18 to any port 50050
ufw allow from 192.168.1.18 to any port 443

When working with a redirector you need to reconfigure your CS listener to point all traffic to the redirector’s domain name or IP address and then create your payload of choice as normal.

Figure 15: Listener set to the redirectors IP address

Once the targets dial back you will notice that the external IP initiates from your redirector IP address.

Figure 16: External IP address shows originating from the redirector

Conclusion

UFW is a very simple to install and use FW solution, it offers users granular control over their testing environment, which can be used to restrict adversaries that may attempt to enumerate red team infrastructure via the use of port scanning processes.