Похоже, в этом году составители тасков решили сильно сжалиться над участниками-магистрами. В прошлом году было в разы сложнее (и одновременно на столько же увлекательней!)
reverse, 15 баллов > mindswiper
Вам в руки попала захватывающая игра. Пройдите все её уровни.
За один из них (Flag level) вам дадут строчку с ответом.
Внимание! За остальные уровни ответы неверные.
Идентичные версии игры предоставлены для трёх
операционных систем (https://yadi.sk/d/FHosjxEPEXf_Sg).
Формат ответа: itmo{...}
Состав архива
Вас посетил товарищ Golang
Обычно, как и в случае с Delphi, пользовательске функции лежат в конце
Прощальная корова
Описание задачи: лабиринт с бомбами и флагами. Бомбы и сами флаги невидимы.
Сам лабиринт
Условия, отвечающие за выбор. Четвертый вариант работает со вторым файлом карт.
В теле игры можно увидеть интересные строки. Они раньше были двордами, но R
делает свою работу
В общем, эта задача хороша своим обилием возможных решений. Мы можем:
- Попробовать изучить структуру файлов уровней, чтобы найти флаги и мины и решить задачу.
- Посмотреть, где можно пропатчить, чтобы не учитывались попадания на мины и ограждения. По-быстрому пройтись по карте и получить ответ.
- Найти карту в памяти, построить ее у себя.
В ходе разбирательств с тем, как работает программа, самым быстрым способом оказался третий (мы же ограничены четырьмя часами, поэтому никто не позволит нам сидеть над одной из семи задач долго).
Будем использовать тайную технику по поверхностному реверсу - опираться на print-ы, хехе.
Самое для нас интересное - это по-быстрому получить карту и пройтись по ней, это дело пяти минут. Всё-таки Golang не очень приятно реверсится без плагинов, которые бы разбирали структурки, поэтому залезать вглубь - трата времени.
Посмотрим на память в переменной main_d
, слишком уж юзер-дефайнутая, да и она является аргументом функции, которая вызывалась до этого, main___Maze__move
.
Попався!
Первым элементом этой структуры является карта предметов (без стен).
Дампим через Tab+E
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| Y | | | | F | 1
+ +---+---+ + + + + +---+ + +---+---+ + +
| | | | | | | | | | | | 2
+ + + + + + + +---+---+---+ + + +---+ +
| | F | | | | | | | | 3
+ +---+ +---+---+ +---+ + + +---+---+---+ + +
| | F | F | | | | F | F | 4
+---+ + +---+---+ +---+ + +---+---+ +---+---+---+
| | | | | | | 5
+ +---+ + + +---+ +---+---+---+ +---+---+---+ +
| | | | | F | | | F | | 6
+ +---+---+ + + +---+ +---+ + + + +---+---+
| | | | | | | | F | 7
+ +---+ +---+---+---+ +---+ +---+ + + +---+ +
| | | | F | | | | | | 8
+---+---+---+ + +---+---+ + + +---+ +---+ + +
| | | | | | F | | | 9
+ + +---+---+---+---+ + + + + +---+---+ + +
| | | | | | | | | | 10
+ + + +---+ +---+ + + +---+---+ + +---+ +
| | F | | | | | | | 11
+ +---+---+ +---+ + + +---+---+---+---+---+---+---+
| | | F | | | F | | | 12
+---+ + +---+ +---+---+ + + + + + +---+ +
| | | | | | | | 13
+ +---+---+---+---+---+---+---+ +---+---+ +---+ + +
| | | | | | | 14
+ +---+---+---+---+ + + + + + +---+---+---+ +
| | | | | 15
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
###Y####B#####F 1
###########B### 2
#F############# 3
####F#F##BF#F## 4
############### 5
#B###F##B##F### 6
#############F# 7
#B#####F####### 8
############F## 9
#####B######### 10
#F############# 11
####F####F##### 12
#############B# 13
############### 14
####B########## 15
Перенесли на карту, теперь остается пройти. Заметим, что в конце нет никакого баннера, который бы по нажатию кнопки завершил приложение после вывода флага, поэтому без бряки или отдельной консоли (например, удаленного отладчика Иды) вам придется проходить игру 2 раза, как и мне)
Вот и решение
Флаг пятого варианта: itmo{b51a26a7b36730ea06ec01be2518232c}
reverse, 15 баллов > pyinstaller
Вас просят разобраться с программой на языке Python 3.7, в которой что-то намудрили
(https://yadi.sk/d/XQ7mLhEVDIiITw). Мало того, что она собрана с помощью Pyinstaller для
запуска на Linux, так ещё и весь функционал почему-то недоступен.
Но с её помощью был зашифрован флаг, который вам очень нужно расшифровать.
Формат ответа: itmo{...}
Рекомендуемое ПО: для решения этого задания Вам понадобится Python 3.7, а так же модули
pyinstaller и uncompyle6, которые можно установить при помощи команды
pip3 install pyinstaller uncompyle6
Структура таска:
.
├── flag.enc
└── main
├── _bisect.cpython-37m-x86_64-linux-gnu.so
├── _blake2.cpython-37m-x86_64-linux-gnu.so
├── _bz2.cpython-37m-x86_64-linux-gnu.so
├── _codecs_cn.cpython-37m-x86_64-linux-gnu.so
├── _codecs_hk.cpython-37m-x86_64-linux-gnu.so
├── _codecs_iso2022.cpython-37m-x86_64-linux-gnu.so
├── _codecs_jp.cpython-37m-x86_64-linux-gnu.so
├── _codecs_kr.cpython-37m-x86_64-linux-gnu.so
├── _codecs_tw.cpython-37m-x86_64-linux-gnu.so
├── _ctypes.cpython-37m-x86_64-linux-gnu.so
├── _datetime.cpython-37m-x86_64-linux-gnu.so
├── _hashlib.cpython-37m-x86_64-linux-gnu.so
├── _heapq.cpython-37m-x86_64-linux-gnu.so
├── _md5.cpython-37m-x86_64-linux-gnu.so
├── _multibytecodec.cpython-37m-x86_64-linux-gnu.so
├── _opcode.cpython-37m-x86_64-linux-gnu.so
├── _pickle.cpython-37m-x86_64-linux-gnu.so
├── _posixsubprocess.cpython-37m-x86_64-linux-gnu.so
├── _random.cpython-37m-x86_64-linux-gnu.so
├── _sha1.cpython-37m-x86_64-linux-gnu.so
├── _sha256.cpython-37m-x86_64-linux-gnu.so
├── _sha3.cpython-37m-x86_64-linux-gnu.so
├── _sha512.cpython-37m-x86_64-linux-gnu.so
├── _socket.cpython-37m-x86_64-linux-gnu.so
├── _ssl.cpython-37m-x86_64-linux-gnu.so
├── _struct.cpython-37m-x86_64-linux-gnu.so
├── base_library.zip
├── binascii.cpython-37m-x86_64-linux-gnu.so
├── crypto.so
├── grp.cpython-37m-x86_64-linux-gnu.so
├── libbz2.so.1.0
├── libcrypto.so.1.0.0
├── libffi.so.6
├── libpython3.7m.so.1.0
├── libreadline.so.6
├── libssl.so.1.0.0
├── libtinfo.so.5
├── libz.so.1
├── main
├── math.cpython-37m-x86_64-linux-gnu.so
├── pyexpat.cpython-37m-x86_64-linux-gnu.so
├── readline.cpython-37m-x86_64-linux-gnu.so
├── resource.cpython-37m-x86_64-linux-gnu.so
├── select.cpython-37m-x86_64-linux-gnu.so
├── termios.cpython-37m-x86_64-linux-gnu.so
├── unicodedata.cpython-37m-x86_64-linux-gnu.so
└── zlib.cpython-37m-x86_64-linux-gnu.so
1 directory, 48 files
> file ./main/main
./main/main: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, for GNU/Linux 2.6.32, BuildID[sha1]=294d1f19a085a730da19a6c55788ec08c2187039, stripped
Используем официальный faq для работы pyinstxtractor’а с линёвыми бинарями.
Рекомендую использовать ту же версию Python или проставить магию в хекс-редакторе из проекта pycdc, иначе у вас будет неправильная магия, а различия в минорных версиях в байт-коде есть, поэтому можно нарваться на ошибки или неправильную интерпретацию. Не хотим же потратить пару часов на разбор, почему условие какое-то кривое?
Содержание:
import sys
from art import *
from ctypes import *
import cowsay, argparse
from sys import platform
shared_lib_path = './crypto.so'
if platform.startswith('win32'):
shared_lib_path = './crypto.dll'
else:
try:
lib = CDLL(shared_lib_path)
except Exception as e:
try:
print(e)
finally:
e = None
del e
art1 = text2art('encrypt like a pro')
print(art1)
print('* in a pro version')
N = 9237641547581911336881323875775007720067963975755521934196540843273520595296207
def pad(s, n):
if len(s) < n:
cnt = n - len(s)
return s + bytes([cnt]) * cnt
return s + bytes([n ** 2]) * n ** 2
def unpad(s):
return s[:-int(s[(-1)])]
def gamma_generator():
seed = 76473342171049830059
while True:
yield seed
seed = pow(seed, 2, N)
def encrypt(filename, out):
try:
data = open(filename, 'rb').read()
except Exception as e:
try:
cowsay.stegosaurus('Error during file open')
return
finally:
e = None
del e
if len(data) > 0:
cowsay.stegosaurus('Encryption is not supported in demo version')
return
edata = b''
passwords = gamma_generator()
for bt in data:
ebt = bt ^ next(passwords) % 256
edata += bytes([ebt])
with open(out, 'wb') as (w):
args = create_string_buffer(pad(edata, 100))
result = lib.make_enc(args, 100)
w.write(result)
cowsay.tux('Encrypted to ' + out)
return result
def decrypt(filename, out):
try:
data = open(filename, 'rb').read()
except Exception as e:
try:
cowsay.stegosaurus('Error during file open')
return
finally:
e = None
del e
if len(data) > 0:
cowsay.stegosaurus('Decryption is not supported in demo version')
return
args = create_string_buffer(data)
result = lib.make_dec(args, 100)
ddata = b''
passwords = gamma_generator()
for bt in unpad(result):
dbt = bt ^ next(passwords) % 256
ddata += bytes([dbt])
with open(out, 'wb') as (w):
w.write(ddata)
cowsay.tux('Decrypted to ' + filename)
return ddata
if __name__ == '__main__':
lib.make_enc.restype = c_char_p
lib.make_enc.argtypes = [c_char_p, c_int]
lib.make_dec.restype = c_char_p
lib.make_dec.argtypes = [c_char_p, c_int]
parser = argparse.ArgumentParser(description='Encrypt and decrypt files')
parser.add_argument('--action', required=True, help='action (encrypt, decrypt)')
parser.add_argument('--infile', required=True, help='input file')
parser.add_argument('--outfile', required=True, help='output file')
args = parser.parse_args(sys.argv[1:])
if args.action == 'encrypt':
result = encrypt(args.infile, args.outfile)
else:
if args.action == 'decrypt':
result = decrypt(args.infile, args.outfile)
else:
cowsay.stegosaurus('Sorry. No such action')
Видим использование внешней зависимости - crypto.so
, тогда нужно проверить и ее, вдруг она проверяет окружение и искажает флаг.
Заодно посмотрите на код - его нужно немножечко полечить от жадности.
До
После
Выходной файл уменьшился на три байта, что звучит законно.
. .
...
\~~~~~/
\ /
\ /
V
|
-----
itmo{AAE796626285F66}
------------------------
Выглядит очень и очень нормально, учитывая, что это результат работы внешней библиотеки, к тому же загаммированный внутри питона.
Давайте посмотрим, что творится в либе.
Точки входа
В функцию декода передается два параметра - блоб и режим. Существует два режима: демо (2) и полный (1). В самом начале бинаря назначается работа в полном режиме, поэтому предупреждение о демо-версии недостижимо. Похоже, таск должен был включить в себя анализ библиотеки, но по какой-то причине этот функционал решили не реализовывать. Всё остальное в бинаре выглядит нормально, без намёка на сокрытие чего-либо.
forensics, 11 баллов > pcap
Очень простая. Чистый траффик по брутфорсу, Basic Auth. При успешной аутентификации сервер возваращает зашифрованный архив. Пароль - в хэдере Basic Auth под b64. Задача очень легкого, немагистрского, уровня.
author, editor: Rakovsky Stanislav, Unicorn CTF