Add memory obfuscation and ps-hidden process detection

This commit is contained in:
Luna 2026-06-13 03:55:09 -07:00
parent cb334c0c94
commit 893409b549
17 changed files with 353 additions and 26 deletions

View file

@ -35,6 +35,7 @@ SID_HIDDEN_UDP_PORT = 100031
SID_HIDDEN_RAW_SOCKET = 100034
SID_RAW_ICMP_SOCKET = 100035
SID_HIDDEN_PROTOCOL_SOCKET = 100037
SID_PS_HIDDEN_PROCESS = 100038
IFF_PROMISC = 0x100
@ -81,6 +82,11 @@ def find_hidden_pids(proc_pids: set[int], alive_pids: set[int]) -> set[int]:
return alive_pids - proc_pids
def find_ps_hidden_pids(proc_pids: set[int], ps_seen: set[int]) -> set[int]:
"""PIDs visible in /proc but missing from ps output."""
return proc_pids - ps_seen
def find_hidden_modules(proc_modules: set[str], sys_live: set[str]) -> set[str]:
"""Modules live in /sys/module but absent from /proc/modules."""
return sys_live - proc_modules
@ -159,6 +165,29 @@ def alive_pids(cap: int) -> set[int]:
return alive
def ps_pids() -> set[int] | None:
try:
res = subprocess.run(
["ps", "-e", "-o", "pid="],
capture_output=True, text=True, timeout=10,
)
except (OSError, subprocess.SubprocessError):
return None
if res.returncode != 0:
return None
out: set[int] = set()
for line in res.stdout.splitlines():
try:
out.add(int(line.strip()))
except ValueError:
continue
return out
def proc_pid_exists(pid: int) -> bool:
return os.path.exists(f"/proc/{pid}")
def proc_modules() -> set[str]:
out: set[str] = set()
try:
@ -393,7 +422,7 @@ def run(cfg: Config, state: SystemState | None = None) -> Iterator[Alert]:
pass
except OSError:
continue
if not os.path.exists(f"/proc/{pid}"):
if not proc_pid_exists(pid):
confirmed.append(pid)
if confirmed:
yield Alert(
@ -404,6 +433,22 @@ def run(cfg: Config, state: SystemState | None = None) -> Iterator[Alert]:
pids=tuple(sorted(confirmed)[:20]),
sid=SID_HIDDEN_PROC, classtype="rootkit-hidden-process")
tool_seen = ps_pids()
if tool_seen is not None:
missing_from_ps = []
for pid in sorted(find_ps_hidden_pids(visible, tool_seen)):
if proc_pid_exists(pid):
missing_from_ps.append(pid)
if missing_from_ps:
yield Alert(
severity=Severity.HIGH, signature="rootkit_ps_hidden_process",
key=f"rk:pshidproc:{min(missing_from_ps)}",
detail=("process(es) visible in /proc but missing from ps output "
"(process tool may be hooked): "
+ ", ".join(map(str, missing_from_ps[:20]))),
pids=tuple(missing_from_ps[:20]),
sid=SID_PS_HIDDEN_PROCESS, classtype="rootkit-hidden-process")
proc_mods = proc_modules()
sys_mods = sys_live_modules()
hidden_mods = find_hidden_modules(proc_mods, sys_mods)