Enumeration
Automation
We can use tools like LinPEAS to automate enumeration for privilege escalation, but below are manual methods for enumerating the system.
System Information
uname -a # Kernel version & system info
cat /etc/os-release # OS version
id # Current user info
whoami # Username
hostname # System hostname
User & Group Enumeration
who # Logged-in users
w # Active sessions
last # Login history
groups # Current user's groups
cat /etc/passwd # List system users
cat /etc/group # List system groups
Sudo & SUID Checks
sudo -l # Check sudo permissions
find / -perm -4000 -type f 2>/dev/null # Find SUID binaries
find / -perm -2000 -type f 2>/dev/null # Find SGID binaries
cat /etc/sudoers # Sudo configuration
Environment & Path
env # List environment variables
printenv # Another way to list environment variables
echo $PATH # Path variable (check for writable dirs)
Network Information
ip a # Show network interfaces
ifconfig # Same as above
netstat -tulnp # List open ports
ss -tulnp # Another way to list open ports
iptables -L -v -n # Check firewall rules
cat /etc/hosts # Show local hostname resolution
Process & Service Enumeration
ps aux # Running processes
ps -ef | grep root # Processes running as root
systemctl list-units --type=service # List system services
Scheduled Tasks & Cron Jobs
crontab -l # Current user's cron jobs
cat /etc/crontab # System-wide cron jobs
ls -la /etc/cron* # Scheduled cron jobs
systemctl list-timers --all # systemd timers (frequently run a job as root)
systemctl cat <name>.service # inspect the paired root-run unit
cat /etc/systemd/system/*.service # unit files: User=, ExecStart=, EnvironmentFile=
scheduled jobs are a prime privesc vector. Look for a root timer/oneshot that runs an interpreter on a file another service can write (e.g. ExecStart=/usr/bin/python3 /path/hook.py) - whoever can write that file gets code execution as root on the next tick. Pair this with any write primitive you already have.
File System & Writable Directories
find / -type f -writable 2>/dev/null # Find writable files
find / -type d -writable 2>/dev/null # Find writable directories
find / -name ".*" 2>/dev/null # Find hidden files and directories
df -h # Check disk usage
mount # Mounted filesystems
Temporary Directories
ls -la /tmp # List /tmp directory
ls -la /var/tmp # List /var/tmp directory
ls -la /dev/shm # List /dev/shm directory
SSH & Credentials
cat ~/.ssh/id_rsa # Check for SSH keys
cat /etc/ssh/sshd_config # SSH configuration
Logs & Interesting Files
cat /var/log/auth.log # Authentication logs
cat /var/log/syslog # System logs
cat ~/.bash_history # Bash command history
cat ~/.zsh_history # Zsh command history
find / -type f \( -name "*_hist" -o -name "*_history" \) -ls 2>/dev/null # Find history files
Installed Packages & Binaries
dpkg -l # List installed packages (Debian-based)
rpm -qa # List installed packages (RedHat-based)
sudo --version # Check sudo version
ls -la /bin /usr/bin /usr/sbin # List installed binaries
Kernel & Exploit Checks
uname -r # Kernel version
lsmod # Loaded kernel modules
cat /proc/version # Kernel and OS details
searchsploit `uname -r` # Search for kernel exploits (requires exploitdb)
Secrets in /proc (Command Line & Environment)
The /proc/<pid>/ files cmdline and environ are world-readable (unless hidepid is set). Jobs and services frequently pass secrets as arguments - --password, --token, API keys, connection strings - which leak to any user who can read the process.
# Read a running process's command line (NUL-separated -> replace with spaces)
tr '\0' ' ' < /proc/<PID>/cmdline ; echo
tr '\0' ' ' < /proc/<PID>/environ ; echo
# Snapshot sweep: any process exposing a password/token on its command line
for p in /proc/[0-9]*; do
cl=$(tr '\0' ' ' < "$p/cmdline" 2>/dev/null)
case "$cl" in *--password*|*--token*|*--pass*|*secret*) echo "$p: $cl";; esac
done
Short-lived processes (a cron job or a systemd Type=oneshot service) appear for only a moment, so a normal sweep misses them. Poll in a tight loop - a shell for loop over every PID is too slow; use Python or a tiny compiled watcher:
# Watch for a secret-bearing process that appears only briefly
import os, time
end = time.time() + 180
while time.time() < end:
for d in os.listdir('/proc'):
if not d.isdigit():
continue
try:
c = open('/proc/%s/cmdline' % d, 'rb').read()
except OSError:
continue
if b'client' in c: # tune the needle (e.g. b'--user')
print(d, c.replace(b'\x00', b' ').decode('utf-8', 'replace'))
pspy (a ready-made watcher)
pspy watches process creation without root, which makes it ideal on an unprivileged foothold. Prefer it when you do not want to write your own poller.
wget https://github.com/DominicBreuker/pspy/releases/latest/download/pspy64
chmod +x pspy64
./pspy64 -pf # -p = process events, -f = print FULL command lines
-fis mandatory here. Without it pspy prints the executed binary but not its arguments, so a--password <value>shows only as e.g.clickhouse-client. With-fyou get the whole command line.-pmonitors process executions and runs unprivileged.-iadds inotify file events but normally needs root (CONFIG_PROC_EVENTS);-cenables colour and-dshows created directories.-pstill polls, so a process that lives only ~100 ms can fall between iterations. Use the "feed it work" trick below, or flood the queue so the job spawns its secret-bearing command repeatedly and stays on screen.
To make a scheduled job fire during your watch window, feed it work if you can (e.g. push an entry into a queue it processes) so the secret-bearing child process actually spawns while you poll.
Related places to check:
ls -la /proc/<PID>/cwd /proc/<PID>/exe # working dir / binary a service runs from
cat /proc/<PID>/maps | grep -i deleted # deleted-but-open files
unset HISTFILE; # and read other users' history if perms allow
Service hardening changes what file-read primitives can reach: ProtectHome=true blocks /home, /root, /run/user; ProtectSystem=strict makes the rest read-only (but still readable). /proc/<pid>/cmdline itself is usually still readable.