Every red teamer knows SSH. It is the bread and butter of remote administration and, often, our primary means of persistence and movement. But most operators only scratch the surface, using it as little more than an encrypted Telnet.

Today, we are diving deep into SSH Multiplexing and Master Control Sockets. This method allows you to channel multiple SSH sessions—shells, file transfers, and port forwards—through a single, authenticated TCP connection. It drastically reduces network overhead, speeds up your workflow, and creates fascinating opportunities for both operational efficiency and post-exploitation lateral movement.

What is SSH Multiplexing?

SSH multiplexing is a capability of OpenSSH that allows multiple distinct SSH sessions to share a single underlying TCP connection. This is implemented through a Master Control Socket, a Unix domain socket (or named pipe on Windows) that acts as a local interface to the established connection.

The Mechanics

When you run ssh user@target, the following typically happens:

  1. TCP Handshake: SYN, SYN-ACK, ACK.
  2. Protocol Negotiation: Versions, KEX, Ciphers.
  3. Authentication: Password, Key exchange, MFA.
  4. Channel Setup: A shell is spawned.

This is noisy. If you run a loop to SCP 10 files, you do this 10 times.

With multiplexing:

  1. Master Connection: The first SSH command establishes the connection and creates a local socket file (e.g., /tmp/ssh-socket).
  2. Slave Connections: Subsequent commands (ssh, scp, sftp) look for this socket. If found, they communicate with the local SSH client process to tunnel their data through the existing TCP connection.
  3. Zero Overhead: No new TCP handshake. No new authentication. Instant session creation.

Why This Matters for Red Teams

  • Speed: Operations that require multiple commands become instantaneous.
  • Stealth (Network Level): You reduce the number of “New Connection” events in firewall logs. Instead of 50 connections from your C2 to the target, you have one long-lived connection.
  • Stealth (Auth Level): You authenticate once. This reduces the noise in /var/log/auth.log or Windows Event ID 4624.
  • Persistence: If you can drop a background master connection, you can come back later without re-entering credentials (as long as the connection holds).

[!WARNING] While multiplexing reduces the volume of authentication logs, long-lived connections are themselves an anomaly. A single TCP connection open for 4 days transferring 2GB of data looks suspicious to a network threat hunter.


Configuration: Set It and Forget It

The professional way to manage multiplexing is via your ~/.ssh/config.

Host target-*
    User operator
    # The socket path. %r=remote_user, %h=host, %p=port
    # %C is a hash of the above, extremely useful to prevent
    # "socket path too long" errors.
    ControlPath ~/.ssh/sockets/%C

    # Automatically become master if no socket exists;
    # Use master if it does.
    ControlMaster auto

    # Keep the connection open for 10 minutes after the last session closes.
    ControlPersist 600
  1. ControlPath: This is where the socket lives. Keep this directory (~/.ssh/sockets/) secure (chmod 700).
  2. ControlMaster auto: Intelligent switching.
  3. ControlPersist: This is the killer feature. If you exit your shell, the TCP connection stays alive in the background. If you run ssh target again 5 minutes later, it’s instant.

Manual Control: The On-the-Fly Method

Sometimes you are on a compromised box and you don’t want to edit config files. You can do this purely via command-line flags.

1. The Master (The Anchor)

# -M: Master mode
# -S: Socket path
# -f: Fork to background
# -N: No command (just forward)
ssh -M -S /tmp/pivot -fN user@10.10.10.5

This command authenticates, establishes the connection, creates /tmp/pivot, and goes to the background.

2. The Slaves (The Users)

Now, use that socket to do work:

# Run a command
ssh -S /tmp/pivot user@10.10.10.5 "id"

# Transfer a file (Note: scp uses -o for this)
scp -o "ControlPath=/tmp/pivot" payload.elf user@10.10.10.5:/tmp/

3. Dynamic Control (The Puppet Master)

You can send control commands to the master process to add port forwards dynamically without restarting the connection.

# Check status
ssh -S /tmp/pivot -O check user@10.10.10.5

# Add a SOCKS proxy on port 1080
ssh -S /tmp/pivot -O forward -D 1080 user@10.10.10.5

# Add a text-book Local Forward
ssh -S /tmp/pivot -O forward -L 8080:localhost:80 user@10.10.10.5

# Stop the SOCKS proxy
ssh -S /tmp/pivot -O cancel -D 1080 user@10.10.10.5

# Kill the master connection
ssh -S /tmp/pivot -O exit user@10.10.10.5

This is incredibly powerful during an engagement where requirements change rapidly.


The Dark Side: SSH Socket Hijacking

Here is where the “Red Team” mindset really kicks in.

A socket file acts as a pre-authenticated session handle. Anyone who can read/write to that socket file can use the SSH connection as the authenticated user.

The Attack Scenario

  1. You compromise a developer machine or a jump box.
  2. You enumerate /tmp or ~/.ssh and find a socket file.
    find /tmp -type s 2>/dev/null
    # Output: /tmp/ssh-UserA-ServerB
    
  3. You check who owns it. It is owned by UserA.
  4. If you are root, or if UserA has set weak permissions (e.g., 777 usually doesn’t work for sockets, but directory permissions matter), you can hijack it.
  5. Pivot without Credentials:
# Assuming you are root and found UserA's socket
ssh -S /tmp/ssh-UserA-ServerB remote_host "mkdir /tmp/.hidden; chmod 777 /tmp/.hidden"

You are now executing commands on ServerB as UserA, and you never saw a password or private key. You bypassed MFA because the session is already established.

Defense

  • Permissions: Ensure ~/.ssh/sockets is 0700.
  • Location: Don’t put sockets in public places like /tmp unless absolutely necessary.
  • Monitoring: Watch for ssh processes with mismatching parent process IDs or unusual socket activity.

Windows and Cross-Platform Nuances

Yes, this works on Windows too, provided you are using the modern OpenSSH Client (bundled with Windows 10/11/Server 2019+).

On Windows, Unix domain sockets don’t exist in the same way, so OpenSSH uses Named Pipes.

# Windows Config
Host target
    ControlPath \\.\pipe\ssh-target

The concept remains identical. This is extremely useful when operating from a Windows C2 implant.


Troubleshooting and Cleanup

The main downside of multiplexing is Stale Sockets. If the network connection dies ungracefully (e.g., ISP drop), the local socket file still exists, and the SSH client thinks it’s connected.

When you try to use it:

mux_client_request_session: read from master failed: Broken pipe

The Fix

You must manually remove the socket file.

# Robust cleanup snippet
socket_path="/tmp/pivot"
if [ -S "$socket_path" ]; then
    # Try graceful exit
    ssh -S "$socket_path" -O exit user@host 2>/dev/null || rm "$socket_path"
fi

Automation Script

Here is a wrapper function I use for mass-commands. It checks for a master connection, creates one if missing, runs the command, and ensures cleanup.

run_multiplexed() {
    local target="$1"
    local cmd="$2"
    local socket="/tmp/ssh-mux-${target##*@}" # socket based on host

    # Check if socket exists and is alive
    if ! ssh -S "$socket" -O check "$target" 2>/dev/null; then
        echo "[*] Establishing Master Connection..."
        # Remove stale socket just in case
        rm -f "$socket"
        ssh -M -S "$socket" -fN "$target"
    fi

    # Run command
    echo "[+] Running: $cmd"
    ssh -S "$socket" "$target" "$cmd"
}

[!NOTE] Always validate input variables in your actual scripts to prevent command injection locally!

Conclusion

Mastering SSH Control Sockets transforms you from a user of tools into a master of the protocol. It allows for stealthier, faster, and more flexible movement through a network. Whether you are automating a deployment or manually pivoting through five jump boxes, multiplexing is the key to sanity.

Stay connected, stay encrypted.

UncleSp1d3r out.


References