
Entschlüsseln und extrahieren Sie FortiOS 8.0.0-Firmware-Images.
Entschlüsselt und extrahiert FortiOS 8.0.0 Firmware-Images.
Dieses Skript erweitert Bishop Fox's Forticrack um Unterstützung für 8.0.0-Firmware-Images. Außerdem war RandoriSecs Artikel zur FortiGate 7.4.7 Firmware-Verschlüsselung sehr hilfreich, um die Verschlüsselung für FortiOS 8.0.0 umzukehren, da sie wie eine neuere Iteration der 7.4.7-Variante aussieht.
Funktioniert sowohl für FGT- als auch für FFW-Images.
Dies wurde sowohl auf FGT- als auch auf FFW- v8.0.0.F-build0167 getestet. Andere Builds erfordern möglicherweise erneutes Reversing des Kernels, um die genauen Kernel-Segmente und virtuellen Adressen des RSA-öffentlichen Schlüssels und des XOR-Schlüssels zu finden.
Das Skript versucht, automatisch zu erkennen, ob die .out-Datei zu FGT oder FFW gehört, basierend auf der Benennung. Es kann auch als optionales Argument angegeben werden, falls nötig.
$ python3 forticrack_v8.py
[x] Usage: python3 forticrack_v8.py <.out datei> [FGT|FFW]
Demo:

Ergebnisverzeichnis:

Es gibt bereits zahlreiche Artikel und Skripte zur FortiOS-Entschlüsselung (wie die zuvor erwähnten). Jedoch trifft keiner auf FortiOS 8.0.0 zu, da Fortinet die Verschlüsselung erneut geändert hat.
Fortinet ermöglicht das Herunterladen von Upgrade-Images sowohl für FortiFirewall als auch für FortiGate unter https://support.fortinet.com/ > Login > Support > VM Images. Diese Images sind .out-Dateien, die dieses Skript als Eingabe erwartet. Bei der Ausführung führt es vier Hauptoperationen durch:
.out-Datei (Bishop Foxs Arbeit)Die .out-Upgrade-Datei ist mit einer benutzerdefinierten XOR-basierten Blockverschlüsselung verschlüsselt. Bishop Fox hat sie reverse-engineered und forticrack zusammen mit einer großartigen Beschreibung veröffentlicht. Dieser Teil des Skripts verwendet praktisch denselben Code wie das originale forticrack von Bishop Fox, der den entsprechenden 32-Byte-Schlüssel extrahiert und die .out-Datei entschlüsselt. Ich empfehle, die Beschreibung zu lesen, wenn Sie mehr darüber erfahren möchten.
Die entschlüsselte Datei ist ein Standard-Fortinet-Firmware-Image. Das Skript extrahiert es mit binwalk und erzeugt das folgende Dateisystem:
ext-root
├── boot
│ ├── cert.der
│ └── grub
│ ├── BOOTX64.EFI
│ ├── grub.cfg
│ └── grubx64.efi
├── boot.msg
├── datafs.tar.gz
├── datafs.tar.gz.bak
├── datafs.tar.gz.chk
├── datafs.tar.gz.chk.bak
├── extlinux.conf
├── filechecksum
├── flatkc
├── flatkc.chk
├── flatkc.sig
├── hash_bin.sha256
├── ldlinux.c32
├── ldlinux.sys
├── rootfs.gz
└── rootfs.gz.chk
Wobei:
boot/ : Verzeichnis mit Bootloader-Dateiendatafs.tar.gz : Daten-Dateisystemflatkc : Linux-Kernel-Bild (bzImage)rootfs.gz : Verschlüsseltes DateisystemAlle für Sicherheitsforscher interessanten Dateien, wie z.B. /sbin/init, sind innerhalb von rootfs.gz verschlüsselt.
rootfs.gz (der neuartige Teil)Dies ist der Teil, der für Version 8.0.0 neu ist. Um dies herauszufinden, wurde Claude Code intensiv genutzt, um die entsprechende Entschlüsselungslogik umzukehren und die hartcodierten virtuellen Adressen im Kernel-Image zu finden, unter Bezugnahme auf RandoriSecs Artikel zu FortiGate 7.4.7. Meiner Erfahrung nach glänzt KI-unterstütztes Reversing wirklich bei der Analyse von Kryptografie-Material, was früher eine klassische Hardcore-Aufgabe war, als manuelles Reversing die einzige Option war.
Die Datei rootfs.gz ist mit einer benutzerdefinierten Stromchiffre namens FORT-RC4 verschlüsselt. Der Schlüssel zur Entschlüsselung ist in einer PKCS#1-RSA-Signatur eingebettet, die am Ende der Datei angehängt ist. Um diese Signatur zu entschlüsseln, muss der entsprechende RSA-öffentliche Schlüssel verwendet werden, der aus dem Kernel-Image gewonnen werden kann.
Da flatkc ein bzImage ist, kann das Kernel-ELF leicht extrahiert werden, indem die gzip-Nutzlast darin lokalisiert und dekomprimiert wird. Innerhalb des ELF, an der virtuellen Adresse 0xffffffff8179a1a0, befinden sich 270 Bytes XOR-codierte DER-Daten, die den RSA-öffentlichen Schlüssel repräsentieren. Der 32-Byte-XOR-Schlüssel zur Decodierung befindet sich bei 0xffffffff8179a2c0. Die Decodierung erfolgt einfach als decoded[i] = encoded[i] ^ xor_key[i & 0x1f], und das Ergebnis analysiert als eine standardmäßige PKCS#1-RSAPublicKey-DER-Struktur (ein RSA-2048-öffentlicher Schlüssel).
Nachdem der RSA-öffentliche Schlüssel wiederhergestellt wurde, wird der Signaturblock (die letzten 256 Bytes von rootfs.gz) entschlüsselt, indem m = sig^e mod n berechnet wird. Das 256-Byte-Ergebnis ist eine PKCS#1 v1.5 Typ 1 gepolsterte Nachricht mit folgendem Layout:
m[0x00] = 0x00
m[0x01] = 0x01
m[0x02..0x9E] = 0xFF (157 Padding-Bytes)
m[0x9F] = 0x00
m[0xA0..0xBF] = SHA256(rootfs.gz[:-256])
m[0xC0..0xDF] = (unbenutzt)
m[0xE0..0xFF] = RC4-Schlüssel (32 Bytes)
Der SHA-256-Hash wird gegen den Hauptteil von rootfs.gz als Sicherheitsprüfung verifiziert, und der 32-Byte-RC4-Schlüssel am Ende ist das, was tatsächlich zum Entschlüsseln der Datei verwendet wird.
Bezüglich FORT-RC4 wurde es komplett vibe-reversed von Claude. So funktioniert es:
FORT-RC4 hat eine standardmäßige KSA, aber eine modifizierte PRGA: Anstatt ein Keystream-Byte pro Runde aus einer einzigen S-Box-Abfrage zu erzeugen, führt es zwei zusätzliche Abfragen mit bit-gemischten Versionen von
iundjdurch, XORiert0xAAin einen Mix-Index und kombiniert zwei S-Box-Werte, um das endgültige Byte zu erzeugen. Es gibt auch einen Unterschied zwischen FGT und FFW: Bei FGT werden sowohlials auchjnach der KSA auf 0 zurückgesetzt, bevor die PRGA startet, während bei FFWjvon der KSA übernommen wird. Dies ist im FGT-Kernel bei Offset+0x83innerhalb der Chiffrierfunktion als Byte-Sequenz31 c0 31 d2(xor eax,eax; xor edx,edx) sichtbar, die in FFW fehlt. Aus diesem Grund muss das Skript die Variante kennen.
Wie erwähnt, war RandoriSecs Artikel zu 7.4.7 eine nützliche Referenz, aber der Verschlüsselungsmechanismus änderte sich ausreichend, so dass ihr Ansatz nicht direkt auf 8.0.0 anwendbar war. Dies sind die Hauptunterschiede:
.init.data-Kernel-Abschnitt verschleiert. Bei 8.0.0 ist dieser Abschnitt voller Nullen, daher wird stattdessen ein einfaches XOR-Schema verwendet.rootfs mit AES-CTR verschlüsselt. Bei 8.0.0 ist es FORT-RC4 (ein benutzerdefinierter Verschlüsselungsalgorithmus).rsa_parse_pub_key lokalisiert werden kann. Der 8.0.0-Kernel ist gestrippt, daher mussten die virtuellen Adressen durch direktes Reversing der Entschlüsselungsroutine gefunden werden.Die virtuellen Adressen für den RSA-Key-Blob liegen nahe beieinander zwischen den Versionen (verschoben um 0x3000), was auch beim Reversing half.
Die entschlüsselte Ausgabe ist eine echte gzip-Datei. Durch Dekomprimieren wird ein CPIO-Archiv erhalten, das das Standard-Linux-initrd-Format ist und einfach mit cpio -idmv extrahiert werden kann.