Skip to content

SSH Session Commands & Port Forwarding Reference

Identity & Permissions Check (Inside SSH)

Who Am I

whoami                    # Current user
id                        # UID, GID, all groups
groups                    # Group names only
cat /etc/passwd | grep $(whoami)  # Your passwd entry
cat /etc/group            # All groups on system

Privilege Escalation Checks

sudo -l                   # What you can run as root (needs password)
getcap -r / 2>/dev/null   # Files with special capabilities
find / -perm -4000 2>/dev/null     # SUID binaries
find / -perm -2000 2>/dev/null     # SGID binaries
find / -writable -type f 2>/dev/null  # World-writable files
find /etc -writable 2>/dev/null    # Writable /etc files

Process Information

ps aux                    # All processes
ps -ef                    # Different format
ps aux | grep root        # What's running as root
ps -u $(whoami)          # Just YOUR processes
top / htop               # Interactive view

# Process details
ls -la /proc/[PID]/exe    # What binary is running
cat /proc/[PID]/cmdline   # Full command line

Check What's Running on Ports (Without Root)

Show Listening Ports

netstat -tuln             # TCP/UDP, listening, numeric (no process names without root)
ss -tuln                  # Modern alternative to netstat
lsof -i -P -n            # Shows only YOUR processes without root

# Raw data (always works)
cat /proc/net/tcp         # TCP connections (hex format)
cat /proc/net/udp         # UDP connections

Without root: You only see ports YOUR user owns, active connections YOU have, and listening port numbers (but not which process owns them).

Port Scanning from Inside

# Test which ports are open locally
for port in {1..1000}; do timeout 1 bash -c "echo >/dev/tcp/localhost/$port" 2>/dev/null && echo "$port open"; done

# Using netcat
nc -zv localhost 1-65535 2>&1 | grep succeeded

# Specific port range
nc -zv localhost 1-1000 2>&1 | grep succeeded

Identify Service on Specific Port

nc -v localhost 3306          # Generic banner grab
nc -v 10.10.10.245 21         # Remote host
telnet localhost 3306         # Alternative to nc

# For HTTP services
curl -I localhost:8080        # Headers only
curl -v http://localhost:8080 # Verbose with banner

# For SSL/TLS services
openssl s_client -connect localhost:443
openssl s_client -connect localhost:3306  # MySQL over SSL

Protocol-Specific Commands

# HTTP
echo -e "GET / HTTP/1.1\r\nHost: localhost\r\n\r\n" | nc localhost 80

# FTP (shows banner immediately)
nc localhost 21

# SSH (shows version string)
nc localhost 22
# Output: SSH-2.0-OpenSSH_8.2p1 Ubuntu-4ubuntu0.5

# SMTP
nc localhost 25
EHLO test

# MySQL (version visible in garbage output)
nc localhost 3306

# Redis
nc localhost 6379
INFO

# PostgreSQL
nc localhost 5432

# MongoDB
nc localhost 27017

Check Multiple Ports at Once

for port in 21 22 25 80 443 3306 5432 6379 27017; do 
    echo "=== Port $port ===" 
    timeout 2 nc -v localhost $port 2>&1
done

Common Service Banners

  • SSH: SSH-2.0-OpenSSH_8.2p1 Ubuntu-4ubuntu0.5
  • HTTP: Server: Apache/2.4.41 (Ubuntu)
  • FTP: 220 ProFTPD 1.3.5 Server
  • MySQL: Gibberish but version visible: 5.7.33-0ubuntu0.16.04.1
  • Redis: -DENIED Redis is running in protected mode...

SSH Local Port Forwarding

Basic Syntax

ssh -L [local_port]:[remote_host]:[remote_port] user@ssh_server

The format means: - local_port = where YOU connect on YOUR machine - remote_host = where SSH server connects to (localhost = same box as SSH, or different IP) - remote_port = port on that remote host - user@ssh_server = SSH server you're connecting through

PostgreSQL Tunnel Examples

# Map local 5432 to remote 5432
ssh -L 5432:localhost:5432 christine@10.129.228.195

# Use different local port (if 5432 already in use locally)
ssh -L 5433:localhost:5432 christine@10.129.228.195

# Explicit localhost binding
ssh -L 127.0.0.1:5432:127.0.0.1:5432 christine@10.129.228.195

# Bind to all interfaces (less secure)
ssh -L 0.0.0.0:5432:localhost:5432 christine@10.129.228.195

Background Tunnel (No Shell Session)

# -f: fork to background
# -N: don't execute remote commands (just tunnel)
ssh -f -N -L 5432:127.0.0.1:5432 christine@10.129.228.195

# Find and kill background tunnel
ps aux | grep "ssh.*5432"
kill [PID]

# Or
pkill -f "ssh.*5432"

Multiple Tunnels Simultaneously

# Forward multiple ports at once
ssh -L 5432:localhost:5432 -L 3306:localhost:3306 -L 6379:localhost:6379 user@host

Tunnel to Different Host Through SSH

# If database is on different machine than SSH server
ssh -L 5432:10.10.10.100:5432 user@10.10.10.245

# Explanation:
# localhost:5432 = database on same box as SSH server
# 10.10.10.100:5432 = database on different box, SSH server routes to it

Verbose Mode for Debugging

# See what's happening with tunnel
ssh -v -L 5432:127.0.0.1:5432 christine@10.129.228.195

# Look for lines like:
# debug1: Local connections to LOCALHOST:5432 forwarded to remote address localhost:5432
# debug1: channel 0: new [client-session]

Verify Tunnel is Working

Step 1: Check Local Port is Listening

# On YOUR local machine (not inside SSH)
netstat -tuln | grep 5432
ss -tuln | grep 5432
lsof -i :5432

# Should see:
# tcp        0      0 127.0.0.1:5432          0.0.0.0:*               LISTEN

Step 2: Test Connection Through Tunnel

# Simple connection test
nc -v localhost 5432
nc -zv localhost 5432    # Just check if port is open

# Python quick test
python3 -c "import socket; s=socket.socket(); s.connect(('localhost',5432)); print('Connected'); s.close()"

Step 3: Verify SSH Process is Running

# Check tunnel process exists
ps aux | grep "ssh.*5432"

# Should show something like:
# user  12345  ssh -L 5432:localhost:5432 user@10.10.10.245

Step 4: Check Remote Service is Actually Running

# From INSIDE the SSH session on remote host
netstat -tuln | grep 5432
ss -tuln | grep 5432

# Should see PostgreSQL listening:
# tcp    LISTEN  0       4096         127.0.0.1:5432         0.0.0.0:*

Connect to PostgreSQL Through Tunnel

From Local Machine (After Tunnel is Established)

# Basic connection
psql -h localhost -p 5432 -U postgres
psql -h 127.0.0.1 -p 5432 -U christine

# List all databases
psql -h localhost -p 5432 -U postgres -l

# Connect to specific database
psql -h localhost -p 5432 -U postgres -d database_name

Install PostgreSQL Client (If Needed)

# Debian/Ubuntu/Parrot
sudo apt install postgresql-client -y

# Mac
brew install postgresql

# Without sudo (compile from source - painful, not recommended)
# Better: use the tunnel from a machine where you have psql

Alternative: Use Python

# If psql not available but python is
pip3 install psycopg2-binary --break-system-packages

python3 << EOF
import psycopg2
conn = psycopg2.connect(
    host="localhost",
    port=5432,
    user="postgres",
    password="your_password",
    database="postgres"
)
cur = conn.cursor()
cur.execute("SELECT version();")
print(cur.fetchone())
conn.close()
EOF

Troubleshooting

Tunnel Not Working - Common Issues

"Connection refused" when testing tunnel: - Tunnel didn't start properly - PostgreSQL not running on remote host - Wrong IP/port in tunnel command - Check: netstat -tuln | grep 5432 on BOTH local and remote

Port already in use:

# See what's using the port
lsof -i :5432
# Kill it or use different local port
ssh -L 5433:localhost:5432 user@host

Nothing listening on local port: - SSH command didn't include -L flag - SSH session died - Permission issue (unlikely for ports >1024) - Try explicit binding: -L 127.0.0.1:5432:...

Works with -N but not without: - Some SSH configurations block forwarding in interactive sessions - Always works with -f -N

PostgreSQL Connection Errors (After Tunnel Works)

"No password supplied": - Tunnel works! Just need to provide password - psql -h localhost -p 5432 -U postgres (will prompt) - Or: PGPASSWORD=yourpass psql -h localhost -p 5432 -U postgres

"Password authentication failed": - Tunnel works! Wrong credentials - Check username exists on remote - Check pg_hba.conf allows password auth

"No route to host": - SSH can't reach target from remote server - Wrong IP in tunnel command

Timeout: - PostgreSQL only listening on unix socket (not TCP) - Firewall blocking on remote - PostgreSQL not running - Check: netstat -tuln | grep 5432 on remote

Dynamic Port Forwarding (SOCKS Proxy)

Create SOCKS Proxy

# Creates SOCKS5 proxy on localhost:1080
ssh -D 1080 -N user@host

# Use with proxychains
proxychains nmap -sT 10.10.10.0/24
proxychains curl http://internal-server/

Configure Tools for SOCKS

# Edit /etc/proxychains.conf
socks5 127.0.0.1 1080

# Or use tools with native SOCKS support
curl --socks5 localhost:1080 http://example.com

Remote Port Forwarding (Reverse Tunnel)

Basic Syntax

# Make YOUR local port accessible from remote host
ssh -R [remote_port]:[local_host]:[local_port] user@ssh_server

# Example: Remote host can access your local web server
ssh -R 8080:localhost:80 user@remote_host
# Now on remote: curl localhost:8080 hits YOUR machine's port 80

Tips & Best Practices

Keep tunnels alive:

# Add to SSH config (~/.ssh/config)
Host *
    ServerAliveInterval 60
    ServerAliveCountMax 3

Multiple tunnels in background:

# Start all at once
ssh -f -N -L 5432:localhost:5432 -L 3306:localhost:3306 user@host

# Or separate processes for easier management
ssh -f -N -L 5432:localhost:5432 user@host
ssh -f -N -L 3306:localhost:3306 user@host

Auto-reconnect tunnel:

# Simple loop
while true; do
    ssh -N -L 5432:localhost:5432 user@host
    sleep 5
done

# Better: use autossh
autossh -M 0 -N -L 5432:localhost:5432 user@host

Security: - Always bind to 127.0.0.1 unless you specifically need other machines to access - Don't use -L 0.0.0.0:... unless necessary (exposes port to network) - Tunnel encrypts traffic - good for insecure networks - Better than opening firewall ports on remote host

Performance: - Minimal overhead for tunnels - Each tunnel is separate SSH channel - Can compress: ssh -C -L ... (helps for slow connections)