NorthSec 2024 - Forensic Challenge (EN)

NorthSec 2024 - Forensic Challenge (EN)

Retinal Systems

Description

Ripple effects in our industry are common. They are in the human body as well, who would have guessed.

Philip was annoyed of losing eyelashes. Long story short, he got scammed and got a cream for that, which infected his eyes, and now the Universal Sight Bridge linking his retina to the brain got impacted and he got an infection. Result? He lost color sighting. I guess that explain why he didn’t take action when our last pentest report was full of red everywhere.

Anyway. Here’s the data flux coming from his cones. See if you can find what happened.

Events that led to the eyes infection

eyes_infection.pcap


Solution

A PCAP file containing USB data is provided. The protocols used are USB and USBMS. To filter only the relevant data with Wireshark, the following condition is applied:

_ws.col.info == "SCSI: Data In LUN: 0x00 (Read(10) Response Data) " && frame.len > 539

This method allows focusing exclusively on the information relevant for solving the challenge.

Extraction

During the extraction, various issues were encountered with tshark, which returned no information. To work around this problem, a Python script was developed to parse the PCAP file.
The script is as follows:

import argparse
from scapy.all import rdpcap, raw

def process_packets(file_path, frame_start, frame_end=None):
    scapy_cap = rdpcap(file_path)
    if frame_end is None:
        frame_end = frame_start

    for i, packet in enumerate(scapy_cap[frame_start-1:frame_end]):
        d = raw(packet).hex()[54:]
        if len(d) > 116:
            if d != "000000051ef000102002000f5c00000000000000000000000000000000000000000000": # Useless strings in capture (No data) 
                print(f"Frame {frame_start + i}: {d}")

def main():
    parser = argparse.ArgumentParser(description='Process a pcapng file and print specific frame data.')
    parser.add_argument('file_path', type=str, help='Path to the pcapng file')
    parser.add_argument('frame_start', type=int, help='Start frame number (inclusive)')
    parser.add_argument('frame_end', type=int, nargs='?', default=None, help='End frame number (inclusive, optional)')

    args = parser.parse_args()

    process_packets(args.file_path, args.frame_start, args.frame_end)

if __name__ == "__main__":
    main()

The objective of this script is to extract the data in hexadecimal format within a specified range provided as parameters.

Analysis

With Wireshark, it's possible to start examining the files being transferred by analyzing the captured data.


NTFS Disk

Upon closer examination, several components of the NTFS system are identified, including:

    1. $MFT
    2. $MftMirr
    3. $LogFile

Among the detected files, some are of type PE (Portable Executable) and others are text files.

File types:

  • PE (Portable Executable)
  • Text

The objective is to retrieve files that can provide crucial clues to solve the challenge. While traversing the PCAP, there is a frame with text.

To do this, the previously mentioned tool is used to extract the relevant data.

python3 extract.py eyes_infection.pcapng 770

We can see a text file with the following data:

We can therefore conclude that there are binary files being transferred. By examining the frames, we can see that a binary file is indeed being transferred. This is evident from the MZ header.

The examination of the data reveals that a binary file is being transferred, allowing for a system update.


Extraction of binary files:

The binwalk command displays the structure of the files contained in the extraction. Here's an example of using dd to extract the identified files:

One of the extracted files is a .NET Assembly file. To analyze it, I use dnSpy.

internal class Eyelashes
{
    private static byte[] XORDecode(byte[] inputBytes, string key)
    {
        byte[] bytes = Encoding.UTF8.GetBytes(key);
        byte[] array = new byte[inputBytes.Length];
        
        for (int i = 0; i < inputBytes.Length; i++)
        {
            byte b = inputBytes[i];
            byte b2 = bytes[i % bytes.Length];
            array[i] = (b ^ b2);
        }
        
        return array;
    }

    private static string ComputeSHA512Hash(string input)
    {
        string result;
        using (SHA512 sha = SHA512.Create())
        {
            byte[] array = sha.ComputeHash(Encoding.UTF8.GetBytes(input));
            StringBuilder stringBuilder = new StringBuilder();
            
            for (int i = 0; i < array.Length; i++)
            {
                stringBuilder.Append(array[i].ToString("x2"));
            }
            
            result = stringBuilder.ToString();
        }
        return result;
    }

    private static void Main()
    {
        Console.WriteLine("[-] Starting up EYELIDS FIX...");
        Thread.Sleep(1000);
        
        Console.WriteLine("[-] Gathering eyes firmware...");
        Thread.Sleep(1000);
        
        Console.WriteLine("[+] Version compatible with fix.");
        Thread.Sleep(500);
        
        Console.WriteLine("[-] Shutting down device to apply fix...");
        Thread.Sleep(1000);
        
        Console.WriteLine("[-] Patching eyes firmware...");
        Thread.Sleep(2000);
        
        try
        {
            string keyName = "HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\ColorFiltering";
            Registry.SetValue(keyName, "Active", 1, RegistryValueKind.DWord);
            Registry.SetValue(keyName, "FilterType", 1, RegistryValueKind.DWord);
            
            Console.WriteLine("[+] Patch applied successfully.");
            Console.WriteLine("[*] Your cones have been disabled in this trial version.");
            Console.WriteLine("[*] To unlock colour vision, please upgrade to the premium firmware.");
        }
        catch (Exception)
        {
            Console.WriteLine("[X] An error has occured applying the eyes patch.");
        }
        
        Thread.Sleep(1000);
        
        Console.WriteLine("[-] Attempting to upgrade to premium...");
        Thread.Sleep(1000);
        
        DriveInfo driveInfo = new DriveInfo(Path.GetPathRoot(AppDomain.CurrentDomain.BaseDirectory));
        if (driveInfo.DriveType == DriveType.Removable)
        {
            Console.WriteLine("[+] The program is running from an approved media.");
            string volumeLabel = driveInfo.VolumeLabel;
            
            byte[] inputBytes = new byte[]
            {
                37, 46, 112, 34, 30, 127, 7, 120, 44, 33, 125, 8, 51, 53, 102, 109,
                54, 38, 105, 47, 120, 114, 11, 39, 99, 82, 32, 62, 40, 56, 61, 112,
                42, 47, 36, 50
            };
            
            Console.WriteLine("[-] Attempting to unlock premium firmware features...");
            Thread.Sleep(1000);
            
            string key = Eyelashes.ComputeSHA512Hash(volumeLabel);
            byte[] bytes = Eyelashes.XORDecode(inputBytes, key);
            string decryptedString = Encoding.UTF8.GetString(bytes);
            
            if (decryptedString.StartsWith("FLAG"))
            {
                Console.WriteLine("[+] The premium firmware have been activated. Activate online to receive instructions on enabling the cone receptors.");
                Console.WriteLine("[+] Activation code: " + decryptedString);
            }
            else
            {
                Console.WriteLine("[X] Unable to activate the premium firmware. Generated activation code is invalid.");
                Console.WriteLine("[+] Activation Code: " + decryptedString);
            }
        }
        else
        {
            Console.WriteLine("[X] The program is not running from an approved media.");
        }
        
        Console.WriteLine("[-] Shutting down EYELIDS FIX...");
    }
}

During the analysis of the extracted code, it was observed that it decrypts an XOR-encoded string using the SHA512 of the name of the USB key on which the executable file is running. To retrieve this name, it is necessary to extract system structures such as $VolumeInformation exchanged during the capture.

Identification of the USB Key

These system structures were exchanged in frame 434.


Analysis of this frame reveals that the USB key has the following label:

EYELIDS-FIX-v.47.4f.41.54.53

C# Script

Here's the C# script developed to solve the challenge by decrypting the XOR-encoded string:

using System;
using System.Security.Cryptography;
using System.Text;

public class Program
{
    private static string ComputeSHA512Hash(string input)
    {
        using (SHA512 sha = SHA512.Create())
        {
            byte[] hashBytes = sha.ComputeHash(Encoding.UTF8.GetBytes(input));
            StringBuilder hashStringBuilder = new StringBuilder(hashBytes.Length * 2);

            foreach (byte b in hashBytes)
            {
                hashStringBuilder.Append(b.ToString("x2"));
            }

            return hashStringBuilder.ToString();
        }
    }

    private static byte[] XORDecode(byte[] inputBytes, string key)
    {
        byte[] keyBytes = Encoding.UTF8.GetBytes(key);
        byte[] outputBytes = new byte[inputBytes.Length];

        for (int i = 0; i < inputBytes.Length; i++)
        {
            outputBytes[i] = (byte)(inputBytes[i] ^ keyBytes[i % keyBytes.Length]);
        }

        return outputBytes;
    }

    private static void Main()
    {

        string volumeLabel = "EYELIDS-FIX-v.47.4f.41.54.53";
        byte[] inputBytes =
        {
            37, 46, 112, 34, 30, 127, 7, 120, 44, 33, 125, 8, 51, 53, 102, 109, 54, 38, 105, 47, 120, 114, 11, 39, 99, 82, 32, 62, 40, 56, 61, 112, 42, 47, 36, 50
        };

        Console.WriteLine("[-] Attempting to unlock premium firmware features...");

        string key = ComputeSHA512Hash(volumeLabel);
        byte[] decodedBytes = XORDecode(inputBytes, key);
        string decodedString = Encoding.UTF8.GetString(decodedBytes);

        if (decodedString.StartsWith("FLAG"))
        {
            Console.WriteLine("[+] The premium firmware has been activated. Activate online to receive instructions on enabling the cone receptors.");
            Console.WriteLine("[+] Activation code: " + decodedString);
        }
        else
        {
            Console.WriteLine("[X] Unable to activate the premium firmware. Generated activation code is invalid.");
            Console.WriteLine("[+] Activation Code: " + decodedString);
        }
    }
}

Challenge Resolution and Flag Acquisition

Following the analysis of the extracted code and the detection of the USB key label, the XOR-encoded string has been decrypted. The obtained flag is:

FLAG-M4LICI0US_USB_INF3CT3D_MY_CONES