
Décrypter et extraire les images du firmware FortiOS 8.0.0.
Déchiffrer et extraire les images du firmware FortiOS 8.0.0.
Ce script étend Bishop Fox's Forticrack pour prendre en charge les images du firmware 8.0.0. De plus, l'article de RandoriSec sur le chiffrement du firmware FortiGate 7.4.7 a été très utile pour inverser le chiffrement de FortiOS 8.0.0, car il ressemble à une itération plus récente de celui du 7.4.7.
Fonctionne pour les images FGT et FFW.
Ceci a été testé sur les versions FGT et FFW v8.0.0.F-build0167. D'autres versions pourraient nécessiter de nouveau inverser le noyau pour trouver les segments exacts du noyau et les adresses virtuelles de la clé publique RSA et de la clé XOR.
Le script tente de détecter automatiquement si le fichier .out correspond à FGT ou FFW en fonction du nom. Il peut également être spécifié comme argument optionnel au cas où.
$ python3 forticrack_v8.py
[x] Usage: python3 forticrack_v8.py <.out file> [FGT|FFW]
Démo:

Répertoire résultant:

Il existe déjà de nombreux articles et scripts sur le déchiffrement de fortiOS (comme ceux mentionnés précédemment). Cependant, aucun d'entre eux ne s'applique à FortiOS 8.0.0, car Fortinet a modifié son chiffrement une fois de plus.
Fortinet permet de télécharger des images de mise à niveau pour FortiFirewall et FortiGate à l'adresse https://support.fortinet.com/ > Connexion > Support > Images VM. Ces images sont des fichiers .out, c'est ce que ce script attend en entrée. Une fois exécuté, il effectue 4 opérations principales :
.out (travail de Bishop Fox)Le fichier de mise à niveau .out est chiffré avec un chiffrement par blocs XOR personnalisé. Bishop Fox l'a rétro-ingénieré et a publié forticrack avec un excellent article. Cette partie du script utilise pratiquement le même code que le forticrack original de Bishop Fox, qui extrait la clé de 32 octets correspondante et déchiffre le fichier .out. Je vous suggère de lire l'article si vous voulez en savoir plus.
Le fichier déchiffré est une image de firmware Fortinet standard. Le script l'extrait en utilisant binwalk, produisant le système de fichiers suivant :
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
Où :
boot/ : Répertoire contenant les fichiers du chargeur d'amorçagedatafs.tar.gz : Système de fichiers de donnéesflatkc : Noyau Linux bzImagerootfs.gz : Système de fichiers chiffréTous les fichiers intéressants pour les chercheurs en vulnérabilités, tels que /sbin/init, sont chiffrés dans rootfs.gz.
rootfs.gz (la partie nouvelle)C'est la partie qui est nouvelle pour la version 8.0.0. Pour la comprendre, Claude Code a été largement utilisé pour inverser la logique de déchiffrement correspondante et obtenir les adresses virtuelles codées en dur dans l'image du noyau, en prenant l'article de RandoriSec sur FortiGate 7.4.7 comme référence. D'après mon expérience, le rétro-ingénierie assistée par IA brille vraiment lorsqu'il s'agit d'analyser des sujets cryptographiques, ce qui était une tâche ardue quand seul le rétro-ingénierie manuel était possible.
Le fichier rootfs.gz est chiffré avec un chiffrement de flux personnalisé appelé FORT-RC4. La clé pour le déchiffrer est intégrée à l'intérieur d'une signature RSA PKCS#1 ajoutée à la fin du fichier. Pour déchiffrer cette signature, la clé publique RSA correspondante doit être utilisée, qui peut être récupérée à partir de l'image du noyau.
Puisque flatkc est un bzImage, l'ELF du noyau peut être facilement extrait en localisant la charge utile gzip à l'intérieur et en la décompressant. À l'intérieur de l'ELF, à l'adresse virtuelle 0xffffffff8179a1a0, se trouvent 270 octets de données DER encodées en XOR représentant la clé publique RSA. La clé XOR de 32 octets pour la décoder se trouve à 0xffffffff8179a2c0. Le décodage est simplement decoded[i] = encoded[i] ^ xor_key[i & 0x1f], et le résultat s'analyse comme une structure DER standard PKCS#1 RSAPublicKey (une clé publique RSA-2048).
Une fois la clé publique RSA récupérée, le bloc de signature (les derniers 256 octets de rootfs.gz) est déchiffré en calculant m = sig^e mod n. Le résultat de 256 octets est un message rembourré PKCS#1 v1.5 de type 1 avec la disposition suivante :
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] = (unused)
m[0xE0..0xFF] = RC4 key (32 bytes)
Le hachage SHA-256 est vérifié par rapport au corps de rootfs.gz comme test de cohérence, et la clé RC4 de 32 octets à la fin est ce qui est réellement utilisé pour déchiffrer le fichier.
Concernant FORT-RC4, il a été complètement vibe-reversed par Claude. Voici comment il fonctionne :
FORT-RC4 a un KSA standard mais un PRGA modifié : au lieu de produire un octet de flux de clé par tour à partir d'une seule recherche dans la boîte S, il effectue deux recherches supplémentaires utilisant des versions mélangées au niveau des bits de
ietj, XOR0xAAdans un index de mélange, et combine deux valeurs de la boîte S pour produire l'octet final. Il y a aussi une différence entre FGT et FFW : dans FGT,ietjsont tous deux réinitialisés à 0 après le KSA avant le début du PRGA, tandis que dans FFW,jcontinue à partir du KSA. Cela est visible dans le noyau FGT au décalage+0x83dans la fonction de chiffrement comme la séquence d'octets31 c0 31 d2(xor eax,eax; xor edx,edx), qui est absente dans FFW. C'est pourquoi le script a besoin de connaître la variante.
Comme mentionné, l'article de RandoriSec sur le 7.4.7 était une référence utile, mais le mécanisme de chiffrement a suffisamment changé pour que leur approche ne s'applique pas directement au 8.0.0, voici donc les principales différences :
.init.data du noyau. Dans le 8.0.0, cette section est entièrement composée de zéros, donc un simple schéma XOR est utilisé à la place.rootfs est chiffré avec AES-CTR. Dans le 8.0.0, c'est FORT-RC4 (un algorithme de chiffrement personnalisé).rsa_parse_pub_key. Le noyau 8.0.0 est dépouillé, donc les adresses virtuelles ont dû être trouvées en inversant la routine de déchiffrement directement.Les adresses virtuelles pour le blob de la clé RSA sont proches entre les versions (décalées de 0x3000), ce qui a également aidé lors du rétro-ingénierie.
La sortie déchiffrée est un véritable fichier gzip. En le décompressant, on obtient une archive CPIO, qui est le format standard Linux initrd et peut être facilement extraite avec cpio -idmv.