Разбор реверса с CTF, проходившего в рамках Kuban CyberSecurity Conference 2019
@ Rakovsky Stanislav | Friday, Nov 22, 2019 | 5 minutes read | Update at Friday, Nov 22, 2019

Единороги заняли на этом соревновании пятое место среди тридцати команд

reverse, 100 баллов > Wrong!!!

I think there's something wrong with this program. @dyisshysvsys

Файл

Перед нами .Net. Открываем в DNSpy, любуемся функцией:

Ставим брейкпоинт на 15 строке, запускаемся

На скрине я уже сменил false на true.


reverse, 200 баллов > Try now

Flag is passphrase. GO! @dyisshysvsys

Нам предоставляют два файла: Rev200.exe и task.png

Снова .Net. Состоит из двух классов – Program и CRYPTED

Класс Program

Нас просят ввести пароль, который вместе с солью и ключом передаются в экземпляр класса CRYPTED. Затем идет сравнение с b64 строкой.

Посмотрим на второй файл задания: это скрин с представлением успешной работы программы. Там закрашена вводимая строка, но видны дата и время запуска – 09.10.2019 10:23. Время не обязательно будет ровно таким же, какое использовалось для ключа и соли, это стоит учесть. Ключ и соль имеют одинаковое значение (шанс того, что в генерация произойдет на 59-ю секунду так, что в соль упадет новая минута, достаточно мал) в виде b64 будут выглядеть так: MTAuMjMuMDkuMTAuMjAxOQ (10.23.09.10.2019)

Второй класс является оберткой над RijndaelManaged (имплементация AES в .Net) с длиной ключа 128 бит, режимом CBC. Помимо конструктора, доступны следующие методы:

  • EncryptToByte
  • EncryptToBase64String, обертка над EncryptoToByte
  • GetKey
  • GetIV
  • ToString

Код EncryptToByte:

public byte[] EncryptToByte(string plain)
{
	ICryptoTransform cryptoTransform = CRYPTED.rijndael.CreateEncryptor();
	byte[] bytes = CRYPTED.unicodeEncoding.GetBytes(plain);
	return cryptoTransform.TransformFinalBlock(bytes, 0, bytes.Length);
}

Код конструктора (доступны три перегруженных конструктора, взял один из них):

public CRYPTED(string base64key, string base64iv)
{
	this.InitializeRijndael();
	CRYPTED.rijndael.Key = Convert.FromBase64String(base64key);
	CRYPTED.rijndael.IV = Convert.FromBase64String(base64iv);
}

У нас есть шифротекст, вектор инициализации и ключ, а также знания об используемом шифровании. Вот самые простые варианты по расшифровке, что приходят в голову:

  • Онлайн сервис (cyberchef)
  • Написать программу на шарпах
  • Изменить через DNSpy исходники, чтобы не открывать среду разработки.

Решим через cyberchef:

Строки wide-формата, можно воспользоваться Find / Replace для устранения недостатка

Ссылка на полный рецепт


reverse, 300 баллов > Bot

We have created the best calculator. Probably..... 
@calculator_kubanctf_bot

Дан телеграм-бот Моя выдержка из общения с ним:

Я, [15.10.19 11:52]
/start

Сalculator_KubanCTF, [15.10.19 11:52]
try now

Я, [15.10.19 11:52]
123

Сalculator_KubanCTF, [15.10.19 11:52]
123

Я, [15.10.19 11:52]
1+2

Сalculator_KubanCTF, [15.10.19 11:52]
3

Я, [15.10.19 11:52]
-23

Сalculator_KubanCTF, [15.10.19 11:52]
-23

Я, [15.10.19 11:52]
a + 3

Сalculator_KubanCTF, [15.10.19 11:52]
try now

Я, [15.10.19 11:52]
a = 4

Сalculator_KubanCTF, [15.10.19 11:52]
try now

Я, [15.10.19 11:52]
//

Сalculator_KubanCTF, [15.10.19 11:52]
try now

Я, [15.10.19 11:52]
exit()

Я, [15.10.19 11:52]
/start

Сalculator_KubanCTF, [15.10.19 11:52]
try now

Я, [15.10.19 11:52]
import os

Сalculator_KubanCTF, [15.10.19 11:52]
123

Я, [15.10.19 11:52]
import os

Сalculator_KubanCTF, [15.10.19 11:52]
don't hack pls

Я, [15.10.19 11:52]
globals()[::]

Сalculator_KubanCTF, [15.10.19 11:52]
__name__

Я, [15.10.19 11:53]
(1,2,3)[2]

Сalculator_KubanCTF, [15.10.19 11:53]
try now

Я, [15.10.19 11:53]
(1,2,3)[2]

Сalculator_KubanCTF, [15.10.19 11:53]
3

Я, [15.10.19 11:53]
import

Сalculator_KubanCTF, [15.10.19 11:53]
try now

Я, [15.10.19 11:53]
eval("import os") and 1

Сalculator_KubanCTF, [15.10.19 11:53]
don't hack pls

Я, [15.10.19 11:54]
eval("import os") and 1

Сalculator_KubanCTF, [15.10.19 11:54]
don't hack pls

Я, [15.10.19 11:54]
str(globals())

Сalculator_KubanCTF, [15.10.19 11:54]
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x7f6f37b84d68>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': '/home/ubuntu/reverse/v1.py', '__cached__': None, 'telebot': <module 'telebot' from '/home/ubuntu/python-virtual-environments/env/lib/python3.6/site-packages/telebot/__init__.py'>, 'os': <module 'os' from '/usr/lib/python3.6/os.py'>, 'apihelper': <module 'telebot.apihelper' from '/home/ubuntu/python-virtual-environments/env/lib/python3.6/site-packages/telebot/apihelper.py'>, 'acos': <built-in function acos>, 'acosh': <built-in function acosh>, 'asin': <built-in function asin>, 'asinh': <built-in function asinh>, 'atan': <built-in function atan>, 'atan2': <built-in function atan2>, 'atanh': <built-in function atanh>, 'ceil': <built-in function ceil>, 'copysign': <built-in function copysign>, 'cos': <built-in function cos>, 'cosh': <built-in function cosh>, 'degrees': <built-in function degrees>, 'erf': <built-in function erf>, 'erfc': <built-in function erfc>, 'exp': <built-in function exp>, 'expm1': <built-in function expm1>, 'fabs': <built-in function fabs>, 'factorial': <built-in function factorial>, 'floor': <built-in function floor>, 'fmod': <built-in function fmod>, 'frexp': <built-in function frexp>, 'fsum': <built-in function fsum>, 'gamma': <built-in function gamma>, 'gcd': <built-in function gcd>, 'hypot': <built-in function hypot>, 'isclose': <built-in function isclose>, 'isfinite': <built-in function isfinite>, 'isinf': <built-in function isinf>, 'isnan': <built-in function isnan>, 'ldexp': <built-in function ldexp>, 'lgamma': <built-in function lgamma>, 'log': <built-in function log>, 'log1p': <built-in function log1p>, 'log10': <built-in function log10>, 'log2': <built-in function log2>, 'modf': <built-in function modf>, 'pow': <built-in function pow>, 'radians': <built-in function radians>, 'sin': <built-in function sin>, 'sinh': <built-in function sinh>, 'sqrt': <built-in function sqrt>, 'tan': <built-in function tan>, 'tanh': <built-in function tanh>, 'trunc': <built-in function trunc>, 'pi': 3.141592653589793, 'e': 2.718281828459045, 'tau': 6.283185307179586, 'inf': inf, 'nan': nan, 'bot': <telebot.TeleBot object at 0x7f6f37ae2cc0>, 'get_text_messages': <function get_text_messages at 0x7f6f37ad92f0>, '__warningregistry__': {'version': 6, ("unclosed file <_io.TextIOWrapper name='flaghere/flag.txt' mode='r' encoding='UTF-8'>", <class 'ResourceWarning'>, 1): True}}

Я, [15.10.19 11:57]
str(open("flaghere/flag.txt", "r").read())

Сalculator_KubanCTF, [15.10.19 11:57]
flag{[email protected][email protected]}

reverse, 500 баллов > neural_hack

neural_hack :)

Дан архив. Нам предоставляют обученную нейронку, которая делает для картинки 75x1010 суждение о том, насколько она похожа на исходную картинку. В определенный момент орги, заметив, что таск никто не решил, выложили хинт, но это никому не помогло.

Моё решение, занявшее ~22 часа работы ноутбука, заключается в расставлении черных и белых точек, вычислении дельты и сохранении текущего результата, если он признан более хорошим.

Если открыть эти картинки в image viewer’е и поперемещаться между ними, можно прочитать текст. Флаг: kubanctf{best_network_hack}

Главная часть кода:

import time
l1_stored = tf.reduce_sum(tf.square(image_array - flag_array))
x = 1010
y = 75


display(imafile)
###
#imafile = Image.open('flag.png')
#imafile = old_image.copy()
###

current_image = imafile.copy()
last = 1322713.5
while 1:
    draw = ImageDraw.Draw(imafile)
    for i in range(4):
        ranx = randint(0, x)
        rany = randint(0, y)
        color = choice(["white", "black"])
        draw.rectangle(((ranx, rany), (ranx, rany)), fill=color)
    image = np.array(imafile)[np.newaxis, :, :, :3] / 255
    image_array = model(image)

    l1_error = tf.reduce_sum(tf.square(image_array - flag_array))
    #print("l1:", l1_error)
    #display(imafile)
    if l1_error< l1_stored:
        l1_stored = l1_error
        current_image = imafile.copy()
        clear_output()
        display(imafile)
        print("l1:", l1_error)
        print("div:", l1_error/1322713.5)
    else:
        imafile = current_image.copy()

Тетрадь Юпитера с решением можно посмотреть здесь


author: Rakovsky Stanislav, Unicorn CTF

editor: Anna Mazurkevich, MPEI CTF

Cats!

Under construction

Wow! Flipable!

Hello from another side of the Moon!

Looking for a flag? Okay, take this:
LFXXKIDBOJSSA43XMVSXIIC6LYQCAIA=

About me

Under construction. You can try to contact me and fill this field… haha… ha…