Bash Basics for Kali Linux

Beginner ~15 min read
Ready to feel like you're actually doing cyber? Bash is the language you'll use to drive Kali Linux — the toolkit ethical hackers reach for every day. Don't try to memorize it all; you'll pick it up by doing. Let's write your first commands.

Why Every Security Pro Uses Bash

The command line is your most powerful tool in cybersecurity. Whether you're running Kali Linux for pentesting, analyzing logs on a server, or competing in a CTF, bash proficiency separates beginners from practitioners. This guide assumes you're on Kali Linux — the go-to distro for security work. Open a terminal and follow along.

💡 Kali Linux default user is kali. Your home directory is /home/kali. The terminal is your best friend.

Navigating the File System

These are the commands you'll run hundreds of times a day:

Navigation & Listing
pwd Print Working Directory — see exactly where you are
ls List files in current directory
ls -la List ALL files (including hidden .files) in long format
ls -lah Same but with human-readable sizes (KB, MB, GB)
ls -lt Sort by modification time, newest first
cd /path/to/dir Change to an absolute path
cd ~ Jump to home directory (/home/kali)
cd - Jump back to the previous directory
cd .. Go up one directory level
tree -L 2 Visual directory tree, 2 levels deep (apt install tree)

File & Directory Operations

Creating, copying, moving, and deleting files. Note: Linux has no Recycle Bin — rm is permanent.

⚠️ rm -rf / or rm -rf /* will delete your entire system with no undo. Always double-check before running rm -rf.
File Management
touch file.txt Create an empty file (or update its timestamp)
mkdir my_dir Create a directory
mkdir -p a/b/c Create nested directories, no error if they exist
cp file.txt copy.txt Copy a file
cp -r dir/ backup/ Copy entire directory recursively
mv file.txt /tmp/ Move a file to /tmp/ (also used to rename)
mv old.txt new.txt Rename a file
rm file.txt Delete a file — no trash, gone forever
rm -rf dir/ ⚠️ Recursively delete directory and all contents
ln -s /real/path link Create a symbolic (soft) link
file mystery_file Identify file type — ignores the extension

Viewing & Searching File Contents

Reading files and hunting for specific data — core skills for CTF forensics, log analysis, and recon:

Viewing Files
cat file.txt Print the entire file to terminal
cat -n file.txt Print file with line numbers
less file.txt Scroll through a file (q = quit, /word = search, n = next match)
head -n 20 file.txt Show first 20 lines of a file
tail -n 20 file.txt Show last 20 lines
tail -f /var/log/syslog Live-follow a log file as it grows
xxd file.bin | head Hex dump — see the raw bytes of any file
strings file.bin Extract printable strings from a binary (key CTF skill!)
Searching
grep "pattern" file.txt Search for a pattern inside a file
grep -r "password" . Recursive search across all files in current directory
grep -i "admin" file.txt Case-insensitive search
grep -n "error" file.txt Show line numbers of matches
grep -v "nologin" /etc/passwd Show lines that do NOT match (invert)
grep -E "flag\{.*\}" *.txt Extended regex — hunt for CTF flags!
find / -name "*.conf" 2>/dev/null Find all .conf files (hide permission errors)
find . -perm -4000 Find SUID files — common privilege escalation target
find / -user root -perm -4000 2>/dev/null Find root-owned SUID binaries
locate secret.txt Fast search using a database (run updatedb first)

Text Processing Power Tools

Transform, filter, and extract data from text streams. These are indispensable for log analysis, wordlist manipulation, and CTF challenges:

Text Processing
cut -d":" -f1 /etc/passwd Cut field 1 using ":" as delimiter — extracts usernames
sort words.txt Sort lines alphabetically
sort -n numbers.txt Sort numerically (not lexicographically)
sort -u words.txt Sort and remove duplicate lines
sort -rn scores.txt Sort numerically in reverse (highest first)
uniq -c sorted.txt Count occurrences of adjacent identical lines (sort first!)
wc -l file.txt Count lines. -w = words, -c = bytes
sed "s/old/new/g" file.txt Replace all "old" with "new" (g = global)
sed -n "10,20p" file.txt Print only lines 10 through 20
awk '{print $1, $3}' file.txt Print columns 1 and 3 (space-delimited)
awk -F: '{print $1}' /etc/passwd Use ":" as field separator
tr "a-z" "A-Z" < file.txt Translate all lowercase to uppercase
base64 -d encoded.txt Decode base64 — extremely common in CTFs!
echo "hello" | rev Reverse a string — classic CTF trick
echo "74657374" | xxd -r -p Convert hex to ASCII

Piping & Redirection

Piping and redirection let you chain commands into powerful one-liners. Understanding stdin, stdout, and stderr is fundamental:

stdin (0) → input to a program
stdout (1) → normal output
stderr (2) → error messages

Example one-liner: cat /etc/passwd | grep -v "nologin" | cut -d: -f1 | sort | tee users.txt
→ Extract all real user accounts, sort them, display them, and save to users.txt — all at once.
Operators
cmd1 | cmd2 Pipe: stdout of cmd1 becomes stdin of cmd2
cmd > file.txt Redirect stdout to file — OVERWRITES existing content
cmd >> file.txt Append stdout to file — preserves existing content
cmd < file.txt Use file contents as stdin
cmd 2>/dev/null Discard error messages (/dev/null is the void)
cmd 2>&1 Redirect stderr to stdout — see ALL output together
cmd > out.txt 2>&1 Save all output (stdout + stderr) to file
cmd | tee file.txt Display output AND simultaneously save it to file
cmd1 && cmd2 Run cmd2 only if cmd1 succeeds (exit code 0)
cmd1 || cmd2 Run cmd2 only if cmd1 fails
cmd1 ; cmd2 Run cmd2 after cmd1 regardless of success/failure
xargs Build commands from stdin: cat urls.txt | xargs curl -O

File Permissions Deep Dive

Linux permissions control exactly who can read, write, and execute files. Understanding them is essential for both hardening systems and finding privesc paths:

-rwxr-xr--
→ Char 1: type (-=file, d=dir, l=symlink)
→ Chars 2–4: owner permissions
→ Chars 5–7: group permissions
→ Chars 8–10: others permissions

🔺 SUID bit (chmod 4755): the file runs with its owner's privileges regardless of who executes it. Finding a root-owned SUID binary on a target is a classic privilege escalation vector — check GTFOBins!
Permission Commands
chmod 755 script.sh Owner: rwx, Group: r-x, Others: r-x
chmod 644 file.txt Owner: rw-, Group: r--, Others: r-- (standard for files)
chmod 600 private.key Owner: rw- only — REQUIRED for SSH private keys!
chmod 700 ~/.ssh Owner only — REQUIRED for your .ssh directory!
chmod +x script.sh Add execute permission (for all users)
chmod u+x,g-w file Owner +execute, Group -write (symbolic notation)
chown kali:kali file.txt Change owner to kali, group to kali
chown -R kali /opt/tools Recursively change ownership of entire directory
find / -perm -4000 2>/dev/null Find SUID files — a key privesc technique
find / -perm -2000 2>/dev/null Find SGID files
find / -writable -type d 2>/dev/null Find world-writable directories

Octal reference:

Oct Symbol Meaning
7 rwx Read + Write + Execute
6 rw- Read + Write
5 r-x Read + Execute
4 r-- Read only
3 -wx Write + Execute
2 -w- Write only
1 --x Execute only
0 --- No permissions

Common combinations:

chmod Result Use Case
755 -rwxr-xr-x Scripts/executables: owner full, others can run
644 -rw-r--r-- Regular files: owner edits, others read
700 -rwx------ Private dirs/scripts: only owner can access
600 -rw------- Private files: SSH keys, config secrets
777 -rwxrwxrwx ⚠️ Dangerous: everyone has full access

Process Management

Monitoring and controlling running processes — essential for detecting malware, managing listeners, and sysadmin work:

Processes & Jobs
ps aux Show all running processes with user, PID, CPU, memory, command
ps aux | grep nginx Filter processes by name
top Live process monitor (press q to quit, k to kill by PID)
htop Colour-coded interactive process viewer (apt install htop)
kill 1234 Send SIGTERM (graceful stop) to PID 1234
kill -9 1234 Send SIGKILL (force stop) — the process cannot ignore this
killall firefox Kill all processes matching that name
pkill -f "python" Kill processes by matching the full command string
cmd & Run command in the background (gets a job number)
jobs List all background jobs in this shell session
fg %1 Bring background job #1 to the foreground
bg %1 Resume a stopped job in the background
Ctrl+Z Pause the current foreground process
nohup cmd & Run command immune to hangup — survives terminal close
screen -S mysession Create persistent named session (Ctrl+A, D to detach)
screen -r mysession Reattach to a detached screen session

Networking Commands on Kali

These commands form your recon toolkit. Understanding your own network and probing target networks:

Network Recon & Configuration
ip a Show all network interfaces and assigned IP addresses
ip route Show routing table — identify the default gateway
ifconfig Classic network interface info (still common on older systems)
ping -c 4 8.8.8.8 Send 4 ICMP packets to test connectivity
traceroute 8.8.8.8 Trace the network path to a destination (each hop)
netstat -tulpn Show listening TCP/UDP ports and their processes
ss -tulpn Faster, modern replacement for netstat
curl -I https://example.com Fetch HTTP response headers only (great for recon)
curl -s url | grep "flag" Silently download and search content
wget -q https://example.com/file Download a file quietly
nc -lvnp 4444 Listen on port 4444 — catch reverse shells here!
nc target.com 80 Connect to port 80 (manual banner grab)
dig google.com Detailed DNS lookup (try dig @8.8.8.8 domain.com)
nslookup domain.com Simple DNS query
whois domain.com Domain registration info and CIDR ranges
arp -a View ARP cache to discover hosts on local network
host domain.com Quick DNS forward/reverse lookup

SSH & SSH Keys — The Complete Guide

SSH (Secure Shell) is how you securely access remote servers — and how you'll pivot between machines during pentests. Key-based authentication is far stronger than passwords and is what professionals use.

🔑 NEVER share your private key (~/.ssh/id_ed25519). Your public key (~/.ssh/id_ed25519.pub) is safe to distribute — that's by design.

Generate a Key Pair

# Ed25519 (modern, recommended)
ssh-keygen -t ed25519 -C "you@email.com"

# RSA (for legacy server compatibility)
ssh-keygen -t rsa -b 4096 -C "you@email.com"

# Accept default location or choose a custom path
# Set a passphrase (recommended for extra protection!)

Creates two files:
~/.ssh/id_ed25519 ← PRIVATE key (never share!)
~/.ssh/id_ed25519.pub ← PUBLIC key (safe to distribute)

View & Verify Your Keys

# See your public key (safe to copy anywhere)
cat ~/.ssh/id_ed25519.pub

# List all SSH files and their permissions
ls -la ~/.ssh/

# Fix permissions if SSH complains
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_ed25519
chmod 644 ~/.ssh/id_ed25519.pub

SSH is strict about permissions. If your private key is readable by others, SSH will refuse to use it.

Deploy Your Public Key to a Server

# Automatic method (if you can already log in)
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@server

# Manual method (append to authorized_keys)
cat ~/.ssh/id_ed25519.pub | ssh user@server \
  "mkdir -p ~/.ssh && chmod 700 ~/.ssh && \
   cat >> ~/.ssh/authorized_keys && \
   chmod 600 ~/.ssh/authorized_keys"

The server stores your PUBLIC key in ~/.ssh/authorized_keys. When you connect, SSH proves you hold the matching private key — without ever transmitting it.

Connect With Key Authentication

# Default (uses ~/.ssh/id_ed25519 automatically)
ssh user@server

# Specify a key explicitly
ssh -i ~/.ssh/id_ed25519 user@server

# Custom port
ssh -p 2222 user@server

# Run a remote command without interactive shell
ssh user@server "cat /etc/os-release"
ssh user@server "ls /var/www/html"

If you get Permission denied (publickey), verify the public key is in the server's ~/.ssh/authorized_keys and permissions are correct.

Create an SSH Config File (~/.ssh/config)

# ~/.ssh/config — alias multiple servers

Host kali-vm
    HostName 192.168.1.100
    User kali
    IdentityFile ~/.ssh/id_ed25519
    Port 22

Host ctf-box
    HostName 10.10.10.5
    User root
    IdentityFile ~/.ssh/ctf_key
    Port 22

# Set permissions!
chmod 600 ~/.ssh/config

# Now connect with just:
# ssh kali-vm
# ssh ctf-box

The config file saves you from typing long commands. You can have different keys for different hosts.

SSH Agent — Store Keys in Memory

# Start the ssh-agent daemon
eval "$(ssh-agent -s)"

# Add your key (enter passphrase once)
ssh-add ~/.ssh/id_ed25519

# List keys currently loaded in agent
ssh-add -l

# Remove all keys from agent
ssh-add -D

# On Kali, add to ~/.bashrc for auto-start:
echo 'eval "$(ssh-agent -s)"' >> ~/.bashrc

The agent holds your decrypted key in memory. You enter your passphrase once per session instead of on every connection.

SSH Port Forwarding (Tunneling)

# LOCAL forward: access a remote service locally
# Access the server's port 80 at localhost:8080
ssh -L 8080:localhost:80 user@server

# REMOTE forward: expose your local service on the server
# Makes your local port 3000 reachable as server:9090
ssh -R 9090:localhost:3000 user@server

# DYNAMIC SOCKS5 proxy (route browser traffic through server)
ssh -D 1080 user@server
# Then configure browser to use SOCKS5 proxy at 127.0.0.1:1080

# Keep-alive tunnel in background (pentest pivoting)
ssh -fN -L 8080:internal-server:80 user@pivot-host

Port forwarding is a key technique in penetration testing for pivoting through network segments and accessing internal services.

Generate & Use Multiple Key Pairs

# Generate a dedicated key for a specific purpose
ssh-keygen -t ed25519 -f ~/.ssh/github_key -C "github"
ssh-keygen -t ed25519 -f ~/.ssh/ctf_key    -C "ctf-labs"

# ~/.ssh/config for multiple identities
Host github.com
    IdentityFile ~/.ssh/github_key
    User git

Host *.htb
    IdentityFile ~/.ssh/ctf_key
    User root

# Copy a CTF target's private key and connect
chmod 600 id_rsa
ssh -i id_rsa user@target

Best practice: use a separate key pair for each context (work, CTFs, personal). If one is compromised, the others remain safe.

Package Management with APT

Kali uses APT (Advanced Package Tool) on top of Debian. Kali's repositories include hundreds of security tools ready to install:

Kali meta-packages: kali-tools-top10 installs the 10 most-used tools. kali-linux-large installs the full toolkit. Start with top10.
APT Commands
sudo apt update Refresh the package index from repositories (do this first!)
sudo apt upgrade Upgrade all installed packages to latest versions
sudo apt full-upgrade Upgrade + handle dependency changes (safer for Kali)
sudo apt install nmap Install a package (e.g., nmap)
sudo apt install -y nmap Install without prompting for confirmation
sudo apt remove nmap Remove a package (keeps config files)
sudo apt purge nmap Remove package and all its configuration files
sudo apt autoremove Clean up unused dependency packages
apt search keyword Search for packages by keyword
apt show nmap Show detailed info about a package
dpkg -i package.deb Install a local .deb file directly
dpkg -l | grep nmap Check if a package is installed

Bash Scripting Basics

Automating repetitive tasks with scripts multiplies your effectiveness enormously. Every security professional should be able to write basic bash scripts:

Scripting Essentials
#!/bin/bash Shebang — first line, tells OS to use bash to run this file
VAR="hello world" Assign a variable — NO spaces around the = sign!
echo $VAR Print a variable's value (prefix with $)
"$VAR" Always quote variables to handle spaces safely
read -p "Enter name: " NAME Prompt user for interactive input
$((5 + 3)) Arithmetic expansion — evaluates to 8
if [ -f file.txt ]; then ... fi Conditional: -f = file exists, -d = dir exists, -z = empty string
if [ "$VAR" = "yes" ]; then ... fi String comparison (use = not ==)
for i in $(seq 1 10); do ... done Loop from 1 to 10
for f in *.txt; do echo "$f"; done Loop over files matching a glob
while IFS= read -r line; do ... done < file Loop over each line in a file (safest method)
function greet() { echo "Hello, $1!"; } Define a function — $1 is first argument
chmod +x script.sh && ./script.sh Make executable, then run it
Example: Host Discovery Script
#!/bin/bash
# Ping-sweep a subnet to find live hosts
# Usage: chmod +x discover.sh && ./discover.sh 192.168.1

TARGET=$1

# Check that an argument was provided
if [ -z "$TARGET" ]; then
    echo "Usage: $0 <subnet>"
    echo "Example: $0 192.168.1"
    exit 1
fi

echo "[*] Scanning $TARGET.0/24 for live hosts..."
ALIVE=0

# Loop through all 254 host addresses
for i in $(seq 1 254); do
    HOST="$TARGET.$i"
    # -c 1 = one packet, -W 1 = 1s timeout, &>/dev/null = suppress output
    if ping -c 1 -W 1 "$HOST" &>/dev/null; then
        echo "[+] ALIVE: $HOST"
        ALIVE=$((ALIVE + 1))
    fi
done

echo "[*] Scan complete. Found $ALIVE live host(s)."
🎯 Key Takeaway

Bash lets you chain commands, automate tasks, and run the security tools in Kali. Start with the basics — moving around, running tools, simple scripts — and build from there. Every pro started exactly where you are now.

// Knowledge Check