What is a Shell?

Shell = command interpreter program that provides an interactive environment for running commands.

Common shells:

  • /bin/bash - Bourne Again Shell (most common)
  • /bin/sh - Bourne Shell (POSIX standard)
  • /bin/zsh - Z Shell
  • /bin/dash - Debian Almquist Shell

What shells do:

  1. Provide interactive prompt for typing commands
  2. Interpret and execute commands
  3. Run other programs
  4. Handle scripting with shell syntax
  5. Manage environment (variables, paths, job control)

Understanding /etc/passwd

/etc/passwd = file containing user account information

Format

Each line represents one user:

username:x:1000:1000:User Name:/home/username:/bin/bash

Field Breakdown

username:x:1000:1000:User Name:/home/username:/bin/bash
    1    2   3    4       5           6            7

Field 1: Username

  • Login name
  • Example: john, alice, root

Field 2: Password Placeholder

  • x = password stored in /etc/shadow (encrypted)
  • Historical: used to store encrypted password here
  • Modern: always x for security

Field 3: User ID (UID)

  • Numeric user identifier
  • 0 = root (superuser)
  • 1-999 = system users (daemons, services)
  • 1000+ = regular users
  • Example: 1000, 1001, 1002

Field 4: Group ID (GID)

  • Primary group numeric identifier
  • Matches group in /etc/group
  • Example: 1000 (often same as UID for personal group)

Field 5: GECOS / Comment

  • User information (full name, contact, etc.)
  • Optional, can be empty
  • Example: John Doe, Alice Smith,Room 123,555-1234

Field 6: Home Directory

  • User’s home directory path
  • Where user starts after login
  • Example: /home/john, /root, /var/www

Field 7: Login Shell

  • Program executed when user logs in
  • Example: /bin/bash, /bin/sh, /usr/sbin/nologin

Real Examples

Regular user:

alice:x:1000:1000:Alice Smith:/home/alice:/bin/bash
  • Username: alice
  • Password: in /etc/shadow
  • UID: 1000
  • GID: 1000
  • Comment: Alice Smith
  • Home: /home/alice
  • Shell: /bin/bash

Root user:

root:x:0:0:root:/root:/bin/bash
  • Username: root
  • UID: 0 (superuser)
  • GID: 0
  • Home: /root
  • Shell: /bin/bash

System user (no login):

www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
  • Username: www-data (web server)
  • UID: 33
  • Shell: /usr/sbin/nologin (prevents login)

Custom shell user:

bandit26:x:11026:11026::/home/bandit26:/usr/bin/showtext
  • Username: bandit26
  • UID: 11026
  • No comment (empty)
  • Shell: /usr/bin/showtext (custom script)

Login Shell vs Current Shell

Login Shell

Login shell = first shell that runs when you authenticate (SSH, console login)

Defined in /etc/passwd field 7:

grep username /etc/passwd
username:x:1000:1000::/home/username:/bin/bash
                                      ^^^^^^^^^
                                      Login shell

When you SSH:

  1. SSH authenticates you
  2. System reads /etc/passwd
  3. Executes the login shell specified
  4. You’re in that shell environment

Current Shell

Current shell = whatever shell you’re running right now

# Check current shell
echo $SHELL

# Or
ps -p $$

You can change shells:

bash    # Start bash
zsh     # Start zsh
sh      # Start sh

Shell Startup Files

Startup files = scripts that run automatically when a shell starts, used to configure environment (set variables, aliases, functions, prompt).

Why Startup Files Exist

Purpose:

  • Set environment variables (PATH, EDITOR, etc.)
  • Define aliases (shortcuts for commands)
  • Configure prompt appearance
  • Load custom functions
  • Set shell options

Without startup files: Every login starts with default, uncustomized environment.


Login Shell Startup Files

Login shell = SSH login, console login, su - username

Loading order (first match wins for user files):

  1. /etc/profile (system-wide, always loaded first)

    • Applies to all users
    • Sets system-wide environment
    • Admin-controlled
  2. ~/.bash_profile (user-specific, bash only)

    • If exists, loads and stops
    • Highest priority user file
    • Bash-specific settings
  3. ~/.bash_login (user-specific, bash only)

    • If exists and no .bash_profile, loads and stops
    • Alternative to .bash_profile
    • Rarely used
  4. ~/.profile (user-specific, shell-agnostic)

    • If exists and no bash-specific files, loads
    • Works with sh, bash, and other shells
    • Most portable

Common pattern in .bash_profile or .profile:

# Source .bashrc for interactive settings
if [ -f ~/.bashrc ]; then
    source ~/.bashrc
fi

Why source .bashrc? Share common settings between login and non-login shells.


Non-Login Interactive Shell Startup Files

Non-login shell = new terminal tab, running bash command, su username (no dash)

Loading order:

  1. ~/.bashrc (user-specific)
    • Interactive shell settings
    • Aliases, functions, prompt
    • Most commonly edited file

Example ~/.bashrc:

# Aliases
alias ll='ls -la'
alias grep='grep --color=auto'

# Prompt
PS1='\u@\h:\w\$ '

# Environment
export EDITOR=vim

# Functions
mkcd() {
    mkdir -p "$1" && cd "$1"
}

Non-Interactive Shell Startup Files

Non-interactive shell = running scripts, ssh user@host "command", cron jobs

No startup files loaded (unless explicitly sourced in script)

Why? Performance - scripts don’t need interactive settings.


Startup File Flow Diagram

SSH Login (Login Shell)
    ↓
/etc/profile (system-wide)
    ↓
Check ~/.bash_profile → exists? → load and stop
    ↓ no
Check ~/.bash_login → exists? → load and stop
    ↓ no
Check ~/.profile → exists? → load
    ↓
(Usually sources ~/.bashrc)
    ↓
~/.bashrc loads
    ↓
Interactive bash prompt


New Terminal Tab (Non-Login Shell)
    ↓
~/.bashrc loads
    ↓
Interactive bash prompt


Script Execution (Non-Interactive)
    ↓
No startup files
    ↓
Script runs

Common Startup File Locations

# System-wide
/etc/profile              # All login shells
/etc/bash.bashrc          # All bash shells (Debian/Ubuntu)
/etc/bashrc               # All bash shells (RedHat/CentOS)

# User-specific (in home directory)
~/.bash_profile           # Bash login shell
~/.bash_login             # Bash login shell (alternative)
~/.profile                # POSIX login shell
~/.bashrc                 # Bash interactive shell
~/.bash_logout            # Runs when bash login shell exits

Example Startup File Contents

~/.bash_profile:

# Load .bashrc for interactive settings
if [ -f ~/.bashrc ]; then
    . ~/.bashrc
fi

# Add personal bin to PATH
if [ -d "$HOME/bin" ]; then
    PATH="$HOME/bin:$PATH"
fi

# Login-specific settings
echo "Welcome, $(whoami)!"

~/.bashrc:

# If not running interactively, don't do anything
case $- in
    *i*) ;;
      *) return;;
esac

# History settings
HISTSIZE=1000
HISTFILESIZE=2000

# Prompt
PS1='\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '

# Aliases
alias ll='ls -alF'
alias la='ls -A'
alias l='ls -CF'
alias grep='grep --color=auto'

# Environment variables
export EDITOR=vim
export VISUAL=vim

Three Ways to Provide Bash Shell to User

Method 1: Set Login Shell in /etc/passwd

Most common method - user gets bash automatically on login.

# View user's login shell
grep username /etc/passwd
username:x:1000:1000::/home/username:/bin/bash

# Change login shell (as root)
sudo usermod -s /bin/bash username

# Or user can change their own shell
chsh -s /bin/bash

When user logs in:

SSH → /etc/passwd → /bin/bash → bash prompt

Method 2: Execute bash in Login Shell Script

Custom login shell that spawns bash.

Example - /usr/bin/custom_shell:

#!/bin/sh
echo "Welcome!"
exec /bin/bash

Set as login shell:

sudo usermod -s /usr/bin/custom_shell username

When user logs in:

SSH → /usr/bin/custom_shell runs → exec /bin/bash → bash prompt

exec = replace current process with bash (no return to custom_shell)


Method 3: Escape from Restricted Shell via Vi

When login shell is restricted (like more or custom script), escape through vi.

Scenario:

# Login shell in /etc/passwd
username:x:1000:1000::/home/username:/usr/bin/showtext

# showtext script
#!/bin/sh
export TERM=linux
exec more ~/text.txt
exit 0

Exploit steps:

  1. Make terminal small (3-4 lines) so more pauses
  2. SSH to server - more shows text with : prompt
  3. Press v - opens vi editor
  4. In vi, type: :set shell=/bin/bash (press Enter)
  5. In vi, type: :shell (press Enter)
  6. Result: Bash shell spawns as the user

Why this works:

  • Vi can spawn shells via :shell command
  • :set shell=/bin/bash configures which shell to use
  • You escape the restricted environment through vi’s features

Shebang (#!)

Shebang = first line of script specifying which interpreter to use

#!/bin/bash

Use bash shell to run this script

#!/bin/bash
for i in {1..5}; do
    echo $i
done

Bash-specific features work (like {1..5} range expansion)

#!/bin/sh

Use sh shell (POSIX-compliant, portable)

#!/bin/sh
i=1
while [ $i -le 5 ]; do
    echo $i
    i=$((i + 1))
done

More portable, fewer features

How Shebang Works

./script.sh

System reads first line:

  • Sees #!/bin/bash
  • Executes: /bin/bash script.sh

Without shebang:

  • Uses current shell to run script

Shell Types Summary

Interactive Login Shell

  • When: SSH login, console login, su - username
  • Loads: /etc/profile, then ~/.bash_profile or ~/.profile
  • Example: ssh user@server
  • Purpose: Initial login environment setup

Interactive Non-Login Shell

  • When: New terminal tab, running bash command, su username
  • Loads: ~/.bashrc
  • Example: Opening terminal in GUI
  • Purpose: Interactive command execution

Non-Interactive Non-Login Shell

  • When: Running scripts, ssh user@server "command", cron jobs
  • Loads: Nothing (unless explicitly sourced)
  • Example: ssh user@server cat file.txt
  • Purpose: Automated command execution

Common Shell Commands

# Shell information
echo $SHELL          # Login shell
echo $0              # Current shell
ps -p $$             # Current shell process

# Change shells
chsh -s /bin/bash    # Change login shell
bash                 # Start bash
exit                 # Exit current shell

# Shell features
shopt                # Shell options (bash)
set                  # Shell settings

# User information
whoami               # Current user
id                   # User ID and groups
grep $USER /etc/passwd  # User entry with login shell

# Check shell type
if shopt -q login_shell; then
    echo "Login shell"
else
    echo "Non-login shell"
fi

Security Implications

Restricted Shells

Purpose: Limit what users can do

Common restrictions:

  • Can’t change directories
  • Can’t modify PATH
  • Can’t execute certain commands
  • Can’t redirect output

Example restricted shells:

  • rbash (restricted bash)
  • Custom scripts that exit immediately
  • Shells that only run specific commands

Escape Techniques

If stuck in restricted shell:

  1. Vi/Vim escape: :set shell=/bin/bash then :shell
  2. Editor escape: Many editors allow shell execution
  3. SSH with command: ssh user@host /bin/bash (if allowed)
  4. Environment manipulation: Modify $SHELL or $PATH if possible

Setuid Shells

Setuid bit on shell = security risk

-rwsr-xr-x 1 root root /bin/bash
    ^
    setuid bit

If bash has setuid:

  • Runs with owner’s privileges (root)
  • Any user can get root shell
  • Major security vulnerability

Never set setuid on shells!


Practical Examples

Example 1: Custom Welcome Shell

#!/bin/bash
# /usr/local/bin/welcome_shell

echo "========================================="
echo "Welcome to the system, $(whoami)!"
echo "Current time: $(date)"
echo "========================================="
echo ""

# Spawn bash
exec /bin/bash

Set as login shell:

sudo usermod -s /usr/local/bin/welcome_shell username

Example 2: Check Shell Type

#!/bin/bash

if [[ $- == *i* ]]; then
    echo "Interactive shell"
else
    echo "Non-interactive shell"
fi

if shopt -q login_shell; then
    echo "Login shell"
else
    echo "Non-login shell"
fi

Example 3: Escape Restricted Shell

# Stuck in restricted shell that runs:
#!/bin/sh
exec more ~/message.txt

# Solution:
# 1. Make terminal small (3-4 lines)
# 2. SSH to server
# 3. Press 'v' in more
# 4. In vi: :set shell=/bin/bash
# 5. In vi: :shell
# 6. Now you have bash!

Key Takeaways

  1. /etc/passwd defines user accounts with 7 fields: username, password placeholder, UID, GID, comment, home directory, login shell
  2. Login shell (field 7) runs when you authenticate
  3. Startup files configure shell environment automatically on startup
  4. Login shells load /etc/profile then ~/.bash_profile or ~/.profile
  5. Non-login shells load ~/.bashrc
  6. Three ways to provide bash: Set in /etc/passwd, exec in script, escape via vi
  7. Shebang determines script interpreter, not login shell
  8. Restricted shells can often be escaped through editor features
  9. exec replaces current process - no return to original shell