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¶
Banner Grabbing¶
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¶
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:
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)