Дивна поведінка архіватора Zip

Доброго часу доби!

Хочу поділитися несподіваним відкриттям, а точніше — розповісти про незвичайну поведінку досить відомого архіватора Zip.

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

Спочатку ми тестували на додаток файлах, стислих з допомогою Zip.
  1. Архівуємо файл:

    $ zip --password 123 secure.zip README.md
    
  2. Перевіряємо вручну, що з цим паролем все працює:

    $ unzip secure.zip
    
  3. Видаляємо той файл, який був згенерований в процесі перевірки для чистоти експерименту;
  4. Чекаємо кілька томливих секунд;
  5. Отримуємо очікуваний висновок нашої програми:

    Success!123
    
Нашому щастю не було меж, програма працює, все зламує, можна йти далі і додавати нові цікаві «фічі», красивий інтерфейс. Але далеко ми не втекли, бо ген завзятого тестувальника сидить в нашій крові з народження, а значить — ми не могли повірити, що програма коректна, поки вона не довела це на всіх придуманих нами найскладніших паролі.

  1. Архівуємо файл:

    $ zip --password 2048 secure.zip README.md
    
  2. І знову болісне очікування;
  3. Отримуємо висновок нашої програми:

    Success!278
    
Стоп! Отримали не зовсім очікуваний результат. Що робити? Аналізувати, розплутувати, виправляти. План був просто прекрасним, але вже на етапі «аналізувати» він пішов прахом.

Першим ділом ми вирішили виключити ймовірність того, що якимось чином наша програма дійсно зламала файл з тим паролем, який вивела. І ось воно! Ось воно розчарування: пароль виявився валідним. Як?!

Але найбільше нас здивувало те, що і попередній пароль теж виявився підходящим.

Тепер поговоримо про сумне. Поки що ця загадка не була розгадана. Ми перевірили наявність цього ефекту на декількох операційних системах (Fedora 20 (Heisenbug), Ubuntu 14.04, OS X 10.9.4); на кожній з них він відтворюється. Висновок, який ми можемо зробити, теж невтішний: користуватися цим архіватором у будь-яких скільки-небудь відповідальних цілях не варто.

Нижче наводжу вихідний код скрипта, щоб читач зміг самостійно ознайомитися з ефектом:

import threading as th
import pexpect as pe

#Derive a class for incapsulating a thread 
#which will be trying to open the encrypted file.
class HackerThread(th.Thread):

def __init__(self, remainder, np, event, filename):
super(HackerThread, self).__init__()
self._remainder = remainder
self._np = np
self._event = event
self._filename = filename

def run(self):

effort = self._remainder
while 1:

print(effort)
if self._event.isSet():
quit()

child = pe.spawn('unzip '+self._filename)

try:
child.expect('пароль:', timeout=2)
except pe.ExceptionPexpect as ex:
#print ex.message
print "didn't get password prompt!"
self._event.set()
quit()

child.sendline(str(effort))

try:
child.expect('reenter:', timeout=2)
except pe.ExceptionPexpect as ex:
print "Success!"+str(effort)
self._event.set()
quit()

effort += self._np


if __name__ == '__main__':

np = 4
filename = "secure.zip"

event = th.Event()

threads = [ HackerThread(i, np, event, filename) for i in range(np) ]

for thread in threads:
thread.start()

for thread in threads:
thread.join(timeout=None) 

Примітка: для тіста просто створіть в директорії, в якій лежить скрипт, запаролених файл «secure.zip» і запустіть скрипт інтерпретатором пітона 2.7.

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.