Skip to content

Commit

Permalink
Merge branch 'develop' into patch-24
Browse files Browse the repository at this point in the history
tclahr authored Jan 20, 2025

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
2 parents f6ce120 + f645467 commit 181e1f3
Showing 13 changed files with 459 additions and 8 deletions.
1 change: 1 addition & 0 deletions .github/workflows/shellcheck.yaml
Original file line number Diff line number Diff line change
@@ -6,6 +6,7 @@ on:
- develop
- main
paths:
- 'bin/**/*.sh'
- 'lib/**'
- 'uac'

8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -4,6 +4,7 @@

### Artifacts

- chkrootkit/hidden_etc_ld_so_preload.yaml: Added collection of hidden /etc/ld.so.preload using debugfs and xfs_db tools [linux] ([mnrkbys](https://github.com/mnrkbys)).
- files/applications/ark.yaml: Added collection of metadata about recently opened archive files in Ark, the KDE archive manager [freebsd, linux, netbsd, openbsd].
- files/applications/dolphin.yaml: Added collection of session data for the Dolphin file manager in the KDE desktop environment. This file contains information about the state of the Dolphin application, such as the currently open directories and their paths and the last accessed locations [freebsd, linux, netbsd, openbsd].
- files/applications/dragon_player.yaml: Added collection of paths to recently opened video files using the Dragon Player [freebsd, linux, netbsd, openbsd].
@@ -16,18 +17,25 @@
- files/system/kactivitymanagerd.yaml: Added collection of activity tracking data used by KActivityManager (part of KDE) to track and manage user activities, such as recently opened files, applications, and other resources [freebsd, linux, netbsd, openbsd].
- files/system/upstart.yaml: Added collection of system-wide and user-session Upstart configuration files [linux].
- files/system/xdg_autostart.yaml: Added collection of system-wide and user-specific XDG autostart files [linux].
- live_response/packages/0install.yaml: Added collection of the list of installed packages managed by Zero Install package manager [linux] (by [Pierre-Gronau-ndaal](https://github.com/Pierre-Gronau-ndaal)).
- live_response/packages/conary.yaml: Added collection of the list of installed packages managed by the Conary package manager [linux] (by [Pierre-Gronau-ndaal](https://github.com/Pierre-Gronau-ndaal)).
- live_response/packages/dpkg.yaml: Updated to verify all packages to compare information about the installed files in the package with information about the files taken from the package metadata stored in the dpkg database [linux] ([mnrkbys](https://github.com/mnrkbys)).
- live_response/packages/package_owns_file.yaml: Added collection of which installed package owns a specific file or command. Note that this artifact is resource-intensive and time-consuming to execute, so it is disabled by default in all profiles [linux] ([mnrkbys](https://github.com/mnrkbys)).
- live_response/packages/paludis.yaml: Added collection of the list of installed packages managed by the Paludis package manager [linux] (by [Pierre-Gronau-ndaal](https://github.com/Pierre-Gronau-ndaal)).
- live_response/packages/portage.yaml: Added the collection of installed package lists using the Portage package management system [linux] (by [Pierre-Gronau-ndaal](https://github.com/Pierre-Gronau-ndaal)).
- live_response/packages/snap.yaml: Updated collection to display installed packages including all revisions [linux] (by [Pierre-Gronau-ndaal](https://github.com/Pierre-Gronau-ndaal)).
- live_response/storage/findmnt.yaml: Added JSON output format for listing all mounted file systems [linux] ([mnrkbys](https://github.com/mnrkbys)).
- live_response/storage/lsblk.yaml: Added JSON output format for listing block devices [linux] ([mnrkbys](https://github.com/mnrkbys)).
- live_response/system/coredump.yaml: Added collection of core dump files information [linux] ([mnrkbys](https://github.com/mnrkbys)).
- live_response/system/getcap.yaml: Added functionality to collect the list of files with associated process capabilities [linux] ([mnrkbys](https://github.com/mnrkbys)).
- live_response/system/journalctl.yaml: Added collection of listing of time periods between boots [linux] ([mnrkbys](https://github.com/mnrkbys)).
- live_response/system/ulimit.yaml: Added collection of all resource limits information [all] ([mnrkbys](https://github.com/mnrkbys)).
- memory_dump/coredump.yaml: Added collection of core dump, ABRT, Apport, and kdump files [esxi, linux, netbsd] ([mnrkbys](https://github.com/mnrkbys)).

### Profiles

- profiles/offline_ir_triage.yaml: New 'offline_ir_triage' profile that can be used during offline triage collections ([clausing](https://github.com/clausing)).

### New Artifacts Properties

- Added the new 'redirect_stderr_to_stdout' property, an optional feature available exclusively for the command collector. When set to true, this property redirects all error messages (stderr) to standard output (stdout), ensuring they are written to the output file.
28 changes: 28 additions & 0 deletions artifacts/chkrootkit/hidden_etc_ld_so_preload.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
version: 1.0
output_directory: /chkrootkit
# Collect /etc/ld.so.preload even if it is hidden by LD_PRELOAD Rootkits.
# ref 1: https://www.youtube.com/watch?v=3UrEJzqqPYQ
# ref 2: https://righteousit.com/wp-content/uploads/2024/04/ld_preload-rootkits.pdf
# ref 3: https://www.youtube.com/watch?v=-K9hhqv21P8
# ref 4: https://righteousit.com/wp-content/uploads/2024/04/xfs_db-ftw.pdf
artifacts:
-
description: Dump /etc/ld.so.preload with debugfs.
supported_os: [linux]
collector: command
condition: command_exists "debugfs" && df -T %mount_point%/etc | tail -n +2 | awk '{print $2}' | grep -q "ext"
command: linux_dump_etc_ld_so_preload.sh -f %mount_point%/etc/ld.so.preload
output_file: etc_ld_so_preload.txt
-
description: Dump /etc/ld.so.preload with xfs_db.
supported_os: [linux]
collector: command
condition: command_exists "xfs_db" && df -T %mount_point%/etc | tail -n +2 | awk '{print $2}' | grep -q "xfs"
command: linux_dump_etc_ld_so_preload.sh -f %mount_point%/etc/ld.so.preload
output_file: etc_ld_so_preload.txt
-
description: Collect file stats for /etc/ld.so.preload even if it is hidden.
supported_os: [linux]
collector: stat
path: /etc/ld.so.preload
output_file: stat_etc_ld_so_preload.txt
4 changes: 2 additions & 2 deletions artifacts/files/logs/journal.yaml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
version: 1.0
version: 1.1
artifacts:
-
description: Collect journal log files.
supported_os: [linux]
collector: file
path: /
name_pattern: ["*.journal"]
name_pattern: ["*.journal", "*.journal~"]
4 changes: 2 additions & 2 deletions artifacts/files/shell/history.yaml
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
version: 3.0
version: 4.0
artifacts:
-
description: Collect shell history files.
supported_os: [all]
collector: file
path: /%user_home%
# lesshst: less command history file
name_pattern: [".*_history", ".*history", "*.historynew", ".lesshst", ".zhistory", "fish_history"]
name_pattern: [".*_history", ".*history", ".cosh_history", ".dash_history", ".esh_history", ".lesshst", ".nash_history", ".sash_history", ".scsh_history", ".xonsh_history", ".zhistory", "*.historynew", "fish_history"]
max_depth: 4
10 changes: 10 additions & 0 deletions artifacts/live_response/packages/0install.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
version: 1.0
condition: command_exists "0install"
output_directory: /live_response/packages
artifacts:
-
description: Display installed packages.
supported_os: [linux]
collector: command
command: 0install list
output_file: 0install_list.txt
7 changes: 6 additions & 1 deletion artifacts/live_response/packages/snap.yaml
Original file line number Diff line number Diff line change
@@ -8,4 +8,9 @@ artifacts:
collector: command
command: snap list
output_file: snap_list.txt

-
description: Display installed Snap packages including all revisions.
supported_os: [linux]
collector: command
command: snap list --all
output_file: snap_list_--all.txt
10 changes: 10 additions & 0 deletions artifacts/live_response/system/journalctl.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
version: 1.0
condition: command_exists "journalctl"
output_directory: /live_response/system
artifacts:
-
description: Show a listing of time periods between boots.
supported_os: [linux]
collector: command
command: journalctl --list-boots
output_file: journalctl_--list-boots.txt
374 changes: 374 additions & 0 deletions bin/linux/linux_dump_etc_ld_so_preload.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,374 @@
#!/bin/bash
# Copyright 2024 Minoru Kobayashi <unknownbit@gmail.com> (@unkn0wnbit)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

# ref 1: https://www.youtube.com/watch?v=3UrEJzqqPYQ
# ref 2: https://righteousit.com/wp-content/uploads/2024/04/ld_preload-rootkits.pdf
# ref 3: https://www.youtube.com/watch?v=-K9hhqv21P8
# ref 4: https://righteousit.com/wp-content/uploads/2024/04/xfs_db-ftw.pdf

set -euo pipefail

usage() {
cat <<EOM
Dump /etc/ld.so.preload on XFS or EXT-based filesystem.
Usage: $0 [-f file] [-h] [-o outputfile] [-v]
-f file Specify a file to dump
-h Show this help message
-o outputfile Specify the output file
-v Enable verbose mode
EOM
exit 1;
}


print_msg() {
local msg=$1
if [ ${verbose_mode} -eq 1 ]; then
echo "${msg}" >&2
fi
}


get_real_path() {
local path=$1
local processed_path=$2

if [[ ! "$path" =~ ^(/|./|../) ]]; then
if [[ "${processed_path}" == "/" ]]; then
path="/${path}"
else
path="${processed_path}/${path}"
fi
fi
realpath -s "${path}"
}


join_remain_path() {
local index=$1
local path_array=("${@:2}")
local sub_path
local old_IFS

old_IFS="${IFS}"
IFS='/'
sub_path="${path_array[*]:${index}}"
IFS="${old_IFS}"
echo "${sub_path}"
}


get_device_fstype() {
local path=$1
local device
local fs_type
local mount_point

read -r device fs_type mount_point <<< "$(df -T "$(dirname "${path}")" | awk 'NR==2 {print $1, $2, $NF}')"
echo "${device}" "${fs_type}" "${mount_point}"
}


get_xfs_inumber_local() {
local device=$1
local root_inumber=$2
local path=$3

xfs_db -r "${device}" -c "inode ${root_inumber}" -c "print" | awk -v path="${path}" '
BEGIN {
found_filename = 0;
found_entry = 0;
filetype = 0;
}
{
if ($0 ~ "u3.sfdir3.list\\[[0-9]+\\].name = \"" path "\"") {
found_filename = 1;
}
if (found_filename && $0 ~ /u3.sfdir3.list\[[0-9]+\].inumber.i4 = [0-9]+/) {
match($0, /u3.sfdir3.list\[[0-9]+\].inumber.i4 = ([0-9]+)/, arr);
inumber = arr[1];
}
# filetype: 1 (regular file), 2 (directory), 7 (symlink)
if (found_filename && $0 ~ /u3.sfdir3.list\[[0-9]+\].filetype = (1|2|7)/) {
match($0, /u3.sfdir3.list\[[0-9]+\].filetype = ([0-9]+)/, arr);
filetype = arr[1];
found_entry = 1;
exit;
}
}
END {
if (!found_entry) {
inumber = 0;
}
print inumber, filetype;
}
'
}


get_xfs_inumber_extents() {
local device=$1
local fsblocks=$2
local path=$3
local fsblock
local result

for fsblock in ${fsblocks}; do
result=$(xfs_db -r "${device}" -c "fsblock ${fsblock}" -c "type dir3" -c "print" | awk -v path="${path}" '
BEGIN {
found_name = 0;
found_entry = 0;
}
{
if ($0 ~ /(du|bu)\[[0-9]+\].inumber = [0-9]+/) {
match($0, /(du|bu)\[[0-9]+\].inumber = ([0-9]+)/, arr);
inumber = arr[2];
}
if ($0 ~ "(du|bu)\\[[0-9]+\\].name = \"" path "\"") {
found_name = 1;
}
if (found_name && $0 ~ /(du|bu)\[[0-9]+\].filetype = (1|2|7)/) {
match($0, /(du|bu)\[[0-9]+\].filetype = ([0-9]+)/, arr);
filetype = arr[2];
found_entry = 1;
exit;
}
}
END {
if (!found_entry) {
inumber = 0;
}
print inumber, filetype;
}
')
if [ "$(echo "${result}" | awk '{print $1}')" -ne 0 ]; then
echo "${result}"
return
fi
done
echo 0 0
}


get_xfs_child_inumber() {
local device=$1
local parent_inumber=$2
local path=$3
local fsblocks
local fsblock

fsblocks=$(xfs_db -r "${device}" -c "inode ${parent_inumber}" -c "bmap" | awk '{print $5}')
if [ -z "${fsblocks}" ]; then
read -r inumber filetype <<< "$(get_xfs_inumber_local "${device}" "${parent_inumber}" "${path}")"
echo "${inumber} ${filetype}"
return
else
read -r inumber filetype <<< "$(get_xfs_inumber_extents "${device}" "${fsblocks}" "${path}")"
echo "${inumber} ${filetype}"
return
fi
}


get_xfs_inumber_from_path() {
local processed_path=""
local full_path
local device
local fs_type
local mount_point
local root_inumber
local parent_inumber
local inumber=0
local filetype=0
local symlink_target
local sub_path
local idx
local path_array
local old_IFS

full_path=$(get_real_path "$1" "${processed_path}")
read -r device fs_type mount_point <<< "$(get_device_fstype "${full_path}")"
# Remove mount_point from full_path if it starts with mount_point
if [[ "${mount_point}" != "/" && "$full_path" == "$mount_point"* ]]; then
full_path="${full_path/#${mount_point}/}"
fi

root_inumber=$(xfs_db -r "${device}" -c "sb 0" -c "print" | awk -F " = " '$1 == "rootino" {print $2}')
parent_inumber=${root_inumber}

old_IFS="${IFS}"
IFS='/'
read -r -a path_array <<< "${full_path}"
IFS="${old_IFS}"

for idx in "${!path_array[@]}"; do
if [ "${idx}" -eq 0 ]; then
processed_path="/"
continue
elif [ "${idx}" -ge 1 ]; then
read -r inumber filetype <<< "$(get_xfs_child_inumber "${device}" "${parent_inumber}" "${path_array[$idx]}")"
if [ "${inumber}" -eq 0 ]; then
print_msg "${path_array[$idx]} not found."
break
elif [ "${filetype}" -eq 7 ]; then # If the file is a symlink, get the target file's inode number.
symlink_target=$(xfs_db -r "${device}" -c "inode ${inumber}" -c "print" | sed -n 's/u3.symlink = "\(.*\)"/\1/p')
print_msg "symlink target: ${symlink_target}"
symlink_target=$(get_real_path "${symlink_target}" "${processed_path}")
sub_path=$(join_remain_path $((idx+1)) "${path_array[@]}")
if [ -n "${sub_path}" ]; then
symlink_target="${symlink_target}/${sub_path}"
fi

read -r inumber filetype <<< "$(get_xfs_inumber_from_path "${symlink_target}")"
if [[ ! "${inumber}" =~ ^[0-9]+$ ]]; then
print_msg "${symlink_target} not found."
return 3
fi

echo "${inumber}" "${filetype}"
return
fi
processed_path="${processed_path}/${path_array[$idx]}"
parent_inumber=${inumber}
fi
done

echo "${inumber}" "${filetype}"
}


dump_xfs_ldsopreload() {
local file=$1
local outputfile=$2
local device=$3
local block_count
local inumber
local filetype
local fsblock_items
local fsblock
local agno
local agblock

# Get an inode number of the file.
read -r inumber filetype <<< "$(get_xfs_inumber_from_path "${file}")"

if [ "${inumber}" -eq 0 ]; then
print_msg "${file} not found."
exit 3
fi

# Get fsblock numbers of the file.
fsblock_items=$(xfs_db -r "${device}" -c "inode ${inumber}" -c "bmap" | awk '{print $5, $8}')

if [ -z "${fsblock_items}" ]; then
print_msg "${file}: bmap not found."
exit 4
fi

while read -r fsblock block_count; do
# Convert fsblock to agno.
agno=$(xfs_db -r "${device}" -c "convert fsblock ${fsblock} agno" | sed -n 's/.*(\([0-9]*\)).*/\1/p')

if [ -z "${agno}" ]; then
print_msg "${file}: agno not found."
exit 5
fi

# Convert fsblock to agblock.
agblock=$(xfs_db -r "${device}" -c "convert fsblock ${fsblock} agblock" | sed -n 's/.*(\([0-9]*\)).*/\1/p')

if [ -z "${agblock}" ]; then
print_msg "${file}: agblock not found."
exit 6
fi

# Dump file data.
sb0_output=$(xfs_db -r "${device}" -c "sb 0" -c "print")
block_size=$(echo "${sb0_output}" | awk -F " = " '$1 == "blocksize" {print $2}')
agblocks=$(echo "${sb0_output}" | awk -F " = " '$1 == "agblocks" {print $2}')
skip_len=$((agno * agblocks + agblock))

if [ -z "${outputfile}" ]; then
dd if="${device}" bs="${block_size}" skip="${skip_len}" count="${block_count}" status=none
else
dd if="${device}" of="${outputfile}" bs="${block_size}" skip="${skip_len}" count="${block_count}" status=none
fi
done <<< "${fsblock_items}"
}


dump_ext_ldsopreload() {
local full_path=$1
local outputfile=$2
local device=$3
local fs_type
local mount_point

read -r device fs_type mount_point <<< "$(get_device_fstype "${full_path}")"

# Remove mount_point from full_path if it starts with mount_point
if [[ "${mount_point}" != "/" && "$full_path" == "$mount_point"* ]]; then
full_path="${full_path/#${mount_point}/}"
fi

if [ -z "${outputfile}" ]; then
debugfs -R "cat \"${full_path}\"" "${device}"
else
debugfs -R "dump \"${full_path}\" \"${outputfile}\"" "${device}"
fi
}


file="/etc/ld.so.preload"
verbose_mode=0
while getopts "f:ho:v" opts; do
case ${opts} in
f) file=${OPTARG}
;;
h) usage
;;
o) outputfile=${OPTARG}
;;
v) verbose_mode=1
;;
*) usage
;;
esac
done

# Which device has /etc/ld.so.preload?
file=$(realpath -s "${file}")
read -r device fs_type mount_point <<< "$(get_device_fstype "${file}")"

# Check filesystem type and dump /etc/ld.so.preload
if [ "${fs_type}" = "xfs" ]; then
dump_xfs_ldsopreload "${file}" "${outputfile:-}" "${device}"
elif [[ "${fs_type}" =~ ^ext ]]; then
dump_ext_ldsopreload "${file}" "${outputfile:-}" "${device}"
else
print_msg "${file} is not on XFS or EXT filesystem."
exit 2
fi
2 changes: 1 addition & 1 deletion profiles/full.yaml
Original file line number Diff line number Diff line change
@@ -24,7 +24,7 @@ artifacts:
- live_response/storage/*
- live_response/containers/*
- live_response/vms/*
- chkrootkit/chkrootkit.yaml
- chkrootkit/*
- hash_executables/hash_executables.yaml
- files/*

2 changes: 1 addition & 1 deletion profiles/ir_triage.yaml
Original file line number Diff line number Diff line change
@@ -24,7 +24,7 @@ artifacts:
- live_response/storage/*
- live_response/containers/*
- live_response/vms/*
- chkrootkit/chkrootkit.yaml
- chkrootkit/*
- hash_executables/hash_executables.yaml
- files/applications/git.yaml
- files/applications/lesshst.yaml
2 changes: 1 addition & 1 deletion profiles/offline.yaml
Original file line number Diff line number Diff line change
@@ -2,6 +2,6 @@ name: offline
description: Offline artifacts collection.
artifacts:
- bodyfile/bodyfile.yaml
- chkrootkit/chkrootkit.yaml
- chkrootkit/*
- hash_executables/hash_executables.yaml
- files/*
15 changes: 15 additions & 0 deletions profiles/offline_ir_triage.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
name: offline_ir_triage
description: Offline incident response triage collection.
artifacts:
- bodyfile/bodyfile.yaml
- chkrootkit/*
- hash_executables/hash_executables.yaml
- files/applications/git.yaml
- files/applications/lesshst.yaml
- files/applications/viminfo.yaml
- files/applications/wget.yaml
- files/logs/*
- files/packages/*
- files/shell/*
- files/ssh/*
- files/system/*

0 comments on commit 181e1f3

Please sign in to comment.