Linux System Hardening
- Physical Security
- Filesystem Encryption
- Firewall Configuration
- Remote Access
- Software and Services
- Updates and Upgrades
- Logs
Physical Security
物理安全,如果入侵者能够物理访问您的电脑,则可以轻松移除磁盘驱动器并将其带走。这是一种简单的攻击,需要很少的技术技能。
因此,考虑到硬盘可以被取走,其中的数据则为重点保护对象。可以考虑添加 GRUB 密码,grub2-mkpasswd-pbkdf2 会提示您输入密码两次并为您生成哈希值。根据 Linux 发行版将生成的哈希添加到适当的配置文件中。此配置将防止未经授权的用户重置您的 root 密码。它将要求用户提供密码才能通过 GRUB 访问高级引导配置,包括使用 root 访问权限登录
root@AttackBox# grub2-mkpasswd-pbkdf2 Enter password: Reenter password: PBKDF2 hash of your password is grub.pbkdf2.sha512.10000.534B77859C13DCF094E90B926E26C586F5DC9D00687853487C4BB1500D57EC29E2D6D07A586262E093DCBDFF4B3552742A25700BAB6B76A8206B3BFCB273EEB4.4BA1447590EA8451CD224AA1C5F8623FE85D23F6D34E2026E3F08C5AA79282DB65B330BAB4944E9374EC51BF11EFF418EDA5D66FF4D7AAA86F662F793B92DA61
需要注意的是 GRUB 添加密码不适用于使用云服务提供商部署的系统
Filesystem Partitioning and Encryption
文件系统分区和加密
许多 Linux 发行版都附带 LUKS(Linux 统一密钥设置)当使用 LUKS 加密分区时,磁盘布局将如下图所示:

下面是一个加密 USB 闪存的真实示例,该闪存最初在 /dev/sdb1 处有一个 NTFS 格式的分区。
root@AttackBox# user@TryHackMe$ sudo lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
sdb 8:16 1 14.3G 0 disk
└─sdb1 8:17 1 14.3G 0 part /run/media/strategos/Strategos
[...]
user@TryHackMe$ sudo blkid
[...]
/dev/sdb1: LABEL="Strategos" BLOCK_SIZE="512" UUID="59402B4A4E12CD06" TYPE="ntfs"
user@TryHackMe$ sudo cryptsetup -y -v luksFormat /dev/sdb1
WARNING: Device /dev/sdb1 already contains a 'ntfs' superblock signature.
WARNING!
========
This will overwrite data on /dev/sdb1 irrevocably.
Are you sure? (Type 'yes' in capital letters): YES
Enter passphrase for /dev/sdb1:
Verify passphrase:
Existing 'ntfs' superblock signature on device /dev/sdb1 will be wiped.
Existing 'dos' partition signature on device /dev/sdb1 will be wiped.
Key slot 0 created.
Command successful.
user@TryHackMe$ sudo cryptsetup luksOpen /dev/sdb1 EDCdrive
user@TryHackMe$ sudo mkfs.ext4 /dev/mapper/EDCdrive -L "Strategos USB"
mke2fs 1.46.5 (30-Dec-2021)
[...]
Allocating group tables: done
Writing inode tables: done
Creating journal (16384 blocks): done
Writing superblocks and filesystem accounting information: done
user@TryHackMe$ sudo mount /dev/mapper/EDCdrive /media/secure-USB
如果您想检查 LUKS 设置,可以发出命令 cryptsetup luksDump /dev/sdb1 。在下面的终端输出中,我们可以看到加密磁盘的UUID。我们还可以看到使用的密码是 aes-xts-plain64 。至于密钥,PBKDF2 使用 SHA256 和提供的盐进行 194180 次迭代。
root@AttackBox# sudo cryptsetup luksDump /dev/sdb1
LUKS header information
Version: 2
Epoch: 3
Metadata area: 16384 [bytes]
Keyslots area: 16744448 [bytes]
UUID: 41199bad-d753-4dce-9284-0a81d27acc95
Label: (no label)
Subsystem: (no subsystem)
Flags: (no flags)
Data segments:
0: crypt
offset: 16777216 [bytes]
length: (whole device)
cipher: aes-xts-plain64
sector: 512 [bytes]
Keyslots:
0: luks2
Key: 512 bits
Priority: normal
Cipher: aes-xts-plain64
Cipher key: 512 bits
PBKDF: argon2id
Time cost: 4
Memory: 965922
Threads: 4
Salt: bd 45 40 96 27 93 cd fa 50 60 f4 28 d4 d8 b2 bd
58 69 72 72 35 2f 26 9c a8 14 ef 91 04 b2 dc cd
AF stripes: 4000
AF hash: sha256
Area offset:32768 [bytes]
Area length:258048 [bytes]
Digest ID: 0
Tokens:
Digests:
0: pbkdf2
Hash: sha256
Iterations: 194180
Salt: 6e e1 70 a4 3f d6 71 44 c8 e6 84 4d 99 51 7d c9
49 66 bf 37 61 b8 c3 d2 4e aa f7 25 27 e2 b3 8a
Digest: c1 87 99 a1 d1 7a 05 8a ca cd 13 74 f0 33 ef 3a
98 c9 d7 a8 70 93 e2 ac 07 0f 2a 5c 89 f1 18 1d
- 安装
cryptsetup-luks.
apt install cryptsetup
yum install cryptsetup-luks
dnf install cryptsetup-luks
- 使用
fdisk -l,lsblk,blkid确认分区名称,有必要可以使用fdisk创建分区 - 设置 LUKS 加密分区:
cryptsetup -y -v luksFormat /dev/sdb1 - 创建一个映射来访问分区:
cryptsetup luksOpen /dev/sdb1 EDCdrive - 确认映射详细信息:
ls -l /dev/mapper/EDCdriveandcryptsetup -v status EDCdrive - 用零覆盖现有数据:
dd if=/dev/zero of=/dev/mapper/EDCdrive - 格式化分区:
mkfs.ext4 /dev/mapper/EDCdrive -L "Strategos USB" - 挂载:
mount /dev/mapper/EDCdrive /media/secure-USB
Firewall
目前的Linux防火墙都是状态防火墙;它们跟踪正在进行的连接,并根据 IP 和 TCP/UDP 标头中的特定字段以及数据包是否是正在进行的连接的一部分来限制数据包
iptables
iptables 提供用户空间命令行工具来使用 netfilter 挂钩配置数据包过滤规则集。为了过滤流量,iptables 有以下默认链:
- Input: 适用于传入防火墙的数据包。
- Output: 适用于从防火墙发出的数据包。
- Forward 适用于通过系统路由的数据包。
假设我们希望能够远程访问系统上的 SSH 服务器。为了使 SSH 服务器能够与外界通信,我们需要两件事:
- 接受目标 TCP 端口 22 的传入数据包。
- 接受来源 TCP 端口 22 的传出数据包。
对应 iptables 命令
$ iptables -A INPUT -p tcp --dport 22 -j ACCEPT
$ iptables -A OUTPUT -p tcp --sport 22 -j ACCEPT
假设您只想允许流向本地 SSH 服务器的流量并阻止其他所有内容。在这种情况下,您需要再添加两条规则来设置防火墙的默认行为:
$ iptables -A INPUT -j DROP 阻止 previous 规则中不允许的所有传入流量
$ iptables -A OUTPUT -j DROP 阻止 previous 规则中不允许的所有传出流量
规则需要按以下顺序应用
$ iptables -A INPUT -p tcp --dport 22 -j ACCEPT
$ iptables -A OUTPUT -p tcp --sport 22 -j ACCEPT
$ iptables -A INPUT -j DROP
$ iptables -A OUTPUT -j DROP
在实践中,在应用新规则之前应刷新(删除)以前的规则,可以使用 iptables -F 实现
nftables
nftables 在内核 3.13 及更高版本中受支持,相对于 iptables 添加了各种改进,特别是在可扩展性和性能方面。
与 iptables 不同,nftables 开始时没有表或链。在添加规则之前,我们需要添加必要的表和链。首先,我们将创建一个表 fwfilter
$ nft add table fwfilter
在我们新创建的表 fwfilter 中,我们将分别为传入和传出数据包添加一个输入链和一个输出链。
$ nft add chain fwfilter fwinput { type filter hook input priority 0 \; }
$ nft add chain fwfilter fwoutput { type filter hook output priority 0 \; }
上面两个命令向表 fwfilter 添加两条链
fwinput是输入链,类型为filter应用于输入挂钩fwoutput是输出链,类型为filter适用于输出挂钩
添加规则以允许 SSH 流量,以下两条规则分别添加到表 fwfilter 的链 fwinput 和 fwoutput 中:
$ nft add fwfilter fwinput tcp dport 22 accept
$ nft add fwfilter fwoutput tcp sport 22 accept
检查表的状态
root@AttackBox# sudo nft list table fwfilter
table ip fwfilter {
chain fwinput {
type filter hook input priority filter;
tcp dport 22 accept
}
chain fwoutput {
type filter hook output priority filter;
tcp sport 22 accept
}
}
UFW
在 Linux 上配置防火墙是一个繁琐且容易出错的过程。但是可以通过 UI 界面来简化工作! UFW 主打一个简单
Protecting Against Password Sniffing/Guessing
防止密码嗅探、猜测
远程访问使用加密协议,开启 SSH 私钥验证,关闭密码验证 vim /etc/ssh/sshd_config:
PubkeyAuthentication yes
PasswordAuthentication no
Securing User Accounts
- 使用 sudo
- 禁用 root
- 使用强密码策略
- 禁用未使用的帐户
禁用 root 和未使用的账户,可以将 /etc/passwd 文件中对应用户的 shell 改为 /sbin/nologin
root:x:0:0:root:/root:/sbin/nologin
michael:x:1000:1000:Michael:/home/michael:/sbin/nologin
RedHat/Fedora: /etc/security/pwquality.conf
Debian/Ubuntu: /etc/pam.d/common-password
root@AttackBox# sudo cat /etc/security/pwquality.conf
difok=5
minlen=10
minclass=3
retry=2
Software and Services
软件和服务
- 禁用不必要的服务
- 阻止不需要的网络端口
- 避免遗留协议,telent 与 ftp/tftp 服务应当升级为 ssh/sftp 服务
- 删除标识字符串,连接远程服务器时,一般会回复版本号,应当避免这种泄露
tomcat 隐藏版本号
vim org/apache/catalina/util/ServerInfo.properties
server.info=Apache Tomcat
Nginx 隐藏版本号
vim /usr/local/nginx/conf/nginx.conf
http {
include mime.types;
default_type application/octet-stream;
server_tokens off; // 添加此行内容
Apache 隐藏版本号
vim /etc/apache2/conf-enabled/security.conf
25 ServerTokens Prod
36 ServerSignature Off
修改 sshd 版本号
$ strings /usr/sbin/sshd | grep OpenSSH_
$ sed -i 's/OpenSSH_5.3/OpenSSH_9.9/g' /usr/sbin/sshd
Update and Upgrade Policies
更新和升级策略,及时更新系统与内核
$ uname -a
Audit and Log Configuration
审计和日志配置
/var/log/messages - Linux 系统的通用日志
/var/log/auth.log - 列出所有身份验证尝试的日志文件(基于 Debian 的系统)
/var/log/secure - 列出所有身份验证尝试的日志文件(基于 Red Hat 和 Fedora 的系统)
/var/log/utmp - 访问日志,包含当前登录系统的用户信息
/var/log/wtmp - 访问日志,包含所有登录和退出系统的用户的信息
/var/log/kern.log - 包含来自内核的消息的日志文件
/var/log/boot.log - 包含启动消息和启动信息的日志文件
新事件一般会附加到日志文件最后,可以使用 tail 查看
Redis 无密码
vim /etc/redis/redis.conf
requirepass [There is password]
默认的 SNMP Agent PUBLIC community 字符串
如果攻击者能够猜测 PUBLIC 社区字符串,他们就能够从远程设备读取 SNMP 数据(取决于安装的 MIB)。这些信息可能包括系统时间、IP 地址、接口、运行的进程等。
- 修复方案
确定检测到的团体字符串是否为私有团体字符串。确定公共社区字符串是否暴露敏感信息。如果不使用 SNMP 服务,请禁用它或更改默认社区字符串。
vim /etc/snmp/snmpd.conf将 71 行与 72 行左右的 Public 改为其他字符串
71 rocommunity public default -V systemonly
72 rocommunity6 public default -V systemonly
Nginx Root 权限运行
可导致被用于提权
vim /etc/nginx/nginx.conf
user www-data;
SSH 弱密码算法
SSH 协议可以免受 LogJam 攻击,可以强制客户使用椭圆曲线 Diffie-Hellman
vim /etc/ssh/sshd_config
KexAlgorithms [email protected]
- 加固项
/etc/ssh/sshd_config
# Ciphers
删除 3des-cbc,aes128-cbc,aes256-cbc
# kexalgorithms
删除 hellman-group1-sha1
保留 diffie-hellman-group14-sha1
# macs
删除 hmac-md5-96
可以选择生成新的 Diffie-Hellman 组
ssh-keygen -G moduli-2048.candidates -b 2048
ssh-keygen -T moduli-2048 -f moduli-2048.candidates
FTP 匿名登录
关闭 FTP 匿名登录
vim /etc/vsftpd.conf
anonymous_enable=NO
Sudo
禁止赋予非管理员用户所有权限,需要特殊权限应当如下赋予
$ sudo addgroup netadmin
$ sudo visudo -f /etc/sudoers.d/networking
---------------------------------------------
%netadmin ALL=NOPASSWD: /usr/bin/ss
$ sudo usermod -aG netadmin netboy
公开的数据库端口
服务器端口应当监听 127.0.0.1 而不是 0.0.0.0
mysql
vim /etc/mysql/mysql.conf.d/mysqld.cnf
31 bind-address = 127.0.0.1
Redis
vim /etc/redis/redis.conf
69 bind 127.0.0.1
