Wright in den Schatten

Dies ist eine Geschichte über eine der Aufgaben, die wir für die CTFZone- Qualifikationsphase vorbereitet haben , die Ende November stattfand. Über den Qualifizierungsvorbereitungsprozess können Sie hier lesen .

Sie beginnen mit zwei Dateien: decrypt_flag.py und ntfs_volume.raw. Schauen wir uns das Skript an. Er öffnet eine Datei mit dem Namen key.bin und versucht dann mithilfe einer Schleife, aus jedem Offset in der Datei eine 34-Byte-Binärzeichenfolge zu ziehen, die dann als Eingabe für die PBKDF2-Funktion verwendet wird. Jeder zurückgegebene Schlüssel wird als XOR-Schlüssel verwendet, um die in den Code eingenähte verschlüsselte Zeichenfolge zu entschlüsseln. Wenn der entschlüsselte MD5-Hash mit dem vorgegebenen Wert in entschlüsselter Form übereinstimmt, verwendet das Skript die empfangenen Daten, um das Flag zu generieren und zu drucken.

Sie müssen also die Datei key.bin finden. Es ist unmöglich, einfach alle Offsets in der Bilddatei (ntfs_volume.raw) zu sortieren, da das Auffinden des Schlüssels zu langsam ist. Dies ist nach den Regeln nicht verboten, aber Sie haben sicherlich keine Zeit vor dem Ende der CTF.

Die Image-Datei enthält eine MBR-Partitionstabelle mit einer Partition. Sein Offset beträgt 2048 512-Byte-Sektoren und enthält das NTFS-Dateisystem, aber die Datei key.bin ist nicht vorhanden:

$ fls -o 2048 -r -p ntfs_volume.raw | grep -F key.bin | wc –l
0

NTFS speichert UTF-16LE-codierte Dateinamen. Lassen Sie uns versuchen, darin zu suchen!


Suchergebnisse für Dateidatensätze

Nachdem wir die Suchergebnisse untersucht haben, konzentrieren wir uns auf Dateidatensätze, die mit der FILE-Signatur beginnen [1]. Hier ist der einzige solche Eintrag:


Rekord gefunden

Das Ziel ist schon nah! Wir haben einen Dateidatensatz, aber wir brauchen Daten. In NTFS werden sie im Attribut $ DATA gespeichert, das resident oder nicht resident sein kann [2]. Für den Datensatz, den wir gefunden haben, beginnt dieses Attribut bei Offset 0 × 3AADD00 und zeigt nicht residente Daten an (dies bedeutet, dass Informationen außerhalb des Dateidatensatzes gespeichert werden).

Wo genau befinden sich die Daten der gewünschten Datei? Um diese Frage zu beantworten, müssen die sogenannten Mapping-Paare oder Datenläufe (Paare „Blocklänge - Blockoffset“) dekodiert werden [3]. Die Datenläufe der gewünschten Datei lauten wie folgt (beachten Sie den Versatz 0 × 3AADD40): 22 53 01 A0 4E 21 05 31 C1 11 38 30 00. Oder wenn wir sie neu anordnen:

1.	22 53 01 A0 4E
2.	21 05 31 C1
3.	11 38 30 00

Die Datei besteht aus drei Fragmenten, deren Größe 339 Cluster beträgt, und beginnt mit Cluster # 20128. Für unseren Code mit PBKDF2 ist dieses Snippet groß. Wie im Dateisystem-Header angegeben, beträgt die Größe eines Clusters 4096 Byte:

$ fsstat -o 2048 ntfs_volume.raw | grep 'Cluster Size'
Cluster Size: 4096


Werfen wir einen Blick auf die Daten für diesen Offset (in Bytes): 2048 * 512 + 20128 * 4096 = 83492864. Wir extrahieren hier eine signifikante Menge an Informationen (z. B. 128 Bytes), fügen sie in eine neue Datei ein, die wir key.bin nennen, führen Sie das Skript aus ... Nichts war erfolgreich.

Möglicherweise wurde die Datei nicht in der aktuellen, sondern in der vorherigen Version des Dateisystems (vorherige Formatierung) gespeichert. Vergessen Sie nicht, dass der Datensatz über die gelöschte Datei mit demselben Namen nicht angezeigt wurde. Wie groß war der Cluster zuvor? Suchen wir nach dem Dateisystem-Header mit der NTFS-Signatur [4]. Vielleicht haben wir Glück und finden wirklich den Header aus der vorherigen Formatierung.


Suchergebnisse für den Dateisystem-Header

Die erste und die letzte Position in den Ergebnissen beziehen sich auf das aktuelle Dateisystem, aber die dazwischen liegenden Dateisystem-Header scheinen zur vorherigen Formatierung zu gehören. Und sie haben eine andere Clustergröße!


Der Dateisystem-Header aus der vorherigen Version.

Eine solche Sektorgröße wird mit einem Versatz von 0 × 4554800B: 00 02 oder 512 geschrieben. Eine solche Clustergröße wird jedoch mit einem Versatz von 0 × 0x4554800D: F7 oder 247 aufgezeichnet.

Wir haben also die Clustergröße (in Bytes) bei uns 512 * 247 = 126464. Irgendein Unsinn! Wenn Sie dem NTFS-Parser [5] glauben, muss ein solcher Wert ein Vorzeichen haben und auf besondere Weise verarbeitet werden, sodass die tatsächliche Clustergröße (in Sektoren) 1 << - (- 9) = 512 beträgt. Oder in Bytes 512 * 512 = 262144 Klingt jetzt glaubwürdiger.

Die Daten beginnen hier bei diesem Offset (in Bytes):
2048 * 512 + 20128 * 262144 = 5277483008. Versuchen wir noch einmal, den gleichen Trick mit den dort gespeicherten Informationen zu machen ... Wieder ein Fehler! Was ist falsch? Wir haben CTF hier, es bedeutet "nicht so", dass alles sein kann.

Die Aufgabe, um die wir uns streiten, heißt In the Shadows. Möglicherweise hat dies etwas mit Schattenkopien des Volumes zu tun. Wir haben also eine Datei aus dem Dateisystem, die zuvor in diesem Volume vorhanden war. Leider können wir die Schattenkopie einfach nicht aufnehmen und mounten, aber wir kennen den genauen Versatz, bei dem die Daten beginnen! Dies ist 5277483008 oder innerhalb des Abschnitts 5277483008 - 2048 * 512 = 5276434432.

Gemäß den Spezifikationen des VSS-Formats [6] werden umgeleitete Datenblöcke in der Blockdeskriptorstruktur beschrieben, die ein 64-Bit-Feld enthält, in dem der ursprüngliche Offset (innerhalb des Volumes) gespeichert ist, und auch ein 64-Bit-Feld, das den Versatz des Zielblocks (innerhalb des Volumes) beschreibt. Suchen wir nach 5276434432 als 64-Bit-Little-Endian-Zahl.

Die Ergebnisse enthalten nur zwei Ergebnisse, von denen sich nur eines in einem gleichmäßigen Versatz befindet.


Gefundener Blockdeskriptor

Zielblockversatz: 00 00 9B 03 00 00 00 00 oder nur 60489728. Endgültiger Versatz: 60489728 + 2048 * 512 = 61538304. Exportieren Sie von hier aus eine bestimmte Datenmenge in eine neue Datei mit dem Namen key.bin und ...

$ ./decrypt_flag.py
ctfzone{my_c0ngr4t5_t0_u,w311_d0n3_31337}

Erledigt!

Verweise


  1. https://flatcap.org/linux-ntfs/ntfs/concepts/file_record.html
  2. https://flatcap.org/linux-ntfs/ntfs/attributes/data.html
  3. https://flatcap.org/linux-ntfs/ntfs/concepts/data_runs.html
  4. https://flatcap.org/linux-ntfs/ntfs/files/boot.html
  5. https://github.com/msuhanov/dfir_ntfs/blob/94bb46d6600153071b0c3c507ef37c42ad62110d/dfir_ntfs/BootSector.py#L58
  6. https://github.com/libyal/libvshadow/blob/master/documentation/Volume%20Shadow%20Snapshot%20(VSS)%20format.asciidoc#431-block-descriptor

Source: https://habr.com/ru/post/undefined/


All Articles