物理安全

安全原则之一是深度防御。因此,我们应该始终考虑安全层。第一层是物理安全。

如果您阻止潜在的对手能够获得对计算机系统的物理访问,那将是最好的。如果入侵者可以进入您的办公室,那么很容易将磁盘驱动器移除并带走。这是一个简单的攻击,需要最少的技术技能。

假设您已经采取了必要的措施,以防止入侵者采取磁盘驱动器或整个计算机系统。此外,您已确保系统密码复杂且无法猜测。如果入侵者可以物理访问系统,那么使用GRUB(一种流行的Linux引导加载程序)重置root密码帐户是一项简单的任务。因此,我们有一句谚语“靴子访问=根访问”。

很明显,我们需要确保电脑系统的实体安全;然而,万一实体安全受到破坏,我们需要提供额外的保护层。许多BIOS和UEFI固件允许您添加靴子密码。此密码将防止未经授权的用户启动系统。但是,这只能用于个人系统;在服务器上使用它没有意义,因为这需要有人亲自在场以提供靴子密码。

我们可以考虑根据要保护的Linux系统添加GRUB密码。许多工具可以帮助实现这一点。其中一个工具是grub2-mkpasswd-pbkdf2,它会提示您输入两次密码并为您生成一个哈希值。根据Linux发行版(例如:FedoraUbuntu)的不同,结果哈希应该被添加到相应的配置文件中。此配置将防止未经授权的用户重置您的root密码。它将要求用户提供密码以通过GRUB访问高级靴子配置,包括使用root访问权限登录。

AttackBox终端

           root@AttackBox# grub2-mkpasswd-pbkdf2
Enter password:
Reenter password:
PBKDF2 hash of your password is grub.pbkdf2.sha512.10000.534B77859C13DCF094E90B926E26C586F5DC9D00687853487C4BB1500D57EC29E2D6D07A586262E093DCBDFF4B3552742A25700BAB6B76A8206B3BFCB273EEB4.4BA1447590EA8451CD224AA1C5F8623FE85D23F6D34E2026E3F08C5AA79282DB65B330BAB4944E9374EC51BF11EFF418EDA5D66FF4D7AAA86F662F793B92DA61

需要注意的是,为GRUB添加密码不适用于使用云服务提供商部署的系统(例如我们的Linux VM); GRUB密码没有意义,因为您没有访问物理终端的权限。

确保适当的物理安全是必须考虑到它是多么容易的攻击者与物理访问肆虐。为GRUB添加密码是一种合理的措施,可以阻止物理访问系统键盘的用户获得访问权限。但是,我们需要一个计划,以防攻击者找到窃取磁盘驱动器的方法。

文件系统分区和加密

加密使数据在没有解密密钥的情况下不可读。在这种情况下,对手有完全的物理访问您的笔记本电脑,例如,通过窃取它,我们要确保它不会对他们有任何用处。一个充满加密数据的磁盘驱动器应该和一个损坏的一样好。

有各种软件系统和工具为Linux系统提供加密。由于许多现代Linux发行版都附带LUKS(Linux统一密钥设置),让我们更详细地介绍它。

当分区使用LUKS加密时,磁盘布局将如下图所示。

LUKS disk layout: LUKS Partition Header, KM1, KM2, ..., KM8, Bulk Data

我们有以下字段:

  • LUKS PHDR:它代表LUKS Partition Header。LUKS phdr存储有关UUID(通用唯一标识符)、使用的密码、密码模式、密钥长度和主密钥的校验和的信息。
  • KM:KM代表关键材料,我们有KM 1,KM 2,…,KM 8。每个密钥材料部分与一个密钥槽相关联,该密钥槽可以在LUKS phdr中被指示为活动的。当钥匙槽处于活动状态时,相关的钥匙材料部分包含用用户密码加密的主钥匙的副本。换句话说,我们可以用第一个用户的密码加密主密钥并保存在KM 1中,用第二个用户的密码加密并保存在KM 2中,依此类推。
  • Bulk Data: 批量数据:这是指由主密钥加密的数据。主密钥保存在密钥材料部分,并由用户密码加密。

LUKS重用现有的块加密实现。加密数据的伪代码使用以下语法:

enc_data = encrypt(cipher_name, cipher_mode, key, original, original_length)

正如我们所看到的,LUKS可以使用不同的密码和密码模式。Original是指长度为original_length的明文数据。用户提供的密码用于导出加密密钥;密钥使用基于密码的密钥导出函数2(PBKDF 2)导出。

key = PBKDF2(password, salt, iteration_count, derived_key_length)

使用具有重复迭代计数的散列函数的盐确保所得密钥对于加密足够安全。有关更多信息,您可能需要参考密码学导论室。

类似地,为了解密数据并恢复原始明文,LUKS使用以下语法:

original = decrypt(cipher_name, cipher_mode, key, enc_data, original_length)

大多数发行版允许您使用图形界面加密驱动器。但是,如果您想从命令行设置LUKS,则步骤沿着以下几行:

  • 安装cryptsetup-luks。(You可以分别为Ubuntu/Debian、RHEL/Cent OS和Fedora发布apt install cryptsetupyum install cryptsetup-luksdnf install cryptsetup-luks
  • 使用fdisk -llsblkblkid确认分区名称。(如果需要,请使用fdisk创建分区。)
  • 为LUKS加密设置分区:cryptsetup -y -v luksFormat /dev/sdb1。(将/dev/sdb1替换为您要加密的分区名称。
  • 创建一个映射来访问分区:cryptsetup luksOpen /dev/sdb1 EDCdrive
  • 确认映射详细信息:ls -l /dev/mapper/EDCdrivecryptsetup -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

在下面的终端中,我们展示了一个加密USB闪存的真实的示例,该闪存最初在/dev/sdb1处有一个分区,格式为NTFS。

AttackBox终端

           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次迭代。

AttackBox终端

           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

防火墙

在开始之前,让我们简要地回顾一下客户机/服务器模型。任何联网设备都可以是客户端、服务器或同时是两者。服务器提供服务,客户端连接到服务器以使用它。服务器的示例包括Web服务器(HTTP和HTTPS)、邮件服务器(SMTP(S)、POP3(S)和IMAP(S))、名称服务器(DNS)和SSH服务器。服务器侦听已知的TCP或UDP端口号,等待传入的客户端连接请求。客户端向监听服务器发起连接请求,服务器响应请求。

防火墙决定哪些包可以进入系统,哪些包可以离开系统。有关防火墙的更多信息,我们建议您查看防火墙室。如果没有防火墙,客户端可以不受限制地与任何服务器通信;此外,客户端可以充当服务器并侦听来自其他客户端的传入连接。换句话说,如果攻击者设法利用没有防火墙的系统上的漏洞,攻击者可以使用该漏洞来侦听受害者机器上选定的端口号并连接到它而不受任何限制。

设置防火墙提供了许多安全方面的好处。首先,防火墙规则提供了对哪些数据包可以离开系统以及哪些数据包可以进入系统的精细控制。因此,防火墙规则通过控制设备之间的网络流量来帮助减轻各种安全风险。更重要的是,可以设计防火墙规则来确保没有客户端可以充当服务器。换句话说,攻击者无法在目标计算机上启动可访问的侦听端口;利用漏洞可以启动侦听端口,但防火墙将阻止所有传入的连接尝试。

基于主机的防火墙是安装在我们想要保护的系统上的一个软件。与基于网络的防火墙不同,基于主机的防火墙将网络数据包限制在单个主机上。防火墙有两个主要功能:

  • 什么东西可以进去?允许或拒绝数据包进入系统。
  • 什么可以离开?允许或拒绝数据包离开系统。

对进入和离开系统的数据包施加规则将显著提高我们的安全状况。让我们研究一下如何在Linux系统上实现这一点。

Linux Firewalls

第一个Linux防火墙是包过滤防火墙,即,无状态防火墙无状态防火墙可以检查IP和TCP/UDP报头中的某些字段以决定数据包,但不维护有关正在进行的TCP连接的信息。因此,数据包可以操纵一些TCP标志,使其看起来像是正在进行的连接的一部分,并逃避某些限制。当前的Linux防火墙是有状态的防火墙;它们跟踪正在进行的连接,并根据IP和TCP/UDP报头中的特定字段以及数据包是否是正在进行的连接的一部分来限制数据包。

进入防火墙规则的IP标头字段包括:

  1. Source IP address
  2. Destination IP address

防火墙规则主要关注的TCP/UDP报头字段包括:

  1. Source TCP/UDP port
  2. Destination TCP/UDP port

值得注意的是,不可能根据进程允许和拒绝数据包,而是根据端口号。如果您希望Web浏览器访问Web,则必须允许相应的端口,例如端口80和443。此限制与MS Windows的内置防火墙不同,后者可以限制和允许每个应用程序的流量。

在Linux系统上,可以使用SE LinuxAppArmor等解决方案对进程及其网络访问进行更精细的控制。例如,我们可以只允许/usr/bin/apache2二进制文件使用端口80和443,同时防止任何其他二进制文件在底层系统上这样做。这两个工具都基于特定的进程或二进制文件强制执行访问控制策略,从而提供了一种更全面的方法来保护Linux系统。

让我们仔细看看不同的可用Linux防火墙。

Netfilter

在核心部分,我们有netfilter。netfilter项目为Linux内核2.4.x和更高版本提供包过滤软件。netfilter钩子需要一个前端,如iptablesnftables来管理。

在下面的示例中,我们使用不同的netfilter前端,以允许传入SSH连接到我们的Linux系统上的SSH服务器。如下图所示,我们希望SSH服务器可以被Internet上任何拥有SSH客户端的人访问。

Figure showing an SSH client connecting to an SSH server.

iptables

作为一个前端,iptables提供了用户空间命令行工具来使用netfilter钩子配置包过滤规则集。为了过滤流量,iptables有以下默认链:

  • Input: 此链适用于传入防火墙的数据包。
  • Output: 此链适用于从防火墙传出的数据包。
  • Forward 转发此链适用于通过系统路由的数据包。

假设我们希望能够远程访问系统上的SSH服务器。为了让SSH服务器能够与世界通信,我们需要两件事:

  1. 接受到TCP端口22的传入数据包。
  2. 接受来自TCP端口22的传出数据包。

让我们将上述两个要求转换为iptables命令:

iptables -A INPUT -p tcp --dport 22 -j ACCEPT
  • -A INPUT添加到INPUT链,即,发送到系统的数据包。
  • -p tcp --dport 22适用于目的端口为22的TCP协议。
  • -j ACCEPT指定(跳转到)目标规则ACCEPT。
iptables -A OUTPUT -p tcp --sport 22 -j ACCEPT
  • -A OUTPUT附加到OUTPUT链,即,数据包离开系统。
  • -p tcp --sport 22适用于源端口为22的TCP协议。

假设您只想允许到本地SSH服务器的流量,并阻止其他所有流量。在这种情况下,您需要添加两个规则来设置防火墙的默认行为:

  • iptables -A INPUT -j DROP阻止所有以前规则中不允许的传入流量。
  • iptables -A OUTPUT -j DROP阻止所有以前规则中不允许的传出流量。

简而言之,以下规则需要按以下顺序适用:

AttackBox终端

           root@AttackBox# 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在Kernel 3.13及更高版本中得到支持,在iptables上增加了各种改进,特别是在可伸缩性和性能方面。

我们将创建一个简单的nftables配置,允许流量到达本地SSH服务器。

与iptables不同,nftables没有表或链。我们需要在添加规则之前添加必要的表和链。开始,我们将创建一个表fwfilter

nft add table fwfilter
  • add用于添加一个表。其他命令包括delete删除表,list列出表中的链和规则,以及flush从表中清除所有链和规则。
  • table TABLE_NAME用于指定我们要创建或处理的表的名称。

在我们新创建的表fwfilter中,我们将分别为传入和传出数据包添加一个输入链和一个输出链。

  • nft add chain fwfilter fwinput { type filter hook input priority 0 \; }

上面的两个命令将两条链添加到表fwfilter

  • fwinput是输入链。它属于类型filter,适用于输入钩子。
  • fwoutput是输出链。它属于类型filter,适用于输出挂钩。

有了表中创建的两个链,我们可以添加必要的规则来允许SSH流量。将以下两个规则分别添加到表fwfilter到链fwinputfwoutput

  • nft add fwfilter fwinput tcp dport 22 accept接受到本地系统目的端口22的TCP流量。
  • nft add fwfilter fwoutput tcp sport 22 accept接受来自本地系统源端口22的TCP流量。

我们可以使用命令fwfilter检查nft list table fwfilter表的形状:

AttackBox终端

           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
}
}

我们希望上面的例子能让你对nftables的工作原理有一个大致的了解。

UFW

在概述了iptables和nftables之后,您可能已经开始产生这样的印象,即在Linux上配置防火墙是一个繁琐且容易出错的过程。我们已经提到iptables就像netfilter的前端;然而,我们可以通过为前端提供一个前端来简化事情!

iptables的前端示例如下图所示,可以分为:

  • 命令行界面(CLI)前端,如firewalld和ufw
  • 图形用户界面(GUI)前端,如fwbuilder

Figure showing the relationship between netfilter, iptables, and the different front ends.

UFW是Uncomplicated Firewall的缩写。让我们看看它是如何实现其简单的承诺的。我们将允许SSH流量。此防火墙规则可以通过以下命令之一来实现:

ufw allow 22/tcp

它将防火墙配置为allow到TCP端口22的流量。我们可以使用命令ufw status确认我们的设置。

AttackBox终端

           root@AttackBox# sudo ufw status
Status: active

To Action From
-- ------ ----
22/tcp ALLOW Anywhere
22/tcp (v6) ALLOW Anywhere (v6)

Firewall Policy

在配置防火墙之前,您需要确定防火墙策略。您可能是防火墙策略的决策者,也可能是涵盖防火墙配置的现有安全策略的执行者。这一切都取决于你所保护的系统。

我们不谈安全政策,因为这超出了本会议室的范围。我们将提到两种主要方法:

  • B阻止一切,并允许某些例外。
  • 允许一切并阻止某些例外。

上述两种方法各有其优点和缺点。使用有限的异常集阻止所有内容将提供更严格和更好的安全性;但是,根据情况,它可能会给用户带来不便。

让我们考虑下面的例子。您负责配置安装在大学计算机上的(主机)防火墙。在此示例中,学术机构已决定阻止除DNS、HTTP和HTTPS流量之外的所有传出和传入流量。在防火墙术语中,这允许UDP端口53和TCP端口80和443。此策略应允许通过HTTP和HTTPS浏览Internet;但是,如果其中一个网站使用非标准的HTTP或HTTPS端口,则会被阻止。处理这些异常将带来一个挑战;随着异常的数量随着时间的推移而增加,保持防火墙规则的组织和正确记录是很棘手的。

远程访问

提供对系统的远程访问是一种非常方便的方法,可以在您不在目标系统的键盘前时访问您的系统和文件。然而,这也意味着您自愿提供攻击者将瞄准的服务。常见的攻击包括:

  1. Password sniffing
  2. Password guessing and brute-forcing
  3. Exploiting the listening service

防止密码嗅探

远程访问可以通过许多不同的协议和服务来实现。尽管所有现代系统都使用加密协议(如SSH协议)进行远程访问,但较旧的系统可能仍然使用明文协议(如HTTPS协议)。

在下图中,尽管用户选择了一个强密码,但它是以明文形式发送的,任何人都可以通过网络路径使用数据包捕获工具读取。

Figure showing a Telnet client connecting to a Telnet server.

确保选择加密流量的协议至关重要。SSH协议已经存在了二十多年。它经受住了时间的考验。它有许多用途,从安全的远程访问到安全的文件传输。

防止密码猜测

当您使用SSH设置Linux系统以进行远程管理时,您还可以使所有相关方都可以使用Linux机器。许多恶意黑客在互联网上搜索侦听SSH服务器,并开始猜测登录凭据;通常,他们会尝试使用最常见的密码root

下图显示系统使用SSH协议来确保加密通信;但是,身份验证依赖于登录凭据。许多用户倾向于使用弱密码或在其他服务中重复使用相同的密码。虽然qwerty1234不在英文字典中,但它通常是前10或20个最常见的密码之一,很容易猜测。

Figure showing an SSH client connecting to an SSH server.

因为您的SSH服务器将被配置为一年365天,一天24小时监听传入连接,所以邪恶的用户有足够的时间尝试一个又一个密码。有几个准则,你可以用途:

  1. 禁用远程登录为root;强制登录为非根用户。
  2. 禁用密码身份验证;改为强制公钥身份验证。

上述准则背后的理由是,您不希望对手能够直接攻击root帐户。此外,即使它是一个非root帐户,如果密码中存在弱点,您也不希望攻击者获得访问权限。

OpenSSH服务器的配置可以通过sshd_config文件控制,通常位于/etc/ssh/sshd_config。您可以通过添加以下行来禁用root登录:

PermitRootLogin no

虽然像9bNfX2gmDZ4o这样的密码很难猜到,但大多数用户发现记住它很不方便。想象一下,如果帐户属于sudoers(sudo组),用户每次需要使用sudo发出命令时都需要输入此密码。你可能必须遵守纪律,但你不能指望这对每个人都有效。

许多用户倾向于选择用户友好的密码或在多个帐户中共享相同的密码。这两种方法都使攻击者更容易猜测密码。

最好依靠SSH的公钥身份验证来帮助提高远程登录系统的安全性,并使其尽可能地防故障。

如果您还没有创建SSH密钥对,则必须发出命令ssh-keygen -t rsa。它将生成保存在id_rsa中的私钥和保存在id_rsa.pub中的公钥。

为了让SSH服务器使用您的公钥而不是密码对您进行身份验证,需要将您的公钥复制到目标SSH服务器。一个简单的方法是发出命令ssh-copy-id username@server,其中username是您的用户名,server是SSH服务器的主机名或IP地址。

最好在禁用密码身份验证之前确保您可以访问物理终端,以避免将自己锁定在外。您可能需要确保在sshd_config文件中有以下两行。

  • PubkeyAuthentication yes启用公钥身份验证
  • PasswordAuthentication no禁用密码验证

保护用户帐户

root帐户具有巨大的权力,因此具有风险。您可能会因为一个简单的错误而导致系统无法启动。建议在日常工作中使用非root帐户,以避免破坏系统。但是,系统维护、安装/删除软件包以及更新/配置系统仍然需要root权限。

Use sudo

为了避免以root的身份登录,更好的方法是在sudoers中添加一个用于管理目的的帐户,即可以使用sudo命令的组。sudo代表超级用户做,它应该在任何需要root权限的命令之前。

根据Linux发行版的不同,我们可以通过以下方式将用户添加到sudoers组。一些发行版,如Debian和Ubuntu,将sudoers组称为sudo。在这种情况下,您需要发出以下命令:

usermod -aG sudo username
  • usermod修改用户帐户。
  • -aG添加到组。
  • sudo是可以在基于Debian的发行版上使用sudo的用户组的名称。
  • username是您要修改的用户帐户的名称。

其他发行版,如RedHat和Fedora,将sudoers组称为wheel。因此,您需要发出以下命令:

usermod -aG wheel username

唯一的区别是sudoers组的名称。

禁用根目录

一旦您出于管理目的创建了帐户并将其添加到sudo/wheel组,您可能会考虑禁用root帐户。一个简单的方法是修改/etc/passwd并将root shell更改为/sbin/nologin。换句话说,编辑/etc/passwd并将行root:x:0:0:root:/root:/bin/bash更改为root:x:0:0:root:/root:/sbin/nologin

实施强密码策略

libpwquality库为密码约束提供了许多选项。配置文件可以在以下位置找到:

  • /etc/security/pwquality.conf在RedHat和Fedora上
  • /etc/pam.d/common-password在Debian和Ubuntu上。您可以使用apt-get install libpam-pwquality安装它。

以下是一些示例选项:

  • difok允许您指定旧密码中不存在的新密码中的字符数。
  • minlen设置新密码允许的最小长度。
  • minclass指定所需的字符类的最小数量;类可以是字符串、字符串和数字等。
  • badwords提供了一个空格分隔的单词列表,这些单词不得包含在所选密码中。
  • retry=N在返回错误之前提示用户N次。

下面是一个例子#1。

AttackBox终端

           root@AttackBox# sudo cat /etc/security/pwquality.conf

difok=5
minlen=10
minclass=3
retry=2

您可以在手册页man pwquality.conf上查看所有可用选项。

Disable Unused Accounts

作为系统维护的一部分,禁用不再需要访问相关系统的用户帐户至关重要。例如,这些用户可能已经转到另一个部门或退出公司。

您可以禁用用户帐户的方式与我们禁用根帐户的方式相同。一个简单的方法是编辑/etc/passwd文件,并将我们要禁用的用户帐户的shell设置为/sbin/nologin

假设我们要禁用用户名为michael的用户Michael的帐户。

  • 启用帐户:michael:x:1000:1000:Michael:/home/michael:/usr/bin/fish
  • 禁用帐户:michael:x:1000:1000:Michael:/home/michael:/sbin/nologin

我们应该为当地服务做同样的事情。换句话说,我们应该为所有本地服务帐户(例如sbin/nologinwww-datamongo)设置shell为nginx。原因是这些服务需要帐户才能在系统上运行,但永远不需要登录和访问shell。这些服务中的任何一个都可能存在RCE(远程代码执行)漏洞,通过将shell设置为nologin,我们至少可以阻止受影响服务帐户的交互式登录。

软件和服务

您在系统上安装的每一个软件也会增加潜在漏洞的数量。换句话说,安装额外的软件包和新服务会增加攻击者可以利用的漏洞,从而访问您的系统,并最终访问您网络上的其他系统。您可以遵循一些指导原则来帮助您减少攻击面。

禁用不必要的服务

改善安全状况的最简单方法之一是删除或禁用不需要的服务和软件包。简而言之,我们需要尽量减少安装的系统软件包的数量,因为每个软件包都有一定的风险,我们无法知道何时会发现相关的漏洞。最好的策略是避免安装不需要的软件包。

例如,如果您不需要Web服务器,则应确保不安装。如果您曾经需要运行Web服务器,但现在不再需要它,您应该删除它或至少禁用它。否则,您将使自己面临不必要的风险。

阻止不需要的网络端口

在您删除任何不需要的软件包并禁用可能不会删除的预安装服务后,相应地设置防火墙规则至关重要。如果您没有Web服务器,则没有理由允许数据包到达TCP端口80和443。这背后的原因是,如果攻击者设法启动禁用的服务,防火墙将阻止其流量,攻击者将无法访问其TCP端口。

避免遗留协议

在过去的某个时候,FTP是远程访问系统的主要协议; TFTP协议通常用于传输文件。这种协议不应该再被允许,因为安全的替代方案已经发布。

SSH协议取代了TCP/IP,现在已经广泛使用。例如,安全文件传输协议(SFTP)协议提供了TFTP协议的一个很好的替代方案。关键是选择和使用安全的替代方案。

删除标识字符串

当你连接到远程服务器时,它通常会回复它的版本号。这些信息会向攻击者泄露各种信息,例如服务器/程序的名称、版本号和主机操作系统。

更新和升级策略

使用最新的安全补丁和错误修复程序更新您的系统至关重要。

您可以使用以下两个命令更新基于Debian的发行版,例如Ubuntu:

  1. apt update从配置的源下载软件包信息
  2. apt upgrade从已配置的源安装所有软件包的可用升级

您可以使用以下方法更新RedHat或Fedora系统:

  • dnf update 在较新版本(Red Hat Enterprise Linux 8及更高版本)
  • yum update 旧版本(Red Hat Enterprise Linux 7及更早版本)

由于我们谈论的是生产系统,因此我们需要选择能够在许多年内继续顺利接收更新的发行版。

Ubuntu LTS版本

例如,Ubuntu每两年发布一次长期支持(LTS)版本。LTS版本有一个偶数版本号(表示年份),04(4月),例如18.04,20.04和22.04。LTS版本将为您提供基本操作系统的五年安全更新,而无需订阅,如果您支付扩展安全维护(ESM),则另外五年。有关更多信息,您可能需要检查Ubuntu生命周期和发布节奏

使用Ubuntu LTS版本,您可以在前五年内无需订阅即可下载更新。考虑以下带有Ubuntu 14.04的Linux系统。它于2014年发布,其免费支持于2019年4月结束。换句话说,免费更新服务将持续到2019年。在下面的终端中,我们看到如果我们有Ubuntu Pro(仅限Ubuntu)订阅(以前称为Ubuntu Advantage(UA)for Infrastructure),我们可以下载和安装133个额外的更新。

AttackBox终端

           root@AttackBox# user@tryhackme$ uname -a
Linux ubuntu-14-vm 4.4.0-148-generic #174~14.04.1-Ubuntu SMP Thu May 9 08:18:11 UTC 2019 i686 athlon i686 GNU/Linux

user@tryhackme$ sudo apt upgrade
Reading package lists... Done
Building dependency tree
Reading state information... Done
Calculating upgrade... Done
0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.

133 additional updates are available with UA Infrastructure ESM.
To see these additional updates run: apt list --upgradable
See https://ubuntu.com/advantage or run: sudo ua status

Ubuntu 14.04是在五年多前发布的,因此不再提供免费更新。从安全的角度来看,用户应该订阅Ubuntu Pro或切换到新的LTS版本,如Ubuntu 22.04。继续运行未接收安全更新的系统将使系统和整个网络面临额外的风险。

RedHat发布

RedHat Enterprise Linux 8和9分三个阶段提供12年的支持:

  1. 五年全面支持
  2. 五年的维护支持
  3. 延长寿命阶段两年

例如,Red Hat Enterprise Linux 9于2022年5月18日发布。它可以从以下更新中受益:

  1. 2027全面支持至2027年5月31日
  2. 维护支持至2032年5月31日

有关详细信息,请查看红帽企业Linux生命周期

内核更新

更新系统不应该局限于已安装的软件;它应该考虑更新内核。例如,在2016年,发现了一个影响Linux内核的安全漏洞。它允许攻击者通过利用写时复制(COW)机制中的竞争条件来获得对系统的根访问权限,并将其命名为“Dirty COW”。从2.6.22开始的所有Linux内核版本中都存在此漏洞。它已经在大多数主要的Linux发行版中打了补丁,但它仍然是对尚未更新的系统的威胁。

由于Dirty COW是一个严重的漏洞,攻击者可以通过该漏洞获得对Linux系统的根访问权限,因此务必使您的系统(包括其内核)保持最新的安全补丁,以降低被利用的风险。

自动更新

既然您有了一个在其整个生命周期中都有安全更新的Linux系统,我们必须确保正确安装了更新,并应用了安全修复程序。

  • 随时了解最新的安全新闻,以防影响您系统的漏洞被披露。
  • 根据您使用的Linux发行版,请考虑配置自动更新。在优先考虑稳定性而不是尖端技术的Linux发行版上自动更新是安全的。

审核和日志配置

Linux系统上的大多数日志文件都存储在/var/log目录中。以下是一些在调查威胁时可以参考的日志:

  • /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查看最后几行。例如,tail -n 12 boot.log将显示最后12行。
  • 搜索包含特定关键字的日志行的一种方法是使用命令grep。例如,grep FAILED boot.log将只显示带有单词FAILED的行。

请注意,您必须以root用户身份登录,或者在命令前加上sudo才能查看系统日志文件。