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>
38 lines
1.3 KiB
Python
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,),
|
|
)
|