Fwanalyzer:文件系统镜像分析工具 – 作者:secist

FwAnalyzer是一个使用一组可配置规则分析(ext2/3/4),FAT/VFat,SquashFS,UBIFS文件系统镜像和目录内容的工具。FwAnalyzer依赖于e2tools用于ext文件系统,mtools用于FAT文件系统,squashfs-tools用于SquashFs文件系统,ubi_reader用于UBIFS文件系统。对ext2/3/4镜像的SELinux/xattr支持需要修补版本的e2tools

概述

FwAnalyzer旨在提供一种快速分析文件系统镜像的工具。FwAnalyzer有一个专门的配置文件,该文件定义了文件和目录的各种规则,并针对给定的文件系统镜像运行已配置的检查。FwAnalyzer的输出是一个报告,其中包含违反配置中指定的任何规则的文件列表。该报告还包含有关文件系统镜像的元信息,以及从分析的文件系统中提取的信息(如果已配置)。报告使用JSON格式,因此可以轻松的将其集成到大型的分析步骤当中。

报告示例:

{
    "fs_type": "extfs",
    "image_digest": "9d5fd9acc98421b46976f283175cc438cf549bb0607a1bca6e881d3e7f323794",
    "image_name": "test/test.img",
    "current_file_tree_path": "test/oldtree.json.new",
    "old_file_tree_path": "test/oldtree.json",
    "data": {
        "Version": "1.2.3",
        "date1 file": "Mon Oct  1 16:13:05 EDT 2018\n"
    },
    "informational": {
        "/bin": [
                "CheckFileTree: new file: 40755 1001:1001 1024 0 SeLinux label: -"
        ],
    },
    "offenders": {
        "/bin/elf_arm32": [
                "script(check_file_elf_stripped.sh) returned=elf_arm32 is not stripped"
        ],
        "/file1": [
                "File not allowed"
        ],
        "/file2": [
                "File is WorldWriteable, not allowed",
                "File Uid not allowed, Uid = 123"
        ],
    }
}

构建和开发

按照构建中描述的步骤安装所有所需项并构建FwAnalyzer。

使用 FwAnalyzer

命令行选项

cfg:string,配置文件的路径

cfgpath:string,配置文件的路径和包含的文件(可以重复)

in:string,文件系统镜像文件或目录路径

out:string,使用’-‘将报告输出到文件或标准输出

tree:string,覆盖目录以从中读取filetree文件

ee:如果存在违规,则error退出

invertMatch:反转(invert )正则表达式匹配(用于测试)

示例:

fwanalyzer -cfg system_fwa.toml -in system.img -out system_check_output.json

使用存储在scripts目录中的自定义脚本的示例:

PATH=$PATH:./scripts fwanalyzer -cfg system_fwa.toml -in system.img -out system_check_output.json

devices文件夹包含用于解包和处理特定设备类型和固件包格式(如Android)的helper脚本。它还包括可以包含在特定于目标的FwAnalyzer配置中的常规配置文件。

scripts文件夹包含可从FwAnalyzer调用的helper脚本,用于文件内容分析和数据提取。

配置选项

全局配置

全局配置用于定义一些常规参数。

FsType(文件系统类型)字段选择用于访问镜像中文件的后端。FsType支持的选项有:

dirfs:从运行fwanalyzer主机上的目录中读取文件(支持的FsTypeOptions:N/A)

extfs:读取ext2/3/4文件系统镜像(支持的FsTypeOptions:selinux)

squashfs:读取SquashFS文件系统镜像(支持的FsTypeOptions:N/A)

ubifs:读取UBIFS文件系统镜像(支持的FsTypeOptions:N/A)

vfatfs:读取VFat文件系统镜像(支持的FsTypeOptions:N/A)

FsTypeOptions允许调整FsTyp驱动程序。

DigestImage选项将生成已分析的文件系统镜像的SHA-256摘要,该摘要将包含在输出中。

示例:

[GlobalConfig]
FsType        = "extfs"
FsTypeOptions = "selinux"
DigestImage   = true

输出示例:

"fs_type": "extfs",
"image_digest": "9d5fd9acc98421b46976f283175cc438cf549bb0607a1bca6e881d3e7f323794",
"image_name": "test/test.img",

Include

Include语句用于将其他FwAnalyzer配置文件包含到包含该语句的配置中。include语句可以出现在配置的任何部分。-cfgpath参数设置包含文件的搜索路径。

示例:

[Include."fw_base.toml"]

全局文件检查

GlobalFileChecks是应用于整个文件系统的更通用的检查。

Suid:bool,(可选)启用后,如果任何文件设置了粘滞位,分析将失败(默认值:false)

SuidWhiteList:string array,(可选)允许Suid检查的白名单文件(按完整路径)

WorldWrite:bool,(可选)启用后,如果任何用户都可以写入任何文件,则分析将失败(默认值:false)

SELinuxLabel:string,(可选)启用后,如果文件没有SeLinux标签,分析将失败

Uids:int array,(可选)指定系统中允许的每个UID,每个文件都需要由此列表中指定的Uid所有

Gids:int array,(可选)指定系统中允许的每个GID,每个文件都需要由此列表中指定的Gid所有

BadFiles:string array,(可选)指定不需要的文件列表,允许使用通配符,如?,* 和 **(此列表中不应存在任何文件)

BadFilesInformationalOnly:bool,(可选)BadFile检查的结果将仅为信息(默认值:false)

示例:

[GlobalFileChecks]
Suid          = true
SuidWhiteList = ["/bin/sudo"]
SELinuxLabel  = false
WorldWrite    = true
Uids          = [0,1001,1002]
Gids          = [0,1001,1002]
BadFiles      = ["/file99", "/file1", "*.h"]

输出示例:

"offenders": {
  "/bin/su": [ "File is SUID, not allowed" ],
  "/file1":  [ "File Uid not allowed, Uid = 123" ],
  "/world":  [ "File is WorldWriteable, not allowed" ],
}

File Stat Check

FileStatCheck可用于为特定文件或目录建模元数据。任何配置的变化都将被报告为违规(offender)。

AllowEmpty:bool,(可选)定义文件的大小可以为0(默认值:false)

Uid:int,(可选)指定文件的UID,不指定UID或指定-1将跳过检查

Gid:int,(可选)指定文件的GID,不指定GID或指定-1将跳过检查

Mode:string,(可选)以八进制指定UN * X文件模式/权限,不指定模式将跳过检查

SELinuxLabel:string,(可选)文件的SELinux标签(如果没有设置,将跳过检查)

LinkTarget:string,(可选)符号链接的目标,未指定链接目标将跳过检查。目前仅dirfs,squashfs和ubifs文件系统支持此功能。

Desc:string,(可选)是一个描述性字符串,如果检查失败,将附加到报告中

InformationalOnly:bool,(可选)检查结果将仅供参考(默认值:false)

示例:

[FileStatCheck."/etc/passwd"]
AllowEmpty = false
Uid        = 0
Gid        = 0
Mode       = "0644"
Desc       = "this need to be this way"

输出示例:

"offenders": {
  "/file2": [ "File State Check failed: size: 0 AllowEmpyt=false : this needs to be this way" ],
}

文件路径所有者检查

FilePathOwner检查可用于为文件系统的整个tree建模文件/目录所有权。如果给定目录中的任何文件或目录不归指定的Uid和Gid(type:int)所有,则检查失败。

示例:

[FilePathOwner."/bin"]
Uid = 0
Gid = 0

输出示例:

"offenders": {
  "/dir1/file3": [ "FilePathOwner Uid not allowed, Uid = 1002 should be = 0",
                   "FilePathOwner Gid not allowed, Gid = 1002 should be = 0" ],
}

文件内容检查

FileContent检查允许检查文件的内容。可以使用四种不同的方法检查文件的内容。通过将InformationalOnly设置为true(默认为false),可以在非强制模式下运行文件内容检查。InformationalOnly检查将产生信息元素替代违规。

示例:整个文件体上的正则表达式

File:string,文件的完整路径

RegEx:string,posix/golang正则表达式

RegExLineByLine:bool,(可选)逐行应用正则表达式,匹配行将在结果中(默认值:false)

匹配:bool,(可选)指示正则表达式匹配或是不匹配(默认值:false)

Desc:string,(可选)是一个描述性字符串,将附加到失败的检查

InformationalOnly:bool,(可选)检查结果将仅供参考(默认值:false)

示例:

[FileContent."RegExTest1"]
RegEx = ".*Ver=1337.*"
Match = true
File  = "/etc/version"

示例:通过文件体计算的SHA-256摘要

File:string,文件的完整路径

Digest:string,HEX编码摘要

Desc:string,(可选)是一个描述性字符串,将附加到失败的检查

InformationalOnly:bool,(可选)检查结果仅供参考

示例:

[FileContent."DigestTest1"]
Digest = "8b15095ed1af38d5e383af1c4eadc5ae73cab03964142eb54cb0477ccd6a8dd4"
File   = "/ver"

输出示例:

"offenders": {
  "/ver": [ "Digest (sha256) did not match found = 44c77e41961f354f515e4081b12619fdb15829660acaa5d7438c66fc3d326df3 should be = 8b15095ed1af38d5e383af1c4eadc5ae73cab03964142eb54cb0477ccd6a8dd4." ],
}

示例:运行一个外部脚本传递文件名到脚本

在执行脚本之前,将文件解压缩到具有临时名称的临时目录中。如果脚本在stdout或stderr上生成输出,则检查会产生违规。

File:string,文件或目录的完整路径

Script: string,脚本的完整路径

ScriptOptions:string array,(可选)第一个元素允许定义包含通配符的模式,如?,* 和 ** 应用于文件名(如果存在)它只会检查与模式匹配的文件,这在目录上运行脚本时非常有用。第二个元素允许传递参数到脚本。

File:string,文件的完整路径,如果路径指向目录,则为目录和子目录中的每个文件运行脚本

Desc:string,(可选)是一个描述性字符串,将附加到失败的检查

InformationalOnly:bool,(可选)检查结果将仅供参考(默认值:false)

如果–存在,则表示下一个参数来自ScriptOptions[1]。该脚本使用以下参数运行:

<tmp filename> <original filename> <uid> <gid> <mode in octal> <selinux label or "-" for no label> [--] [script options argument]

示例:

[FileContent."ScriptTest1"]
Script = "check_file_x8664.sh"
File   = "/bin"

输出示例:

"offenders": {
  "/bin/elf_arm32": [ "script(check_file_x8664.sh) returned=elf_arm32 not a x86-64 elf file" ],
}

Json 字段对比

File:string,文件的完整路径

Json:string,字段名称,使用点(.)表示法访问对象内的字段,冒号(:)分隔所需的值。所有类型都将转换为字符串并作为字符串进行比较。Json数组可以通过提供索引而不是字段名来进行索引。

Desc:string,(可选)是一个描述性字符串,将附加到失败的检查

InformationalOnly:bool,(可选)检查结果将仅供参考(默认值:false)

示例:

[FileContent."System_Arch"]
Json = "System.Arch:arm64"
File   = "/system.json"
Desc = "arch test"

输出示例:

{
  "System": {
    "Version": 7,
    "Arch": "arm32",
    "Info": "customized"
  }
}
Example Output:
```json
"offenders": {
  "/system.json": [ "Json field System.Arch = arm32 did not match = arm64, System.Arch, arch test" ],
}

File Tree Check

FileTree检查生成完整的文件系统树(每个文件和目录的列表),并将其与先前保存的文件树进行比较。该检查将生成一个信息输出,列出新文件,已删除文件和已修改文件。

CheckPath(string array)指定应包含在检查中的路径。如果未设置CheckPath,它将设置为[“/”]并将包含整个文件系统。如果CheckPath设置为[],它将生成文件树,但不会检查任何文件。

OldFileTreePath指定从旧filetree读取的文件名,如果生成了新的filetree(例如因为旧文件树不存在),则新生成的filetree文件为OldFileTreePath,并添加“.new”后缀。

OldFileTreePath是相对于配置文件的。这意味着’-cfg testdir/test.toml’与 OldTreeFilePath = “test.json将尝试读取’testdir/test.json’。-tree命令行选项可用于覆盖路径:’-cfg testdir/test.toml -tree test1’将尝试读取’test1/test.json’。类似地,新生成的filetree文件将存储在同一目录中。

文件修改检查可使用以下参数自定义:

CheckPermsOwnerChange:如果更改了所有者或权限(模式),bool,(可选)会将文件标记为已修改(默认值:false)

CheckFileSize:bool,(可选)将标记文件,因为修改后的大小已更改(默认值:false)

CheckFileDigest:bool,(可选)会在内容发生变化时将文件标记为已修改(比较它的SHA-256摘要)(默认值:false)

SkipFileDigest:bool,(可选)跳过计算文件摘要(用于处理非常大的文件,默认为:false)

示例:

[FileTreeCheck]
OldTreeFilePath       = "testtree.json"
CheckPath             = [ "/etc", "/bin" ]
CheckPermsOwnerChange = true
CheckFileSize         = true
CheckFileDigest       = false

输出示例:

"informational": {
    "/bin/bla": [ "CheckFileTree: new file: 40755 1001:1001 1024 0 SeLinux label: -" ]
}

目录内容检查

DirCheck(目录内容)检查在指定目录中指定一组允许或需要检查的文件。在该目录中找到的任何其他文件或目录都将被报告为违规。如果未找到Allowed文件,则检查将通过。如果找不到Required文件,则会将其报告为违规。

文件项可以包含通配符,如?,*和**。allowed模式已在golang文档中描述。

每个目录只能存在一个DirCheck项。

示例:

[DirContent."/home"]
Allowed = ["collin", "jon"]
Required = ["chris"]

数据提取

DataExtract选项允许从文件中提取数据并将其包含在报告中。可以通过正则表达式,运行外部脚本或读取JSON对象来提取数据。提取的数据之后可由后处理脚本使用。

数据提取功能将数据作为key:value对的映射添加到报表中。key被定义为语句的名称或可选的Name参数。该值是正则表达式或脚本输出的结果。

示例:基于正则表达式的数据提取

正则表达式生成的输出将存储为此语句名称的值,下面的示例名为“Version”。

File:string,文件的完整路径

RegEx:string,带有一个匹配字段的正则表达式

Name:string,(可选)键名

Desc:string,(可选)描述

示例:

键“Version”将包含正则表达式的输出。

[DataExtract."Version"]
File   = "/etv/versions"
RegEx  = ".*Ver=(.+)\n"
Desc   = "Ver 1337 test"

输出示例:

"data": {
  "Version": "1.2.3",
}

示例:基于脚本的数据提取

脚本生成的输出将存储为此语句名称的值,下面的示例名为LastLine。

File:string,文件的完整路径

Script:string,脚本的完整路径

Name:string,(可选)键名

Desc:string,(可选)描述

该脚本使用以下参数运行:

<tmp filename> <original filename> <uid> <gid> <mode in octal> <selinux label or "-" for no label>

示例:

键“script_test”将包含脚本的输出。该语句的名称为“scripttest”

[DataExtract.scripttest]
File   = "/etc/somefile"
Script = "extractscripttest.sh"
Name   = "script_test"

输出示例:

"data": {
  "script_test": "some data",
}

示例:JSON数据提取

脚本生成的输出将存储为此语句名称的值,下面的示例名为LastLine。

File:string,文件的完整路径

Json:string,使用点(.)表示法访问对象中字段的字段名称

Name:string,(可选)键名

Desc:string,(可选)描述

示例:

键“ROS_Info”将包含来自/etc/os_version.json下System对象的Info字段内容。

{
  "System": {
    "Version": 7,
    "Arch": "arm32",
    "Info": "customized"
  }
}
[DataExtract.OS_Info]
File   = "/etc/os_version.json"
Json   = "System.Info"
Name   = "OSinfo"

输出示例:

"data": {
  "OSinfo": "customized",
}

可以通过提供索引而不是字段名来索引Json数组。

示例:高级用法

DataExtract语句允许具有相同名称(相同键)的多个条目。这对于配置多种提取相同信息的方法非常有用。生成有效输出的第一个数据提取语句将设置给定键的值。这适用于正则表达式和脚本以及两者同时使用。

下面的示例显示了两个语句,它们都将为键“Version”创建键值对。如果“1”没有产生有效输出,则尝试下一个输出,在本例中为“2”。

示例:

[DataExtract."1"]
File  = "/etc/versions"
RegEx = ".*Ver=(.+)\n"
Name  = "Version"
[DataExtract."2"]
File  = "/etc/OSVersion"
RegEx = ".*OS Version: (.+)\n"
Name  = "Version"

*参考来源:GitHub,FB小编secist编译,转载请注明来自FreeBuf.COM

来源:freebuf.com 2019-10-20 15:00:57 by: secist

© 版权声明
THE END
喜欢就支持一下吧
点赞0
分享
评论 抢沙发

请登录后发表评论