Points: 30

Description

Having contacted the NSA liaison at the FBI, you learn that a facility at this address is already on a FBI watchlist for suspected criminal activity.

With this tip, the FBI acquires a warrant and raids the location.

Inside they find the empty boxes of programmable OTP tokens, but the location appears to be abandoned. We’re concerned about what this APT is up to! These hardware tokens are used to secure networks used by Defense Industrial Base companies that produce critical military hardware.

The FBI sends the NSA a cache of other equipment found at the site. It is quickly assigned to an NSA forensics team. Your friend Barry enrolled in the Intrusion Analyst Skill Development Program and is touring with that team, so you message him to get the scoop. Barry tells you that a bunch of hard drives came back with the equipment, but most appear to be securely wiped. He managed to find a drive containing what might be some backups that they forgot to destroy, though he doesn’t immediately recognize the data. Eager to help, you ask him to send you a zip containing a copy of the supposed backup files so that you can take a look at it.

If we could recover files from the drives, it might tell us what the APT is up to. Provide a list of unique SHA256 hashes of all files you were able to find from the backups. Example (2 unique hashes):

  471dce655395b5b971650ca2d9494a37468b1d4cb7b3569c200073d3b384c5a4
  0122c70e2f7e9cbfca3b5a02682c96edb123a2c2ba780a385b54d0440f27a1f6

Downloads:

  • disk backups (archive.tar.bz2)

Prompt:

  • Provide your list of SHA256 hashes

Solution

The first thing we can do is extract the archive they gave us and see what we’re working with.

cobra@arch:~/codebreaker/task2$ bzip2 -dk archive.tar.bz2
cobra@arch:~/codebreaker/task2$ mkdir archive  
cobra@arch:~/codebreaker/task2$ tar -xf archive.tar -C archive
cobra@arch ~/codebreaker/task2$ ls -lah archive
total 1.1M
drwxr-xr-x 2 cobra cobra 4.0K Sep 14 16:38 .
drwxr-xr-x 3 cobra cobra 4.0K Dec 19 17:47 ..
-rw-r--r-- 1 cobra cobra  81K Aug  1 01:55 logseq138261767820292-i
-rw-r--r-- 1 cobra cobra  42K Aug  1 01:55 logseq14669698420205-i
-rw-r--r-- 1 cobra cobra  43K Aug  1 01:55 logseq17809182496366-i
-rw-r--r-- 1 cobra cobra  31K Aug  1 01:55 logseq187302913726519-i
-rw-r--r-- 1 cobra cobra  48K Aug  1 01:55 logseq199712321025410-i
-rw-r--r-- 1 cobra cobra  40K Aug  1 01:55 logseq201461584419366-i
-rw-r--r-- 1 cobra cobra  49K Aug  1 01:55 logseq2304276425182-i
-rw-r--r-- 1 cobra cobra  61K Aug  1 01:55 logseq236891182712038-i
-rw-r--r-- 1 cobra cobra  59K Aug  1 01:55 logseq29920229659121-i
-rw-r--r-- 1 cobra cobra  55K Aug  1 01:55 logseq30588840423278-i
-rw-r--r-- 1 cobra cobra  62K Aug  1 01:55 logseq30590811430113-i
-rw-r--r-- 1 cobra cobra  46K Aug  1 01:55 logseq31407132647765
-rw-r--r-- 1 cobra cobra  69K Aug  1 01:55 logseq498760695008-i
-rw-r--r-- 1 cobra cobra  74K Aug  1 01:55 logseq54663075211698-i
-rw-r--r-- 1 cobra cobra  34K Aug  1 01:55 logseq7737201525442-i
-rw-r--r-- 1 cobra cobra  54K Aug  1 01:55 logseq7819270382483-i
-rw-r--r-- 1 cobra cobra  46K Aug  1 01:55 logseq79153023022478-i
-rw-r--r-- 1 cobra cobra  47K Aug  1 01:55 logseq810856689053-i
-rw-r--r-- 1 cobra cobra  73K Aug  1 01:55 logseq88587469155-i
-rw-r--r-- 1 cobra cobra  66K Aug  1 01:55 logseq9251232232337-i

Let’s identify what these files are.

cobra@arch:~/codebreaker/task2/archive$ file logseq138261767820292-i
logseq138261767820292-i: ZFS snapshot (little-endian machine), version 17, type: ZFS, destination GUID: 26 FFFFFF95 2E FFFFFFB9 FFFFFF83 FFFFFFD9 FFFFFFE3 26, source GUID: 11 FFFFFFEE FFFFFFE9 47 FFFFFF9D 53 6B 3D, name: 'fpyspool/lkfs@logseq138261767820292'

Ok, so we have a bunch ZFS snapshots.

As visible in the file information above, these snapshots are incremental. Each snapshot only contains the modifications to the data in the snapshot before it. This is why we can see both a source and destination GUID.

To load them, we will need to create a ZFS pool then apply the snapshots in the correct order.

The base snapshot is logseq31407132647765 since it doesn’t have the -i at the end.

After this snapshot is applied, we need to look at the source GUID of all other snapshots, and apply the one whose source GUID matches the destination GUID of the base snapshot. We can then repeat this process until all snapshots have been applied to our pool.

We can write a Bash script to automate this entire process.

POOL_NAME="temp_pool"
DATASET_NAME="restore"

if zpool list | grep -q "$POOL_NAME"; then
    sudo zfs unmount "$POOL_NAME" 2>/dev/null
    sudo zpool destroy "$POOL_NAME"
fi
rm -f /tmp/zfspool.img

truncate -s 1G /tmp/zfspool.img
sudo zpool create "$POOL_NAME" /tmp/zfspool.img

FULL_SNAPSHOT="archive/logseq31407132647765"
echo "Applying base snapshot: $FULL_SNAPSHOT"
sudo zfs recv "$POOL_NAME/$DATASET_NAME" < "$FULL_SNAPSHOT"

SNAPSHOT_FILES=(archive/logseq*)

declare -A SOURCE_GUIDS
declare -A DEST_GUIDS
declare -A FILE_NAMES

for file in "${SNAPSHOT_FILES[@]}"; do
    if [[ "$file" == "$FULL_SNAPSHOT" ]]; then
        continue
    fi

    source_guid=$(file "$file" | grep -oP '(?<=source GUID: ).+?(?=,)' | tr -d ' ')
    dest_guid=$(file "$file" | grep -oP '(?<=destination GUID: ).+?(?=,)' | tr -d ' ')

    SOURCE_GUIDS["$source_guid"]="$file"
    DEST_GUIDS["$dest_guid"]="$source_guid"
    FILE_NAMES["$file"]="$dest_guid"
done

current_guid=$(file "$FULL_SNAPSHOT" | grep -oP '(?<=destination GUID: ).+?(?=,)' | tr -d ' ')

while [[ -n "${SOURCE_GUIDS[$current_guid]}" ]]; do
    next_snapshot="${SOURCE_GUIDS[$current_guid]}"
    echo "Applying incremental snapshot: $next_snapshot"
    sudo zfs recv "$POOL_NAME/$DATASET_NAME" < "$next_snapshot"
    current_guid=$(file "$next_snapshot" | grep -oP '(?<=destination GUID: ).+?(?=,)' | tr -d ' ')
done

echo "All snapshots applied successfully!"
cobra@arch:~/codebreaker/task2$ bash solve.sh
Applying base snapshot: archive/logseq31407132647765
Applying incremental snapshot: archive/logseq7737201525442-i
Applying incremental snapshot: archive/logseq201461584419366-i
Applying incremental snapshot: archive/logseq14669698420205-i
Applying incremental snapshot: archive/logseq17809182496366-i
Applying incremental snapshot: archive/logseq79153023022478-i
Applying incremental snapshot: archive/logseq810856689053-i
Applying incremental snapshot: archive/logseq199712321025410-i
Applying incremental snapshot: archive/logseq2304276425182-i
Applying incremental snapshot: archive/logseq30588840423278-i
Applying incremental snapshot: archive/logseq29920229659121-i
Applying incremental snapshot: archive/logseq236891182712038-i
Applying incremental snapshot: archive/logseq187302913726519-i
Applying incremental snapshot: archive/logseq7819270382483-i
Applying incremental snapshot: archive/logseq30590811430113-i
Applying incremental snapshot: archive/logseq9251232232337-i
Applying incremental snapshot: archive/logseq498760695008-i
Applying incremental snapshot: archive/logseq88587469155-i
Applying incremental snapshot: archive/logseq54663075211698-i
Applying incremental snapshot: archive/logseq138261767820292-i
All snapshots applied successfully!

We can see the directory planning is now in /temp_pool/restore.

cobra@arch:/temp_pool/restore$ ls -lah planning/*
planning/logseq:
total 10K
drwxrwxr-x 2 root root   4 Jan 20  2024 .
drwxrwxr-x 4 root root   4 Jan 20  2024 ..
-rw-rw-r-- 1 root root 15K Jan 20  2024 config.edn
-rw-rw-r-- 1 root root   0 Jan 20  2024 custom.css

planning/pages:
total 30K
drwxrwxr-x 2 root root   11 Jan 20  2024  .
drwxrwxr-x 4 root root    4 Jan 20  2024  ..
-rw-rw-r-- 1 root root  266 Jan 20  2024  contents.md
-rw-rw-r-- 1 root root 4.2K Jan 20  2024 'CUDA elliptic.md'
-rw-rw-r-- 1 root root 2.6K Jan 20  2024 'Elliptic curve recovery.md'
-rw-rw-r-- 1 root root 3.9K Jan 20  2024  golang.md
-rw-rw-r-- 1 root root 6.1K Jan 20  2024  LLM.md
-rw-rw-r-- 1 root root 4.8K Jan 20  2024  todo.md
-rw-rw-r-- 1 root root 3.6K Jan 20  2024 'token generation.md'
-rw-rw-r-- 1 root root 5.2K Jan 20  2024  tools.md
-rw-rw-r-- 1 root root 2.9K Jan 20  2024 'ZFS snapshots.md'

However, in order to submit hashes of every file, we need to access the files at each incremental snapshot which are visible under /temp_pool/restore/.zfs/snapshot.

cobra@arch:/temp_pool/restore/.zfs/snapshot$ ls -lah
total 10K
drwxrwxrwx 22 root root 2 Dec 19 18:30 .
drwxrwxrwx  1 root root 0 Dec 19 18:30 ..
drwxrwxr-x  3 root root 3 Sep 10 15:01 logseq138261767820292
drwxrwxr-x  3 root root 3 Sep 10 15:01 logseq14669698420205
drwxrwxr-x  3 root root 3 Sep 10 15:01 logseq17809182496366
drwxrwxr-x  3 root root 3 Sep 10 15:01 logseq187302913726519
drwxrwxr-x  3 root root 3 Sep 10 15:01 logseq199712321025410
drwxrwxr-x  3 root root 3 Sep 10 15:01 logseq201461584419366
drwxrwxr-x  3 root root 3 Sep 10 15:01 logseq2304276425182
drwxrwxr-x  3 root root 3 Sep 10 15:01 logseq236891182712038
drwxrwxr-x  3 root root 3 Sep 10 15:01 logseq29920229659121
drwxrwxr-x  3 root root 3 Sep 10 15:01 logseq30588840423278
drwxrwxr-x  3 root root 3 Sep 10 15:01 logseq30590811430113
drwxr-xr-x  2 root root 2 Sep 14 16:36 logseq31407132647765
drwxrwxr-x  3 root root 3 Sep 10 15:01 logseq498760695008
drwxrwxr-x  3 root root 3 Sep 10 15:01 logseq54663075211698
drwxrwxr-x  3 root root 3 Sep 10 15:01 logseq7737201525442
drwxrwxr-x  3 root root 3 Sep 10 15:01 logseq7819270382483
drwxrwxr-x  3 root root 3 Sep 10 15:01 logseq79153023022478
drwxrwxr-x  3 root root 3 Sep 10 15:01 logseq810856689053
drwxrwxr-x  3 root root 3 Sep 10 15:01 logseq88587469155
drwxrwxr-x  3 root root 3 Sep 10 15:01 logseq9251232232337

Each of these directories contain all the files at the point of each snapshot.

So to get a list of SHA256 hashes, we can iterate through each of these directories and hash all the files. In order to remove any files that weren’t modified between snapshots, we need also need to make sure to remove any duplicate hashes.

cobra@arch:/temp_pool/restore/.zfs/snapshot$ find . -type f -exec sha256sum {} \; | awk '{print $1}' | sort | uniq
0057fab85c9c6ae6e53db9809a2f24a224dcac13336fca2f3e0e89ec1a3648cf
00f3337f082248c1ac30dc516dc59814882fa6938499f47df8e7be02f893eb88
027bf7b570d3e6c67ad6e6a6f25e09c0398be9f4daabb125bd4e07f95b075ead
...

We can submit that list to complete the task.

Result

That is correct!