OpenSSL PPC QCTF 2016
По просьбам участников выкладываю еще один райтап таск по программированию.
Задание таска: нам дан зашифрованный файл
(уберите окончание) и 13 типов шифрования с паролями:
-rc2 4f0c6a3e90401fa7bc51a5ae9982845c
-cast5-cfb 6fbdbcb790138cc054556b45dfaff777
-aes-192-ecb 4befaa7b927a349af5d9f7c321419c8c
-desx 296c5b3207bf00fa3271287447b5e53a
-des-ecb acc6cccd9ee0df92e1f329151ac28a9d
-des3 5324a480df9a59e444f4b82aa1e29b30
-aes-128-cbc e11f3ce8443d192bb376d1d025de2540
-camellia128 617223fdcaf2532a633b2dc0675b9663
-seed e1930b4927e6b6d92d120c7c1bba3421
-aes-256-cbc 146983842e420321011e74145a59aa48
-bf ae9d5595593d62eefa1687551497db39
-des-ede 5f6b93462201020193c8664c600e3faa
-aes256 df2240f7fd137880c89f375a81728256
Файл был зашифрован 13 раз с неизвестной нам последовательностью. Требуется восстановить исходный файл.
Первое, что стоит заметить: файлы были закодированы утилитой openssl. Работать с ней наиболее удобно именно в терминальной версии. Или проще говоря - делать этот таск легче всего в UNIX-based системах. Лично я сделал этот таск на Linux и MacOS.
Для удобства помещаем файлы в отдельную пустую папку:
ciphertext0 - изначально данный зашифрованный файл (и переименованный из ciphertext.lol).
passwords.txt - изначально данный список типов шифрования с паролями (13 строк с разделенными пробелами, как и дано в условии).
script.py - python файл в который мы впишем скрипт для решения таска.
Теперь перейдем непосредственно к решению. Представляю вам готовый скрипт, написанный на python (работает как на второй, так и на третьей версии питона).
import os
f = open('passwords.txt')
n = f.read().split('\n')
f.close()
filename = 'ciphertext'
number = 0
while len(n)>0:
for x in n:
cipher = x.split(' ')[0]
password = x.split(' ')[1]
s = os.popen('openssl enc -in '+ filename + str(number) + ' -out '+ filename + str(number+1) + ' -d '+cipher+' -k '+password+' 2>&1').read()
if s == '':
n.remove(x)
break
f.close()
number+=1
Разберем код подробнее.
f = open('passwords.txt')
n = f.read().split('\n')
f.close()
Тут идет разделение нашего файла на массив из 13 ячеек, каждая из которых является строкой в файле passwords.txt.
while len(n)>0:
Каждый раз, как мы будем находить нужный тип для шифрования - мы будем удалять его из массива. То есть, когда мы расшифруем полностью файл, то длинна массива будет равна 0.
for x in n:
cipher = x.split(' ')[0]
password = x.split(' ')[1]
s = os.popen('openssl enc -in '+ filename + str(number) + ' -out '+ filename + str(number+1) + ' -d '+cipher+' -k '+password+' 2>&1').read()
if s == '':
n.remove(x)
break
f.close()
В данном коде происходит следующее:
1. Разделяем строку (например строку '-rc2 4f0c6a3e90401fa7bc51a5ae9982845c') на две части cipher='-rc2' и password='4f0c6a3e90401fa7bc51a5ae9982845c'
2. Пробуем расшифровать файл с данным типом шифрования и паролем. Например:
s = os.popen('openssl enc -in ciphertext0 -out ciphertext1 -d -rc2 -k 4f0c6a3e90401fa7bc51a5ae9982845c 2>&1').read()
3. Если наш файл не смогли расшифровать, то openssl будет ругаться (выдавать разного рода ошибки). А при успешной расшифровке - вывод будет отсутствовать. Поэтому мы после каждой попытки проверяем вывод, и в случае его отсутствия удаляем данный тип шифрования из нашего массива, и выходим из цикла for.
Пример:
if s == '':
n.remove('-rc2 4f0c6a3e90401fa7bc51a5ae9982845c')
break
Ну и увеличиваем номер файла на 1:
number+=1
В итоге после запуска скрипта в папке вы сможете наблюдать следующую структуру:
Открываем последний файл (ciphertext13) и получаем флаг!
QCTF_8446b05078b9779cf46f46cc861f2f8c
Стоит отметить проблему, возникшую во время реализации - python никак не хотел перехватывать вывод команды openssl, поэтому на соревновании пришлось вручную 13 раз прогонять программу и искать где вывод отсутствует. Но уже дома, погуглив минут 15 было найдено решение дописать в конец строки 2>&1 .
И для тех, кому лень все копировать, я сделал готовый архив с тремя файлами: script.py, passwords.txt и ciphertext0 -
- Автор: drakylar
- Комментарии: 0
- Просмотры: 3556