Expand monitoring for credential theft and covert protocols

This commit is contained in:
Luna 2026-06-13 03:30:36 -07:00
parent 3e5f8fc3f7
commit cb334c0c94
17 changed files with 675 additions and 25 deletions

View file

@ -18,6 +18,10 @@ from pathlib import Path
_INO_RE = re.compile(r"\bino:(\d+)")
_USER_RE = re.compile(r'users:\(\("([^"]+)",pid=(\d+),fd=\d+')
_SS_NETIDS = frozenset({
"tcp", "udp", "raw", "sctp", "dccp", "mptcp",
"p_raw", "p_dgr", "packet", "tipc", "xdp", "vsock",
})
@dataclass
@ -65,6 +69,23 @@ class Process:
out[k] = v
return out
@cached_property
def fd_targets(self) -> dict[str, str]:
"""Open file descriptor targets, keyed by fd number as a string."""
out: dict[str, str] = {}
fd_dir = f"/proc/{self.pid}/fd"
try:
names = sorted(os.listdir(fd_dir),
key=lambda x: int(x) if x.isdigit() else 0)
except OSError:
return out
for name in names:
try:
out[name] = os.readlink(os.path.join(fd_dir, name))
except OSError:
continue
return out
@cached_property
def status(self) -> dict[str, str]:
out: dict[str, str] = {}
@ -105,6 +126,7 @@ class Socket:
inode: int | None
comm: str
pid: int | None
kind: str = ""
class SystemState:
@ -166,8 +188,19 @@ class SystemState:
if self._injected_socks is not None:
return self._injected_socks
out: list[Socket] = []
for args in (["-tanep"], ["-uanep"]):
out.extend(self._parse_ss(self._run_ss(args)))
for args, kind in (
(["-tanep"], "tcp"),
(["-uanep"], "udp"),
(["-wanep"], "raw"),
(["-Sanep"], "sctp"),
(["-danep"], "dccp"),
(["-0anep"], "packet"),
(["-Manep"], "mptcp"),
(["--tipc", "-anep"], "tipc"),
(["--xdp", "-anep"], "xdp"),
(["--vsock", "-anep"], "vsock"),
):
out.extend(self._parse_ss(self._run_ss(args), kind=kind))
return out
@staticmethod
@ -182,13 +215,16 @@ class SystemState:
return ""
@staticmethod
def _parse_ss(text: str) -> list[Socket]:
def _parse_ss(text: str, *, kind: str = "") -> list[Socket]:
socks: list[Socket] = []
for line in text.splitlines():
parts = line.split()
if len(parts) < 5:
continue
state, _rq, _sq, local, peer = parts[:5]
if parts[0].lower() in _SS_NETIDS and len(parts) >= 6:
state, local, peer = parts[1], parts[4], parts[5]
else:
state, local, peer = parts[0], parts[3], parts[4]
rest = line
ino_m = _INO_RE.search(rest)
usr_m = _USER_RE.search(rest)
@ -199,6 +235,7 @@ class SystemState:
inode=int(ino_m.group(1)) if ino_m else None,
comm=usr_m.group(1) if usr_m else "",
pid=int(usr_m.group(2)) if usr_m else None,
kind=kind,
))
return socks