enodia-sentinal/enodia_sentinel/detectors/reverse_shell.py
Luna 586f74b929 Relicense under GPL-3.0-or-later
Replace MIT with the full GNU GPLv3 text, update license metadata in
pyproject.toml (+ trove classifiers) and PKGBUILD, and add
SPDX-License-Identifier headers to all Python modules and shell scripts.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 06:52:34 -07:00

38 lines
1.3 KiB
Python

# 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,),
)