Forensics Git 2

Published: March 20, 2026

Description

The agents interrupted the perpetrator's disk deletion routine. Can you recover this git repo?

Download and decompress the disk image.

Mount the image and inspect the filesystem for a damaged git repository.

gunzip disk.img.gz
sudo mount -o loop disk.img /mnt/disk

Solution

  1. Step 1Decompress and quick strings check
    Extract the disk image. The deletion routine was interrupted, so git objects may still be present. Run strings first as a fast check.
    gunzip disk.img.gz
    strings disk.img | grep picoCTF
    Learn more

    When a deletion process is interrupted, the filesystem may be in an inconsistent state: some files are deleted (their directory entries removed) but their data blocks have not yet been overwritten. The raw bytes of the deleted content remain on disk until the operating system reuses those blocks for new data. strings | grep picoCTF scans the raw image and finds these bytes even though the filesystem no longer has a path to them.

    This is the principle behind file carving: recovering files by their content patterns rather than their filesystem metadata. Known file types have recognizable headers (magic bytes) — for example, JPEG files start with FF D8 FF, ZIP files with 50 4B 03 04, and git objects are zlib-compressed with a characteristic header. Carving tools like Foremost and PhotoRec scan raw disk images looking for these magic bytes and extract complete files even from unallocated space.

  2. Step 2Detect partition layout and mount
    Use mmls to identify the partition offset, then mount the filesystem.
    mmls disk.img
    sudo mount -o loop,offset=$((512*<start_sector>)) disk.img /mnt/disk
    ls /mnt/disk
    Learn more

    Even when files are deleted, the partition table and filesystem superblock are usually intact because they are written early in the deletion process and are often the last to be cleared. mmls reads the partition table to locate the data partition, and Linux can still mount and read the filesystem structure even if individual file inodes have been cleared.

    Linux ext4 filesystems mark deleted inodes as free in the inode bitmap but do not immediately zero the inode's block pointers. This means the Sleuth Kit's ils (inode list) and ifind tools can still see deleted inodes and their data block addresses for a period after deletion — long enough to recover recently deleted files. The fls -r -d command from TSK lists deleted files and directories by scanning for inodes marked as unallocated.

  3. Step 3Find surviving git objects
    Search for .git directories or HEAD files that survived the partial deletion. If the repository directory is gone, scan for loose object files.
    find /mnt/disk -name '.git' -type d 2>/dev/null
    find /mnt/disk -name 'HEAD' 2>/dev/null
    find /mnt/disk -path '*/objects/*/*' 2>/dev/null | head
    Learn more

    Git loose object files are stored in .git/objects/XX/YYYYYYYY... where XX is the first two hex characters of the object's SHA-1 hash. Each file is zlib-compressed and contains either a blob (file content), tree (directory snapshot), commit (history entry), or tag. Even if the .git directory itself was deleted, individual object files that haven't been overwritten can be recovered and reassembled.

    The HEAD file in a git repository contains a ref pointer like ref: refs/heads/main or a raw SHA-1 hash (detached HEAD). Finding an intact HEAD file tells you the repository's root and whether the ref structure survived. If HEAD is gone but object files remain, you can still reconstruct history by running git fsck in a directory containing those object files.

    Git also supports pack files (.git/objects/pack/*.pack) which bundle many objects into a single compressed archive with a corresponding index file. Pack files are more space-efficient than loose objects and are created by git gc or when fetching from a remote. If pack files survived, they may contain all the repository's history even if loose objects were deleted.

  4. Step 4Recover the repository
    Copy any surviving git directory or objects to a writable path and run git fsck to reconstruct reachable history.
    mkdir /tmp/recovered && cp -r /mnt/disk/<path>/.git /tmp/recovered/.git
    cd /tmp/recovered && git fsck --unreachable
    git log --all --oneline 2>/dev/null
    git fsck --lost-found && ls .git/lost-found/other/
    Learn more

    git fsck (filesystem check) verifies the integrity of the object database. It traverses all refs and objects, checks SHA-1 hashes for corruption, and reports dangling (unreachable) objects. Running it after recovering partial object files tells you which parts of the history survived and whether any objects are corrupt (truncated or overwritten blocks).

    If git log reports errors about missing objects, you can sometimes reconstruct the missing pieces by finding their raw bytes in the disk image using grep for the partial SHA-1 hash, or by using git hash-object -w to re-add a found blob. The recovery process is iterative: find surviving objects, identify which are missing, search for them in unallocated space, and repeat until the history is complete enough to read the flag.

  5. Step 5Use TSK to recover deleted files if needed
    If the .git directory itself was deleted, use The Sleuth Kit to recover deleted inodes from the raw image.
    fls -r disk.img | grep -i git
    icat disk.img <inode> > recovered_object
    file recovered_object
    Learn more

    The Sleuth Kit (TSK) provides low-level filesystem access. fls (file list) lists files and directories, including deleted ones (marked with *). It uses inode metadata rather than directory entries, so it finds files even after their directory entries are removed. -r recurses into directories and -d filters for deleted entries only.

    icat (inode cat) reads the data blocks of a specific inode and writes the raw file content to stdout. This works even for deleted inodes as long as their block pointers haven't been reused. Each git object file recovered this way is a zlib-compressed blob. You can verify it with file (which recognizes zlib streams) and add it to a recovered git repository with git hash-object -w recovered_object after decompressing.

    This level of filesystem forensics is used in real criminal investigations. Law enforcement agencies routinely recover deleted files from seized devices using tools like TSK, EnCase, and FTK (Forensic Toolkit). The key insight is that deletion on most filesystems is a metadata operation — it removes the directory entry and marks the inode as free, but the actual data remains until overwritten.

  6. Step 6Extract the flag
    Read flag content from whichever commit, blob, or recovered file contains it.
    git cat-file -p <blob-hash>
    git show <commit>
    cat .git/lost-found/other/<hash>
    Learn more

    After recovery, git cat-file -p and git show let you read the content of any recovered object. The .git/lost-found/other/ directory (created by git fsck --lost-found) contains hard links to all dangling blob objects, named by their SHA-1 hash. These files can be read directly with cat since they are plain blobs (not the zlib-compressed loose object format — git fsck decompresses them into lost-found).

    This challenge is a microcosm of real incident response: a threat actor attempted to destroy evidence by deleting a repository, the deletion was interrupted, and forensic investigators recover what they can from the surviving artifacts. The same skills — mounting disk images, using TSK, recovering git objects — are used in real forensic investigations of developer workstations, source code repositories, and cloud storage buckets.

Flag

picoCTF{...}

The repository was partially deleted. Surviving git objects or deleted inodes on the disk hold the flag. Use git fsck --lost-found and TSK icat to recover them.

Want more picoCTF 2026 writeups?

Useful tools for Forensics

More Forensics