Regardless of the engagement, whether it’s a full-scale penetration test of a large corporation or a small capture the flag (CTF) tournament online, we as security professionals often run into real-time host intrusion protection, or even just simple firewalls in some instances. Both intrusion detection/prevention systems (IDS/IPS), and firewalls, are relatively simple at a high-level, and therefore can be bypassed with high-level strategy. In this article, we will go from the basics of establishing command and control (C2), to popping bind, reverse, and encrypted reverse shells, in a lab environment. Hopefully, this article leaves you wanting more but provides a solid base of understanding at an introductory level.
So We’ve Found a Vulnerable Object…
Situation 1: Through our initial reconnaissance, whether active or passive, we have found a system that appears to be vulnerable to some flavor of command execution or arbitrary code execution.
Situation 2: Either through OSINT or other recon techniques, we’ve achieved a list of users and their contact information… let the phishing begin.
Regardless of the situation, we want to achieve command and control of a machine on the target network, and depending on what we know about that network, our approach is going to vary. There are a variety of reasons why we may need to go with one connection over another, but there is almost always some option if we can at least achieve code execution on a target.
In my experience, if we put aside users as the weakest link, one of the most common ways into a network is if a company hosts its own web services. A poorly configured PHP page, for example, will often allow us to execute arbitrary code and pop a shell as the web-server user through a PHP trigger. As a result, I strongly recommend that for those companies who don’t explicitly spend money on security, or really, ultimately require they own their hosting for some reason, go with an external hosting provider. I have found that school systems are specifically a common place where this becomes effective.
If we go this route with our hosting, we transfer risk. The result of poorly written code in this context is a compromise of what is usually an isolated virtual machine in a provider’s network, not a shell on a server in a DMZ, one hop away from a core DNS server or domain controller. I digress…
A Refresher in Network Address Translation (NAT)
IPv4, what a game changer–we can give everyone an, “internet street address,” and… oh er…. looks like we ran out of addresses. Unfortunately, while the original IPv4 address framework gives us about 4 billion unique addresses, we’ve totally depleted its availability. With the government and large educational institutions hoarding IP space (even with /8 networks reserved entierly to themselves), and especially with the explosive take-off of the Internet of Things (IoT) recently, hindsight is an obvious 20/20 even if complete saturation was never conceivable in the original design.
To provide businesses with more usable address space, RFC 1918 was developed. This is more commonly known as private address space comprised of non-routable addresses. These are your 192.168.0.0/16, 172.16-32.0.0/12 and 10.0.0.0/8 networks that are commonly used on internal LANs and then translated out through network address translation. GET TO THE POINT! ok, alright… so NAT ultimately gives us the ability to assign one public IP to a massive corporation and then have all their internal clients use that single address to communicate with the public network.
This means, however, that per the below diagram, 10.0.0.3 knows where a web server is online, but the webserver only knows about the router at 18.104.22.168. When the client on the internal 10.0.0.0/8 network wants to get out, they talk to the NAT service–this is also called port address translation (PAT); the terms are synonymous. Then using an assigned socket (public IP and port) NAT keeps track of what sessions are associated with what private addresses. For this reason, due to NAT, an internal client can exclusively reach out and establish a session, but since their address is private, a public server (or attacker) can only enumerate against the public address associated with the internal network. Fortunately, we can defeat this with a reverse shell.
*in the case of port-forwarding, where NAT has hard coded a socket (public ip and port) to a local client, this may not be the case. Think back to running Minecraft servers on your home computer and having to setup port forwarding. That was binding a public port to your system.
Common Firewall Configuration
The most common firewall implementation is a host-based firewall, in the form of Windows Firewall on most Windows networks, or iptables on Linux machines. In general, however, the most important thing to remember is that the big rule in firewalls is implicit deny. For clarification, “implicit deny,” means that we are denying everything unsolicited. Assuming we are discussing stateful firewalls here: unless a session was established by the host with the firewall installed, anything that comes in will automatically be dropped or denied (but typically dropped). This is typically the same concept for network firewalls. We can once again defeat this with a reverse shell (by initiating the session on the victim machine).
The Wonderful World of IDS/IPS
If you’ve ever been to a security conference, these are exactly the fancy new toys you’ve seen startup reps attempting to sell to exhausted CISOs. In reality, a solid intrusion detection system, like the products that FireEye sells, can work wonders to reduce your attack surface, but alas they are not fool-proof, **and for that reason we need defense-in-depth**. Regardless, an IDS will typically be placed on a mirrored port, and will typically be set up in-line within the scope of the mission you are trying to defend. Once it has been set up to receive and/or forward traffic, it will provide alerts based on rules or heuristic variance. Ultimately though, the key here is that an IDS or IPS needs to be able to read traffic to analyze it, and that is why businesses will often implement https/TLS proxies–so they can provide end-to-end encryption but still give collectors access to the traffic. I digress….. this is when we will implement encrypted sockets, preventing an IDS from analyzing our shell.
Let’s Pop Some Shells!
Without further ado, let’s get in the lab and provide some examples. For this demo, I’ll be using nc–the IP swiss-army-knife–and ncat, which was originally developed for use within the nmap enumeration tool. For the windows box, I’m running Windows 10, and for Linux, I’m using Kali 19Q4, although any distribution would do just fine.
In a real environment, say you do get code execution on a web server running PHP, you will need to trigger the shell with PHP code, but you can still receive it with NC or OpenSSL. Ultimately the code is going to look a bit different, but the strategy is identical. Please see the write-ups listed at the bottom for PHP examples in a more complete context.
In a bind shell, we are connecting directly through the network to a device, and asking for a shell. The device isn’t initiating anything, we as the attacker are. The victim must, however, be listening for a connection. Once we establish the session, we have a shell.
It’s unusual that you don’t hit a host firewall (layer 7) on the way in, but it can happen, especially in CTF or lab environments. This also won’t work in a NAT’td network, as you can’t target an internal address (RFC1918) without a port mapping. Ultimately the host has to have an open port that is able to receive the connection and handle it. I’ll be honest, success with a bind shell is incredibly rare, but it’s good to know and critical to wholistic understanding.
In figure 1.1 you can see a forward(bind) connection as I listen in Windows 10, and then trigger the session from the attacking box (Kali in this case) on port TCP/4444. I run >systeminfo, pulling only the first five lines, and finally close the shell with >exit.
A reverse shell is arguably much more common. With a reverse shell, the victim user or host triggers, or is triggered to, execute a command. This opens a session that reaches back to the attacker, who is listening for the connection. Once the attacker receives the session they will either get a shell (if it was already sent) or they will be able to communicate and ask for one now that a session has been established.
This typically bypasses both NAT and any existing firewalls, as the connection is coming from an internal device. Sure, we can blacklist known-dangerous public IPs, but generally speaking, it’s very difficult to defend against a reverse shell without an IDS/IPS, and even with one it can be tricky to prevent. Typically reverse shells use common ports like 80 and 443 to avoid detection, and since those are often allowed out by the firewall, to let users browse the public internet. Regardless, this is one of the most common forms of persistence on a compromised host.
In figure 1.2 you can see a reverse shell. I start with a listener on the attacker (in this case Kali), and then simulate code execution, or more likely a user clicking a malicious link on the victim network, and a session is connected. Same deal as last time, I run >systeminfo, pulling only the first five lines, and close the session with >exit.
I have a confliction categorizing this as a third type of shell. Honestly, it’s more of a layered component on top of the other two. Both bind and reverse shells in their above form are plaintext streams. That means that an analyst or more importantly an IDS/IPS is able to review the connection. The way around this is to encrypt the session with TLS (or SSL if we must), and make the data unintelligible without the key. The idea of a secure shell might be obvious actually… SSH, ie: secure shell, is the most commonly used form of remote administration for UNIX in today’s modern internet. It replaced the much less secure plaintext Telnet protocol.
Here we can use ncat with the -SSL flag, or sbd (secure back door), to generate an encrypted shell with either a bind or reverse stream. Keep in mind that if one side, for example, the compromised client, requests SSL, but the listening attacker is setup only for plaintext, the connection will fail.
In figure 1.3, you can see we are once again using a reverse shell, but in this case we have also implemented the –SSL flag. This tells the binary to encrypt the session. You can see ncat generate a SHA-1 signature on both sessions, and then the connection is established on TCP/4444. Finally, the same as before, we run systeminfo with a pipe to head, and exit.
Are you sure its encrypted? What does the IDS see?
Yes, it is encrypted! and I captured the traffic to prove it. In figure 2.1 you can see the transaction from the unencrypted session. After identifying and reassembling the stream, you can see the whole conversation. The server provides the shell head in red, then we as the attacker (in blue) run our command. Finally, the server responds and we close the connection.
Everything is visible!
In the encrypted instance, we just have junk… as observable in figure 2.2. The IDS/IPS can’t observe jack, and as a result we could potentially bypass a security mechanism.
Shells provide us control of a compromised system, and are often the first step to further movement or privilege escalation in a network. Understanding how and when to use a specific strategy is vital to successfully penetrating a network, and accessing the juiciest bits of information. Shells vary in language primarily upon the compromised service, but in the end it’s all the same technique, every single method boils down to simple C2.
Please see the following hack the box write-ups for real CTF examples: