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:
- $MFT
- $MftMirr
- $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