CH04 — LAB

Process Management — Hands-On

Five exercises covering process inspection, CPU priority manipulation, signal sending, job control, and security-focused process hunting — the tools you use every time something goes wrong on a server.

Platform: Linux Terminal
Exercises: 5
Difficulty: Intermediate
Est. Time: 50–65 min

Lab Objectives

1
Process Inspection with ps and top
PS / TOP
SCENARIOA server is running slowly. Your first step is always to understand what is currently running — how many processes, which are consuming the most resources, and what state they are in.
  1. Get a full process snapshot: ps aux. Identify the column headers: USER, PID, %CPU, %MEM, VSZ, RSS, STAT, START, TIME, COMMAND.
  2. Sort processes by CPU usage: ps aux --sort=-%cpu | head -15
  3. Sort processes by memory: ps aux --sort=-%mem | head -15
  4. Show the process tree: pstree -p | head -30 or ps --forest -eo pid,ppid,comm | head -30
  5. Count total running processes: ps aux | wc -l (subtract 1 for the header)
  6. Launch top, let it run for 30 seconds. While in top: press P (sort by CPU), then M (sort by memory), then 1 (show per-CPU data), then q to quit.
  7. Non-interactive top snapshot: top -bn1 | head -20 (useful for scripts)
# Understanding ps aux columns $ ps aux | head -3 USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.0 0.1 168532 9200 ? Ss Jan15 0:03 /sbin/init root 2 0.0 0.0 0 0 ? S Jan15 0:00 [kthreadd] # STAT codes: S=sleeping, R=running, D=uninterruptible # Z=zombie, T=stopped, s=session leader # VSZ=virtual memory, RSS=resident set size (actual RAM used)
2
CPU Priority with nice and renice
NICE
SCENARIOYou need to run a CPU-intensive backup script during business hours without impacting other users. Set it to low priority and verify the nice value is applied correctly.
  1. Check the default nice value for new processes: nice (run with no arguments shows the default)
  2. Start a background process with elevated niceness (low priority): nice -n 15 sleep 300 &
  3. Verify the nice value: ps -p $! -o pid,comm,nice (where $! is the last background PID)
  4. See all processes with their nice values: ps -eo pid,comm,nice | sort -k3 -rn | head -20
  5. Change the nice value of the running sleep process: renice -n 5 -p $SLEEP_PID
  6. Verify the change: ps -p $SLEEP_PID -o pid,comm,nice
  7. Kill the test process: kill $SLEEP_PID
  8. Try to set a negative nice value without sudo: nice -n -5 sleep 10 & — observe the permission error
# Practical nice workflow $ nice -n 15 sleep 300 & [1] 4821 $ ps -p 4821 -o pid,comm,nice PID COMMAND NI 4821 sleep 15 $ renice -n 5 -p 4821 4821 (process ID) old priority 15, new priority 5 $ ps -p 4821 -o pid,comm,nice PID COMMAND NI 4821 sleep 5
3
Signals and Process Termination
SIGNALS
SCENARIOA web server process has become unresponsive. Practice the signal-sending workflow: graceful shutdown first, force kill only as a last resort.
  1. Start a test process to practice on: sleep 9999 & TESTPID=$!
  2. List all available signals: kill -l
  3. Send SIGTERM (graceful): kill -15 $TESTPID — verify it terminated: ps -p $TESTPID 2>/dev/null || echo "Process ended"
  4. Start another test: sleep 9999 & TESTPID2=$!
  5. Stop (pause) it: kill -19 $TESTPID2 — verify state is T: ps -p $TESTPID2 -o pid,stat
  6. Resume it: kill -18 $TESTPID2 — state returns to S
  7. Force kill: kill -9 $TESTPID2
  8. Use pkill by name: sleep 1000 & sleep 1000 & pkill -f "sleep 1000"
# Signal workflow: graceful first $ sleep 9999 & [1] 5001 $ kill -15 5001 # SIGTERM - polite $ ps -p 5001 2>/dev/null || echo "Process ended" Process ended # Process cleaned up and exited # Stop and resume a process $ sleep 9999 & [2] 5010 $ kill -STOP 5010 # Pause the process $ ps -p 5010 -o pid,stat PID STAT 5010 T # T = stopped $ kill -CONT 5010 # Resume $ kill -9 5010 # Force kill
4
Job Control and Background Execution
JOB CONTROL
SCENARIOYou need to run multiple long-running processes from a single terminal session while keeping the terminal available for other work. Practice the full job control workflow.
  1. Start a foreground process: ping localhost — it blocks the terminal
  2. Suspend it: press Ctrl+Z — the terminal returns, process is stopped
  3. See the job list: jobs — note the job number in brackets
  4. Resume it in the background: bg %1 — it continues running, terminal is free
  5. Bring it back to foreground: fg %1 — then Ctrl+C to terminate
  6. Start directly in background: sleep 500 & sleep 600 & sleep 700 &
  7. List all jobs: jobs -l (with PIDs)
  8. Terminate all background jobs: kill %1 %2 %3 2>/dev/null; jobs
  9. nohup for persistent processes: nohup sleep 9999 > ~/nohup-test.log 2>&1 & — this survives terminal closure
# Job control workflow $ ping localhost # Running in foreground PING localhost... Ctrl+Z # Suspend with Ctrl+Z [1]+ Stopped ping localhost $ jobs [1]+ Stopped ping localhost $ bg %1 [1]+ ping localhost & $ jobs [1]+ Running ping localhost & $ fg %1 # Bring back to foreground ping localhost ^C # Ctrl+C to terminate
5
Security-Focused Process Hunting
THREAT HUNTING
SCENARIOYou have received an alert that a server may be compromised. Use process management tools to investigate — look for suspicious processes, unexpected network connections, and anomalies in the process tree that could indicate malicious activity.
  1. List all processes running as root: ps aux | grep "^root" — know what should and should not run as root
  2. Find processes with suspicious names (common malware patterns): ps aux | grep -E "\.\.|\.\//|/tmp|/dev/shm" 2>/dev/null
  3. Check /proc for process count discrepancy: echo "ps count: $(ps aux | wc -l)" && echo "/proc count: $(ls /proc | grep -E '^[0-9]+$' | wc -l)"
  4. Find processes listening on network ports: ss -tlnp or netstat -tlnp 2>/dev/null
  5. Check what files a specific process has open: lsof -p $$ | head -20 (using your own shell's PID)
  6. Find all processes running from /tmp (red flag): ls -la /proc/*/exe 2>/dev/null | grep tmp
  7. Document any anomalies: ps aux --sort=-%cpu | awk '$3 > 0.5 {print}' > ~/high-cpu-procs.txt
# Threat hunting: check for processes from suspicious locations $ ls -la /proc/*/exe 2>/dev/null | grep -E "tmp|dev/shm|var/tmp" # If this returns results, it is a serious red flag # Legitimate processes should run from /usr/bin, /usr/sbin, /bin, /sbin # Verify process count matches between tools $ echo "ps: $(ps aux | wc -l) processes" $ echo "/proc: $(ls /proc | grep -E '^[0-9]+$' | wc -l) directories" # Mismatch = possible rootkit hiding processes from ps # Check all listening network services $ ss -tlnp State Recv-Q Send-Q Local Address:Port LISTEN 0 128 0.0.0.0:22 # SSH - expected LISTEN 0 511 0.0.0.0:80 # HTTP - expected if web server # Unexpected ports (4444, 9001, 31337) are suspicious
INCIDENT RESPONSE: PROCESS ANALYSIS
During a real incident, take a process snapshot early: ps auxf > ~/snapshot-$(date +%Y%m%d-%H%M%S).txt. Preserve it before any remediation. Rootkits specifically target ps and ls to hide their presence — if /proc shows more processes than ps, you have a rootkit. Use the raw /proc filesystem as your ground truth. The lsof tool (list open files) is invaluable: malware must have files open (executable, config, socket) and lsof reveals them even when the original file has been deleted (the inode remains open).

Lab Complete

Mark complete when you have finished all five exercises.

Lab progress saved. Move on to Chapter 5!