Lab 02 — Linux Local Privilege-Escalation Auditor

Operation Cedar Lattice, Phase 04. Your first Linux foothold on a Meridian Freight host is an unprivileged user. The operator's next question mirrors the Windows one: what on this box turns "a user" into root (uid 0)? This lab is the auditor that answers it from a synthetic enumeration snapshot — the same facts LinPEAS, pspy, getcap -r /, and sudo -l surface — and, for every finding, names the ATT&CK technique, the escalation note, and the detection (an auditd rule idea).

Safety. Authorized-lab only. This is an auditor over host metadata: it reasons about enumeration output (LinuxFacts), never a live host. It runs no GTFOBins one-liner, drops no payload, and escalates nothing. Every finding ends in its detection. Same boundary as the security track's offensive-methodology-mastery/ labs.

The problem

Linux local privesc is overwhelmingly abuse of legitimate mechanisms: a SUID binary that happens to have a shell escape, a file capability that is root by another name, a sudo rule that is too generous, a writable directory on root's PATH, a root cron whose script you can edit, or membership in a root-equivalent group. The skill is to read the host's privilege surface and see which legitimate feature has become a path to uid 0 — and to write the auditd rule that would have caught the abuse.

What you build (lab.py)

audit(facts) -> [findings], composed from focused helpers:

  • suid_findings(facts) — SUID/SGID root binaries whose basename matches a curated GTFOBins-style allowlist (find, vim, bash -p, python, …). T1548.001.
  • capability_findings(facts) — file capabilities (getcap) that grant root: cap_setuid, cap_dac_override, cap_sys_admin, cap_sys_ptrace, cap_sys_module, … T1068 / T1548.001.
  • sudo_findings(facts) — sudo misconfig: ALL, a GTFOBins-runnable binary, a * wildcard command (argument injection), and env_keep keeping LD_PRELOAD/LD_LIBRARY_PATH (a dynamic-linker hijack to root). T1548.003 / T1574.006, NOPASSWD noted.
  • path_findings(facts) — a directory on root's PATH the user can write → command hijack. T1574.007.
  • cron_findings(facts) — a root cron whose script the user can overwrite. T1053.003.
  • group_findings(facts) — membership in docker/lxd/disk/shadow/sudo/wheel. T1611 / T1548.003.

Each Finding carries technique, escalation, and detection.

Attack cases the tests cover

  • A GTFOBins SUID (find) is flagged; benign SUID (passwd, mount) is not.
  • cap_setuid+ep on a binary is flagged; cap_net_raw (ping) is not.
  • Sudo NOPASSWD GTFOBins, sudo * wildcard, sudo ALL, and sudo env_keep=LD_PRELOAD each detected.
  • Writable dir on root's PATH; only the user-writable root cron (not the read-only one); a dangerous group (docker).
  • A hardened clean host yields no findings; every finding has an ATT&CK id and an auditd detection; output is deterministic and severity-sorted.

Run

pip install -r requirements.txt
LAB_MODULE=solution python3 -m pytest -q   # reference passes (16 tests)
python3 -m pytest -q                         # your implementation after the TODOs

Hardening / detection (what each finding ships)

FindingHardeningDetection (auditd / tooling)
Dangerous SUIDremove the SUID bit; nosuid mounts; replace the binaryexecve of a known-GTFOBins SUID by auid>=1000; ruid≠0/euid=0 child shell
Dangerous capabilitydrop the capability; baseline getcap -r /watch the cap-bearing binary's execve; alert on new file caps
Sudo misconfigexact-path commands, no shells/pagers, no *, no linker env_keep-w /etc/sudoers -p wa; auth.log sudo of a shell/wildcard
Writable root PATHremove group/world write from PATH dirs-w <dir> -p wa; file-create/execve in an admin-only PATH dir
Writable cronACL the script to root; cron dirs root-only-w /etc/cron* -w /var/spool/cron -p wa; pspy shows the periodic root job
Dangerous groupremove the membership; restrict docker/lxd-w /etc/group -p wa; container creates bind-mounting host root

Extensions (build in your own isolated range)

  • Parse real linpeas/getcap -r //sudo -l output and resolve effective writability with stat/ACLs instead of a pre-labeled flag.
  • Add kernel-exploit surface scoring (uname/kernel vs a known-CVE table) and a namespace/cgroup container-escape check (privileged container, host PID//proc, cap_sys_admin).
  • Expand the GTFOBins allowlist from the project's real data and emit a Sigma rule per finding.
  • Re-implement the SUID/cap walk in Rust or Go as a read-only collector on an owned host.

Interview / resume

"Built a Linux privilege-escalation auditor that ingests enumeration (SUID/SGID, file capabilities, sudoers, root PATH, cron, group membership), maps each escalation path to its ATT&CK technique and a concrete root note, and pairs every finding with an auditd rule — turning offensive enumeration into a defensible, hardening-first deliverable."

Limitations: a curated GTFOBins-style sample (not the full project) over synthetic facts; exploitability on a real host depends on binary version, kernel, full sudoers parse, mount options, and SELinux/AppArmor confinement. Output is leads to verify on an owned range, not proof.