
Расшифровка и извлечение образов прошивки FortiOS 8.0.0.
Расшифровывайте и извлекайте образы прошивок FortiOS 8.0.0.
Этот скрипт расширяет Forticrack от Bishop Fox для поддержки образов прошивок 8.0.0. Кроме того, статья RandoriSec о шифровании прошивок FortiGate 7.4.7 очень помогла при реверсе шифрования для FortiOS 8.0.0, поскольку оно выглядит как более новая итерация версии 7.4.7.
Работает как с образами FGT, так и FFW.
Это было протестировано на FGT и FFW v8.0.0.F-build0167. Для других сборок может потребоваться повторный реверс ядра, чтобы найти точные сегменты ядра и виртуальные адреса открытого ключа RSA и XOR-ключа.
Скрипт пытается автоматически определить, соответствует ли файл .out образу FGT или FFW, по имени файла. На всякий случай это также можно указать в качестве необязательного аргумента.
$ python3 forticrack_v8.py
[x] Usage: python3 forticrack_v8.py <.out file> [FGT|FFW]
Демонстрация:

Результирующий каталог:

В сети уже есть множество статей и скриптов по расшифровке fortiOS (например, упомянутые выше). Однако ни один из них не применим к FortiOS 8.0.0, поскольку Fortinet вновь изменил своё шифрование.
Fortinet позволяет загружать образы обновлений как для FortiFirewall, так и для FortiGate по адресу https://support.fortinet.com/ > Login > Support > VM Images. Эти образы представляют собой файлы .out, которые скрипт и ожидает на входе. При выполнении он выполняет 4 основные операции:
.out (работа Bishop Fox)Файл обновления .out зашифрован с помощью специального блочного шифра на основе XOR. Bishop Fox провели его реверс-инжиниринг и опубликовали forticrack вместе с отличным разбором. В этой части скрипт использует практически тот же код из оригинального forticrack от Bishop Fox, который извлекает соответствующий 32-байтовый ключ и расшифровывает файл .out. Если хотите узнать больше, рекомендую прочитать этот разбор.
Расшифрованный файл — это стандартный образ прошивки Fortinet. Скрипт извлекает его с помощью binwalk, создавая следующую файловую структуру:
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
Где:
boot/ : Каталог с файлами загрузчикаdatafs.tar.gz : Файловая система данныхflatkc : Ядро Linux bzImagerootfs.gz : Зашифрованная файловая системаВсе интересующие исследователей уязвимостей файлы, такие как /sbin/init, зашифрованы внутри rootfs.gz.
rootfs.gz (новая часть)Эта часть является новой для версии 8.0.0. Чтобы в ней разобраться, активно использовался Claude Code для реверса соответствующей логики расшифровки и получения захардкоженных виртуальных адресов внутри образа ядра, при этом за основу была взята статья RandoriSec о FortiGate 7.4.7. По моему опыту, реверс-инжиниринг с помощью ИИ действительно хорош при анализе криптографии — что раньше было классической задачей повышенной сложности, когда единственным вариантом был ручной реверс.
Файл rootfs.gz зашифрован специальным потоковым шифром под названием FORT-RC4. Ключ для его расшифровки встроен в подпись PKCS#1 RSA, добавленную в конец файла. Чтобы расшифровать эту подпись, необходимо использовать соответствующий открытый ключ RSA, который можно восстановить из образа ядра.
Поскольку flatkc — это bzImage, ELF-образ ядра можно легко извлечь, найдя внутри gzip-нагрузку и распаковав её. Внутри ELF по виртуальному адресу 0xffffffff8179a1a0 находятся 270 байт XOR-закодированных данных DER, представляющих открытый ключ RSA. 32-байтовый XOR-ключ для их декодирования находится по адресу 0xffffffff8179a2c0. Декодирование — это просто decoded[i] = encoded[i] ^ xor_key[i & 0x1f], а результат разбирается как стандартная структура PKCS#1 RSAPublicKey DER (открытый ключ RSA-2048).
После восстановления открытого ключа RSA блок подписи (последние 256 байт rootfs.gz) расшифровывается вычислением m = sig^e mod n. Результат размером 256 байт представляет собой сообщение с заполнением PKCS#1 v1.5 Type 1 и следующей структурой:
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)
SHA-256 хеш проверяется по телу rootfs.gz в качестве контрольной проверки, а 32-байтовый RC4-ключ в конце — это то, что фактически используется для расшифровки файла.
Что касается FORT-RC4, он был полностью восстановлен по вайбу с помощью Claude. Вот как он работает:
FORT-RC4 имеет стандартный KSA, но модифицированный PRGA: вместо генерации одного байта ключевого потока за раунд из одного обращения к S-блоку, он выполняет два дополнительных обращения, используя побитово перемешанные версии
iиj, применяет XOR с0xAAк индексу смешивания и комбинирует два значения из S-блока для получения итогового байта. Также есть различие между FGT и FFW: в FGT иi, иjсбрасываются в 0 после KSA перед запуском PRGA, тогда как в FFWjсохраняет значение после KSA. Это видно в ядре FGT по смещению+0x83внутри функции шифрования как последовательность байт31 c0 31 d2(xor eax,eax; xor edx,edx), которая отсутствует в FFW. Именно поэтому скрипту нужно знать вариант.
Как уже упоминалось, статья RandoriSec о 7.4.7 была полезным справочным материалом, но механизм шифрования изменился настолько, что их подход нельзя было напрямую применить к 8.0.0. Вот основные отличия:
.init.data. В 8.0.0 эта секция полностью состоит из нулей, поэтому вместо этого используется простая XOR-схема.rootfs шифруется с помощью AES-CTR. В 8.0.0 — с помощью FORT-RC4 (специального алгоритма шифрования).rsa_parse_pub_key. Ядро 8.0.0 лишено символов, поэтому виртуальные адреса пришлось находить путём прямого реверса процедуры расшифровки.Виртуальные адреса блоба ключа RSA близки между версиями (сдвинуты на 0x3000), что тоже помогло при реверсе.
Расшифрованный результат — это настоящий gzip-файл. После его распаковки получается CPIO-архив, который является стандартным форматом Linux initrd и легко извлекается с помощью cpio -idmv.