Zip бомба як працює. Що таке ZIP-бомби або як маленький архів може запросто «укласти» ваш комп'ютер

До образливого тихо і непомітно відбулася одна дуже цікава та важлива подія. Президент Росії Володимир Путін зустрівся і розмовляв з одним із керівників державної служби, ім'я якого нечасто потрапляє до преси. Ні, ця людина - не таємний агент, хоча за діяльністю він має доступ до секретної інформації, і навіть може вважатися своєрідним «бійцем невидимого фронту». Загалом Путін спілкувався з головою Федерального архівного агентства Андрієм Артизовим.

Розмова глави держави з главою агентства мала діловий характер, можливі наслідки якого здатні де-не-де викликати ефект бомби, що розірвалася, а дехто й детонацію персонального сопла.

Президент зробив неголосну заяву, що їм прийнято рішення про розсекречення багатьох архівних документів, причому указ буде підписано того ж дня. Крім того, Путін повідомив про передачу Росархіву у пряме підпорядкування президенту Росії, оскільки багато матеріалів відомства «представляють особливу цінність і мають світове значення».

Глава агентства у свою чергу інформував президента, що архівний фонд Росії зберігає 500 мільйонів справ і що «ніколи за останні десятиліття планова, організована робота з розсекречення не проводилася так, як вона проводиться зараз».

Ключовий момент - відразу після розсекречення архівні документи будуть доступні на офіційному сайті Росархіву, для чого вже створено спеціальну базу даних.

Серед уже розсекречених архівів – матеріали, на які давно облизувалися вітчизняні та зарубіжні історики: 1400 унікальних директив Сталіна, розпоряджень Ставки, фронтових наказів, оперативних карт, постанов та фотографій того часу, які ще недавно зберігалися в архівах під грифом «цілком таємно».

Можна лише щиро порадіти за істориків, побажати їм свіжих та цікавих праць, в основі яких лежатимуть вищезгадані документи, але тільки розсекречення торкнеться не єдиної військово-історичної тематики.

Джерело, близьке до Росархіву, повідомляє цікаві подробиці: «Мова, наскільки я знаю за інформацією з архівного відомства, йдеться про період з 1930 по 1989 роки. Там є справи, вибачте, стукачів – як і невинно репресованих, із дуже цікавими прізвищами. Там будуть дані про космічні та військові розробки, які вже можна повідомити. Крім того, розсекречуються дані про перебіг битв, накази та отриману розвідінформацію під час Великої Вітчизняної війни, так само, як і про міждержавні відносини в період війни холодної».

І дуже вагомо додає: «Деякі документи суспільство здивують. Власну історію треба знати, якою б вона не була».

Архіви мають довгу пам'ять і несуть у собі потенційний заряд не гірше за водневу бомбу. Не випадково в нашій країні досі продовжують залишатися засекреченими «справа маршалів» та «справа лікарів», які тривалий час створюють ґрунт для всіляких спекуляцій. Нещодавно у Великобританії спеціальна комісія розбиралася з архівними документами, чий термін секретності добігав кінця, але на дані про передвоєнні контакти британської розвідки з гітлерівською ЦД було вирішено продовжити режим секретності ще на 50 років.

Застереження про «деякі документи суспільство здивують» зроблено не випадково. Наприкінці 1980-х, як у Росії, так і в республіках колишнього СРСР, на хвилі «демократизації» до влади прийшли різні люди.

Багато хто виявляє вражаючу політичну живучість, незважаючи на явну відсутність управлінських талантів і схильність вчити народ демократії зі своєї точки зору.

У найближчому зарубіжжі колишні лідери «народних фронтів», які змінили світогляд з антирадянського на антиросійське, міцно прикипіли до влади та проводять недружню політику щодо Росії зі своєї території – від організації з'їздів усіляких позбавлененців із «Відкритої Росії» до навчання профашистських бойовиків та надання військової бандерівцям.

Європейській спільноті, як і громадянам цих лімітрофів, буде цікаво дізнатися із розсекречених документів Росархіву – хто із записників «євродемократів» перебував в інформаторах КДБ. Чутками про те, що в пору туманної юності в КДБ «стукали» колишній лідер НФ Литви Ландсбергіс та нинішня мадам президент Даля Грибаускайте – земля наповнюється. Тепер про цю сторону їхньої біографії, гадаю, можна буде дізнатися з першоджерела.

Судити про те, що «це було давно, і неправда», «бизлом поросло», можна скільки завгодно, але не варто недооцінювати забійну силу таких викриттів.

Можна згадати, як минулого року ефектно рвонув у польській пресі пакет документів, розкопаний Інститутом національної пам'яті, про співпрацю Леха Валенси (під оперативним погонялом «Болік») у розпал його діяльності на Гданській судноверфі. Інформаційний вибух не залишив каменя на камені від іміджу ікони, «поляка №1», лідера «Солідарності», лауреата Нобелівської премії миру та першого президента антирадянської Польщі. Відтепер і навіки Валенса – просто вусатий жирний старий, руїна минулої епохи, чию ганьбу можна побачити на власні очі у вигляді виставлених у тому самому Інституті національної пам'яті 17 розписок в отриманні грошей за передану спецслужбам стук-стук-інформацію.

Залишається лише шкодувати, що архівна «бомба» не рвонула під днищем агента «Болека» у 1980-х, коли він та його «Солідарність», що співалися із західними спецслужбами, розхитували соціалістичну Польщу.

Маса цікавих несподіванок може чатувати і на записників вітчизняних ліберальчиків. Їх звивистий життєвий шлях багато в чому схожий із шляхом Валенси до вершин влади. На превеликий жаль, у КДБ не поспішали з викриттям інформаторів, що перекувалися, з багатьох причин, серед яких етичні були не на останньому місці. Адже якщо розкриєш агента, особливо добровільного, то хто піде на співпрацю? На агентурі, спійманій при скоєнні непристойних вчинків і на цьому грунті завербованих, далеко не поїдеш.

У ЗМІ проривається неофіційна інформація про те, що «видні діячі ліберально-демократичного руху Росії» йшли на співпрацю з радянськими спецслужбами добровільно, зі шкурних спонукань: цікаві відрядження, просування кар'єрними сходами, престижна робота тощо.

Можна тільки уявити, якими гадючниками стукача були різні творчі об'єднання письменників, театральних діячів і кінематографістів.

У багатьох критиків СРСР та радянського ладу батьки були не просто видними партійними чи господарськими діячами, а й служили в органах НКВС-МДБ-КДБ, і навіть брали особисту участь у репресіях.

Звичайно, діти за батьків не відповідають, але на душі стає гидко, коли викривати і зривати покриви приймаються нащадки, що перефарбувалися, не бажають згадувати минуле своїх батьків, але колись без усяких докорів совісті скористалися їх високим становищем, як трампліном в персональне світле майбутнє.

Розсекречені архіви здатні вплинути на розміщення сил і в обандереній Україні. Можна згадати, як низка документів, опублікованих у соцмережах Мирославої Бердник ще до майданного путчу, що стосувалися співпраці ватажків ОУН із МДБ та МВС, викликали напади корчі та фонтани горлової діареї у шанувальників бандерівських умертв. Свідоміти сипали прокляття, обзивали фотокопії документів «ефесбешними фальшивками», але аргументовано нічого не могли заперечити.

Чому це важливо? Український радикальний націоналізм – зло без жодних застережень. Але його сповідують різні люди. Серед сучасних оунівців є свої ідеалісти, які бажають очистити український націоналізм від найбільш одіозних постатей Бандери та Шухевича, оскільки вони давно й безповоротно скомпрометували себе як гітлерівські маріонетки та карники. Як би там не було, але повоєнна радянська розвідка непогано розібралася в почуттях німецьких націоналістів, які чітко відокремлювали себе від гітлерівців і прихильників генерала Гелена, які легли під американців. Німецькі націоналісти, які вважали своїм кумиром Бісмарка, переживши жахи війни і бачачи те, як американці штовхають ФРН у нову війну з СРСР, вважали за краще працювати на радянську та східнонімецьку розвідки. Цей момент обов'язково варто врахувати.

З іншого боку, в Україні повно затятих і не страждаючих надлишком гидливості необандерівців, яких не лякають жодні документальні свідчення співпраці їхніх кумирів із гітлерівськими спецслужбами. А якщо буде опубліковано розсекречені документи, які говорять, що їхні ідоли, на кшталт Василя Кука, зливали МДБ інформацію на «побратимів», що сидять по схованках?

Якщо раптово виявиться, що всякі там правозатичники і незалежники пізньорадянського періоду постукували КДБ для пом'якшення режиму відсидки, за додаткову посилку сала з дому чи пачку махорки з табірної ларьки? Чи витримає подібне випробування на міцність переконань бандерівська «спільнота», яка бачить всюди довгу руку Москви, ФСБ і особисто Путіна?

Інформація подібного роду може викликати найпотужніший викид термоядерної плазми зі свідомих дуп, власники яких хизуються «національною чистотою» та «свідомістю». Когось викриття кумирів можуть змусити відсахнутися і одуматися.

Було б цікаво дізнатися і про подвійне життя ватажків самозваного «меджлісу», як і інших мерзопакостних діячів, що знемагають під самочинно взятим на себе тягарем «совісті нації».

Тож під чиїм персональним задом рветься перша архівна «бомба»? Хто піде «паровозом», що розмотує довгий ланцюг викриттів?

[Оновлення] Тепер я в якомусь списку спецслужб, бо написав статтю про якийсь вид «бомби», чи не так?

Якщо ви коли-небудь хостили веб-сайт або адміністрували сервер, то, напевно, добре знаєте про поганих людей, які намагаються зробити різні погані речі з вашою власністю.

Коли я у віці 13 років вперше заховав свою маленьку Linux-коробочку з доступом по SSH, я дивився логи і щодня бачив IP-адреси (в основному, з Китаю та Росії), які намагалися підключитися до моєї солоденької маленької коробочки (яка насправді справі була старим ноутом ThinkPad T21 зі зламаним дисплеєм, що дзижчало під ліжком). Я повідомляв ці IP їхнім провайдерам.

Насправді, якщо у вас Linux-сервер з відкритим SSH, то можете самі подивитися, скільки спроб підключень відбувається щодня:

Grep "authentication failures" /var/log/auth.log


Сотні невдалих спроб авторизації, хоча на сервері взагалі відключено авторизацію за паролем і він працює на нестандартному порту

Wordpress нас засудив

Гаразд, визнаємо, сканери веб-уразливостей існували і до Wordpress, але після того, як ця платформа стала настільки популярною, більшість сканерів почали перевіряти неправильно налаштовані папки wp-admin і непропатчені плагіни.

Так що якщо маленька хакерська банда хоче отримати трохи свіженьких обліків, вони скачають один з цих сканерських інструментів і нацькують його на купу веб-сайтів в надії отримати доступ до якого-небудь сайту і дефейснуть його.


Зразок логів під час сканування інструментом Nikto

Ось чому всі сервери та адміни веб-сайтів мають справу з гігабайтами логів, повними спроб сканування. Тож я подумав…

Чи можна завдати удару у відповідь?

Після експериментів з можливістю потенційного застосування IDS або Fail2ban я згадав про старі добрі ZIP-бомби з минулого.

Що за штука така – ZIP-бомба?

Як з'ясувалося, стиснення ZIP чудово справляється з даними, що повторюються, так що якщо у вас є гігантський текстовий файл, заповнений повторюваними даними на зразок всіх нулів, він дуже добре стиснеться. У сенсі, ДУЖЕ добре.

Як показав 42.zip, можна стиснути 4,5 петабайта (4 500 000 гігабайт) у 42 кілобайти. Коли ви спробуєте подивитися вміст архіву (витягти або розархівувати його), то у вас, ймовірно, буде витрачено весь дисковий простір або оперативна пам'ять.

Як скинути ZIP-бомбу на сканер уразливостей?

На жаль, веб-браузери не розуміють ZIP, але вони розуміють GZIP.

Так що насамперед створимо 10-гігібайтний файл GZIP, заповнений нулями. Можна зробити багато вкладених стисків, але почнемо з простого.

Dd if = / dev / zero bs = 1M count = 10240 | gzip > 10G.gzip


Створення бомби та перевірка її розміру

Як бачите, її обсяг 10 МБ. Можна було стиснути і краще, але поки що вистачить.

Тепер встановимо PHP-скрипт, який доставить її клієнту.

Готово!

Тепер ми можемо використовувати її як простий захист:

Очевидно, цей скрипт не є взірцем елегантності, але він може захистити нас від скрипт-кідді, згаданих раніше, які взагалі поняття не мають, що в сканерах можна змінювати user-agent.

Отже… Що буде, коли запустити цей скрипт?


(якщо ви перевіряли бомбу на інших пристроях/браузерах/скриптах, будь ласка,

У статті згадується 9 шарів zip файлів, тому це не простий випадок скріплення купою нулів. Чому 9, чому 10 файлів у кожному?

По-перше, стаття Вікіпедії в даний час говорить про 5 шарів по 16 файлів. Не знаєте де відбувається невідповідність, але це не все, що доречно. Реальне питання у тому, чому використання гніздування насамперед.

DEFLATE, єдиний підтримуваний метод стиснення для zip файлів *, має максимальний ступінь стиснення 1032. Це може бути досягнуто асимптотично для будь-якої послідовності, що повторюється 1-3 байти. Незалежно від того, що ви робите з zip файлом, доки він використовується тільки за допомогою DEFLATE, розмір розпакованого файлу буде не більше ніж у 1032 рази більше розміру вихідного zip файлу.

Тому для досягнення дійсно обурливих коефіцієнтів стиснення необхідно використовувати вкладені файли zip. Якщо у вас є 2 шари стиснення, максимальне відношення дорівнює 1032 ^ 2 = 1065024. Для 3 це 1099104768 і так далі. Для 5 шарів, що використовуються в 42.zip, теоретичний максимальний ступінь стиснення становить 1170572956434432. Як ви можете бачити, фактичний розмір 42.zip далекий від цього рівня. Частина цього є накладними витратами формату zip, а частина його полягає в тому, що їм просто байдуже.

Якби я мав здогадатися, я б сказав, що 42.zip був сформований шляхом створення великого порожнього файлу та багаторазового копіювання та копіювання. Неможливо натискати межі формату або максимізувати стиснення або ще щось - вони просто довільно вибрали 16 копій на шар. Суть полягала у тому, щоб створити велике корисне навантаження без особливих зусиль.

Примітка. Інші формати стиснення, такі як bzip2, пропонують набагато, набагато, набагато більші максимальні коефіцієнти стиснення. Однак більшість zip-парсерів їх не беруть.

P.S. Можна створити zip файл, який розпаковуватиме копію самого себе (quine). Ви також можете зробити той, хто розпаковує кілька копій. Тому, якщо ви рекурсивно розпаковуєте файл назавжди, максимально можливий розмір нескінченний. Єдине обмеження у тому, що може збільшитися лише на 1032 кожної ітерації.

P.P.S. Значення 1032 передбачає, що дані файлу zip не перетинаються. Одна з особливостей формату zip файлу полягає в тому, що він має центральний каталог, в якому перераховані файли в архіві та усунення даних файлу. Якщо ви створюєте кілька записів у файлах, що вказують на ті самі дані, ви можете досягти набагато більш високих коефіцієнтів стиснення навіть за відсутності вкладеності, але такий zip файл, швидше за все, буде відхилений парсерами.

Тестування декомпресійної бомби

Декомпресійна бомба є файлом, розробленим у тому, щоб збивати чи видаляти марну програму чи систему, считывающую її, тобто. відмовляти в обслуговуванні. Файли цього проекту можуть бути використані для перевірки вразливості програми для цього типу атаки.

Завантажити Bombs

Zip бомба, також відома як zip of death або декомпресійна бомба, є шкідливим файлом архіву, розробленим для того, щоб збивати або видаляти марну програму або систему, що її зчитує. Він часто використовується для вимкнення антивірусного програмного забезпечення, щоб створити отвір для більш традиційних вірусів. Замість того, щоб перехоплювати нормальну роботу програми, бомба zip дозволяє програмі працювати належним чином, але архів ретельно обробляється так, що його розпакування (наприклад, за допомогою антивірусного сканера для пошуку вірусів) вимагає занадто багато часу, дискового простору або пам'яті.

Zip бомба є невеликим файлом для спрощення його передачі і уникнення підозр. Однак, при спробі розпакування цього файлу, його вміст вимагає більшого, ніж система може обробити. Ще одним прикладом zip бомби є файл 42.zip, який являє собою zip файл, що містить 42 кілобайти стиснутих даних, що містить п'ять рівнів вкладених ZIP-файлів в наборах по 16, кожен архів нижнього рівня, що містить 4,3 гігабайта (4 294 967 295 байт, ~ 3,99 GiB), загальної складності 4,5 петабайта (4503599626321920 байт, ~ 3,99 PiB) стиснутих даних. Подібні файли все ще можна завантажити з різних веб-сайтів на просторах інтернету. У багатьох антивірусних сканерах в архівах виконується лише кілька рівнів рекурсії, щоб запобігти атакам, які могли б викликати переповнення буфера, стан нестачі пам'яті або перевищити прийнятний час виконання програми. Zip-бомби часто (якщо не завжди) покладаються на повторення ідентичних файлів, щоб досягти своїх граничних коефіцієнтів стиснення. Методи динамічного програмування можна використовуватиме обмеження обходу таких файлів, отже кожному рівні рекурсивно виконується лише одне файл, ефективно перетворюючи їх експоненційне зростання в лінійний.

При тестуванні завжди краще починати з малого та продовжувати працювати на підвищення. Починаючи з найбільшим файлом можна серйозно нашкодити додатку чи системі – користуйтеся цими бомбами з великою обережністю.

Всі файли були стиснуті (bzipped), щоб уникнути обмеження завантаження файлів GitMub 50 МБ. Групи файлів були заархівовані, а потім знову стиснуті (bzipped). Видаліть ці додаткові кодування перед скануванням.

Додаткові джерела

  • HTTP/2: Поглиблений аналіз чотирьох основних недоліків веб-протоколу наступного покоління (HTTP/2: In-depth
  • Ви не дивіться на загальну картину.
  • У компресійному гнізді Hornet, дослідження безпеки стиснення даних у мережевих службах.
  • Диявольська HTTP компресія – компресійні бомби (

*Є дві версії 42.zip: стара 42374 байт, і більш нова на 42838 байт. Різниця в тому, що нова вимагає пароль перед розпакуванням. Ми порівнюємо лише зі старою версією. Ось копія файлу, якщо він вам потрібний: 42.zip.

Zip-бомби повинні подолати той факт, що алгоритм стиснення DEFLATE, що найбільш часто підтримується парсерами, не може перевищити ступінь стиснення 1032 до 1. З цієї причини zip-бомби зазвичай покладаються на рекурсивну декомпресію, вкладаючи zip-файли в zip-файли, щоб отримати додатковий коефіцієнт 1032 із кожним шаром. Але трюк працює лише у реалізаціях, які розпаковують рекурсивно, а більшість цього не роблять. Найвідоміша бомба 42.zip розширюється до грізних 4,5 ПБ, якщо всі шість шарів рекурсивно розпакувати, але на верхньому шарі у неї дрібниці 0,6 МБ. Zip-квайни, як у Кокса та Еллінгсена, видають копію самих себе і, таким чином, розширюються нескінченно при рекурсивному розпакуванні. Але вони теж абсолютно безпечні під час розпакування один раз.

У цій статті показано, як створити нерекурсивну zip-бомбу, ступінь стиснення якої перевищує межу DEFLATE у 1032 році. Вихідний розмір zip-бомби зростає квадратично від розміру вхідного; тобто ступінь стиснення покращується зі збільшенням розміру бомби. Конструкція залежить від особливостей zip та DEFLATE: вона не переноситься безпосередньо на інші формати файлів або алгоритми стиснення. Бомба сумісна з більшістю zip-парсерів, крім потокових, які аналізують файли в один прохід, не перевіряючи центральний каталог zip-файлу. Ми намагаємося збалансувати дві суперечливі цілі:

  • Збільшити ступінь стиснення. Ми визначаємо ступінь стиснення як суму розмірів всіх файлів в архіві, поділеному на розмір файлу zip. Тут не враховуються імена файлів або інші метадані файлової системи, а лише вміст.
  • Зберегти сумісність. Zip – це складний формат, і парсери відрізняються, особливо у прикордонних ситуаціях та додатковими функціями. Не використовувати прийоми, які працюють лише з певними парсерами. Ми відзначимо деякі способи підвищення ефективності zip-бомби за певної втрати сумісності.

Структура zip-файлу

Zip-файл складається з центрального каталогупосилань на файли.

Центральний каталог знаходиться наприкінці файлу ZIP. Це список заголовків центрального каталогу. Кожен заголовок центрального каталогу містить метадані одного файлу, такі як ім'я файлу та контрольна сума CRC-32, а також зворотний покажчик заголовка локального файлу. Заголовок центрального каталогу має довжину 46 байт плюс довжину імені файлу.

Файл складається із заголовка локального файлу, за яким слідують стислі дані файлу. Довжина заголовка локального файлу – 30 байт плюс довжина імені файлу. Він містить надмірну копію метаданих із заголовка центрального каталогу, а також розмірів стисненого та стисненого файлів даних за ним. Zip – це формат контейнера, а не алгоритм стиснення. Дані кожного файлу стискаються за допомогою алгоритму, вказаного в метаданих - зазвичай DEFLATE .

Цей опис формату zip опускає багато деталей, які потрібні розуміння zip-бомби. Для отримання повної інформації див. розділ 4.3 APPNOTE.TXT або «Структуру файлу PKZip» Флоріана Бухгольця, або див.

Значна надмірність та багато двозначностей у форматі zip відкривають можливості для пустощів різних видів. Zip-бомба – це лише верхівка айсберга. Посилання для подальшого читання:

$ python3 -m zipfile -e overlap.zip . Traceback (останній останній call): ... __main__.BadZipFile: File name in directory "B" and header b"A" differ.
Далі ми розглянемо, як змінити конструкцію для узгодженості імен файлів, зберігши при цьому більшість переваг файлів, що перекриваються.

Друге відкриття: цитування заголовків локальних файлів

Нам потрібно розділити заголовки локальних файлів кожного файлу, у своїй повторно використовувати одне ядро. Просте об'єднання всіх заголовків не працює, тому що парсер zip знайде той заголовок локального файлу, де він очікує на початок потоку DEFLATE. Але ідея працюватиме, з невеликими змінами. Будемо використовувати функцію DEFLATE стиснених блоків, щоб «цитувати» заголовки локальних файлів, щоб вони здавалися частиною того самого потоку DEFLATE, який закінчується в ядрі. Кожен заголовок локального файлу (крім першого) інтерпретуватиметься двома способами: як код (частина структури zip-файлу) і як дані (частина вмісту файлу).

Потік DEFLATE є послідовністю блоків , де кожен блок може бути стиснутим або стиснутим. Ми зазвичай думаємо тільки про стислі блоки, наприклад, ядро ​​- це один великий стислий блок. Але є і стислі, які починаються з 5-байтового заголовка з полем довжини, що означає просто: «Виведіть наступні nбайтів дослівно». Розпакування стиснутого блоку означає лише видалення 5-байтового заголовка. Стислі та стиснені блоки можуть вільно змішуватися в потоці DEFLATE. На виході виходить конкатенація результатів розпакування всіх блоків по порядку. Поняття «нестиснутий» має значення лише на рівні DEFLATE; дані файлу, як і раніше, вважаються «стиснутими» на рівні zip, незалежно від того, які блоки використовуються.

Найпростіше уявити цю конструкцію як внутрішнє перекриття від останнього файлу до першого. Починаємо зі вставки ядра, яке формуватиме кінець файлу даних для кожного файлу. Додаємо заголовок локального файлу LFH Nта заголовок центрального каталогу CDH Nщо вказує на нього. Встановлюємо поле метаданих «стислий розмір» у LFH Nта CDH Nна стислий розмір ядра. Тепер додаємо 5-байтовий заголовок стисненого блоку (зеленим кольором на діаграмі), поле довжини якого дорівнює розміру LFH N. Додаємо другий заголовок локального файлу LFH N−1 та заголовок центрального каталогу CDH N−1 , який свідчить про нього. Встановлюємо поле метаданих «стислий розмір» як новий заголовок стисненого розміру ядра плюсрозмір стисненого заголовка блоку (5 байт) плюсрозмір LFH N .

На даний момент zip-файл містить два файли з іменами Y та Z. Давайте пройдемося, що побачить парсер при розборі. Припустимо, що стислий розмір ядра 1000 байт, а розмір LFH N- 31 байт. Починаємо з CDH N−1 і слідуємо покажчику на LFH N−1 . Ім'я першого файлу Y, а стислий розмір файлу даних 1036 байт. Інтерпретуючи наступні 1036 байт як потік DEFLATE, ми спочатку стикаємося з 5-байтовим заголовком стиснутого блоку, який каже скопіювати наступні 31 байт. Записуємо наступні 31 байт, які є LFH N, які ми розпаковуємо та додаємо у файл Y. Рухаючись далі у потоці DEFLATE, знаходимо стислий блок (ядро), який розпаковуємо у файл Y. Тепер ми досягли кінця стислих даних та закінчили з файлом Y.

Переходячи до наступного файлу, ми слідуємо вказівнику від CDH Nдо LFH Nта знаходимо файл з ім'ям Z, стислий розмір якого становить 1000 байт. Інтерпретуючи ці 1000 байт як потік DEFLATE, ми відразу стикаємося зі стислим блоком (знову ядро) і розпаковуємо його у файл Z. Тепер ми досягли кінця фінального файлу і закінчили. Вихідний файл Z містить розпаковане ядро; вихідний файл Y той самий, але додатково з префіксом 31 байт LFH N .

Завершуємо конструкцію, повторюючи процедуру цитування, доки zip-архів не включатиме потрібну кількість файлів. Кожен новий файл додає заголовок центрального каталогу, заголовок локального файлу та стислий блок для цитування безпосередньо наступного заголовка локального файлу. Стиснуті файлові дані, як правило, являють собою ланцюжок стиснених блоків DEFLATE (процитованих заголовків локальних файлів), за якими слідує стиснене ядро. Кожен байт в ядрі вносить близько 1032 Nу вихідний розмір, тому що кожен байт є частиною всіх Nфайлів. Вихідні файли теж різного розміру: більш ранні більше, ніж пізніші, тому що більше цитують заголовки локальних файлів. Вміст вихідних файлів не має особливого сенсу, але ніхто не говорив, що він повинен мати сенс.

У цій конструкції цитування з перехльостом краще сумісність, ніж у конструкції повного перекриття з попереднього розділу, але сумісність досягається рахунок стиснення. Там кожен доданий файл коштував лише заголовка центрального каталогу, тут він стоїть заголовка центрального каталогу, заголовка локального файлу та ще 5 байт для заголовка цитування.

Оптимізація

Отримавши базову конструкцію zip-бомби, намагатимемося зробити її максимально ефективною. Ми хочемо відповісти на два запитання:
  • Який максимальний ступінь стиснення для даного розміру zip-файлу?
  • Який максимальний ступінь стиснення з огляду на обмеження формату zip?

Стиснення ядра

Нам вигідно максимально стиснути ядро, адже кожен розпакований байт множиться на N. З цією метою використовуємо кастомний компресор DEFLATE під назвою bulk_deflate, спеціалізований на стисненні рядка байтів, що повторюються.

Всі пристойні архіватори DEFLATE наближаються до ступеня стиснення 1032 на нескінченному потоці байтів, що повторюються, але нас хвилює конкретний розмір. У нашому розмірі архіву bulk_deflate вміщує більше даних, ніж архіватори загального призначення: приблизно на 26 КБ більше, ніж zlib та Info-ZIP, і приблизно на 15 КБ більше, ніж Zopfli, який жертвує швидкістю заради якості стиснення.

Ціна високого ступеня стиснення bulk_deflate – відсутність універсальності. Він може стискати тільки рядки з байт, що повторюються, і тільки певної довжини, а саме 517 + 258 kдля цілого числа k≥ 0. Крім хорошого стиснення, bulk_deflate працює швидко, виконуючи роботу практично за один і той же час незалежно від розміру вхідних даних, не рахуючи роботу з фактичного запису стисненого рядка.

Імена файлів

Для наших цілей імена файлів – практично мертвий вантаж. Хоча вони роблять внесок у вихідний розмір, будучи частиною цитованих заголовків локальних файлів, але байт в імені файлу робить набагато менше, ніж байт в ядрі. Ми хочемо, щоб імена файлів були якомога коротшими, при цьому різними, не забуваючи про сумісність.

Кожен байт, витрачений на ім'я файлу, означає два байти, не витрачених на ядро ​​(два, тому що кожне ім'я файлу з'являється двічі: у заголовку центрального каталогу та заголовку локального файлу). Байт імені файлу приводить в середньому тільки до ( N+ 1) / 4 байта виведення, в той час як байт в ядрі вважається як 1032 N. Приклади: , , .

Першим міркуванням сумісності є кодування. У специфікації формату zip зазначено, що імена файлів повинні інтерпретуватися як CP 437 або UTF-8, якщо встановлено певний біт прапора (APPNOTE.TXT, додаток D). Це основний момент несумісності між парсерами zip, які можуть інтерпретувати імена файлів у деякому фіксованому або специфічному для локалі кодуванні. Тому для сумісності краще обмежитися символами з однаковим кодуванням як CP 437, так і UTF-8. А саме, це 95 символів US-ASCII.

Ми також пов'язані з обмеженнями іменування файлової системи. Деякі файлові системи нечутливі до регістру, тому "а" та "А" не вважаються різними іменами. Поширені файлові системи, такі як FAT32, забороняють певні символи , такі як "*" та "?".

Як безпечний, але не обов'язково оптимальний компроміс, наша zip-бомба буде використовувати імена файлів з 36-символьного алфавіту, який не включає спеціальні символи та символи різного регістру:

0 1 2 3 4 5 6 7 8 9 A B C D E F G H I J K L M N O P Q R S T V
Імена файлів генеруються очевидно, всі позиції по черзі, з додаванням позиції в кінці циклу:

"0", "1", "2", ..., "Z", "00", "01", "02", ..., "0Z", ..., "Z0", "Z1", "Z2", …, "ZZ", "000", "001", "002", …
Існує 36 імен файлів довжиною в один символ, 36 ² імен довжиною два символи і так далі. Чотирьох байтів достатньо для 1727604 різних імен файлів.

Враховуючи, що у імен файлів в архіві зазвичай буде різна довжина, як їх краще впорядкувати: від найкоротшого до найдовшого чи навпаки? Якщо трохи подумати, краще ставити найдовші імена останніми. Таке впорядкування додає більше 900 МБ виводу в zblg.zip, порівняно з упорядкуванням від найдовшого до найкоротшого. Втім, це незначна оптимізація, тому що 900 МБ – лише 0,0003% від загального розміру видачі.

Розмір ядра

Конструкція цитування з перехльостом дозволяє розмістити стисло ядро ​​даних, а потім дешево скопіювати його багато разів. Для конкретного розміру zip-файлу Xскільки місця оптимально виділити для зберігання ядра, а скільки для створення копій?

Щоб знайти оптимальний баланс, потрібно оптимізувати лише одну змінну N, кількість файлів у zip-архіві Кожне значення Nвимагає певного обсягу накладних витрат для заголовків центрального каталогу, заголовків локальних файлів, заголовків блоків цитування та імен файлів. Решта простір буде зайнято ядром. Оскільки Nмає бути цілим числом, а ви можете помістити тільки певну кількість файлів, перш ніж розмір ядра впаде до нуля, достатньо перевірити кожне можливе значення Nта вибрати те, що дає найбільшу видачу.

Застосування процедури оптимізації до X= 42 374 для 42.zip знаходить максимум у N= 250. Ці 250 файлів вимагають 21195 байт службових даних, залишаючи 21179 байт для ядра. Ядро такого розміру розпаковується в 21841249 байт (співвідношення 1031,3 до 1). 250 копій розпакованого ядра плюс трохи процитованих заголовків локальних файлів дає загальний розпакований вихід 5461307620 байт і ступінь стиснення 129000.

CRC-32 можна змоделювати як станову машину, що оновлює 32-розрядний регістр стану для кожного вхідного біта. Основні операції поновлення для бітів 0 і 1 такі:

Uint32 crc32_update_0(uint32 state) ( // Shift out the least significant bit. bit b = state & 1; state = state >> 1; // If the shifted-out bit was 1, XOR with the CRC-32 constant. if (b == 1) state = state^0xedb88320; return state;
Якщо ви представляєте регістр стану як 32-елементний двійковий вектор і використовуєте XOR для додавання та множення, то crc32_update_0 є лінійним відображенням ; т. е. його можна як множення на бінарну матрицю переходу 32×32. Щоб зрозуміти, чому, зверніть увагу, що множення матриці на вектор - це підсумовування стовпців матриці після множення кожного стовпця на відповідний елемент вектора. Операція зсуву state >> 1 просто бере кожен біт iвектор стану і множить його на вектор, який дорівнює нулю скрізь, крім біта i− 1 (нумерація бітів праворуч наліво). Умовно кажучи, кінцеве XOR state ^ 0xedb88320 відбувається лише тоді, коли біт b дорівнює одиниці. Це можна уявити як перше множення b на 0xedb88320, а потім XORинг у даний стан.

Крім того, crc32_update_1 – це просто crc32_update_0 плюс (XOR) константа. Це робить crc32_update_1 афінним перетворенням: множення матриці з наступним відображенням (тобто векторне додавання). Ми можемо уявити множення матриці і відображення за один крок, якщо збільшимо розміри матриці перетворення до 33×33 і додамо додатковий елемент вектора стану, який завжди дорівнює 1 (таке уявлення називається однорідними координатами).


Матриці перетворення 33×33 M 0 і M 1 які обчислюють зміну стану CRC-32, виконане бітами 0 і 1, відповідно. Вектори стовпців зберігаються з найбільш значним бітом унизу: читаючи перший стовпець знизу вгору, ви бачите поліноміальну константу CRC-32 edb8832016 = 111 011 011 0111 0001 0000011 001 00000 2 . Ці дві матриці розрізняються тільки в кінцевому стовпці, який представляє вектор трансляції однорідних координатах. У M 0 трансляція дорівнює нулю, а M 1 - edb88320 16 поліноміальна константа CRC-32. Одиниці одразу над діагоналлю представляють стан операції state >> 1

Обидві операції crc32_update_0 та crc32_update_1 можна представити матрицею переходу 33×33. Показані матриці M0 та M1. Перевага матричного уявлення у тому, що матриці можна множити. Припустимо, ми хочемо побачити зміну стану, проведене обробкою ASCII-символу "a", двійкове уявлення якого дорівнює 01100001 2 . Ми можемо уявити сукупну зміну стану CRC-32 цих восьми біт в одній матриці перетворення:


І ми можемо уявити зміну стану рядка повторюваних "а" шляхом перемноження багатьох копій Ма - зведення матриці в ступінь. Ми можемо швидко це зробити, використовуючи алгоритм швидкого зведення в ступінь , який дозволяє обчислити M n всього за log 2 n кроків. Наприклад, ось матриця зміни стану рядка із 9 символів "а":
Алгоритм швидкого множення матриць корисний для обчислення M kernel , матриці для несжатого ядра, оскільки ядро ​​являє собою рядок байтів, що повторюються. Щоб отримати контрольну суму CRC-32 з матриці, помножте матрицю на нульовий вектор (нульовий вектор знаходиться в однорідних координатах, тобто 32 нуля, а потім одиниця; тут ми опускаємо незначне ускладнення перед-і постобробки контрольної суми для перевірки на відповідність). Щоб обчислити контрольну суму для кожного файлу, ми працюємо у зворотному напрямку. Починаємо з ініціалізації M:= M kernel. Контрольна сума ядра також є контрольною сумою кінцевого файлу N, тому множимо Mна нульовий вектор і зберігаємо отриману контрольну суму CDH N і LFH N . Дані файлу N−1такі ж, як файлові дані файлу N, але з доданим префіксом LFH N . Тому обчислюємо матрицю зміни стану для LFH N і оновлюємо. Тепер Mпредставляє кумулятивну зміну стану обробки LFH N за ядром. Обчислюємо контрольну суму для файлу N−1, знову помноживши Mна нульовий вектор. Продовжуємо процедуру, накопичуючи матриці зміни стану в M, доки всі файли не будуть оброблені.

Розширення: Zip64

Раніше ми зіткнулися з проблемою розширення через обмеження формату zip - неможливо було видати більше 281 ТБ, незалежно від того, наскільки спритно запакований zip-файл. Можна перевершити ці обмеження, використовуючи Zip64 розширення формату zip, яке збільшує розмір деяких полів заголовка до 64 біт. Підтримка Zip64 аж ніяк не універсальна, але це одне з найпоширеніших розширень. Що стосується ступеня стиснення, то ефект Zip64 полягає у збільшенні розміру заголовка центрального каталогу з 46 до 58 байт, а розміру заголовка локального каталогу з 30 до 50 байт. Подивившись на формулу оптимального коефіцієнта розширення у спрощеній моделі, ми бачимо, що zip-бомба у форматі Zip64, як і раніше, зростає квадратично, але повільніше через більший знаменник - це видно на діаграмі внизу. За рахунок втрати сумісності та уповільнення зростання у нас знімаються практично будь-які обмеження на розмір файлу.

Припустимо, нам потрібна zip-бомба, яка розширюється до 4,5 ПБ, як 42.zip. Наскільки більшим має бути архів? За допомогою двійкового пошуку ми бачимо, що мінімальний розмір такого файлу становить 46 МБ.

  • zbxl.zip 46 MB → 4,5 PB (Zip64, менш сумісний)
zipbomb --mode=quoted_overlap --num-files=190023 --compressed-size=22982788 --zip64 > zbxl.zip
4,5 петабайта - приблизно стільки даних записав Телескоп горизонту подій для першого зображення чорної дірки: стійки та стійки з жорсткими дисками у дата-центрі.

З Zip64 вже практично нецікаво розглядати максимальний ступінь стиснення, тому що ми можемо просто продовжувати збільшувати розмір zip-файлу та ступінь стиснення разом з ним, поки навіть стислий zip-файл не стане непомірно більшим. Цікавий поріг, однак, становить 264 байти (18 EB або 16 EiB) - стільки даних не поміститься в більшості файлових систем. Двійковий пошук знаходить найменшу zip-бомбу, яка виробляє принаймні стільки вихідних даних: вона містить 12 мільйонів файлів та стисло ядро ​​1,5 ГБ. Загальний розмір zip-файлу становить 2,9 ГБ, і він розпаковується в 264+11727895877 байт зі ступенем стиснення більше 6,2 млрд до одного. Я не викладав цей файл, але ви можете згенерувати його самостійно, використовуючи . Має файли такого розміру, що виявився навіть баг в Info-ZIP UnZip 6.0.

Zipbomb --mode=quoted_overlap --num-files=12056313 --compressed-size=1482284040 --zip64 > zbxxl.zip

Розширення: bzip2

DEFLATE є найбільш поширеним алгоритмом стиснення для формату zip, але це лише один із багатьох варіантів. Ймовірно, другим найпоширенішим алгоритмом є bzip2. Хоча він не такий сумісний, як DEFLATE. Теоретично, у bzip2 максимальний ступінь стиснення близько 1,4 мільйона до одного, що дозволяє щільніше упаковувати ядро.

Bzip2 насамперед кодує «крок виконання» (run-length encoding), зменшуючи довжину рядка байтів, що повторюються, в 51 раз. Потім дані поділяються на блоки 900 КБ і кожен блок стискається окремо. Теоретично один блок може стиснутися до 32 байт. 900 000 × 51/32 = 1 434 375.

Незважаючи на втрати сумісності, чи дозволяє bzip2 зробити більш ефективну бомбу?

Так – але тільки для невеликих файлів. Проблема в тому, що bzip2 не має нічого схожого на несжаті блоки DEFLATE, які ми використовували для цитування заголовків локальних файлів. Таким чином, неможливо перекривати файли і повторно використовувати ядро ​​- для кожного файлу потрібно записувати власну копію, тому загальний ступінь стиснення буде не кращим, ніж коефіцієнт для будь-якого окремого файлу. На графіці внизу ми бачимо, що без перекриття bzip2 перевищує DEFLATE лише для файлів розміром близько мегабайта.

Залишається надія лише альтернативний засіб цитування заголовків в bzip2, що обговорюється у наступному розділі. Крім того, якщо ви знаєте, що певний zip-парсер підтримує bzip2 ідопускає невідповідність імен файлів, ви можете використовувати конструкцію повного перекриття, яка не потребує цитування.

Порівняння коефіцієнта стиску у різних zip-бомб. Зверніть увагу на логарифмічні вісі. Кожна конструкція показана з і без Zip64. Конструкції без перекриття мають лінійну швидкість росту, що видно по постійному співвідношенню осей. Вертикальне зміщення графіка bzip2 означає, що ступінь стиснення bzip2 приблизно тисячу разів більше, ніж у DEFLATE. У конструкцій DEFLATE із цитуванням квадратична швидкість зростання, про що свідчить нахил до осей 2:1. Варіант Zip64 є трохи менш ефективним, але дозволяє видавати більше 281 ТБ. Графіки для bzip2 з цитуванням через додаткове поле переходять із квадратичних в лінійні при досягненні або максимального розміру файлу (2 32 −2 байти), або максимально дозволеної кількості файлів

Розширення: цитування через додаткове поле

До цих пір ми використовували функцію DEFLATE для цитування заголовків локальних файлів, і ми тільки-но побачили, що цей трюк не працює в bzip2. Однак є альтернативний спосіб цитування, дещо обмеженіший, який використовує тільки функції формату zip і не залежить від алгоритму стиснення.

Наприкінці структури заголовка локального файлу є додаткове полезмінної довжини для зберігання інформації, яка не вписується у звичайні поля заголовка (APPNOTE.TXT, розділ 4.3.7). Додаткова інформація може включати, наприклад, мітку точного часу або uid/gid з Unix. Інформація Zip64 також зберігається у додатковому полі. Додаткове поле представлене у вигляді структури length-value; якщо збільшити довжину без додавання значення, то додаткове поле включить те, що за ним у zip-файлі, саме наступний заголовок локального файла. Використовуючи цей метод, кожен заголовок локального файлу може "цитувати" наступні заголовки, укладаючи їх у власне додаткове поле. У порівнянні з DEFLATE тут три переваги:

  1. Цитування через додаткове поле вимагає лише 4 байти, а не 5, залишаючи більше місця для ядра.
  2. Воно не збільшує розмір файлів, що означає більший розмір ядра з огляду на обмеження формату zip.
  3. Воно забезпечує цитування bzip2.
Незважаючи на ці переваги, цитування через додаткові поля менш гнучке. Це не ланцюжок, як у DEFLATE: кожен заголовок локального файлу повинен містити не тільки наступний заголовок, а й Усенаступні заголовки. Додаткові поля збільшуються при наближенні до початку zip-файлу. Оскільки максимальна довжина поля 2 16 −1 байт, можна цитувати лише до 1808 заголовків локальних файлів (або 1170 у Zip64), припускаючи, що імена (у випадку DEFLATE ви можете використовувати додаткове поле для цитування перших (найкоротших) заголовків локальних файлів, а потім перейти на цитування DEFLATE для інших). Інша проблема: щоб відповідати внутрішній структурі даних додаткового поля, необхідно вибрати 16-бітний тег для типу (APPNOTE.TXT, розділ 4.5.2), що передує цитування. Ми хочемо вибрати тег типу, який змусить парсери ігнорувати дані в лапках, а не намагатися інтерпретувати їх як значущі метадані. Zip-парсери повинні ігнорувати теги невідомого типу, тому ми можемо вибирати теги випадковим чином, але є ризик, що у майбутньому якийсь тег порушить сумісність конструкції.

Попередня діаграма ілюструє можливість використання додаткових полів у bzip2, c та без Zip64. На обох графіках є точка перелому, коли зростання переходить від квадратичного до лінійного. Без Zip64 це відбувається там, де досягається максимальний розмір стисненого файлу (2 32 −2 байти); потім можна збільшити лише кількість файлів, але їх розмір. Графік повністю закінчується, коли кількість файлів досягає 1809, тоді ми закінчуємо місце в додатковому полі для цитування додаткових заголовків. З Zip64 перелом відбувається на 1171 файлі, після чого може бути збільшено лише розмір файлів, але не їх кількість. Додаткове поле допомагає і у випадку DEFLATE, але різниця настільки мала, що візуально непомітна. Вона збільшує рівень стиснення zbsm.zip на 1,2%; zblg.zip на 0,019%; та zbxl.zip на 0,0025%.

Обговорення

У своїй роботі на цю тему Плетц з колегами використовують перехльостування файлів для створення майже самореплікованого zip-архіву. Саме перехльостування файлів запропонував раніше (слайд 47) Гінваель Колдвінд.

Ми розробили конструкцію zip-бомби з перехльостом цитування з урахуванням сумісності - низки відмінностей у реалізаціях, деякі з яких показані в таблиці нижче. Отримана конструкція сумісна з zip-парсерами, які працюють звичайним способом, тобто спочатку перевіряючи центральний каталог та використовуючи його як індекс файлів. Серед них унікальний zip-парсер із Nail, який автоматично генерується з формальної граматики. Однак конструкція несумісна з «струмовими» парсерами, які аналізують zip-файл від початку до кінця за один прохід без попереднього читання центрального каталогу. За своєю природою потокові парсери не допускають перекриття файлів у жодному вигляді. Швидше за все, вони витягнуть лише перший файл. Крім того, вони можуть навіть видати помилку, як у випадку з

mob_info