Cheia AES-256 din PDF-uri: doar 9 biți de aleatorietate
Cum funcționează criptarea PDF?
Am descoperit că mai multe implementări PDF generează cheile de fișier AES-256 din spații de stat suficient de mici pentru a fi enumerate. În MuPDF, doar 9 biți aleatorii afectează cheia reală AES-256.
Știri de Ultimă Oră
Cutremur la Rapid după eșecul cu FCSB: Revoluție totală în lot pentru iarnă!
Concurs de pescuit cu artificii pe malul Prutului: „Natura nu suferă de câteva bețe în baltă
Datele a peste 41.000 de agenți americani, expuse pe internet: O nouă breșă uriașă de securitate la Washington
Spania, în doliu și revoltă: 68 de morți în tragedia feroviară de lângă UrdaAlți editori PDF, cum ar fi Foxit, bazează cheia AES-256 pe șansa bazată pe timp și, prin urmare, duc la cheie care sunt triviale de recuperat.
Criptarea PDF protejează corziile și fluxurile de date dintr-un document PDF, inclusiv metadatele, cu excepția cazului în care este lăsată în mod explicit necriptată. Mecanismul de protecție a parolului a trecut printr-o grămadă de revizii de-a lungul anilor, trecând de la RC4 la AES și întărind hashing-ul parolului împotriva atacurilor brute force.
Versiunea actuală, revizuire 6, utilizează AES-256. Când un PDF este criptat cu AES-256, parola nu criptă documentul direct. Implementarea generează o cheie de fișier aleatoriu de 32 de biți, care criptă conținutul.
Parola și o sare sunt apoi hashate pentru a obține o cheie separată, care criptă această cheie de fișier aleatoriu de 32 de biți. Reviziunea 6 încetinește în mod deliberat acest hashing; versiunea 5 mai veche AES-256 nu. Un PDF poate avea o parolă de utilizator pentru vizualizare și o parolă de proprietar pentru modificarea permisiunilor.
De ce e vulnerabil generatorul aleatoriu?
Ori desblochează aceeași cheie de fișier, astfel încât restricțiile depind de cititor: cu parola de vizualizare, puteți face și o copie nelimitată.
Am descoperit că această aleatorietate este adesea generată foarte nesigur, permițând decriptarea fără parola a fișierelor PDF protejate.
Versiunile MuPDF înainte de 1.28.5 folosesc o implementare a familiei drand48 pentru a genera numere aleatorii.
Acest generator este semănat o dată, folosind epoca actuală în secunde: generatorul este un generator congruențial liniar de 48 de biți: fz_srand48() scrie starea ca trei cuvinte de 16 biți.
Cuvântul scăzut este constanta 0x330e, iar timestampul de 32 de biți ocupă state bits 16 până la 47: Când MuPDF trebuie să genereze o cheie, ea cheamă fz_memrnd (), care va lua în mod repetat un număr aleatoriu, pasul generatorul de numere aleatoriu înainte, și apoi folosește cel mai mic byte al acestui număr aleatoriu ca un byte aleatoriu.
Cum se exploatează Foxit?
Schimbul arunca biturile de stat 0-16 și aruncarea la car nesignată arunca tot ce este deasupra bitului 24.
Prin urmare, fiecare byte de ieșire provine de la biturile 17 la 24 din starea LCG.
Problema este că biturile mai înalte ale statului nu afectează niciodată biturile inferioare. Multiplicarea și adăugarea pot duce biturile în sus, dar nu în jos.
Deoarece fiecare byte de ieșire vine de la 17 la 24 de bits, orice mai mare de 24 de bits poate fi ignorat, chiar și după trecerea generatorului înainte.
Asta lasă 25 de bits care pot afecta ieșirea. 16 de jos sunt întotdeauna inițializate la 0x330e, așa că doar nouă bilete de la materia de timestamp.
Stampele de timp diferite cu 512 de secunde produc exact același flux de byte.
De unde provine această derivare de cheie?
Deoarece spațiul de cheie posibil este atât de mic, putem doar forța brută acest lucru prin generarea tuturor cheilor posibile de 32 de biți și test de decriptare: MuPDF folosește același generator pentru documentul /ID, care este stocat în remorcare în text simplu. Atunci când scrie un nou document, acesta va trage mai întâi 32 de bați din același LCG și apoi să prezinte imediat cheia de decriptare după aceea, astfel încât /ID poate fi utilizat ca verificare suplimentară.
Căutarea tuturor 512 de fluxuri într-o implementare Python foarte neoptimizată folosind forța brută pură durează aproximativ 11 milliseconde. Pe un document de testare: Cheia decriptă documentul fără nici o parolă.
Foxit PDF Reader 2026.1.3.36551 derivă cheia fișierului ca un hash al timestampului actual, 32 de bați neiniționați și o constantă. În practică, aceste byte neinițiate sunt zero pline și nu adaugă nici o aleatorietate. Sau ca un snippet Python echivalent: Blocul de permisiuni /Perms conține text simplu cunoscut, astfel încât verificarea candidatului este un hash și un bloc AES de decriptare, fără hashing de parolă și decriptare a documentelor: Implementarea noastră Rust caută timestamps în jos de la timpul actual, folosind Rayon pentru multithreading.
Pe un Ryzen 9 7950X cu 32 de fire, acesta susține 370 până la 376 de milioane de timestamps pe secundă: a doua linie acoperă fiecare timestamp din 1970 până în prezent.
În practică, pentru un document care a fost generat relativ recent, acest lucru va fi în ordinea de milisecunde.