Flare-on 8 2021 CTF writeup'ы

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Закончился очередной конкурс Flare-on от компании FireEye. Он привлекает любителей и профессионалов обратной разработки со всего мира. Ежегодно FireEye предлагает всем желающим 10-12 заданий нарастающей сложности. Участие в подобных конкурсах позволяет поддерживать свои инженерные навыки в тонусе и каждый раз стимулирует учиться новым интересным вещам. Субъективно задания этого года были проще, чем задания прошлых лет и это косвенно подтверждается большим числом победителей в этом году. Сложности при прохождении в основном возникали из-за неочевидности использования (применения) известных данных, нежели какие-то технологические или алгоритмические трудности - нужно только было правильно сопоставить "А" и "Б". Практически все предложенные задания решались в ручном режиме в отладчике без необходимости применения узкоспециализированных приёмов и инструментов.

Я узнал об этих соревнованиях только в 2019 году, сразу же решил зарегистрироваться и получил от решения всех головоломок огромное удовольствие. На счету у меня теперь третий памятный приз от команды FireEye и в этот раз занял 39 место в общемировом рейтинге (4-ое среди россиян):

Все флаги Flare-On Challenge традиционно оканчиваются на flare-on.com. Давайте приступим к разбору заданий.

Первое задание Flare-on обычно не вызывает никаких затруднений. В этом году это простая авторизационная html-форма с полями ввода имени пользователя и пароля. Посмотрим, как проверяется валидность данных:

исходный код функции checkCreds()
<script>
var form = document.getElementById("credform");
var username = document.getElementById("usrname");
var password = document.getElementById("psw");
var info = document.getElementById("infolabel");
var checkbtn = document.getElementById("checkbtn");
var encoded_key = "P1xNFigYIh0BGAofD1o5RSlXeRU2JiQQSSgCRAJdOw=="

function checkCreds() {

	if (username.value == "Admin" && atob(password.value) == "goldenticket") 
	{
		var key = atob(encoded_key);
		var flag = "";
		for (let i = 0; i < key.length; i++)
		{
			flag += String.fromCharCode(key.charCodeAt(i) ^ password.value.charCodeAt(i % password.value.length))
		}
		document.getElementById("banner").style.display = "none";
		document.getElementById("formdiv").style.display = "none";
		document.getElementById("message").style.display = "none";
		document.getElementById("final_flag").innerText = flag;
		document.getElementById("winner").style.display = "block";
	}
	else
	{
		document.getElementById("message").style.display = "block";
	}
}

</script>

Ну, ок. Прописываем перед if ( ... )

username.value = "Admin";
password.value = btoa("goldenticket");

вводим в форму произвольные данные для вызова проверочного скрипта и получаем первый ключ:

В наличии программа-распаковщик UnlockYourFiles.exe и 6 зашифрованных файлов:

capa.png.encrypted
cicero.txt.encrypted
commandovm.gif.encrypted
critical_data.txt.encrypted
flarevm.jpg.encrypted
latin_alphabet.txt.encrypted

При запуске программа просит ввести ключ расшифровки. Легко обнаружить, что программа читает и пишет блоками по 8 байт. Также легко проверить, что изменение одного байта ключа влияет только на один байт блока данных. Программа небольшая - всего 9 функций и единственная функция, похожая на дешифровщик данных, выглядит вот так:


Тот случай, когда ассемблер понятнее вывода дизассемблера.
Проще всего декодировать файл с алфавитом. Перепишем алгоритм на Python:

alphabet = "ABCDEFGH"
b = [0x0f,0xce,0x60,0xbc,0xe6,0x2f,0x46,0xea]
for i in range(8):
    for c in range(256):
        if (rol(c^b[i],i,8) -i )== ord(alphabet[i]):
            print(chr(c),end='')

Ключ расшифровки - No1Trust, а флаг - You_Have_Awakened_Me_Too_Soon_EXE@flare-on.com

Здесь мы добрались до чего-то интересного. Дан докер-контейнер. Я решил не возиться с установкой и настройкой системы развёртывания, а для начала изучить его структуру. Технически он представляет собой каталоги с json-описателем и с содержимым в виде tar-архива. Один контейнер содержит файл./AntiochOS, остальные контейнеры - некоторое подмножество файлов a.dat..z.dat. Файлы *.dat нигде не повторяются. У каждого контейнера свой уникальный автор, по другим полям (кроме ID) описания контейнеров не различаются.

Отлично. Запустим ./AntiochOS:

В гидре напрямую можно увидеть, что ./AntiochOS поддерживает четыре команды: "help", "quit", "approach" и "consult".

Вводный текст команды approach - отслылка к популярной британской фэнтезийной кинокомедии Монти Пайтон и Священный Грааль, и в сцене 22 можно найти ответы на вопросы: имя - Sir Lancelot, квест - Holy Grail, любимый цвет - Blue. Три правильно угаданные буквы дают право открыть две шкатулки угаданных слова выдают пользователю некоторое число. В ./AntiochOS есть массив структур {hash_name, hash_color, res_value}, Программа вычисляет хэши от введённых вами строковых данных, и если проверки пройдены - возвращает вам соответствующим им res_value - уникальный номер в диапазоне [1..30]. Иначе... AAARGH! Имя квеста нигде не используется.

Замечаем, что Sir Lancelot является создателем одного из контейнеров докера с [a.dat ... z.dat], следовательно, хэши от других имён тоже можно найти в этом массиве структур, а значит, для каждого имени можно подсмотреть свой res_value, даже не зная ответов на 2 и 3 вопросы, в gdb это несложно сделать:

как это сделано

после вычисления хеша мы проходим по циклу по i до совпадения с data[i].hash_name, после выхода из цикла регистр rdx уже будет указывать на следующий элемент структуры, а значит, что [rdx-0x4] - на data[i-1].res.value

и т.д. Смотрите - мы не угадали с цветом, но номер всё равно получили. Далее из каждого контейнера нужно скопировать [a.dat...z.dat] в общее хранилище согласно этим порядковым номерам (порядок важен, из-за пропусков не все *.dat результирующего набора будут из последнего добавленного хранилища). Если всё сделать верно, в псевдографике по команде "consult" можно прочитать флаг Five_Is_Right_0ut@flare-on.com.

Сидел над заданием больше суток - много неочевидных вещей, дольше всего думал над последним шагом - номера получил, все нужные файлы a.dat..z.dat на руках, бинарник изучен вдоль и поперёк, а что делать с этим богатством дальше - совершенно непонятно.

Нам предлагают поиграть в мультимедийную игру-угадайку и получить в качестве приза флаг. Стандартная практика для нулевых - standalone-приложение, движок + проект в одном флаконе. Например, AutoPlay Media Studio, генераторы электронных учебников, игровые движки - были сотни таких программ. CFF Explorer намекает нам, что приложение упаковано:

а комментарий приложения гласит, что это приложение сделано с помощью Multimedia Builder:

Приложение можно декомпилировать и сохранить проект Multimedia Builder отдельно от приложения. Я решил скачать триальную версию ММВ и открыть этот проект там. К сожалению, распакованный проект в нём открывается как-то совсем криво:

У меня не получилось получить доступ к ресурсам проекта через ММВ, а также понять в нём, к чему привязан каждый из скриптов, но зато получил подказку, что нужно обратить внимание на папку TEMP (см. скриншот). Аккуратно выпишем все скрипты, может пригодиться:

Script01: part1$='derelict:MZZWP'; PluginSet("PlugIn","part1$")
Script02: part2$='lagan:BAJkR'; PluginSet("PlugIn","part2$")
Script03: part2$='flotsam:DFWEyEW'; PluginSet("PlugIn","part2$")
Script04: part1$='flotsam:PXopvM'; PluginSet("PlugIn","part1$")
Script05: part2$='derelict:LDNCVYU'; PluginSet("PlugIn","part2$")
Script06: part3$='derelict:yXQsGB'; PluginSet("PlugIn","part3$")
Script07: part2$='jetsam:newaui'; PluginSet("PlugIn","part2$")
Script08: part3$='lagan:QICMX'; PluginSet("PlugIn","part3$")
Script09: part1$='lagan:rOPFG'; PluginSet("PlugIn","part1$")
Script10: part3$='jetsam:HwdwAZ'; PluginSet("PlugIn","part3$")
Script11: part1$='jetsam:SLdkv'; PluginSet("PlugIn","part1$")
Script12: part2$='derelict:LSZvYSFHW'; PluginSet("PlugIn","part2$")
Script13: part3$='flotsam:BGgsuhn'; PluginSet("PlugIn","part3$")
Script14: part4$='lagan:GTYAKlwER'; PluginSet("PlugIn","part2$")
Script15: part4$='derelict:RTYXAc'; PluginSet("PlugIn","part4$")
Script16: part2$='lagan:GTXI'; PluginSet("PlugIn","part2$")
Script17:
PluginRun("PlugIn","PluginFunc19")
PluginGet("PlugIn","var1$")
NextPage()
LoadVariable("visitors","count")
count = count + 1
SaveVariable("visitors","count")
vc$='Visitor Counter: ' + CHAR(count)
CreateText("mytext","visitlabel$,1050,580,yippy")
LoadText("visitlabel$","vc$")
colr$='TEXTCOLOR=255,0,0'
SetObjectParam("outlabel$","colr$")
SetObjectParam("outlabel$","FONTNAME=Comic Sans MS")
SetObjectParam("outlabel$","FONTSIZE=24")
colors$[1] = '255,0,0'
colors$[2] = '0,255,0'
colors$[3] = '0,0,255'
colors$[4] = '255,0,0'
colors$[5] = '0,255,0'
colors$[6] = '0,0,255'
colors$[7] = '255,0,0'
colors$[8] = '0,255,0'
colors$[9] = '0,0,255'
colors$[10] = '255,0,0'
colors$[11] = '0,255,0'
colors$[12] = '0,0,255'
colors$[13] = '255,0,0'
colors$[14] = '0,255,0'
colors$[15] = '0,0,255'
For Loop= 1 To 1000
  For Counter= 1 To 15
    CreateText("mytext","outlabel$,20,100 + 50 * Counter,yippy")
    LoadText("outlabel$","var1$")
    colr$='TEXTCOLOR='+colors$[Counter]
    SetObjectParam("outlabel$","colr$")
    SetObjectParam("outlabel$","FONTNAME=Comic Sans MS")
    SetObjectParam("outlabel$","FONTSIZE=48")
    Pause("1000")
    DeleteObject("outlabel$")
  Next Counter
Next Loop

Так. Значит, при вызове скриптов в памяти приложения формируются четыре строки (derelict, lagan, flotsam, jetsam), а на последнем шаге вызывается результирующий скрипт Script17. Согласно подсказке в папке TEMP обнаруживаем fathom.dll, а в нём - экспортируемую функцию PluginFunc19 (aдрес 0x10002e40). x64dbg позволяет установить брейкпойнт в момент загрузки конкретной DLL, а будучи загруженной, можно определить относительный адрес нужной функции. Каких-то хитрых трюков в решении данного таска как таковых нет, просто нужно раз -нцать пройтись отладчиком по данной функции (она небольшая) и получить ответы на следующие вопросы:

  • за какой скрипт отвечает каждая картинка игрового приложения

  • все ли данные для нас актуальны (ответ - не все)

  • что за преобразования происходят с данными (если вдруг запутались - очень помогает выписать на бумаге пошагово 1-2 прохода тела цикла - такого типа комментарии смотри в ch10)

  • на вход какой хеш-функции подаётся блок (ответ - 0x8003 - md5).

так выглядит пошаговый анализ этого задания в отладчике

Я переписал алгоритм PluginFunc19 на Python:

d = ('MZZWP','LDNCVYU', 'yXQsGB', 'LSZvYSFHW', 'RTYXAc')
l = ('BAJkR','QICMX', 'rOPFG', 'GTYAKlwER','GTXI')
f = ('DFWEyEW', 'PXopvM', 'BGgsuhn')
j  = ('newaui', 'HwdwAZ', 'SLdkv')

import binascii
import random
import hashlib

x = '00A8A3FCD1A79DD2BA8F8F87A4E4CBF9169E81F938E5AF9F909A96A3A9A42596'
x = binascii.unhexlify(x)
x =x[::-1]

for w in range(10):
    for loop in range(10*w):
        f_str = ''
        j_str = ''
        for i in range(3):
            j_str = j_str + j[random.randint(0,2)]
        for i in range(w+1):
            f_str = f_str + f[random.randint(0,2)]
            for i in range(31):
                r[i]= x[i] ^ ord(f_str[i % len(f_str)])
                r[i] = ( r[i] - ord(j_str[i % len(j_str)])) % 256
                if hashlib.md5(r).hexdigest() == '6c5215b12a10e936f8de1e42083ba184':
                    print ('yes')
                    print(j_str)
                    print(f_str)
                    print(hashlib.md5(r).hexdigest())
                    exit

запустил на исполнение, получил верную последовательность, которая даёт эталонный хэш. После нажатия правильной игровой комбинации получил верный ключ: s1gn_my_gu357_b00k@flare-on.com

Да, это виртуальная машина с неизвестным содержимым внутри. Минимальный набор уважаемого исследователя чужих виртуальных машин выглядит так:

cat ~/.bash*
find / -type f -mtime -60 -mtime +1 -exec ls -la {} \: 2>/dev/null | less
ls -la ~
ls -la Documents
crontab -a

Это даст нам полезные, явно не системные файлы, со свежей датой создания 26 августа 2021 года:

  • /usr/bin/zyppe // утилита, устанавливающая слой шифрования

  • /usr/bin/dot // утилита, требующая ввести какой-то пароль

  • некие константы NUMBER и aлиас FLARE

  • кучу зашифрованных файлов в папке Documents

Начинаем разбираться.

Необходимо снять слой шифрования. Все текстовые документы раздела Documents имеют размер 1024 байта. Утилита /usr/bin/zyppe использует симметричный алгоритм, так что всё, что нам нужно, это повторно применить её к содержимому папки Documents.

Теперь почитаем сами документы:

[user@localhost Documents]$ cat udon_noddles.txt.broken 
"ugali", "unagi" and "udon noodles" are delicious. What a coincidence that all of them start by "u"!

[user@localhost Documents]$ cat ugali.txt.broken 
Ugali with Sausages or Spaghetti is tasty. It doesn’t matter if you rotate it left or right, it is still tasty! You should try to come up with a great recipe using CyberChef

[user@localhost Documents]$ cat unagi.txt.broken 
The 1st byte of the password is 0x45

Документы на букву "s" зашифрованы с помощью команд ror или rol. Исходный вариант:

[user@localhost Documents]$ xxd sausages.txt.broken 
00000000: 2a34 b210 19b9 3a10 31bc 3ab2 10b7 3310  *4....:.1.:...3.
00000010: 3a34 b210 38b0 b9b9 bbb7 3932 10b4 b910  :4..8.....92....
00000020: 183c 991a 0500 0000 0000 0000 0000 0000  .<..............

Преобразованный вариант:

sausages.txt:         The 2st byte of the password is 0x34
strawberries.txt:     In the FLARE team we like to speak in code. 
spaghetti.txt:        In the FLARE language "spaghetti" is "c3BhZ2hldHRp". 
strawberries.txt:     You should learn our language, otherwise you want be able to speak with us when you escape 
                      (if you manage to escape!). For example, instead of "strawberries" we say "c3RyYXdiZXJyaWVz".

Подсказок, к каким документам применять указанные алгоритмы больше не будет и необходимо следовать своей интуиции. Документы на букву "r" написаны кодировкой Base64:

[user@localhost Documents]$ cat rasberries.txt.broken 
VGhlIDNyZCBieXRlIG9mIHRoZSBwYXNzd29yZCBpczogMHg1MQo=

Сконвертируем их в человеко-понятный вид:

rasberries.txt      The 3rd byte of the password is: 0x51
reeses.txt          We LOVE "Reese\'s", they are great for everything! They are amazing 
                    in ice-cream and they even work as a key for XOR encoding 

Документы на букву "b" накрыты операцией ХОR, где первый операнд - исходный текст, второй - i-тый байт "Reese's". Преобразовываем и продолжаем копаться в чужом белье:

blue_cheese.txt:         The 4th byte of the password is: 0x35
backberries.txt:         If you are not good in maths, the only thing that can save you is to be a bash expert. 
                         Otherwise you will be locked here forever HA HA HA!
banana_chips.txt:        Are you good at maths? We love maths at FLARE!
                         We use this formula a lot to decode bytes: "ENCODED_BYTE + 27 + NUMBER1 * NUMBER2 - NUMBER3"

Отлично, пока не очень сложно. Следующие документы - это просто chr(ord(symbol) + 0x4 )):

iced_coffee.txt          The only problem with RC4 is that you need a key. The FLARE team normally uses this number: "SREFBE" (as an UTF-8 string). 
                         If you have no idea what that means, you should give up and bake some muffins.
instant_noodles.txt      The 5th byte of the password is: 0xMS
ice_cream.txt            это рецепт вкусного десерта, попробуем его позже, на данный момент
                         оттуда нам важно выяснить, что C -> 0,  B -> 1,  L -> 2...

Зная ключ для RC4 вскроем документы на букву "n":

nachos.txt             In the FLARE team we really like Felix Delastelle algorithms,
                       specially the one which combines the Polybius square with transposition, 
                       and uses fractionation to achieve diffusion.
natillas.txt           Do you know natillas? 
                       In Spain, this term refers to a custard dish made with milk and KEYWORD, 
                       similar to other European creams as crème anglaise.
                       In Colombia, the delicacy does not include KEYWORD, and is called natilla
nutella.txt            The 6th byte of the password is: 0x36

По-видимому, этот шифр малоизвестен в русскоязычной среде. До Flare-2021 pанее в литературе мне нигде не попадались упоминания о нём. Расшифровать такой шифртекст удобно на ресурсе cryptii.com ( https://cryptii.com/pipes/bifid-cipher ). Ура, мы можем прочесть тексты на букву d, например, такой:

Abn lef emadkxp frceqdnhe? Tah gdcktm temyku xxo qo ktyhzn! Zd'k raooua, por uda ztykqh.
are you missing something? you should search for it better! it's hidden, but not really.

(читателю для сравнения дан текст до расшифровки и после). Узнаём, что есть скрытый файл с фразой "the 7th byte of the password is: 0x66" и что "giovan battista bellaso loved microwaves". А вы знали, что шифр Виженера придуман не им? Теперь и вы это знаете.

Применяем шифр Виженера с ключевым словом microwaves к текстам на букву "o", получаем 8-ой байт пароля "0x60", и информацию о том, что Flare Team публикует в твиттере массу интересных публикаций и это поможет вскрыть тексты на оставшуюся букву "t". Увы, я не справился с последним шагом, но известных символов мне хватило, чтобы брутфорсом подобрать нужный пароль для приложения /usr/bin/dot.

как это сделано

Приложение dot вычисляет sha256 от введённой строки и сравнивает её с эталонной. Можно воспользоваться мощной утилитой hashcat для подбора хеша, а можно написать свой брутфорс.

Пароль: E4Q45d6f`lD5I, флаг: H4Ck3r_e5c4P3D@flare-on.com

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

Дан pcap-файл с двумя tcp-сессиями между хостом и A xn--zn8hscq4eeafedhjjkl.flare-on.com. Первая сессия - передача png-котика и некоторого двоичного файла. Вторая сессия - общение мелкими пакетами друг с другом. Заметна определённая структура - двочные файлы начинаются с "MEOW", Dword value, Dword value, "PA30". Увы, Wireshark умеет сохранять сессию в бинарном виде только как единое целое, то есть можно сохранить и после нарезать bin по совпадению с MEOW, но я принял более универсальное решение - сохранить дамп как массивы "C" и быстро набросал python-скрипт по конвертации массивов в множество bin-файлов, благо анализ сетевого траффика - частая встречающаяся задача и удобный инструмент конвертации наверняка пригодится ещё.

Так, что, собственно, с этим добром делать? Извлечённая картинка было совершнно типовой. Стеганографический анализ утилитой zsteg ничего не выявил, PNG-файл содержал правильные заголовки и никаких лишний секций не имел Второй двоичный файл первой сессии имел размер 10Кб и на полноценную программу (даже упакованную) никак не тянул.

Довольно быстро нашлось, что 50 41 33 30 (PA30) - это сигнатура Package Delta Format, но этот в сети пример повёл меня по ложному пути - видно, что у такого файла средняя энтропия и бывают повторяющеся символы, а своих файлов PA30 на компе не нашлось. Какое-то время потратил на подбор алгоритма сжатия, пока не понял, что это совершенно бесполезное занятие.

Выручила вот эта найденная ссылка и опубликованный проект delta_patch.py на гитхабе. И, да, это действительно Package Delta Format! Сложно передать, но это было огромное потрясение. Так умело подобрать данные, нормальное изображение 660 кб патчем в 10 кб превратить в полноценное dll-приложение весом в 1.4 мб. Фокус, похлеще фокусов Гуддини и Копперфильда.

Друзья, простите меня за это большое лирическое отступление, но я никак не ожидал, что оно сработает. Остальное оказалось элементарным делом. Порт и хост можно подсмотреть в tcp-трафике, настроить сеть, написать серверное приложение и сымитировать внешнюю атаку по перехваченным запросам со второй сессии. Выяснилось, dll при установлении соодинения создаёт cmd-подпроцесс, получает shell-команды и отправляет результат их исполнения. Злоумышленник с помощью специальных запросов мог переходить по каталогам файловой системы, читать файлы, запрашивать перечень файлов. В одном прочитанном таким образом файле и содержался ключ 1m_H3rE_Liv3_1m_n0t_a_C4t@flare-on.com.

Расшифровка и создание патчей осуществлялось библиотечными функциями CreateDeltaB и ApplyDeltaB. Второй вариант решения задачи - написать свой расшифровщик, но я предпочёл просто читать выделенную память в отладчике после вызова ApplyDeltaB, посылая на вход не только сами запросы, но и перехваченные ответы.

прикладываю пример расшифрованной команды и ответа:
@echo off & for /f %a in ('dir /s /b') do echo %~fa %~za

C:\Users\user\Desktop\SuperSecret\2021_FlareOn\Cat_Memes 0
C:\Users\user\Desktop\SuperSecret\2021_FlareOn\Great_Ideas 0
C:\Users\user\Desktop\SuperSecret\2021_FlareOn\Never 0
C:\Users\user\Desktop\SuperSecret\2021_FlareOn\No_Flags_Here 0
C:\Users\user\Desktop\SuperSecret\2021_FlareOn\NO_SERIOUSLY_EVEN_MORE_BESTEST_IDEAS 0
C:\Users\user\Desktop\SuperSecret\2021_FlareOn\Okay_Ideas 0
C:\Users\user\Desktop\SuperSecret\2021_FlareOn\Swag 0
C:\Users\user\Desktop\SuperSecret\2021_FlareOn\The_BEST_Ideas 0
C:\Users\user\Desktop\SuperSecret\2021_FlareOn\Cat_Memes\meow.txt 64
C:\Users\user\Desktop\SuperSecret\2021_FlareOn\Great_Ideas\meow.txt 64
C:\Users\user\Desktop\SuperSecret\2021_FlareOn\Never\Gonna 0
C:\Users\user\Desktop\SuperSecret\2021_FlareOn\Never\Gonna\Give 0
C:\Users\user\Desktop\SuperSecret\2021_FlareOn\Never\Gonna\Give\You 0
C:\Users\user\Desktop\SuperSecret\2021_FlareOn\Never\Gonna\Give\You\Up 0
C:\Users\user\Desktop\SuperSecret\2021_FlareOn\Never\Gonna\Give\You\Up\FlagPit 0
C:\Users\user\Desktop\SuperSecret\2021_FlareOn\Never\Gonna\Give\You\Up\Gotcha.txt 1806
C:\Users\user\Desktop\SuperSecret\2021_FlareOn\Never\Gonna\Give\You\Up\meow.txt 64
C:\Users\user\Desktop\SuperSecret\2021_FlareOn\Never\Gonna\Give\You\Up\The_Real_Challenge 0
C:\Users\user\Desktop\SuperSecret\2021_FlareOn\Never\Gonna\Give\You\Up\FlagPit\me0000000w.txt 812
C:\Users\user\Desktop\SuperSecret\2021_FlareOn\Never\Gonna\Give\You\Up\The_Real_Challenge\Mugatuware.exe 1532928
C:\Users\user\Desktop\SuperSecret\2021_FlareOn\Never\Gonna\Give\You\Up\The_Real_Challenge\mydude.exe 650105
C:\Users\user\Desktop\SuperSecret\2021_FlareOn\No_Flags_Here\meow.txt 64
C:\Users\user\Desktop\SuperSecret\2021_FlareOn\No_Flags_Here\what_did_you_expect.txt 1658
C:\Users\user\Desktop\SuperSecret\2021_FlareOn\NO_SERIOUSLY_EVEN_MORE_BESTEST_IDEAS\meow.txt 64
C:\Users\user\Desktop\SuperSecret\2021_FlareOn\Okay_Ideas\meow.txt 64
C:\Users\user\Desktop\SuperSecret\2021_FlareOn\Swag\meow.txt 64
C:\Users\user\Desktop\SuperSecret\2021_FlareOn\The_BEST_Ideas\meow.txt 64

Бонус - адрес сайта после декодирования url:

Источник: https://habr.com/ru/post/584672/


Интересные статьи

Интересные статьи

Хабр, привет! Под катом хотелось бы поговорить об опыте участия нашей команды из лаборатории моделирования природных систем Национального центра когнитивных разработок Университета ИТМО в хакатон...
Предлагаем вашему вниманию подборку с ссылками на новые материалы из области фронтенда и около него. Читать дальше →
Написание четкого и удобочитаемого кода необходимо для улучшения его качества. Кроме того, чистый код легче тестировать. Нет причин не потратить пять лишних минут на рефа...
У HR-ров есть шутка: раньше мы искали антикризисных менеджеров, которые боролись с кризисом и побеждали его, а сейчас тоже нуждаемся в них, но с противоположными компетенциями, способ...
Сейчас самое время навести порядок в своем списке дел и завести новый онлайн-планировщик, органайзер или календарь, чтобы в этом году уж наверняка стать более эффективным и продуктивным. ...