Linux Operating Systems Fundamentals · Lesson 10
Securing Your System
Auditing and disabling network services, legacy access controls, password and root-access security, user auditing and limits, cryptography basics, SSH, and GPG.
Lesson purpose
Security is something an administrator practices every day, not a product you install once. This lesson applies the skills from earlier lessons to three jobs:
- Shrinking the network attack surface: find and disable services you don’t need, and control access to the ones you keep.
- Tightening local security: protect passwords, limit root access, audit who logs in, set resource limits, and hunt for dangerous permissions.
- Protecting data with cryptography: use SSH for secure remote access and file transfer, and GPG to encrypt and sign files.
Learning objectives
- Explain attack surface and audit listening services with
nmap,netstat,ss,systemctl list-sockets,lsof, andfuser. - Disable unneeded services on systemd and SysVinit systems.
- Describe how super servers (
xinetd) and TCP Wrappers restrict access to services, and how they compare with firewalls. - Explain how Linux stores and checks passwords, and troubleshoot common login problems.
- Limit root access with
suandsudo, configure sudo safely, and explain nonrepudiation. - Audit user sessions with
who,w, andlast, set limits withulimitandlimits.conf, and find SUID and SGID files. - Explain symmetric and asymmetric encryption, hashing, and digital signatures.
- Use SSH for logins, remote commands,
scp, key-based authentication,ssh-agent, and tunneling, and hardensshd. - Use GPG to generate, export, and import keys, encrypt and decrypt files, sign and verify files, and revoke a key.
LPIC-1 exam focus
- 110.1 Perform security administration tasks
- 110.2 Set up host security
- 110.3 Securing data with encryption
1. Attack surface
An attack surface is every point where an attacker could try to get in. Every listening service is like a door to the outside. Every outdated or poorly configured service is a door with a bad lock.
The basic process is always the same:
- Audit what’s running and listening.
- Compare it to a list of required services.
- Disable or remove everything else.
- Restrict and patch what remains.
2. Auditing listening services
nmap: the view from the network
nmap (Network Mapper) scans ports the way an attacker would. Scanning from the inside (loopback) and the outside (the server’s real address) shows what the firewall lets through.
$ nmap -sT 127.0.0.1 # TCP ports, inside the firewall
$ nmap -sT 192.168.0.103 # TCP ports, as the network sees them
$ sudo nmap -sU 127.0.0.1 # UDP ports (requires root)
$ sudo nmap -sU -6 ::1 # IPv6
$ nmap -p 1-1024 192.168.0.103 # limit the port range
PORT STATE SERVICE
22/tcp open ssh
25/tcp open smtp
111/tcp open rpcbind
631/tcp open ipp
- PORT is the port number and protocol, STATE is open, closed, or filtered, and SERVICE is the name from
/etc/services. - If a port is open on
127.0.0.1but not on the external address, it’s either bound only to loopback or blocked by the firewall. - Legal and ethical caution: scan only systems you own or have written permission to test. Scanning other networks can violate law and school policy.
netstat and ss: the view from inside
$ netstat --tcp --listening # deprecated; -u for UDP
$ ss -ltu # listening TCP and UDP sockets
$ sudo ss -ltunp # add numeric ports and owning processes
- A port is a number that identifies a service, such as 22 for SSH or 53 for DNS.
- A socket is one end of a connection: an IP address plus a port on the local system.
netstatis deprecated, andssreplaces it.- A Local Address of
0.0.0.0or*means the service listens on every interface.127.0.0.1means local connections only.
systemd socket units
systemd can listen on a socket itself and start the service only when a connection arrives (socket activation). These sockets need auditing too.
$ systemctl list-sockets --all --no-pager --full
$ systemctl list-unit-files --type=socket
$ systemctl cat rpcbind.socket # ListenStream=0.0.0.0:111 ...
$ man systemd.socket
ListenStream=is a TCP (or stream) socket, andListenDatagram=is a UDP socket.- A socket unit that shows disabled only means systemd isn’t handling that socket. The service itself may still be running and listening on its own.
lsof and fuser: open files and processes
Linux treats network sockets as files, so file tools can find them. Both commands need sudo to see every process.
$ sudo lsof -iUDP # all UDP sockets
$ sudo lsof -iTCP -sTCP:LISTEN # listening TCP sockets
$ sudo lsof -i tcp:22 # everything using TCP port 22, including established sessions
$ sudo fuser -vn tcp 22 # PIDs and users using TCP port 22
$ sudo fuser -vn udp 822
Services that start at boot
$ systemctl list-unit-files --type=service --state=enabled # systemd
$ chkconfig --list # SysVinit, Red Hat
$ service --status-all # SysVinit, Debian
$ ls /etc/init.d/ # SysVinit scripts
On very old systems, also check /etc/inittab.
3. Disabling unneeded services
systemd:
$ sudo systemctl stop cups
$ sudo systemctl disable cups # or: disable --now to do both at once
$ systemctl is-enabled cups # should print "disabled"
$ sudo systemctl mask cups # optional: block it from being started at all
SysVinit:
# service cups stop ; service cups status
# chkconfig cups off ; chkconfig --list cups # Red Hat: off at every runlevel
# update-rc.d -f cups remove # Debian
The best option is to remove a service you’ll never need by uninstalling its package (Lesson 2). A package that isn’t installed can’t be attacked or started by accident.
4. Super servers and TCP Wrappers (legacy access controls)
Super servers: inetd and xinetd
A super server listens on ports for several services and starts each service only when a connection arrives. The original was inetd; xinetd (the extended super daemon) added access control and logging. Most services now run as their own daemons or use systemd socket activation. You’ll mainly see xinetd on older systems, but it’s on the exam.
/etc/xinetd.confholds the globaldefaults { }settings and ends withincludedir /etc/xinetd.d./etc/xinetd.d/SERVICEhas one file per service. Settings there override the defaults.
service echo
{
disable = yes # yes = off; set to no to enable the service
id = echo-stream
type = INTERNAL
wait = no
socket_type = stream
only_from = 192.168.0.0/24
instances = 10
}
| Directive | Meaning |
|---|---|
disable |
yes turns the service off |
only_from / no_access |
Hosts or subnets allowed / denied |
instances |
Maximum simultaneous processes for the service (UNLIMITED for no limit) |
per_source |
Maximum processes per client IP address |
cps |
Connection rate limit: 50 10 means pause for 10 seconds after 50 connections per second |
max_load |
Refuse connections above this 1-minute load average |
log_type |
SYSLOG facility severity or FILE path |
log_on_success / log_on_failure |
Extra details to log (PID, HOST, USERID, DURATION, EXIT, ATTEMPT) |
Restart xinetd after making changes.
TCP Wrappers
Programs linked with the libwrap library check two files before accepting a connection. Check whether a program supports it with ldd /usr/sbin/sshd | grep libwrap.
# /etc/hosts.allow
sshd: 172.243.24.15, 172.243.24.16
sshd: 172.243.24. # trailing dot = the whole 172.243.24.0/24 subnet
# /etc/hosts.deny
ALL: ALL
Evaluation order:
- If a match is found in
hosts.allow, access is allowed and nothing else is checked. - Otherwise, if a match is found in
hosts.deny, access is denied. - If neither file matches, access is allowed.
Because of rule 3, a secure setup puts ALL: ALL in hosts.deny (default deny) and lists only approved clients in hosts.allow. PARANOID is a special pattern that matches hosts whose name and address don’t agree in DNS.
Current practice: TCP Wrappers are deprecated. Red Hat removed them in RHEL 8, and newer OpenSSH builds don’t include libwrap. Enforce network access with a firewall (firewalld, nftables, or ufw) and with each service’s own configuration, such as AllowUsers in sshd_config. Learn TCP Wrappers for the exam.
5. How Linux protects passwords
Hashing and salting
- Passwords are stored as hashes, the output of a one-way function. Nobody can reverse a hash back into the password.
- At login, the system hashes what you type with the same salt and compares the result to the stored hash.
- Salt is random data added to each password before hashing. Because every account has a different salt, two identical passwords produce different hashes, and precomputed rainbow tables (lists of hashes for common passwords) become useless. The book implies rainbow tables still defeat salted hashes; the salt is what stops them.
- The remaining threat is offline guessing against the hash. That’s why the hashes must stay unreadable and passwords must be long.
Protecting the hashes
$ ls -l /etc/passwd /etc/shadow
-rw-r--r-- 1 root root 2631 ... /etc/passwd # everyone can read it; no hashes
-rw-r----- 1 root shadow 1425 ... /etc/shadow # only root (and the shadow group) can read it
$ ls -l /usr/bin/passwd
-rwsr-xr-x 1 root root 59640 ... /usr/bin/passwd # s = SUID
- Hashes are stored in
/etc/shadow, not the world-readable/etc/passwd. If you find hashes in/etc/passwd, runpwconv. - Ordinary users can change their own passwords because
passwdis SUID root (Lesson 4): it runs with root’s authority, only for that job. Changing another user’s password still requiressudo. passwddoesn’t echo anything as you type, not even asterisks.
Troubleshooting a user who can’t log in
| Check | Command | What to look for |
|---|---|---|
| Does the account exist? | getent passwd JKirk |
A record with a valid login shell |
| Is a password set? | sudo getent shadow JKirk |
! or !! alone means no password has been set |
| Is it locked? | sudo passwd -S KJaneway |
L or LK, and a ! in front of the hash in shadow |
| Has the account expired? | sudo chage -l JArcher |
“Account expires” date in the past. Fix with chage -E. |
| Has the password expired? | sudo chage -l |
“Password expires” and inactive dates |
| Is the user typing it correctly? | — | Usernames are case-sensitive. Check Caps Lock and the keyboard layout. |
- Unlock with
usermod -Uorpasswd -u. - Follow current guidance (NIST SP 800-63B): favor length over complicated composition rules, and check new passwords against lists of known-compromised passwords.
- Linux enforces password rules through PAM modules such as
pam_pwquality(strength),pam_pwhistory(reuse), andpam_faillock(lock after failed attempts).
6. Limiting root access
Good account practice:
- Don’t log in directly as root.
- Give each person their own account and never share accounts.
- Set expiration dates on temporary accounts (Lesson 7).
- Remove accounts that are no longer used.
su (switch user)
$ su - # become root with a full login environment (needs root's password)
$ su - rich # become rich (needs rich's password)
$ su -c "passwd rich" # run one command as root; quote a command that has spaces
$ exit
- The
-gives you the target user’s complete login environment (PATH, home directory, and startup files). Plainsukeeps your own environment, which can cause subtle mistakes. surequires the target account’s password, so root’s password has to be shared. On Ubuntu the root account is locked by default, sosu -doesn’t work there.
sudo (run a command with elevated privileges)
sudo asks for your own password, checks your permissions in the sudoers policy, and logs every command. Because each action is tied to a named person, you get nonrepudiation: nobody can credibly deny what they did. When several administrators share the root password, no one can prove who ran a command, which is a repudiation environment.
$ sudo chage -l BCrusher
[sudo] password for Christine:
$ journalctl -r | grep sudo # also /var/log/auth.log or /var/log/secure
... sudo[3609]: Christine : TTY=pts/0 ; PWD=/home/Christine ; USER=root ; COMMAND=/usr/bin/chage -l BCrusher
The sudoers policy
# /etc/sudoers -- ALWAYS edit with visudo
root ALL=(ALL:ALL) ALL
%sudo ALL=(ALL:ALL) ALL # Debian/Ubuntu admin group
%wheel ALL=(ALL) ALL # Red Hat admin group
@includedir /etc/sudoers.d # older files write this as #includedir
The format is WHO HOST=(RUN-AS-USER:RUN-AS-GROUP) COMMANDS:
- WHO: a username, or
%groupfor a group. - HOST: which hosts the rule applies to (
ALLfor any host). - (RUN-AS): which users and groups the person may run commands as.
- COMMANDS: which commands, using full paths or
ALL.
# /etc/sudoers.d/helpdesk -- least privilege: only what the job requires
%helpdesk ALL=(root) /usr/bin/passwd, /usr/bin/chage -l *
- Always use
visudo(orvisudo -f /etc/sudoers.d/file). It locks the file and checks the syntax before saving. A syntax error in sudoers can lock every administrator out of sudo. - Grant full sudo by adding the person to the admin group:
usermod -aG sudo alice(Debian/Ubuntu) orusermod -aG wheel alice(Red Hat). - Put custom rules in
/etc/sudoers.d/rather than editing the main file. sudo -llists what you’re allowed to run.sudo -iorsudo -sgives a root shell (still logged), but use it sparingly.
7. Auditing user access
$ who # who is logged in, on which terminal, since when, from where
$ who am i # your own session (so does "who mom likes")
$ w
09:58:31 up 49 min, 5 users, load average: 0.81, 0.37, 0.27
USER TTY LOGIN@ IDLE JCPU PCPU WHAT
rich tty3 09:56 1:35 0.85s 0.81s top
$ last # login and logout history, newest first (from /var/log/wtmp)
$ last -f /var/log/wtmp.1 # a rotated wtmp file
$ sudo lastb # failed login attempts (from /var/log/btmp)
$ lastlog # each account's most recent login
- The first line of
wshows the current time, how long the system has been up, the number of users, and the 1-, 5-, and 15-minute load averages. - The
wcolumns:- USER is the account name.
- TTY is the terminal.
- LOGIN@ is when the user logged in.
- IDLE is how long since the user last typed anything.
- JCPU is total CPU time used by the terminal’s processes.
- PCPU is CPU time used by the current process.
- WHAT is the command the user is running now.
- Data sources:
whoandwread/var/run/utmp(current sessions).lastreads/var/log/wtmp(history), andlastbreads/var/log/btmp(failures). These files are rotated (Lesson 7). - Removing an intruder: lock the account (
usermod -L), end its processes (pkill -KILL -u username), and create/etc/nologin(sudo touch /etc/nologin, optionally with a message inside) to block all non-root logins until you remove the file.
8. Resource limits
Limits keep a runaway program, or a malicious user, from using up every process slot, all the memory, or every file handle on the system.
$ ulimit -a # show all limits for this shell
$ ulimit -u 200 # at most 200 processes
$ ulimit -n 4096 # at most 4096 open files
$ ulimit -c 0 # no core dump files
$ ulimit -Sn / ulimit -Hn # soft / hard limit for open files
| Option | Limit |
|---|---|
-a |
Show all limits |
-c |
Core file size |
-d |
Data segment size |
-e |
Scheduling priority |
-f |
Size of files the shell can write |
-i |
Pending signals |
-l |
Locked memory |
-m |
Resident set size |
-n |
Open file descriptors |
-p |
Pipe size (in 512-byte blocks) |
-r |
Real-time priority |
-s |
Stack size |
-t |
CPU time in seconds |
-u |
Number of user processes |
-v |
Virtual memory |
-x |
File locks |
- Soft vs. hard: a user can raise their soft limit up to the hard limit. Only root can raise a hard limit.
ulimitaffects only the current shell and the programs it starts.- Persistent limits for users and groups belong in
/etc/security/limits.confor/etc/security/limits.d/*.conf, which PAM applies at login. The book suggests puttingulimitin startup files;limits.confis the standard way.
# /etc/security/limits.conf
# domain type item value
@students hard nproc 100
@students hard maxlogins 2
* soft core 0
The book’s option table says -p counts 512k blocks and lists a -k option. On Linux, -p counts 512-byte blocks, and -k (kqueues) exists only on BSD.
9. Finding SUID and SGID files
SUID and SGID programs run with the authority of the file’s owner or group (Lesson 4). A root-owned SUID file that shouldn’t exist is a classic backdoor. Build a baseline, then compare it regularly.
$ sudo find / -perm /6000 -type f 2>/dev/null > SUID-SGID_baseline.txt
$ sudo find / -perm /6000 -type f 2>/dev/null > SUID-SGID_today.txt
$ diff SUID-SGID_baseline.txt SUID-SGID_today.txt
> /usr/bin/threat-actor
$ ls -l /usr/bin/threat-actor
-rwsrwsrwx 1 root root 0 Jun 13 17:25 /usr/bin/threat-actor
/6000means “SUID (4000) or SGID (2000) is set.” The leading/means any of these bits. The older+6000form is obsolete.-type flimits the search to regular files.2>/dev/nullhides “Permission denied” noise.- Protect the baseline file (make it root-owned with mode 600), and automate the comparison with a script run by cron (Lesson 9).
10. Cryptography concepts
Encryption turns plaintext into ciphertext using an algorithm and a key. Decryption reverses it.
| Symmetric (secret key) | Asymmetric (public/private key pair) | |
|---|---|---|
| Keys | One shared key encrypts and decrypts | A public key (shared freely) and a private key (kept secret, usually protected by a passphrase) |
| Speed | Fast | Slower |
| Main problem | You must share the key securely | Proving whose public key you really have |
| Examples | AES | RSA, ECDSA, Ed25519 |
The book calls symmetric keys “private keys.” Call them secret keys in class, so students don’t confuse them with the private half of a key pair.
Rule of thumb:
- To send someone a secret, encrypt with the recipient’s public key. Only their private key can decrypt it.
- To prove you wrote something, sign with your own private key. Anyone with your public key can verify it.
Real protocols such as SSH and TLS combine both types: asymmetric keys authenticate the parties and agree on a random symmetric session key, which then encrypts all the traffic quickly.
Hashing
- A hash (message digest, fingerprint) is a fixed-length, one-way summary of data. The same input always produces the same hash, so comparing hashes shows whether two files are identical or whether a download was corrupted or altered.
- The algorithm must be collision-resistant: two different inputs mustn’t produce the same hash. MD5 and SHA-1 aren’t collision-resistant anymore. Use SHA-256 or stronger.
$ sha256sum ubuntu.iso # compare with the published checksum
- A keyed message digest (HMAC) mixes a secret key into the hash. It proves the data wasn’t changed and that it came from someone who has the key. SSH uses HMACs to protect every packet.
Digital signatures
- The sender hashes the message and encrypts the hash with the sender’s private key. That’s the signature.
- The receiver decrypts the signature with the sender’s public key and hashes the received message.
- If the two hashes match, the message is authentic (it came from the owner of that private key) and unchanged.
Signatures defend against a man-in-the-middle who substitutes their own message or key. You still have to be sure that the public key really belongs to the sender, which is why SSH shows host key fingerprints and GPG uses key trust.
11. SSH: secure remote access
SSH (Secure Shell) encrypts logins, commands, and file transfers, replacing insecure tools such as telnet, rsh, and ftp. OpenSSH is the standard implementation.
- Packages:
openssh-clientsandopenssh-server(Red Hat), oropenssh-clientandopenssh-server(Debian and Ubuntu). - Service:
sshd(calledsshon Ubuntu). The server must be running and TCP port 22 open in the firewall.
Connecting and host keys
$ ssh Christine@192.168.0.105
The authenticity of host '192.168.0.105' can't be established.
ED25519 key fingerprint is SHA256:BnaCbm+ensyrkflKk1rRSVwxHi4NrBWOOSOdU+14m7w.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.0.105' (ED25519) to the list of known hosts.
- The syntax is
ssh [options] [user@]host. Leave outuser@if your username is the same on both systems. - The first time you connect, SSH shows the server’s host key fingerprint. Verify it through a separate, trusted channel before typing
yes. The key is then saved in~/.ssh/known_hosts. - “WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED” means the server’s key doesn’t match the saved one. It may be a reinstalled server, or it may be an attack. Investigate before continuing. Remove the old entry with
ssh-keygen -R hostonly after confirming the change is legitimate. /etc/ssh/ssh_known_hostsis a system-wide list of trusted host keys. Pre-loading it means users see a warning only when something has really changed, which keeps them from learning to ignore warnings.
Remote commands and file copies
$ ssh Christine@192.168.0.104 "ls Project42.txt" # run one command remotely
$ scp Project42.txt Christine@192.168.0.104:~ # copy to the remote home directory
$ scp Christine@192.168.0.104:/etc/hosts . # copy from the remote system
$ scp -r labs/ Christine@192.168.0.104:backup/ # copy a directory
$ sftp Christine@192.168.0.104 # interactive transfers
$ ssh -p 1138 192.168.0.104 # non-default port
The colon matters. scp file user@host: copies to the remote host. Without the colon, scp makes a local copy named user@host.
Configuration files
| File | Purpose |
|---|---|
~/.ssh/config |
Your personal client settings (overrides the system client file) |
/etc/ssh/ssh_config |
Client settings for everyone on this machine |
/etc/ssh/sshd_config |
Server settings (restart or reload sshd after changes) |
Command-line options override ~/.ssh/config, which overrides /etc/ssh/ssh_config.
# ~/.ssh/config
Host lab
HostName 192.168.0.104
User Christine
Port 1138
With that entry, ssh lab is all you need to type.
Hardening sshd_config
| Directive | Recommended setting and reason |
|---|---|
PermitRootLogin |
no. Root is the first account attackers guess. Log in as yourself and use sudo. (The current OpenSSH default is prohibit-password, which allows root to log in with a key only. The book gives the default as yes.) |
PasswordAuthentication |
no once everyone uses keys. This stops password-guessing attacks. |
AllowUsers / AllowGroups |
Only the listed accounts may log in over SSH |
Port |
Changing it from 22 reduces automated scanning noise, but it isn’t real protection. A firewall and keys matter more. |
X11Forwarding |
no unless people need it |
AllowTcpForwarding |
no unless people need tunnels |
- Protocol 1: SSH protocol 1 is broken. Current OpenSSH supports only protocol 2, and the old
Protocoldirective has been removed. The book’s advice to setProtocol 2applies only to very old systems. - Test before you disconnect. Check the file with
sudo sshd -t, reload the service, and confirm that a second session can log in before closing the one you’re using. ForwardX11is a client option inssh_config. The server’s option isX11Forwarding.
Host keys
$ ls /etc/ssh/*key*
/etc/ssh/ssh_host_ecdsa_key /etc/ssh/ssh_host_ecdsa_key.pub
/etc/ssh/ssh_host_ed25519_key /etc/ssh/ssh_host_ed25519_key.pub
/etc/ssh/ssh_host_rsa_key /etc/ssh/ssh_host_rsa_key.pub
$ sudo ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key # regenerate one type
$ sudo ssh-keygen -A # create any missing host keys
- The files are named
ssh_host_TYPE_key(private) andssh_host_TYPE_key.pub(public). - Key types:
- ed25519 is the modern default.
- ecdsa is also current.
- rsa is widely supported (use 3072 bits or more).
- dsa is obsolete and removed from current OpenSSH.
- Permissions: private host keys must be readable only by root (0600, or 0640 with a special group on some distributions). Public keys are world-readable.
sshdrefuses to use a private key with loose permissions.
Key-based user authentication
$ ssh-keygen -t ed25519 # creates ~/.ssh/id_ed25519 and id_ed25519.pub; set a passphrase
$ ssh-copy-id -n Christine@192.168.0.104 # dry run: show which keys would be installed
$ ssh-copy-id Christine@192.168.0.104 # append the public key to the server's ~/.ssh/authorized_keys
$ ssh Christine@192.168.0.104 # now authenticates with the key
- Generate a key pair on the client.
- Install the public key in the server account’s
~/.ssh/authorized_keys.ssh-copy-iddoes this securely in one step. Without it, copy the.pubfile withscpand append it withcat id_ed25519.pub >> ~/.ssh/authorized_keys. - The private key never leaves the client.
- Permissions:
~/.sshmust be 700, and the private key andauthorized_keysshould be 600. OpenSSH ignores keys whose permissions are too open. - Default file names:
id_ed25519,id_ecdsa, orid_rsain~/.ssh/. - Key files without a passphrase are convenient, but anyone who copies the file can use it. Use a passphrase together with an agent.
ssh-agent
The agent holds your decrypted private key in memory, so you type the passphrase once per session.
$ eval "$(ssh-agent)" # start an agent in this shell (the book uses: ssh-agent /bin/bash)
$ ssh-add ~/.ssh/id_ed25519 # enter the passphrase once
$ ssh-add -l # list the loaded keys
$ ssh Christine@192.168.0.104 # no password or passphrase prompt
$ ssh-add -d ~/.ssh/id_ed25519 # remove the key from the agent
Most desktop sessions start an agent automatically. When the agent session ends, you have to add the key again.
Tunneling (port forwarding)
SSH can carry other traffic through its encrypted connection:
$ ssh -X user@remote-host # X11 forwarding: run remote GUI programs (Lesson 6)
$ ssh -L 5901:localhost:5901 user@server # local forward: localhost:5901 -> server's 5901 (VNC)
$ ssh -R 8080:localhost:80 user@server # remote forward: server's 8080 -> your port 80
- X11 forwarding requires
X11Forwarding yeson the server. The book’s listing caption calls this “AllowTCPForwarding,” but the directive checked isX11Forwarding. - Avoid
ssh -Y(trusted X11). It gives the remote host broad access to your display. - Port forwarding requires
AllowTcpForwarding yeson the server.
12. GPG: encrypting and signing files
GNU Privacy Guard (GPG, GnuPG) implements the OpenPGP standard (based on PGP). It encrypts and signs individual files and email. The command is gpg, or gpg2 on some older systems.
Keys
$ gpg --gen-key # or --full-generate-key to choose type, size, and expiration
$ gpg --list-keys # public keys on your keyring
$ gpg --list-secret-keys # your private (secret) keys
- GPG asks for your name, email address, and a passphrase. The email address identifies the key, and the passphrase protects the private key.
- Keys are stored on your keyring in
~/.gnupg/. gpg-agentstarts automatically to cache your unlocked private key, so no service needs to be enabled.- In
--list-keysoutput,pubis the primary key ([SC]= sign and certify) andsubis a subkey ([E]= encrypt). Theuidline shows the owner and your trust level ([ultimate]for your own key,[unknown]for others). - Key generation needs random data. Modern kernels provide plenty. On old systems, the book suggests running
rngdto speed this up.
Sharing public keys
$ gpg --export cb1234@example.edu > CB_gpg.pub # binary format
$ gpg --export --armor cb1234@example.edu > CB_gpg.asc # ASCII, easy to email or post
$ gpg --import RB_gpg.pub # add someone else's public key
$ gpg --fingerprint rb4242@example.com # compare with the owner by phone or in person
Public keys aren’t secret. You can email them or post them on a web page or key server. Verify the fingerprint before trusting an imported key; otherwise, you might be using an attacker’s key.
Encrypting and decrypting
$ gpg --out encryptfile --recipient rb4242@example.com --encrypt secretfile.txt
$ gpg --out message.txt --decrypt encryptfile # the recipient enters their passphrase
- “It’s all about the recipient.” To send someone a secret file, encrypt it with their public key (
--recipient). They decrypt it with their private key. - Add
--armorfor ASCII output that can be pasted into email. gpg -c fileis symmetric encryption with a passphrase only, for when both people know the passphrase.
Signing and verifying
$ gpg --sign file.txt # binary signed file (file.txt.gpg)
$ gpg --clearsign note.txt # readable text with an ASCII signature block
$ gpg --detach-sign release.tar.gz # separate signature file: release.tar.gz.sig
$ gpg --verify release.tar.gz.sig release.tar.gz
$ gpg --sign --encrypt -r rb4242@example.com report.pdf # sign and encrypt in one step
$ gpg --decrypt report.pdf.gpg > report.pdf # decrypts and checks the signature
- A signature uses your private key (you’ll be asked for your passphrase). Verifying it needs your public key on the recipient’s keyring. Otherwise they see “Can’t check signature: No public key.”
- “Good signature from …” means the file is authentic and unchanged.
- The book encrypts and signs in two separate steps and verifies in two steps. The single
--sign --encryptcommand above, followed by--decrypt, is the normal practice. - Detached signatures are how Linux distributions sign packages and ISO images. The file itself stays readable.
Revoking a key
If your private key is lost or stolen:
$ gpg --output key-revocation.asc --gen-revoke cb1234@example.edu # choose the reason: 1 = compromised
$ gpg --import key-revocation.asc # revoke it on your own keyring
Then distribute the certificate to everyone who has your public key: upload it to the key server or web page where you published the key. They import it the same way.
Best practice: create a revocation certificate when you create the key, and store it offline, so you can still revoke the key if you lose the passphrase. Modern GnuPG does this automatically in ~/.gnupg/openpgp-revocs.d/.
Classroom application
- Attack-surface audit. On a lab VM, compare
nmap -sT 127.0.0.1with a scan of the VM’s own address from a second VM,sudo ss -ltunp, andsystemctl list-sockets. Build a table of each listening service, whether it’s needed, and what to do about it. Disable one unneeded service and show that it no longer appears. - sudo policy. Create a
helpdeskgroup, write/etc/sudoers.d/helpdeskwithvisudo -fso it allows onlypasswdandchage -l, test allowed and denied commands withsudo -l, and find the log entries in the journal. - Login detective. Create an account without a password, a locked account, and an expired account. Have a partner diagnose each one using only
getent,passwd -S, andchage -l. - SUID baseline. Create a SUID baseline, then (on a lab VM) set SUID on a copy of a harmless binary, rerun the scan, and find the difference with
diff. Remove the test file afterward. - SSH keys and hardening. Generate an ed25519 key with a passphrase, install it with
ssh-copy-id, load it intossh-agent, and connect without a password. Then setPermitRootLogin noandPasswordAuthentication no, check the file withsshd -t, reload, and confirm key login still works from a new terminal before closing the old one. - GPG exchange. Partners generate keys, exchange public keys as ASCII files, compare fingerprints aloud, send each other an encrypted and signed file, verify and decrypt it, and then change one byte of a signed file to watch verification fail.
Common misconceptions
- “Disabling a service in systemd removes the risk.”
disableonly stops it from starting at boot. Stop it now, considermask, and uninstall it if it’s never needed. - “An empty hosts.deny is secure.” When no rule matches, TCP Wrappers allow access. Use
ALL: ALLinhosts.deny. Better yet, use a firewall. - “Salted hashes can be cracked with rainbow tables.” Salt is what defeats rainbow tables. The remaining risk is brute-force guessing against stolen hashes.
- “
suandsudoare equally secure.”surequires the shared root password and gives no per-person accountability.sudouses your own password and logs every command. - “Edit /etc/sudoers with any editor.” Use
visudo. A syntax error can lock out every administrator. - “Changing the SSH port secures SSH.” It only reduces noise. Keys,
PermitRootLogin no,AllowUsers, and a firewall provide the real protection. - “Ignore the ‘host identification has changed’ warning.” It may be a man-in-the-middle attack. Verify the fingerprint first.
- “Encrypt with your own public key to send a secret.” Encrypt with the recipient’s public key. Sign with your own private key.
- “Encryption alone proves who sent a file.” Only a signature proves the sender and that the file wasn’t changed.
- “MD5 is fine for integrity checks.” MD5 and SHA-1 have known collisions. Use SHA-256 or stronger.
Lesson summary
- Network security: audit with
nmap,ss/netstat,systemctl list-sockets,lsof, andfuser. Disable or remove unneeded services. xinetd and TCP Wrappers (hosts.allowis checked beforehosts.deny, andALL: ALLmakes access default-deny) are legacy access controls; firewalls are the modern replacement. - Local security: salted hashes in root-only
/etc/shadow, with the SUIDpasswdprogram for self-service changes. Troubleshoot logins withgetent,passwd -S, andchage -l. Usesudo(edited withvisudo, rules in/etc/sudoers.d) for accountable root access. Audit sessions withwho,w,last, andlastb, block logins with/etc/nologin, set limits withulimitandlimits.conf, and compare SUID/SGID scans (find / -perm /6000 -type f) against a baseline. - Cryptography: symmetric keys are fast but must be shared. Asymmetric key pairs use public keys for encryption and verification and private keys for decryption and signing. Hashes show integrity, HMACs add a shared key, and signatures prove authenticity.
- SSH: check host keys in
known_hosts, usescpand remote commands, understand the client and server configuration files, hardensshd_config, manage host keys, use key authentication withssh-keygen,ssh-copy-id, andauthorized_keys, usessh-agentwithssh-add, and forward ports and X11. - GPG: generate, list, export, and import keys; encrypt with the recipient’s public key and decrypt with your private key; sign, clearsign, detach-sign, and verify; and revoke compromised keys.
This lesson completes the course’s coverage of the LPIC-1 topics. Its tools and habits (least privilege, auditing against a baseline, verifying before trusting, and encrypting in transit) apply to everything students learned in Lessons 1 through 9.
Course Notes