Hodžův blog

29 Kvě

Když „neobnovitelná“ data obnovíte za jedno odpoledne

Každý bezpečnostní analytik zná ten pocit.

Zazvoní telefon, zákazník hlásí problém a během několika minut sedíte na vzdálené ploše serveru, o kterém jste ještě před hodinou netušili, že existuje.

Tentokrát šlo o starý Windows file server. Během několika minut z něj zmizelo přibližně 15 GB dat. Několik tisíc souborů bylo pryč a nikdo netušil proč.

Na první pohled to nevypadalo jako ransomware. Spíš jako klasický lidský faktor. Jenže bezpečnostní incidenty mají jednu nepříjemnou vlastnost – často nejsou tím, čím se na první pohled zdají být.

Rozhodl jsem se proto nepodceňovat situaci a začal jsem vyšetřovat.

Na serveru nebyl aktivní Windows File Auditing. V době incidentu bylo připojeno větší množství uživatelů. A zákazník ještě neměl nasazený NetFlow kolektor.

První hodina investigace tak nepřinesla prakticky nic.

A právě tehdy se případ začal stávat zajímavým.

Složka, která mi zkazila večer

Na serveru běžel Bitdefender BEST.

– Incident Sensor mlčel.
– Karanténa byla prázdná.
– EDR nikde neukazoval nic podezřelého.

Procházel jsem jeden log za druhým a postupně si odškrtával všechny slepé uličky.

– Žádný audit.
– Žádná použitelná telemetrie.
– Žádný incident.

Pak jsem si všiml jedné složky.

C:\Program Files\Bitdefender\Endpoint Security\cryptoStorage

Název byl natolik výmluvný, že jsem na chvíli přestal scrollovat.

Otevřel jsem ji.

A v tu chvíli jsem věděl, že ten večer neskončím v rozumnou hodinu.

Adresář obsahoval velké množství souborů vytvořených přesně v době incidentu.

To samo o sobě ještě nemuselo nic znamenat.

Jenže vedle nich ležel soubor crypt.db.

První stopa

Po otevření se ukázalo, že jde o obyčejnou SQLite databázi.

Obsahovala metadata uložených objektů včetně původních cest, velikostí, hashů, SID identifikátorů a dalších atributů.

Po několika SQL dotazech začala vystupovat zajímavá korelace.

Objekty uložené v CryptoStorage odpovídaly konkrétním souborům, které během incidentu zmizely.

A nejen to.

Jejich velikosti byly identické.

To už nebyla náhoda.

Pokud Bitdefender uchovává metadata a zároveň má uložený obsah souborů, proč by neměla existovat možnost jejich obnovy?

Telefonát s podporou

Rozhodl jsem se nehádat s implementací a zeptat se přímo výrobce.

Na Bitdefenderu jsem založil tiket.

Musím říct, že zkušenost s technickou podporou byla velmi příjemná. Diagnostická data se přenesla jediným kliknutím z GravityZone portálu a celý proces fungoval překvapivě hladce.

O něco později přišlo vyjádření antimalware týmu.

– Nešlo o ransomware.
– Nešlo o malware.
– Nešlo o kompromitaci serveru.

To byla dobrá zpráva.

Bez zaznamenané detekce v době incidentu momentálně neexistuje podporovaný způsob ani nástroj, jak tyto soubory obnovit.

Zavřel jsem tiket.
Pak jsem se podíval na monitor.
Pak znovu na tiket.
A pak zase na monitor.

Protože ve vedlejším okně jsem měl otevřený adresář obsahující několik gigabajtů dat, která podle všeho nešlo obnovit.

Druhý den ráno

Kdo někdy dělal reverzní inženýrství ví, že existují problémy, které člověku nedají spát.

Tohle byl přesně jeden z nich.

Druhý den ráno jsem si udělal kafe, otevřel Ghidru a rozhodl se zjistit, jak CryptoStorage skutečně funguje.

Moje původní hypotéza byla poměrně jednoduchá.

Bitdefender uloží soubor -> zašifruje jej -> klíč uloží do databáze nebo jiného interního úložiště -> při obnově provede opačný proces.

Pokud by tomu tak bylo, potřeboval bych najít použitý algoritmus, způsob práce s klíči, inicializační vektor a formát uložených dat.

Jenže žádný klíč se neobjevoval.

Forenzní analýza .bdf souborů


crypt.db
DOC200126-20012026081723.pdf
f6698329ed296fd9f4f0bd76022fba4a.bdf

První kontrola byla čistě forenzní.


PDF size: 3904919 bytes
BDF size: 3904919 bytes

– Velikosti byly identické.
– Bez headeru.
– Bez paddingu.
– Bez jakékoliv režie.

Pak jsem si všiml další zajímavosti.

MD5 hash původního PDF byl:

f6698329ed296fd9f4f0bd76022fba4a

A přesně stejnou hodnotu nesl název .bdf souboru.

To byl první okamžik, kdy jsem začal mít pocit, že jsem blíž pravdě, než jsem si původně myslel.

Když přestane fungovat databáze

Než jsem otevřel disassembler, provedl jsem několik základních kryptoanalytických testů.

Na první pohled vše připomínalo proudovou šifru.

Jenže žádný z běžných scénářů neseděl.

– opakující se XOR klíč
– XOR proti MD5 hashi
– GUID hodnoty z databáze
– analýza opakujících se bloků

Nic.

Všechno vedlo do slepé uličky.

To bývá okamžik, kdy se z forenzní analýzy stává archeologie. Přestanete hledat odpovědi v datech a začnete je hledat v hlavách vývojářů.

Ghidra nelže


DataStorage::AddFile
DataStorage::RestoreBuffer
DataStorage::_InsertDataStorageItemInDatabase
DataStorage::_RunInsertRefQuery

Workflow začalo postupně dávat smysl:


soubor -> .bdtf -> SQLite metadata -> .bdf

Nakonec jsem skončil ve funkci DataStorage::AddFile.

Po několika hodinách dekompilace jsem byl připravený na AES.
Možná Blowfish.
Možná nějakou proprietární šílenost.

Rozhodně jsem nebyl připravený na to, co jsem našel.

Nejkratší „šifrovací algoritmus“, jaký jsem za poslední dobu viděl


buffer[i] = (bVar6 ^ buffer[i]) + cVar11;

bVar6 = bVar6 + 3;
cVar11 = cVar11 + 0x14;

Chvíli jsem si myslel, že jsem něco přehlédl.

Pak jsem funkci přečetl znovu.
Pak potřetí.
Pak jsem si otevřel assembler.

A pak mi došlo, že se právě dívám na celý transformační algoritmus.

– žádný AES.
– žádný klíč.
– žádný IV.
– žádná key derivation.

Pouze XOR a modulární sčítání.
Opakovaně.
Po blocích 64 kB.

Decryptor


def decrypt_chunk(data: bytes) -> bytes:
    out = bytearray(len(data))

    for i, value in enumerate(data):
        xor_key = (0x19 + 3 * i) & 0xFF
        add_key = (0x2B + 0x14 * i) & 0xFF

        out[i] = ((value - add_key) & 0xFF) ^ xor_key

    return bytes(out)

Když jsem decryptor poprvé spustil, přišel okamžik pravdy.


decrypted MD5:
F6698329ED296FD9F4F0BD76022FBA4A

original MD5:
F6698329ED296FD9F4F0BD76022FBA4A

Hash byl identický.

Obnovený dokument byl bajtově přesnou kopií originálu.

Co si z toho odnést

Nejdůležitější závěr celé analýzy není technický detail transformační funkce.

Je to připomínka, že mezi pojmy:

– uložená data
– obfuskovaná data
– kryptograficky chráněná data

existuje zásadní rozdíl.

Z pohledu uživatele mohou všechny tři varianty vypadat stejně.

Z pohledu reverzního inženýra jde ale o tři úplně odlišné světy.

Původním cílem nebylo reverzovat Bitdefender. Cílem bylo zachránit data zákazníka po bezpečnostním incidentu.

Nakonec se ukázalo, že odpověď neleží v databázi crypt.db, ale několik vrstev hlouběji v implementaci DataStorage::AddFile.

A někdy stačí jedno odpoledne, několik šálků kávy a trochu zvědavosti, aby se z „neobnovitelných“ dat stal běžný PDF soubor otevřený v Adobe Readeru.

Leave a Reply

Hodžův blog is is proudly powered by Wordpress and the Magellan Theme