Falco, a CNCF project, can detect interactive shell sessions within containers by monitoring Linux syscalls.

Here’s a live example:

Imagine a container running a simple web server. You want to see if anyone is trying to get an interactive shell inside it.

First, ensure Falco is running in your Kubernetes cluster, either as a DaemonSet or a standalone deployment. It needs to be able to see the syscalls from your containerized workloads.

Let’s simulate an interactive shell session. In a running pod (e.g., a busybox pod):

kubectl exec -it my-busybox-pod -- sh

Now, within that sh session, you might run commands like ls, cat /etc/passwd, or even try to download a script. Falco, if configured correctly, will be logging these activities.

A typical Falco rule to detect this might look like this:

- rule: Terminal Access
  desc: An interactive shell was spawned in a container.
  condition: >
    container and proc.name in ("bash", "sh", "ash", "zsh", "ksh") and
    proc.tty != 0
  output: >
    An interactive shell was spawned in container %container.name.
    (user: %user.name %user.id,
    executable: %proc.name %proc.id,
    command: %proc.cmdline,
    tty: %proc.tty)
  priority: WARNING
  tags: [container, interactive, shell]

Let’s break down this rule:

  • container: This ensures the event originates from within a containerized environment. Falco automatically enriches events with container metadata.
  • proc.name in ("bash", "sh", "ash", "zsh", "ksh"): This part specifically looks for common shell executables. If an attacker or unauthorized user gains access, they’re likely to use one of these.
  • proc.tty != 0: This is the crucial piece. proc.tty refers to the controlling terminal for a process. A value of 0 typically means the process is running in the background or as a daemon without a controlling terminal. A non-zero value indicates the process is attached to a terminal, which is characteristic of an interactive session.

When the kubectl exec -it ... sh command is run, the sh process inside the container is spawned and attached to a pseudo-terminal (TTY). Falco observes the execve syscall for sh and checks its associated TTY. Because proc.tty will be non-zero, the rule triggers.

The output field provides valuable context: the container name, the user who initiated the process (if known/propagated), the shell executable and its ID, the full command line arguments used to start the shell, and the TTY device.

To see this in action, you’d typically configure Falco to output to stdout, a file, or send alerts to a SIEM. For example, if outputting to stdout:

kubectl logs -f <falco-pod-name> -n falco

You would see an output similar to this when the interactive shell is opened:

{
  "output": "An interactive shell was spawned in container my-busybox-container. (user: root 0, executable: sh 1234, command: sh, tty: 3)",
  "priority": "WARNING",
  "rule": "Terminal Access",
  "scause": "execve",
  "time": "2023-10-27T10:30:00Z",
  "container": {
    "id": "abcdef1234567890...",
    "name": "my-busybox-container",
    "image": "busybox:latest",
    "runtime": "containerd"
  },
  "user": {
    "name": "root",
    "id": 0,
    "idgroups": [0]
  },
  "proc": {
    "pid": 1234,
    "ppid": 1,
    "name": "sh",
    "cmdline": "sh",
    "exe": "/bin/sh",
    "tty": 3
  }
}

This detection mechanism is powerful because it doesn’t rely on application-level logs, which attackers can easily tamper with or disable. Falco operates at the kernel level, capturing fundamental system activity.

The proc.tty != 0 condition is key. It leverages the fact that interactive shells require a terminal for input/output, while background processes or daemons typically don’t have one. This distinction allows Falco to filter out legitimate non-interactive process executions.

Furthermore, you can extend this rule. For instance, you might want to alert on specific commands run within the shell, or on shells spawned by unusual parent processes. You could add conditions like:

and proc.cmdline contains "/bin/bash -i"

or

and proc.parent.name != "kubectl"

This allows for fine-grained control over what constitutes suspicious interactive shell activity in your environment.

The next concept you’ll likely encounter is detecting privilege escalation attempts within these interactive sessions.

Want structured learning?

Take the full Falco course →