# SPDX-License-Identifier: GPL-3.0-or-later """reverse_shell — an interpreter with a network socket on its stdio. A real reverse shell dups a TCP/UDP socket onto fd 0/1/2 (``nc -e /bin/bash``, ``bash -i >& /dev/tcp/...``). Interactive shells get a pty, and daemons get unix sockets/pipes — neither is a network socket, so requiring the stdio socket to appear in the network socket table is what keeps false positives near zero. """ from __future__ import annotations from collections.abc import Iterator from ..alert import Alert, Severity from ..config import Config from ..system import SystemState def detect(state: SystemState, cfg: Config) -> Iterator[Alert]: peer_by_inode = state.net_peer_by_inode for proc in state.processes: if proc.comm not in cfg.interpreters: continue inode = proc.stdio_socket_inode() if inode is None: continue peer = peer_by_inode.get(inode) if not peer: # unix socket / pipe — benign continue yield Alert( severity=Severity.CRITICAL, signature="reverse_shell", key=f"rsh:{proc.pid}", detail=( f"pid={proc.pid} comm={proc.comm} stdio=net-socket " f"peer=[{peer}] cmd=[{proc.cmdline[:90]}]" ), pids=(proc.pid,), )