NorthSec 2024 - Forensic Challenge (FR)
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
Un fichier PCAP contenant des données USB est fourni. Les protocoles utilisés sont USB et USBMS.
Pour filtrer uniquement les données utiles avec Wireshark, la condition suivante est appliquée :
_ws.col.info == "SCSI: Data In LUN: 0x00 (Read(10) Response Data) " && frame.len > 539
Cette méthode permet de se concentrer exclusivement sur les informations pertinentes pour la résolution du challenge.
Extraction
Lors de l'extraction, divers problèmes ont été rencontrés avec tshark, qui ne retournait aucune information. Pour contourner ce problème, un script Python a été élaboré pour parser le fichier PCAP.
Le script est le suivant :
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()
L'objectif de ce script est d'extraire les données au format hexadecimal dans un range specifiés en parametres.
Analysis
Avec Wireshark, il est possible de commencer à examiner les fichiers qui transitent en analysant les données capturées.
Disque NTFS
Composant Systeme NTFS
En explorant plus en détail, plusieurs composants du système NTFS sont identifiés, tels que :
- $MFT
- $MftMirr
- $LogFile
Parmi les fichiers détectés, certains sont de type PE et d'autres sont des fichiers texte.
Types de fichiers :
- PE (Portable Executable)
- Texte
L'objectif est de récupérer les fichiers qui peuvent fournir des indications cruciales pour résoudre le challenge. Lors du parcours du pcap, il y'a une trame avec du texte.
Pour ce faire, l'outil précédemment mentionné est utilisé pour extraire les données pertinentes.
python3 extract.py eyes_infection.pcapng 770
On peut y voir un fichier texte avec la donnée suivante :
On peut donc se dire qu'il y'a donc des fichiers binaires qui transitent.
En regardant les trames, on voit bien qu'un fichier binaire transite. On le constate avec le header MZ
L'examen des données montre qu'un fichier binaire transite, permettant une mise à jour du système.
Extraction des fichiers binaires :
La commande binwalk montre la structure des fichiers contenus dans l'extraction. Voici un exemple d'utilisation de dd
pour extraire les fichiers identifiés :
Un des fichiers extraits est un fichier .NET Assembly. Pour analyser ce fichier, j'utilise 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...");
}
}
Lors de l'analyse du code extrait, il a été observé que celui-ci déchiffre une chaîne XORée en utilisant le sha512 du nom de la clé USB sur laquelle le fichier exécutable est exécuté. Pour récupérer ce nom, il est nécessaire de récupérer les structures système telles que $VolumeInformation
échangées pendant la capture.
Identification de la Clé USB
Ces structures système ont été échangées à la trame 434.
L'analyse de cette trame révèle que la clé USB a le label suivant :
EYELIDS-FIX-v.47.4f.41.54.53
Script C# pour la Solution du Challenge
Un script en C# a été développé pour résoudre le challenge en déchiffrant la chaîne XORée. Voici le script :
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);
}
}
}
Résolution du Challenge et Obtention du Flag
Suite à l'analyse du code extrait et à la détection du label de la clé USB, la chaîne XORée a été déchiffrée. Le flag obtenu est :
FLAG-M4LICI0US_USB_INF3CT3D_MY_CONES