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:
- Provide interactive prompt for typing commands
- Interpret and execute commands
- Run other programs
- Handle scripting with shell syntax
- 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
xfor 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:
- SSH authenticates you
- System reads
/etc/passwd - Executes the login shell specified
- 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):
/etc/profile(system-wide, always loaded first)- Applies to all users
- Sets system-wide environment
- Admin-controlled
~/.bash_profile(user-specific, bash only)- If exists, loads and stops
- Highest priority user file
- Bash-specific settings
~/.bash_login(user-specific, bash only)- If exists and no
.bash_profile, loads and stops - Alternative to
.bash_profile - Rarely used
- If exists and no
~/.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:
~/.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:
- Make terminal small (3-4 lines) so
morepauses - SSH to server -
moreshows text with:prompt - Press
v- opens vi editor - In vi, type:
:set shell=/bin/bash(press Enter) - In vi, type:
:shell(press Enter) - Result: Bash shell spawns as the user
Why this works:
- Vi can spawn shells via
:shellcommand :set shell=/bin/bashconfigures 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_profileor~/.profile - Example:
ssh user@server - Purpose: Initial login environment setup
Interactive Non-Login Shell
- When: New terminal tab, running
bashcommand,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:
- Vi/Vim escape:
:set shell=/bin/bashthen:shell - Editor escape: Many editors allow shell execution
- SSH with command:
ssh user@host /bin/bash(if allowed) - Environment manipulation: Modify
$SHELLor$PATHif 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
/etc/passwddefines user accounts with 7 fields: username, password placeholder, UID, GID, comment, home directory, login shell- Login shell (field 7) runs when you authenticate
- Startup files configure shell environment automatically on startup
- Login shells load
/etc/profilethen~/.bash_profileor~/.profile - Non-login shells load
~/.bashrc - Three ways to provide bash: Set in
/etc/passwd, exec in script, escape via vi - Shebang determines script interpreter, not login shell
- Restricted shells can often be escaped through editor features
execreplaces current process - no return to original shell