Hardening/Linux
Login
System users
Disable login for system users:
for u in `getent passwd | awk -F: '!/^(root|joe)/ {print $1}'`; do chsh -s /usr/sbin/nologin $u # passwd -e on Solaris passwd -d $u # delete password entry done
To verify which users are left with a valid shell/password, use:
getent passwd | grep -v nologin
getent shadow | grep -F \$ # $1$ - MD5
# $2a$ - Blowfish
# $2y$ - Blowfish, correctly handling 8-bit characters
# $5$ - SHA-256
# $6$ - SHA-512 - see also shadow passwords
Password hashing
On most Linux systems, pam_unix(8) is able to hash ("encrypt") the user's passwords with a strong cryptographic hash function:
$ grep ^p /etc/pam.d/common-password password [success=1 default=ignore] pam_unix.so obscure sha512 password requisite pam_deny.so password required pam_permit.so password optional pam_ecryptfs.so
libpam-unix2 is problematic, more on this later! See also Unix crypt with SHA-256/512 and bcrypt in Debian! It may also not work with eCryptfs!
To tighten password security even more, we use passwdqc or pam_cracklib and pam_unix2(8):
$ apt-get install libpam-unix2 libpam-passwdqc $ grep ^[CB] /etc/security/pam_unix2.default CRYPT=des CRYPT_FILES=blowfish BLOWFISH_CRYPT_FILES=5 CRYPT_YP=des
And add those to the PAM password stack:
$ grep ^p /etc/pam.d/common-password password requisite pam_cracklib.so retry=3 minlen=8 difok=3 password [success=1 default=ignore] pam_unix2.so blowfish password requisite pam_deny.so password required pam_permit.so password optional pam_ecryptfs.so
tmpfs
Moving temporary filesystems to tmpfs
and setting them to nosuid,nodev,noexec[1]
could help mitigate random program execution as well:
echo "tmpfs /tmp tmpfs nodev,nosuid,noexec,mode=1777 0 0" >> /etc/fstab mv /tmp /tmp2 && mkdir -m1777 /tmp && mount /tmp && rsync -avP /tmp2/ /tmp && rm -rf /tmp2
Now, mount(8)
should look something like this:
$ mount | grep tmpfs tmpfs on /lib/init/rw type tmpfs (rw,nosuid,mode=0755,size=10485760) varrun on /var/run type tmpfs (rw,nosuid,mode=0755,size=10485760) varlock on /var/lock type tmpfs (rw,nosuid,nodev,noexec,mode=1777,size=10485760) udev on /dev type tmpfs (rw,mode=0755) tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev,size=10485760) tmpfs on /tmp type tmpfs (rw,nosuid,nodev,noexec,mode=1777)
For SELinux enabled systems, this might help:
$ restorecon -v -R /tmp restorecon reset /tmp context unconfined_u:object_r:default_t:s0->system_u:object_r:tmp_t:s0 $ echo "tmpfs /tmp tmpfs nosuid,noexec,context=system_u:object_r:tmp_t:s0 0 0" >> /etc/fstab
Note:
Per-user /tmp
Per-user /tmp
is a way to create temporary files securely[2] and is implemented quite differently.
Debian/Ubuntu
apt-get install libpam-tmpdir echo 'session optional pam_tmpdir.so' >> /etc/pam.d/common-session
Logout & login again:
$ ls -ld $TMP $TMPDIR drwx------ 2 alice root 40 Jan 11 09:35 /tmp/user/1000 drwx------ 2 alice root 40 Jan 11 09:35 /tmp/user/1000
Fedora
There's no libpam-tmpdir
for Fedora but there is pam_namespace
[3], which can be configured[4] in a similar way:
TBD!
openSUSE
pam_mktemp is a PAM plugin to provide per-user TMP
directories:
zypper install pam_mktemp echo 'session optional pam_mktemp.so' >> /etc/pam.d/common-session
Logout & login again:
$ ls -ld $TMP $TMPDIR drwx-----T 2 root root 4096 Sep 11 05:10 /tmp/.private/root drwx-----T 2 root root 4096 Sep 11 05:10 /tmp/.private/root
Encrypted swap
Assuming sda2
is our current swap partition:
swapoff -a DEV=/dev/sda2 [ "$PARANOID" = 1 ] && dd if=/dev/urandom of=$DEV bs=1M cryptsetup -c twofish -s 128 -d /dev/urandom create swap $DEV mkswap -f /dev/mapper/swap
To enable enable encrypted swap during boot:
echo "swap $DEV /dev/urandom swap,noearly,cipher=twofish-xts-essiv:sha256,size=256,hash=sha512" >> /etc/crypttab
Or, with AES:
echo "swap $DEV /dev/urandom swap,noearly,cipher=aes-xts-essiv:sha256,size=256,hash=sha512" >> /etc/crypttab
echo "/dev/mapper/swap none swap sw 0 0" >> /etc/fstab
Start the newly configured swap device via systemd:
systemctl daemon-reload systemctl restart cryptsetup.target
Gentoo
For Gentoo the procedure is slightly different:
emerge sys-fs/lvm2
Deactivate the current swap device (sda2) and create a dm-crypt layer on top of it:
DEV=/dev/sda2 swapoff $DEV echo "0 `blockdev --getsize $DEV` crypt aes-cbc-essiv:sha256 `openssl rand -hex 1024 | cut -c-64` 0 $DEV 0" | dmsetup create swap mkswap -f /dev/mapper/swap swapon /dev/mapper/swap
To enable encrypted swap during startup, an executable boot script can be put in e.g. /etc/local.d/01-cryptswap.start
, containing the commands above.
Note: sys-fs/device-mapper
has been merged into sys-fs/lvm2
, c.f. #262836 and #389361
Kernel
dmesg
With Linux v2.6.37-rc2 the kernel config option CONFIG_SECURITY_DMESG_RESTRICT can be set. Once enabled, setting kernel.dmesg_restrict
to true restricts non-root users from being able to view the kernel's log buffer:
$ /sbin/sysctl kernel.dmesg_restrict kernel.dmesg_restrict = 1 $ dmesg klogctl: Operation not permitted
Unecessary kernel modules
$ while true; do lsmod | awk '/0 $/ {print $1}' | grep -vE "b43|coretemp|e1000|ideapad_laptop|microcode|tg3|usb_storage" | \ xargs rmmod -v 2>/dev/null || break done
- Replace
e1000
with your NIC's driver name! - Now we can add something like this to
/etc/rc.local
:
/sbin/rmmod psmouse lp ppdev parport_pc parport ...
- Or, better yet, blacklist these modules:
$ cat /etc/modprobe.d/local.conf blacklist psmouse blacklist lp blacklist ppdev blacklist parport_pc blacklist parport
initrd.img
$ ls -lhgo /boot/initrd.img* -rw-r--r-- 1 9.8M Feb 11 23:21 /boot/initrd.img-3.2.0-4-amd64 $ rmmod .... $ lsmod | awk '!/^Module/ {print $1}' | sort >> /etc/initramfs-tools/modules $ sed 's/^MODULES=.*/MODULES=list/' -i /etc/initramfs-tools/initramfs.conf $ update-initramfs -u $ ls -lhgo /boot/initrd.img* -rw-r--r-- 1 2.4M Feb 11 23:28 /boot/initrd.img-3.2.0-4-amd64
Filesystem security
We also want to keep track of filesystem security[5].
Permission lockdown
For example, /var/log
doesn't need to be visiable by anyone but the system administrator:
chmod 0711 /var/log && chmod o-rwx /var/log/* setfacl -m g:staff:r-- /var/log/wtmp # Needed for last(1)
Logrotate tends to create new logfiles with world-readable pemissions again, thus reverting our last step on the next logrotate
run. The following should change all logrotate configuration files from "create 644"
to "create 640"
:
cd /etc/logrotate.d for a in *; do sed '/create/s/4\ /0 /' -i.bak "$a"; done
Check if everything is in order, then:
rm -f *.bak
SUID
Find all SUID/SGID files:
find / -type f \( -perm -04000 -o -perm -02000 \)
Find world-writable files and directories:
find / -perm -2 ! -type l
Find files and directories with an unknown user and/or group:
find / \( -nouser -o -nogroup \)
We could eliminate all SUID binaries by just mounting with the nosuid
[6] mount option.
Or we could remove[7] all SUID (and SGID) bits from the affected binaries:
$ sudo find / -xdev -type f \( -perm -04000 -o -perm -02000 \) -ls /bin/mount /bin/umount /bin/rdisc6 /bin/ping6 /bin/ping /bin/su /sbin/pam-tmpdir-helper /usr/lib/eject/dmcrypt-get-device /usr/lib/openssh/ssh-keysign /usr/lib/pt_chown /usr/bin/sudoedit /usr/bin/fping6 /usr/bin/ndisc6 /usr/bin/chfn /usr/bin/fping /usr/bin/sudo /usr/bin/gpasswd /usr/bin/chsh /usr/bin/rltraceroute6 /usr/bin/newgrp /usr/bin/passwd
Note: we may want to leave SUID bits in place for e.g. su
or sudo
, if needed:
$ find / -xdev -type f -perm -4000 | grep -vwE 'ping|ping6|su|sudo|pam-tmpdir-helper' | xargs chmod -c u-s
Capabilities
Removing SUID bits may leave the affected binaries unusable for normal users (e.g. ping
) and we could implement POSIX capabilities[8] instead:
sudo apt-get install libcap2-bin # Debian, Ubuntu sudo yum install libcap # Fedora, RHEL
ping | CAP-NET-RAW (13) |
traceroute | CAP-NET-RAW (13) |
chsh | CAP-CHOWN (0), CAP-DAC-READ-SEARCH (2), CAP-FSETID (4), CAP-SETUID (7) |
chfn | CAP-CHOWN (0), CAP-DAC-READ-SEARCH (2), CAP-FSETID (4), CAP-SETUID (7) |
chage | CAP-DAC-READ-SEARCH (2) |
passwd | CAP-CHOWN (0), CAP-DAC-OVERRIDE (1), CAP-FOWNER (3) |
mount | CAP-DAC-OVERRIDE (1), CAP-SYS-ADMIN (21) |
umount | CAP-DAC-OVERRIDE (1), CAP-SYS-ADMIN (21) |
Example:
$ fping localhost fping: can't create raw socket (must run as root?) : Operation not permitted $ sudo setcap 13=ep /usr/bin/fping $ fping localhost localhost is alive
Or, for multiple capabilities:
sudo setcap 0,1,3=ep /usr/bin/passwd
/proc
Hiding some elements of /proc
can help making potential attacks harder.
chmod 1775 /dev/shm # ECryptfs needs /dev/shm to be world-writable![9] chmod 0440 /proc/interrupts chown root:munin /proc/interrupts # This way, Munin can still print interrupt statistics chmod go-rwx /boot /sys/devices/*/*/resources /sys/kernel/slab /sys/kernel/slab/*/ctor \ /proc/buddyinfo /proc/bus /proc/cmdline /proc/devices /proc/iomem /proc/ioports \ /proc/kallsyms /proc/modules /proc/net/ptype /proc/pagetypeinfo \ /proc/slabinfo /proc/timer_list /proc/vmallocinfo /proc/zoneinfo /dev/kmsg \ /proc/cgroups /proc/consoles /proc/crypto /proc/diskstats \ /proc/dma /proc/driver /proc/execdomains /proc/fb /proc/filesystems /proc/fs \ /proc/irq /proc/key-users /proc/locks /proc/misc /proc/mtrr /proc/partitions \ /proc/softirqs /proc/swaps /proc/sysvipc /proc/tty \ /proc/device-tree /proc/pmu /proc/powerpc
The Linux kernel v3.3-rc1[10] can use the hidepid=
and gid=
options to resrict access to /proc/PID
directories:
$ mount | grep ^proc
proc on /proc type proc (rw,noexec,nosuid,nodev,hidepid=2)
$ ps -e | wc -l
14
$ sudo ps -e | wc -l
169
- hidepid=0 is the default behaviour, all users can see all
/proc/PID
directories. - hidepid=1 means users may not access any
/proc/<pid>/
directories, but their own. - hidepid=2 means hidepid=1 plus all
/proc/PID
will be invisible to other users.
Note: this has been backported into Debian/wheezy, see Debian #669028 for details!
Random Numbers
On most system, the following random sources should be available:
/dev/urandom
Serves as a PRNG, non-blocking, good throughput./dev/random
Serves as a RNG, blocking I/O when not enough entropy is available, poor throughput.
The Linux entropy pool[11] can be queried via the /proc
filesystem:
$ sysctl kernel.random.entropy_avail kernel.random.entropy_avail = 3457
On systems with limited sources of real randomness[12], we'd like to use some kind of PRNG to gather additional random bits.
rng-tools
rngd needs a kernel device for random source. Also, it's only available for Linux.
apt-get install rng-tools # Debian[13], Ubuntu dnf install rng-tools # Fedora, CentOS
As root, we can list all available (and disabled) sources of entropy:
$ sudo rngd -l Entropy sources that are available but disabled 1: TPM RNG Device (tpm) 4: NIST Network Entropy Beacon (nist) Available and enabled entropy sources: 0: Hardware RNG Device (hwrng) 2: Intel RDRAND Instruction RNG (rdrand) 5: JITTER Entropy generator (jitter)
Check kernel.random.entropy_avail
to verify that it's working! Test with rngtest
:
$ rngtest -c 1000 < /dev/random
rngtest: starting FIPS tests...
rngtest: bits received from input: 20000032
rngtest: FIPS 140-2 successes: 999
rngtest: FIPS 140-2 failures: 1
rngtest: FIPS 140-2(2001-10-10) Monobit: 0
rngtest: FIPS 140-2(2001-10-10) Poker: 0
rngtest: FIPS 140-2(2001-10-10) Runs: 0
rngtest: FIPS 140-2(2001-10-10) Long run: 1
rngtest: FIPS 140-2(2001-10-10) Continuous run: 0
rngtest: input channel speed: (min=26.982; avg=38.635; max=11028.374)Kibits/s
rngtest: FIPS tests speed: (min=17.030; avg=44.287; max=181.652)Mibits/s
rngtest: Program run time: 505958874 microseconds
Without a proper random source[14] we get:
$ rngtest -c 1000 < /dev/zero
rngtest: starting FIPS tests...
rngtest: bits received from input: 20000032
rngtest: FIPS 140-2 successes: 0
rngtest: FIPS 140-2 failures: 1000
rngtest: FIPS 140-2(2001-10-10) Monobit: 1000
rngtest: FIPS 140-2(2001-10-10) Poker: 1000
rngtest: FIPS 140-2(2001-10-10) Runs: 1000
rngtest: FIPS 140-2(2001-10-10) Long run: 1000
rngtest: FIPS 140-2(2001-10-10) Continuous run: 1000
rngtest: input channel speed: (min=1.693; avg=17.183; max=18.626)Gibits/s
rngtest: FIPS tests speed: (min=82.928; avg=460.623; max=733.596)Mibits/s
rngtest: Program run time: 42713 microseconds
haveged
haveged is based on the HAVEGE[15] random number generator and is said to work on systems withouth a hardware RNG while still producing good[16] random numbers. While this may or may not be true, it can be run additionally to rngd.[17]
apt-get install haveged # Debian, Ubuntu dnf install haveged # Fedora, CentOS
Let's run it in foreground for demonstration purposes:
$ haveged -F -v1 -w 1024 haveged starting up haveged: ver: 1.8; arch: x86; vend: GenuineIntel; opts: (T); collect: 128K haveged: cpu: (L4 VC); data: 32K (L2 L4 V); inst: 32K (L2 L4 V); idx: 21/40; sz: 32701/60538 haveged: tot tests: BA8: A:1/0 B: 1/0; continuous tests: B: A:0/0 B: 0/0; last entropy estimate 8.00131 haveged: fills: 0, generated: 0
Check kernel.random.entropy_avail
to verify that it's working or test with rngtest again.
See also
Links
- Arch Linux: Security
- Tails: kernel hardening
- Ubuntu: Kernel Hardening / Outflux: security things in Linux (2021-04-05)
- Linux Hardening Guide (2022-03-19)
References
- ↑ How useful is mounting /tmp noexec?
- ↑ Creating temporary files securely
- ↑ Improve security with polyinstantiation
- ↑ Infrastructure/FedoraPeopleConfig: polyinstantiated tempdirs
- ↑ Linux Security HOWTO: Files and File system Security
- ↑ mount(8)
- ↑ Replace setuid apps where possible with file capabilities
- ↑ Harden a Linux System: POSIX capabilities (CEG 4420/6420: Computer Security)
- ↑ Ah yes, the dreaded “Ecryptfs error locking counter” on your home directory after a reboot...
- ↑ procfs: add hidepid= and gid= mount options
- ↑ LCE: Don't play dice with random numbers
- ↑ Sources of Randomness for Userspace
- ↑ rng-tools. Note: This is an unofficial version of rng-tools which has been extensively modified to add multithreading and a lot of new functionality
- ↑ Linux kernel module for high throughput RFC1149.5-compliant random number generation
- ↑ HAVEGE: Hardware Volatile Entropy Gathering and Expansion
- ↑ Is it appropriate to use haveged as a source of entropy on virtual machines?
- ↑ LCE: Don't play dice with random numbers