Blog section
CTF

picoCTF 2024 Forensics

picoCTF 2024 Forensics writeups covering image analysis, metadata, and disk forensics.

picoCTFCTFForensics

picoCTF 2024 - Forensics

challenge screenshot

Forensics Challenges

Solved: 8/8 challenges


Blast from the past

Tags: `Forensics` `browser_webshell_solvable` `metadata`

Description

The judge for these pictures is a real fan of antiques. Can you age this photo to the specifications? Set the timestamps on this picture to 1970:01:01 00:00:00.001+00:00 with as much precision as possible for each timestamp. In this example, +00:00 is a timezone adjustment. Any timezone is acceptable as long as the time is equivalent. As an example, this timestamp is acceptable as well: 1969:12:31 19:00:00.001-05:00. For timestamps without a timezone adjustment, put them in GMT time (+00:00). The checker program provides the timestamp needed for each.

challenge screenshot

Solution Strategy

exiftool '-AllDates=1970:01:01 00:00:00.001' -OffsetTime="+00:00" original.jpg

exiftool -SubSecTime="001" -SubSecTimeOriginal="001" -SubSecTimeDigitized="001" original.jpg

challenge screenshot

challenge screenshot

hexedit original.jpg
#Change 170051381420 -> 000000000001

challenge screenshot

ExifTool Version Number         : 12.65
File Name                       : original.jpg
Directory                       : .
File Size                       : 2.9 MB
File Modification Date/Time     : 2024:03:18 21:59:22+07:00
File Access Date/Time           : 2024:03:18 21:59:22+07:00
File Inode Change Date/Time     : 2024:03:18 21:59:22+07:00
File Permissions                : -rw-rw-r--
File Type                       : JPEG
File Type Extension             : jpg
MIME Type                       : image/jpeg
Exif Byte Order                 : Little-endian (Intel, II)
Image Description               : 
Make                            : samsung
Camera Model Name               : SM-A326U
Orientation                     : Rotate 90 CW
X Resolution                    : 72
Y Resolution                    : 72
Resolution Unit                 : inches
Software                        : MediaTek Camera Application
Modify Date                     : 1970:01:01 00:00:00
Y Cb Cr Positioning             : Co-sited
Exposure Time                   : 1/24
F Number                        : 1.8
Exposure Program                : Program AE
ISO                             : 500
Sensitivity Type                : Unknown
Recommended Exposure Index      : 0
Exif Version                    : 0220
Date/Time Original              : 1970:01:01 00:00:00
Create Date                     : 1970:01:01 00:00:00
Offset Time                     : +00:00
Components Configuration        : Y, Cb, Cr, -
Shutter Speed Value             : 1/24
Aperture Value                  : 1.9
Brightness Value                : 3
Exposure Compensation           : 0
Max Aperture Value              : 1.8
Metering Mode                   : Center-weighted average
Light Source                    : Other
Flash                           : On, Fired
Focal Length                    : 4.6 mm
Sub Sec Time                    : 001
Sub Sec Time Original           : 001
Sub Sec Time Digitized          : 001
Flashpix Version                : 0100
Color Space                     : sRGB
Exif Image Width                : 4000
Exif Image Height               : 3000
Interoperability Index          : R98 - DCF basic file (sRGB)
Interoperability Version        : 0100
Exposure Mode                   : Auto
White Balance                   : Auto
Digital Zoom Ratio              : 1
Focal Length In 35mm Format     : 25 mm
Scene Capture Type              : Standard
Compression                     : JPEG (old-style)
Thumbnail Offset                : 1144
Thumbnail Length                : 64000
Image Width                     : 4000
Image Height                    : 3000
Encoding Process                : Baseline DCT, Huffman coding
Bits Per Sample                 : 8
Color Components                : 3
Y Cb Cr Sub Sampling            : YCbCr4:2:0 (2 2)
Time Stamp                      : 1970:01:01 07:00:00.001+07:00
MCC Data                        : United States / Guam (310)
Aperture                        : 1.8
Image Size                      : 4000x3000
Megapixels                      : 12.0
Scale Factor To 35 mm Equivalent: 5.4
Shutter Speed                   : 1/24
Create Date                     : 1970:01:01 00:00:00.001
Date/Time Original              : 1970:01:01 00:00:00.001
Modify Date                     : 1970:01:01 00:00:00.001+00:00
Thumbnail Image                 : (Binary data 64000 bytes, use -b option to extract)
Circle Of Confusion             : 0.006 mm
Field Of View                   : 71.5 deg
Focal Length                    : 4.6 mm (35 mm equivalent: 25.0 mm)
Hyperfocal Distance             : 2.13 m
Light Value                     : 4.0

Flag

MD5 of your picture:
6bc3fc93ab60e34d0284e37ee2066f2c  test.out

Checking tag 1/7
Looking at IFD0: ModifyDate
Looking for '1970:01:01 00:00:00'
Found: 1970:01:01 00:00:00
Great job, you got that one!

Checking tag 2/7
Looking at ExifIFD: DateTimeOriginal
Looking for '1970:01:01 00:00:00'
Found: 1970:01:01 00:00:00
Great job, you got that one!

Checking tag 3/7
Looking at ExifIFD: CreateDate
Looking for '1970:01:01 00:00:00'
Found: 1970:01:01 00:00:00
Great job, you got that one!

Checking tag 4/7
Looking at Composite: SubSecCreateDate
Looking for '1970:01:01 00:00:00.001'
Found: 1970:01:01 00:00:00.001
Great job, you got that one!

Checking tag 5/7
Looking at Composite: SubSecDateTimeOriginal
Looking for '1970:01:01 00:00:00.001'
Found: 1970:01:01 00:00:00.001
Great job, you got that one!

Checking tag 6/7
Looking at Composite: SubSecModifyDate
Looking for '1970:01:01 00:00:00.001'
Found: 1970:01:01 00:00:00.001
Great job, you got that one!

Checking tag 7/7
Timezones do not have to match, as long as it's the equivalent time.
Looking at Samsung: TimeStamp
Looking for '1970:01:01 00:00:00.001+00:00'
Found: 1970:01:01 00:00:00.001+00:00
Great job, you got that one!

challenge screenshot


CanYouSee

Tags: `Forensics` `browser_webshell_solvable`

Description

How about some hide and seek?

challenge screenshot

exiftool ukn_reality.jpg

challenge screenshot

Flag

challenge screenshot


Dear Diary

Tags: `Forensics` `browser_webshell_solvable` `disk`

Description

If you can find the flag on this disk image, we can close the case for good!

challenge screenshot

file disk.flag.img.gz

gzip -d disk.flag.img.gz

challenge screenshot

Using Autopsy, the built-in tool in Kali Linux.

challenge screenshot

Open a new case and import a disk.flag.img.

challenge screenshot

Wait for analysis to finish, then click Keyword Search.

challenge screenshot

Enter .txt for keyword search.

challenge screenshot

Flag

After reading all the files, the first flag fragment starts at file 7.

pic

pic

oCT

oCT

F{1

F{1

_53

_53

3_n

3_n

4m3

4m3

5_8

5_8

0d2

0d2

4b3

4b3

0}

0}

picoCTF{1_533_n4m35_80d24b30}

endianness-v2

Tags: `Forensics` `browser_webshell_solvable`

Description

Here's a file that was recovered from a 32-bits system that organized the bytes a weird way. We're not even sure what type of file it is.

challenge screenshot

hexedit challengefile

challenge screenshot

Solution Strategy

def correct_byte_order(input_file_path, output_file_path):
    """
    Corrects the byte order within each 32-bit word of the file.

    Parameters:
    - input_file_path: Path to the input file with incorrect byte order.
    - output_file_path: Path where the corrected file will be saved.
    """
    corrected_bytes = bytearray()
    
    with open(input_file_path, 'rb') as file:
        while True:
            word = file.read(4)
            if not word:
                break
            corrected_bytes.extend(word[::-1])
    
    with open(output_file_path, 'wb') as corrected_file:
        corrected_file.write(corrected_bytes)

input_file_path = 'challengefile'
output_file_path = 'fixed_challengefile.jpeg'
correct_byte_order(input_file_path, output_file_path)

print(f'Corrected file has been saved to: {output_file_path}')
  • The correct_byte_order function corrects the byte order within each 32-bit word of a file.
  • It takes two parameters: input_file_path (path to the input file with incorrect byte order) and output_file_path (path where the corrected file will be saved).
  • Inside the function, it initializes an empty bytearray to store the corrected bytes.
  • It then opens the input file in binary mode and iterates over the file content in chunks of 4 bytes.
  • For each 32-bit word read from the file, it reverses the byte order (from little-endian to big-endian or vice versa) and appends it to the corrected_bytes bytearray.
  • After processing the entire input file, it opens the output file in binary write mode and writes the corrected bytes to it.
  • Finally, an example usage of the function is provided where it takes an input file named 'challengefile', corrects the byte order, and saves the corrected file as 'fixed_challengefile.jpeg'.
  • Upon execution, it prints a message indicating the path where the corrected file has been saved.

Flag

challenge screenshot


Mob psycho

Tags: `Forensics` `browser_webshell_solvable` `apk`

Description

Can you handle APKs?

unzip mobpsycho.apk

challenge screenshot

find /home/waaris_m/Downloads/picoCTF_2024/Mob_psycho/ -type f -name "flag.*"

cat /home/waaris_m/Downloads/picoCTF_2024/Mob_psycho/res/color/flag.txt

challenge screenshot

Solution Strategy

# Hexadecimal string from flag.txt
hex_string = "7069636f4354467b6178386d433052553676655f4e5838356c346178386d436c5f38356462643231357d"

# Convert the hexadecimal string to ASCII
ascii_string = bytes.fromhex(hex_string).decode()

print(ascii_string)

Flag

challenge screenshot


Scan Surprise

Tags: `Forensics` `qr_code` `browser_webshell_solvable` `shell`

Description

I've gotten bored of handing out flags as text. Wouldn't it be cool if they were an image instead?

QR-CODE IN SOURCE CODE

QR-CODE IN SOURCE CODE

Flag

Thanks https://me-qr-scanner.com/qr-scanner

picoCTF{p33k_@_b00_b5ce2572}

picoCTF{p33k@b00_b5ce2572}


Secret of the Polyglot

Tags: `Forensics` `file_format` `polyglot`

Description

The Network Operations Center (NOC) of your local institution picked up a suspicious file, they're getting conflicting information on what type of file it is. They've brought you in as an external expert to examine the file. Can you extract all the information from this strange file?

challenge screenshot

Flag

challenge screenshot

challenge screenshot


Verify

Tags: `Forensics` `checksum` `browser_webshell_solvable` `grep`

Description

People keep trying to trick my players with imitation flags. I want to make sure they get the real thing! I'm going to provide the SHA-256 hash and a decrypt script to help you know that my flags are legitimate.

challenge screenshot

#decrypt.sh
        #!/bin/bash

        # Check if the user provided a file name as an argument
        if [ $# -eq 0 ]; then
            echo "Expected usage: decrypt.sh <filename>"
            exit 1
        fi

        # Store the provided filename in a variable
        file_name="$1"

        # Check if the provided argument is a file and not a folder
        if [ ! -f "/home/ctf-player/drop-in/$file_name" ]; then
            echo "Error: '$file_name' is not a valid file. Look inside the 'files' folder with 'ls -R'!"
            exit 1
        fi

        # If there's an error reading the file, print an error message
        if ! openssl enc -d -aes-256-cbc -pbkdf2 -iter 100000 -salt -in "/home/ctf-player/drop-in/$file_name" -k picoCTF; then
            echo "Error: Failed to decrypt '$file_name'. This flag is fake! Keep looking!"
        fi

Solution Strategy

import os
import subprocess
import sys

if len(sys.argv) != 2:
    print("Expected usage: decrypt.py <directory_path>")
    sys.exit(1)

directory_path = sys.argv[1]

if not os.path.isdir(directory_path):
    print(f"Error: '{directory_path}' is not a valid directory. Provide a valid directory path!")
    sys.exit(1)

for file_name in os.listdir(directory_path):
    full_path = os.path.join(directory_path, file_name)
    if os.path.isfile(full_path):
        print(f"Attempting to decrypt: {file_name}")
        try:
            subprocess.run(['openssl', 'enc', '-d', '-aes-256-cbc', '-pbkdf2', '-iter', '100000', '-salt', 
                            '-in', full_path, '-k', 'picoCTF'], check=True)
            print(f"Decrypted: {file_name}")
        except subprocess.CalledProcessError:
            print(f"Error: Failed to decrypt '{file_name}'. This flag might be fake or the file is not encrypted with the expected parameters!")

print("Finished processing all files.")
  • This script is designed to decrypt files within a specified directory using OpenSSL.
  • It expects one command-line argument, which should be the path to the directory containing the files to decrypt.
  • If the argument count is not exactly 2, it prints an error message and exits with a status code of 1.
  • It checks if the provided directory path exists and is indeed a directory; if not, it prints an error message and exits with a status code of 1.
  • It iterates over each file in the directory, attempting to decrypt each file using OpenSSL with AES-256 CBC encryption, PBKDF2 key derivation, 100000 iterations, and a salt.
  • If decryption is successful, it prints a success message; otherwise, it prints an error message indicating the failure to decrypt the file.
  • Finally, it prints a message indicating that it has finished processing all files in the directory.

Flag

challenge screenshot