Kalos Cybersecurity LLC

FG09 — Create and verify a forensic container

FG09 · v23

1. Container workflow · 2. Linux validation · 3. Windows validation · 4. Create and verify your container

C01–C16 apply the foundation to a new exercise; they are not additional numbered deck slides.

C01 Create an isolated practice workspace

Application tutorial C01 · Supports slides 2–4; no separate deck slide

Command syntax

set -euo pipefail
for cmd in stat sha256sum tar getfacl \
  getfattr findmnt mktemp; do
  command -v "$cmd" >/dev/null || exit 1
done
lab=$(mktemp -d "$HOME/ContainerLab.XXXXXXXX")
mkdir "$lab/source" "$lab/records" \
  "$lab/received"
printf 'Synthetic forensic container lab\n' \
  > "$lab/source/evidence.log"
cd "$lab/source"

Why this syntax: mktemp creates a new run folder. The synthetic evidence.log is the only evidence fixture in this exercise. Stop at an error.

OS and time effect: Creates new directories and a synthetic file with new filesystem timestamps. It does not touch original evidence.

Gotcha or ProTip: Do not replace the fixture with original evidence. Provision missing tools before the lab; do not bypass permissions by switching to root.

Connection to the container lesson: Foundation claims F3–F4: container scope and transition verification

Recorded result or expected outcome: Capture your result: printf '%s\n' "$lab" ls -l "$lab/source" Expected fixture: evidence.log

Analyst takeaway: A new run folder prevents an earlier result from being mistaken for current evidence.

C02 Record the source environment

Application tutorial C02 · Supports slides 2–4; no separate deck slide

Command syntax

{
  date -u --iso-8601=ns
  cat /etc/os-release
  uname -a
  findmnt -T . \
    -o TARGET,SOURCE,FSTYPE,OPTIONS
  stat --version
  tar --version
} > environment.txt
cat environment.txt

Why this syntax: Record the clock context, OS, tool versions, filesystem and mount policy before interpreting timestamps.

OS and time effect: These queries record clock, filesystem, mount policy and tool versions needed to interpret later timestamps.

Gotcha or ProTip: The reference run used ext4 with relatime. Your filesystem and time policy may produce different results.

Connection to the container lesson: Foundation claims F3–F4: container scope and transition verification

Recorded result or expected outcome: Local qualification: Ubuntu 26.04.1 under WSL1, wslfs mounted noatime. Your classroom environment must be recorded separately.

Analyst takeaway: Timestamp findings belong to the recorded environment and operation.

C03 Capture metadata BEFORE hashing

Application tutorial C03 · Supports slides 2–4; no separate deck slide

Command syntax

# Remain in "$lab/source"
stat evidence.log > source-state.txt
getfacl -p evidence.log > evidence.acl
getfattr -d -m- evidence.log \
  > evidence.xattrs
cat source-state.txt
cat evidence.acl
cat evidence.xattrs

Why this syntax: stat records identity, size and times. getfacl records ACLs; getfattr records extended attributes independently of the content digest.

OS and time effect: stat reads recorded metadata; getfacl and getfattr record separate metadata classes before the content hash read.

Gotcha or ProTip: An empty xattr listing can be valid; an error is not. Keep offsets and fractional seconds. Metadata capture is not a write blocker.

Connection to the container lesson: Foundation claims F3–F4: container scope and transition verification

Recorded result or expected outcome: Local qualification: basic ACL recorded; xattr listing empty. Populated ACL/xattr preservation was not established.

Analyst takeaway: Capture source state before a content read can change access time.

C04 Hash content and record the post-read state

Application tutorial C04 · Supports slides 2–4; no separate deck slide

Command syntax

sha256sum evidence.log > evidence.sha256
stat evidence.log > after-hash-state.txt
cat evidence.sha256
rc=0
diff -u source-state.txt \
  after-hash-state.txt || rc=$?
# diff: 0 = equal, 1 = differences
# Greater than 1 = comparison error
if (( rc > 1 )); then exit "$rc"; fi

Why this syntax: The checksum uses a relative filename so it can be checked after extraction. Compare the metadata before and after hashing.

OS and time effect: SHA-256 reads the content. The filesystem and mount policy decide whether that read changes atime.

Gotcha or ProTip: Compare source-state.txt with after-hash-state.txt. An unchanged atime here does not prove that reads never change it.

Connection to the container lesson: Foundation claims F3–F4: container scope and transition verification

Recorded result or expected outcome: Local qualification: the synthetic content check passed. Retained stat records document this run’s state.

Analyst takeaway: A matching content hash and a metadata change can both be valid observations.

C05 Define exactly what enters the container

Application tutorial C05 · Supports slides 2–4; no separate deck slide

Command syntax

ls -l -- \
  evidence.log \
  evidence.sha256 \
  source-state.txt \
  after-hash-state.txt \
  environment.txt \
  evidence.acl \
  evidence.xattrs

Why this syntax: One evidence file and six supporting records enter this small container. The archive and its own hash will live outside source/.

OS and time effect: The explicit list fixes collection scope. An omitted file cannot be recovered by validating the archive hash.

Gotcha or ProTip: Hash equality cannot reveal a file omitted before packaging. Record selection scope and reasons for exclusions in your custody record.

Connection to the container lesson: Foundation claims F3–F4: container scope and transition verification

Recorded result or expected outcome: Seven explicit members No wildcard expansion No archive inside its own source set Capture the inventory before packaging.

Analyst takeaway: Define the collection scope before declaring a container complete.

C06 Create the forensic file container

Application tutorial C06 · Supports slides 2–4; no separate deck slide

Command syntax

# Working directory: "$lab/source"
tar --format=pax --acls --xattrs \
  --numeric-owner --atime-preserve=system \
  -czf "$lab/evidence.tar.gz" \
  evidence.log evidence.sha256 \
  source-state.txt after-hash-state.txt \
  environment.txt evidence.acl evidence.xattrs

Why this syntax: -c creates, -z gzip-compresses, -f names the archive. pax supports extended metadata. --acls/--xattrs request supported metadata.

OS and time effect: TAR creates a new archive and reads its members. --atime-preserve=system requests protection against source atime changes.

Gotcha or ProTip: --atime-preserve=system attempts to avoid TAR read effects. It does not undo earlier reads or preserve original ctime/birth on extraction.

Connection to the container lesson: Foundation claims F3–F4: container scope and transition verification

Recorded result or expected outcome: Local qualification: TAR creation completed with the seven explicit members.

Analyst takeaway: Package selected content and metadata, then verify what the archive actually contains.

C07 List the archive before transfer

Application tutorial C07 · Supports slides 2–4; no separate deck slide

Command syntax

cd "$lab"
tar -tzf evidence.tar.gz \
  > records/archive-members.txt
cat records/archive-members.txt

Why this syntax: -t lists members, -z reads gzip compression, -f selects the archive. Compare every listed name with the seven-file scope.

OS and time effect: Listing reads the archive directory without extracting its members. Compare the names against the intended scope.

Gotcha or ProTip: Stop on missing or unexpected members and unresolved errors. A correct member list does not prove that the original collection scope was sufficient.

Connection to the container lesson: Foundation claims F3–F4: container scope and transition verification

Recorded result or expected outcome: Expected names, not a recorded screenshot: evidence.log · evidence.sha256 source-state.txt · after-hash-state.txt environment.txt · evidence.acl · evidence.xattrs

Analyst takeaway: Verify archive membership as well as its digest.

C08 Hash the finished container

Application tutorial C08 · Supports slides 2–4; no separate deck slide

Command syntax

sha256sum evidence.tar.gz \
  > evidence.tar.gz.sha256
cat evidence.tar.gz.sha256
date -u --iso-8601=ns
# Retain an independent receipt BEFORE transfer:
# case/run ID, filename, complete SHA-256,
# sender, recipient, UTC time, scope and method

Why this syntax: Hash the completed archive. Give the full digest and identifying details to the instructor through the designated receipt process.

OS and time effect: Hashing reads the finished archive bytes. Its digest covers the container, not just evidence.log.

Gotcha or ProTip: A sidecar stored beside an editable archive is not independent authentication. The archive digest and each member digest answer different questions.

Connection to the container lesson: Foundation claims F3–F4: container scope and transition verification

Recorded result or expected outcome: Local archive SHA-256 begins 50658bf7; the full digest is retained in the qualification receipt. Use your own new digest.

Analyst takeaway: Keep an independently trusted expected digest before the file leaves the source.

C09 Transfer the archive to Windows

Application tutorial C09 · Supports slides 2–4; no separate deck slide

Command syntax

# Obtain the real account, host and destination.
# This example contains placeholders.
scp -p \
  "$lab/evidence.tar.gz" \
  "$lab/evidence.tar.gz.sha256" \
  analyst@lab.example:/cases/lab409/

Why this syntax: The instructor must provide a reachable, verified SSH/SFTP endpoint and a valid destination path. -p requests outer-file times and mode bits.

OS and time effect: The receiver creates a new filesystem object. scp -p requests access/modification times and mode bits; it does not preserve every metadata class.

Gotcha or ProTip: The Windows server’s path syntax and permissions must be tested. Stop for an unverified host key. No supplied capture demonstrates this endpoint transfer.

Connection to the container lesson: Foundation claims F3–F4: container scope and transition verification

Recorded result or expected outcome: Evidence still needed for this step: Exact endpoint command and exit status Sender/receiver paths and UTC times Receiver hash matched to trusted receipt

Analyst takeaway: Transfer the intact archive and independently verify its bytes at the receiver.

C10 Verify receipt on Windows

Application tutorial C10 · Supports slides 2–4; no separate deck slide

Command syntax

$archive = Read-Host 'Received archive path'
$expected = (Read-Host 'Trusted SHA256').Trim()
if ($expected -notmatch '^[0-9A-Fa-f]{64}$') {
  throw 'Expected 64 hexadecimal characters'
}
$actual = (Get-FileHash -LiteralPath $archive `
  -Algorithm SHA256).Hash
if ($actual -ine $expected) {
  throw 'Container hash mismatch'
}
'Container bytes match the supplied receipt'

Why this syntax: Paste the independently recorded sender digest. The comparison stops on a malformed receipt or a mismatch.

OS and time effect: Get-FileHash reads the received archive. A match verifies its bytes against the independently supplied expected digest.

Gotcha or ProTip: A successful hash check covers the received archive bytes. It does not establish the sender’s identity, original scope or metadata restoration.

Connection to the container lesson: Foundation claims F3–F4: container scope and transition verification

Recorded result or expected outcome: Actual local receipt-code checks: Matching digest: accepted Changed digest: rejected Malformed digest: rejected These checks did not test an SSH transfer.

Analyst takeaway: Verify before extraction, and preserve the received archive intact.

C11 Rehearse receipt verification on Linux

Application tutorial C11 · Supports slides 2–4; no separate deck slide

Command syntax

cp -- "$lab/evidence.tar.gz" "$lab/received/"
cp -- "$lab/evidence.tar.gz.sha256" \
  "$lab/received/"
cd "$lab/received"
sha256sum -c evidence.tar.gz.sha256
sha256sum evidence.tar.gz

Why this syntax: The first check uses the sidecar’s relative filename. Compare the second printed digest to the independent instructor receipt too.

OS and time effect: The local copy creates a receipt rehearsal on Ubuntu. It does not test network transport or a Windows filesystem.

Gotcha or ProTip: This local rehearsal is not the Windows network transfer. After a real return transfer to Ubuntu, verify again before analysis.

Connection to the container lesson: Foundation claims F3–F4: container scope and transition verification

Recorded result or expected outcome: Expected success text: evidence.tar.gz: OK Capture the actual output and full digest. A missing file or mismatch is a stop condition.

Analyst takeaway: Each transfer has its own recorded verification boundary.

C12 Extract into a new Linux directory

Application tutorial C12 · Supports slides 2–4; no separate deck slide

Command syntax

cd "$lab/received"
tar -tzf evidence.tar.gz
mkdir extracted
tar --acls --xattrs --no-same-owner \
  -xzf evidence.tar.gz -C extracted
cd extracted

Why this syntax: -x extracts; -C chooses the new destination. --no-same-owner makes the ordinary-user exercise explicit. Preserve the received archive.

OS and time effect: Extraction creates new destination objects. Stored mtime may survive while inode, ctime and birth time describe extraction.

Gotcha or ProTip: Existing extracted/ causes mkdir to fail. Do not overwrite an earlier result. GNU tar’s default xattr extraction scope is the user namespace.

Connection to the container lesson: Foundation claims F3–F4: container scope and transition verification

Recorded result or expected outcome: Local qualification: extraction completed into a new directory. All seven members matched their source bytes.

Analyst takeaway: Extraction creates destination objects, even when member content remains identical.

C13 Verify extracted content before analysis

Application tutorial C13 · Supports slides 2–4; no separate deck slide

Command syntax

stat evidence.log \
  > "$lab/records/destination-before-hash.txt"
sha256sum -c evidence.sha256
stat evidence.log \
  > "$lab/records/destination-after-hash.txt"
cat "$lab/records/destination-before-hash.txt"

Why this syntax: The stored relative checksum now names the extracted evidence.log. Capture metadata before and after the verification read.

OS and time effect: The extracted-file hash reads evidence.log. Capture metadata before and after to distinguish extraction from read effects.

Gotcha or ProTip: Capture this run’s full digest, output and any errors. An earlier PASS is not evidence for the current extraction.

Connection to the container lesson: Foundation claims F3–F4: container scope and transition verification

Recorded result or expected outcome: Local qualification: extracted evidence.log matched its stored SHA-256.

Analyst takeaway: Verify both the container bytes and the extracted evidence bytes.

C14 Compare timestamps and identity

Application tutorial C14 · Supports slides 2–4; no separate deck slide

Command syntax

cat source-state.txt
cat "$lab/records/destination-before-hash.txt"
rc=0
diff -u source-state.txt \
  "$lab/records/destination-before-hash.txt" \
  || rc=$?
if (( rc > 1 )); then exit "$rc"; fi

Why this syntax: Compare Access, Modify, Change, Birth, inode/device, size, mode and ownership. Record the offset and full available precision.

OS and time effect: Comparison is observational: differences in identity and creation/change fields can be expected for new destination objects.

Gotcha or ProTip: diff exit 1 means differences, not a failed command. Expected differences still need explanation. ctime is not creation time or a tamper-proof clock.

Connection to the container lesson: Foundation claims F3–F4: container scope and transition verification

Recorded result or expected outcome: Compare the retained source and destination stat records. Do not import inode/time values from the earlier ext4 screenshot run.

Analyst takeaway: Report which fields survived and which describe the new destination object.

C15 Compare ACLs and extended attributes

Application tutorial C15 · Supports slides 2–4; no separate deck slide

Command syntax

getfacl -p evidence.log \
  > "$lab/records/destination.acl"
getfattr -d -m- evidence.log \
  > "$lab/records/destination.xattrs"
rc=0
diff -u evidence.acl \
  "$lab/records/destination.acl" || rc=$?
if (( rc > 1 )); then exit "$rc"; fi
rc=0
diff -u evidence.xattrs \
  "$lab/records/destination.xattrs" || rc=$?
if (( rc > 1 )); then exit "$rc"; fi

Why this syntax: Compare the stored source listings with fresh destination listings. Explain unsupported fields and ownership differences.

OS and time effect: ACLs and xattrs are separate from the content digest. Matching empty xattr listings cannot validate populated xattr preservation.

Gotcha or ProTip: An empty matching xattr pair tests no populated attributes. Qualify broader preservation claims with populated test metadata.

Connection to the container lesson: Foundation claims F3–F4: container scope and transition verification

Recorded result or expected outcome: Local qualification: basic ACL listings matched; both xattr listings were empty. Stronger metadata coverage remains open.

Analyst takeaway: A file-content digest does not replace an ACL or extended-attribute comparison.

C16 Record a bounded preservation conclusion

Application tutorial C16 · Supports slides 2–4; no separate deck slide

Command syntax

Container digest matched trusted receipt: ____
Seven named members accounted for: ____
Extracted evidence hash matched: ____
Metadata compared and differences explained: ____
Unverified steps and limitations recorded: ____

Why this syntax: State: “I verified these archive bytes against receipt [ID]. The extracted file matched its stored digest. Fields [X] matched; [Y] changed because [supported reason].”

OS and time effect: The conclusion separates content equality, preserved metadata and newly created destination state; each needs its own supporting record.

Gotcha or ProTip: Do not claim a whole filesystem, every timestamp, or an untested endpoint was preserved. Retain failed checks and explain their resolution.

Connection to the container lesson: Foundation claims F3–F4: container scope and transition verification

Recorded result or expected outcome: Review gates: All intended members present Both digest comparisons pass Metadata differences explained Custody and exceptions documented

Analyst takeaway: Make each preservation claim traceable to commands, records and verified results.

Student submission and primary references

For each command ID, record your actual command, UTC time, tool/OS versions, filesystem and policy, before/after fields, full hashes, screenshot and raw-log filenames, and any warning or skipped step. Explain why the observed result supports the stated conclusion and what it cannot establish. Keep the source, container, receipt and extracted working copy distinguishable.

Guttman, B., White, D. R., & Walraven, T. (2022). Digital evidence preservation: Considerations for evidence handlers (NIST IR 8387). https://doi.org/10.6028/NIST.IR.8387

Free Software Foundation. (n.d.). GNU tar manual. https://www.gnu.org/software/tar/manual/tar.html

Free Software Foundation. (n.d.). GNU Coreutils manual. https://www.gnu.org/software/coreutils/manual/coreutils.html

Linux man-pages project. (n.d.). inode(7). https://man7.org/linux/man-pages/man7/inode.7.html

Microsoft. (n.d.). File times. https://learn.microsoft.com/en-us/windows/win32/sysinfo/file-times

Microsoft. (n.d.). Robocopy. https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/robocopy

OpenBSD Project. (n.d.). scp(1). https://man.openbsd.org/scp.1

Zimmerman, E. (n.d.). MFTECmd. https://github.com/EricZimmerman/MFTECmd

Local sources: the two validation workbooks; Linux_Forensic_Time_Validator.sh; the controlled Windows procedure and automated harness; saved MFT/USN CSVs; and QA/Native_Container_20260920. Original captures remain unchanged in Source. The source map identifies each image and command ID.

Preservation principle: Preserve what you can; document what you cannot preserve; verify every transition.

Email qualification: the comparison concerns unverified loose-file attachments. MIME can carry optional date parameters, but actual sender/receiver support must be checked. A verified intact archive can use an authorized transport with handling records. See https://www.rfc-editor.org/rfc/rfc2183.html.

Student downloads

The packet captures support the packet-parsing companion; the timestamp experiments use synthetic files. The Windows harness and the controlled 00–10 procedure are separate sources with different step numbers.

1. Container workflow · 2. Linux validation · 3. Windows validation · 4. Create and verify your container