TulaCTF2024 & Киберколизей

TulaCTF2024 & Киберколизей

Капибары

Общие впечатления: 🤩 TulaCTF - очень классное соревнование с кучей интересных задач. Больше всего понравился результат, 14-ые 🥳🏆 И приглашение в ФИНАЛ!

Киберколизей тоже прошел увлекательно 🤩, научились куче всего нового, но уже подустали и сил на него не хватило.

Оглавление:

Введение

Еще раз вспомним два "золотых" правила:

  1. Начинаем с самых легких задач
  2. Ищем подсказки от "оргов"

И в Колизее и в ТулеCTF очень много было хороших подсказок, на которые мы, правда, в силу неопытности не всегда обращали внимание 😢

Поэтому на этой неделе будем усиленно подтягивать свои знания и навыки 😁

Начнем с того, что добавим еще два правила:

3. Встретив что-то новое, не опускай руки, а ищи информацию. Интернет - это великая сила! 🤩

4. Заниматься нужно каждый день! Появилась минутка: поиграй, отдохни, появилась вторая - займись спортом, появилась третья - вперед, в бой! Мы на этой неделе обязательно домучаем обзор площадок, на которых можно потренироваться, ну а пока Добро пожаловать на лучшую в России.


OSINT

Трагедия (КК, 200)

Условие: в этом месте в 1983 году произошел ужасный случай, в котором был замешан актер. Укажите в качестве флага дату его рождения в формате CODEBY{YYYYMMDD}.

Национальный парк Боржоми-Харагаули

Решение: Сам парк был создан позднее трагедии и поиск по Боржоми не дал ничего. А вот связка "трагедия 1983 Грузия" навела на теракт в самолете в это время. Очень хорошая статья про эту историю. "Один из террористов, Герман Кобахидзе (жених), был актером и работал на студии «Грузия-фильм»". Ищем в гугле его дату рождения и вводим в качестве флага.

Флаг: CODEBY{19620726}


Задача про аэропорт (КК, 350, не решена)

Условие: Мой друг очень большой любитель аниме пропал в аэропорту Токио 17 января 2024 года. Если вы посмотрите куда он полетел, то сразу поймете почему. Через два часа он вернулся, но ничего не рассказал. В качестве ответа нужно ввести номер борта, на котором он отправился в полет. Формат флага: CODEBY{XX-XXX}.

Решение:

Отрабатывали версию о самолетах для любителей аниме. Как ни странно, таких - много 😁

JA73AB от Тайваньских авиалиний

Для поиска рейсов, которые сделал тот или иной самолет, есть куча хороших сервисов, например, самый известный - FlightRadar. Но он не очень для нас удобен в этой задаче, так как у него для даты "старше", чем 3 месяца требуется покупка Premium'а. И здесь первый вопрос, который у нас возник, 17 января то ли было выбрано как "очень особенный" день или просто, чтобы выйти за "бесплатную версию" FlightRadar'а.

Поиск в гугле по дате 17 января ничего, кроме истории, что рейс из Токио в Ситл вернулся потому что пассажир укусил проводника за руку не дал (но зомби это не аниме :)), бортовой номер к формату флага не подходит ни у одного, ни у другого самолета. Начали искать аналогичные флайтрадару сервисы. И нашли. И еще ряд интересных ресурсов:

JA73NG


JA602A
JA616A


Его знает каждый (TulaCTF, 100)

Условие задачи:

Решение задачи:

Скармливаем картинку сервису "поиск по изображениям" Яндекса вылетает много мусора, обрезаем ключевую часть - получаем страницу:

Памятники на ул. Кирова в Челябинске

Переходим на Яндекс.Карты и определяем координаты.

К тому моменту организаторы уточнили, что вводить надо только 4 знака после запятой.

Флаг: TulaCTF{55.1654_61.4004}

Klasa_mistrzowska (TulaCTF, 100)

Условие задачи: Я где то был на мастерклассе и что то забыл, помогите найти телефон, в памяти осталась только фотка гостиницы

Решение: Поиск по картинке в яндексе ничего не дает, нужно искать через либо текстом, либо через гугл.картинки

Находим, что гостиница находится в г. Торун (Польша) на ул. Рабяньская и рядом находится музей торуньского пряника (прям как Тульского).

Вбиваем вместо флага номер телефона.

Флаг: TulaCTF{48422154242}

Реконструкция (TulaCTF, 271)

Условие задачи:

Церквушка на макушки земли Русской где годы и высота взяли свое

Промежуток лет и высота дадут ответ

Формат флага: TulaCTF{1234-1421-600.3}

Фото таблички

Решение задачи:

Задача, направленная на поиск информации в сети. Ищем в гугле или яндексе строку: Церкви Тепло-Огаревский район. Нам подошел вот этот ресурс.

Дальше руками проверяем 10 храмов. Наиболее похожей оказалось церковь Богоявления Господня в селе Раево.

Переходим на Яндекс.Карты и в ее фотографиях находим фото таблички.

Флаг: TulaCTF{1864-1880-293.2}

Давным-давно (TulaCTF, 620}

Условие задачи:

Решение:

Первым шагом нужно было найти скважину на карте. Нужно было открыть карту побольше, тогда становится видно, что на ней есть реки Чирча и Тыяха. По их поиску место находится достаточно легко.

На второй фотке есть дорога, тундра, болота, забор и насыпан какой-то песок. Ключевой момент, что это какая-то закрытая территория. Можно предположить, что как раз вот какой-то из этих двух тупиков.


Затем мы перешли к единому фонду геологической информации. Затем переключаемся на режим карты и ищем похожее место. Очень быстро находится Южно-Надымская, 2 поисковая скважина. Щелкаем по ней, выпадает куча документов.

Перейдя по ссылке, мы получаем кучу всей информации, но глубины в ней нет 😢 и вот третьем шагом нужно было найти ФГБУ ВНИГНИ.

или сразу перейдя по ссылке

в разделе "Информация по бурению" мы получили глубину скважины.

Флаг: TulaCTF{4082}

Я ваще (TulaCTF, 676)

Условие задачи:

molot.jpg

Решение:

На самом деле на картинке изображен не молот, а пешеход, да, по фантазии автора - это, именно, пешеход!

В метаданных была соответствующая подсказка:

Смотрим еще раз на условие задачи и выбираем ключевые слова для поиска: Тула вывеска пешеход и должно появиться что-то вроде:

Есть и пост в ВК и статья, в которой можно было прочитать сообщение: Водитель и пешеход, будьте взаимно предупредительными.

Флаг: TulaCTF{предупредительными}.


Crypto

Простая задача (КК)

Условие задачи:

яблоко-.-. банан--- апельсин-.. виноград. ананас-... яблоко-.-- банан{ апельсин-.. виноград.---- ананас-.. яблоко..--.- банан-.-- апельсин----- виноград..- ананас..--.- яблоко.-. банан...-- апельсин-.-. виноград----- ананас--. яблоко-. банан.---- апельсин--.. виноград...-- ананас..--.- яблоко-- банан----- апельсин.-. виноград... ананас...-- яблоко..--.- банан-.-. апельсин----- виноград-.. ананас...-- яблоко..--.. банан}

Решение задачи:

Яблоки, бананы и т.д. здесь просто для отвлечения внимания, удаляем их при помощи "замены" в любом текстовом редакторе, остается вот такая строчка.

-.-. --- -.. . -... -.-- { -.. .---- -.. ..--.- -.-- ----- ..- ..--.- .-. ...-- -.-. ----- --. -. .---- --.. ...-- ..--.- -- ----- .-. ... ...-- ..--.- -.-. ----- -.. ...-- ..--.. }

Скармливаем транслятору Азбуки Морзе и получаем

Флаг: CODEBY{D1D_Y0U_R3C0GN1Z3_M0RS3_C0D3?}


Холмы (КК)

Условие задачи: файл

Решение:

Как говорится в подсказке - это шифр Хилла (ссылка 1, ссылка 2, ссылка 3).

Лучше всего расшифровывать онлайн декодером . Заполняем матрицу как в условии и получаем флаг.

Флаг: CODEBY{BTW_EXISTS_AN_INTERESTING_FILM_ABOUT_HILLS}


Misc

Странный код (КК, 350)

Условие: Архив с кодом, в котором крякозябры

Решение: По расширению файла, стилистики кода сразу становится ясно, что это питон 😁

kassth wmos dw z
wptqfw fcgh64 eu p64
i = "u09gfxnbs000wp83crixznixznujurqqvt8zvn80l0patrq9"
i = d64.p64giecgi(h).rhgqrh()
g = "ecqktoww!\p"
rhj r(h, g=0.2):
  jqf f mp h:
    svkbw(g, gbg='', jnivl=vfxi)
    z.goigd(g)
t(e+s)

но какой-то странный, первые строчки в классической программе - это, как правило import. Меняются только буквы, а цифры нет. Причем в первый раз import это kassth, а во второй - wptqfw, в первый раз b64 это p64, а во второй d64, а в третий - f64. Натравливаем на этот код распознавалку от dcode и на определенной итерации он, наконец, выдает, что это шифр Вижинера (этот шаг всегда проверяйте руками, если видно, что есть соответствие буквы в букву, но каждый раз разное).

Натравливаем декодер Вижинера по известному слову import и получаем правильный код

Декодер от qCode

и на ключе CODE получаем

import time as x
import base64 as b64
f = "q09erujze000tl83adftxzftxzrfsdnmtf8wrl80x0mwrdn9"
e = b64.b64decode(f).decode()
c = "congrats!\n"
def p(t, d=0.2):
  for c in t:
    print(c, end='', flush=true)
    x.sleep(d)
p(c+e) 

Довольные - запускаем полученный код в питоне и получаем ошибку декодировки base64. После небольшого анализа становится понятно почему

Регистр букв . qCode все преобразовывает в маленький, а это неправильно. Мы решили последовательным изменением регистров в "четверках" (BASE64 преобразовывает 4 символа исходного кода в три байта) так, чтобы получался красивый код. В итоге ключ оказался вот таким:

Q09ERUJZe000Tl83aDFTXzFTXzRfSDNMTF8wRl80X0MwRDN9

и программа нам выдала

Флаг: CODEBY{M4N_7h1S_1S_4_H3LL_0F_4_C0D3}

Земля Санникова (КК, 350)

Условие: Гулформа по адресу: https://docs.google.com/forms/d/e/1FAIpQLSf1TPaUeq68KoBjThBinu0u5FEosLq1llykroSbelbW7EuPpg/viewform

Решение: Честно говоря, не очень поняли почему такое за 350, начали с просмотра кода страницы и сразу бросилось в глаза внизу страницы.

FB_PUBLIC_LOAD_DATA_ = [null,[null,[[505817847,"Где расположена Земля Санникова?",null,0,[[945920828,null,1,null,[[2,101,["Unfortunately, it never existed. It's all the ice's fault :("],"67,79,68,69,66,89,123,108,52,115,116,95,113,117,51,115,116,49,111,110,95,119,52,115,95,104,52,99,107,101,100,125"]]]],null,null,null,null,[["1-o5is_3eBWg_JPcnc6k76SUayDVPLoedPHO_0VXiR_DPXhk",null,[676,547,0]]],null,[null,"\u003cb\u003eГде расположена Земля Санникова?\u003c/b\u003e"]]],null,null,[null,null,null,null,null,[null,null,null,[255,152,0,null,1],[255,219,166,null,1],null,[["Roboto",24,400,2],["Roboto",12,400,2],["Roboto",11,400,2]]]],null,null,null,"Контрольный вопрос",67,[null,null,null,2,null,null,1],null,null,null,null,[2],[[1,1,1,1,1],1,0,2,0],null,null,null,null,null,null,null,null,[null,"Контрольный вопрос"]],"/forms","Контрольный

Преобразование его в ASCII строку - дает нам

Флаг: CODEBY{l4st_qu3st1on_w4s_h4cked}

Дебри лабиринтов (TulaCTF, 100)

Условие задачи:

Решение:

По задумке авторов, такая задача и слово "кубы" должны были натолкнуть на игру Minecraft. Нужно было просканить порты и найти сервер Майнкрафта на сервере tulactf.ru.

nmap -sV tulactf.ru

он открыт на самом деле по умолчанию 25565.

Там было три лабиринта с разными ловушками.

Флаг: TulaCTF{cheel_and_relax_with_minecraft}


Reverse

Разминка (КК, 200)

Условие задачи: архив с файлами

Решение: Беглый взгляд на файлы показал, что они используют .Net Framework 4.8

Такие файлы лучше всего анализировать в dotPeek. Начнем с библиотеки

using System.IO;
using System.Security.Cryptography;

namespace EncryptionLibrary
{
 public class EncryptionHelper
 {
  public static byte[] EncryptStringToBytes_Aes(string plainText, byte[] Key, byte[] IV)
  {
   byte[] array;
   using (Aes aes = Aes.Create())
   {
    aes.Key = Key;
    aes.IV = IV;
    ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
    using (MemoryStream memoryStream = new MemoryStream())
    {
     using (CryptoStream cryptoStream = new CryptoStream((Stream) memoryStream, encryptor, CryptoStreamMode.Write))
     {
      using (StreamWriter streamWriter = new StreamWriter((Stream) cryptoStream))
       streamWriter.Write(plainText);
      array = memoryStream.ToArray();
     }
    }
   }
   return array;
  }
 }
}

в принципе, говорящее название функции и простой код сразу подсказывают, что здесь строчка шифруется AES'ом без всяких дополнительных хитростей.

идем в программу. Здесь byte[] a2 и кусок кода:

  Console.Write("Введите пароль для шифрования: ");
  if (Program.ByteArraysAreEqual (EncryptionHelper.EncryptStringToBytes_Aes( Console.ReadLine(), Encoding.UTF8.GetBytes("CODEBY__PASSWORD"), Encoding.UTF8.GetBytes("IV82941840912841")), a2))
   Console.WriteLine("Размялся? А теперь серьёзные таски! :)");
  else
   Console.WriteLine("Попробуй ещё, ты точно справишься! UwU");

подсказывает, что флаг это массив a2, расшифрованный с помощью ключа "CODEBY__PASSWORD" и "IV82941840912841".

Наша задача по быстрому ее расшифровать, можно написать программу на любом языке, можно воспользоваться сервисом. Лучше всего, конечно, воспользоваться тем языком программирования и теми библиотеками, которые использовал автор задачи. У нас это C# (хорошая статья и вторая на эту тему).

    public static string DecryptStringToBytes_Aes(byte[] plainText, byte[] Key, byte[] IV)
    {
      string array;
      using (Aes aes = Aes.Create())
      {
        aes.Key = Key;
        aes.IV = IV;
        Byte[] outputBytes = plainText;
        ICryptoTransform encryptor = aes.CreateDecryptor(aes.Key, aes.IV);
        using (MemoryStream memoryStream = new MemoryStream(outputBytes))
        {
          using (CryptoStream cryptoStream = new CryptoStream((Stream)memoryStream, encryptor, CryptoStreamMode.Read))
          {
            using (StreamReader srDecrypt = new StreamReader(cryptoStream))
            {
              array = srDecrypt.ReadToEnd();
            }
          }
        }
      }
      return array;
    }

string ps = EncryptionLibrary.EncryptionHelper.DecryptStringToBytes_Aes(a2, Encoding.UTF8.GetBytes("CODEBY__PASSWORD"), Encoding.UTF8.GetBytes("IV82941840912841"));

но программа несложная, можно воспользоваться и Питоном (в сложных может быть путаница с внутренностями в библиотеками, разными форматами входных данных и т.д.). Статьи на будущее (1, )

from Crypto.Cipher import AES

code = [90,90,131,173,3,108,139,21,101,136,11,35,101,154,191,222,178,128,45,197,220,65,122,138,18,173,210,128,16,101,247,74]

key = 'CODEBY__PASSWORD'
iv =  'IV82941840912841'

key = bytes(key.encode('utf-8')) 
iv = bytes(iv.encode('utf-8')) 

def decrypt(encrypted,key,iv):
    cipher = AES.new(key, AES.MODE_CBC, iv)
    decryptedtext = cipher.decrypt(encrypted) 
    decryptedtextP = decryptedtext.rstrip(b'\01').decode("UTF-8")  # remove the Zero padding
    return decryptedtextP

print(decrypt(bytes(code),key,iv))

Запуск программы дает нам

Флаг: CODEBY{p@sSw0rd_1n_EXE_anD_DLL}


Зачем пароль на пароль (TulaCTF)

Решение:

Декомпилировали файлик, нашли, что это шрифт Винженера и дальше надо было найти ключевое слово для расшифровки. Подсказка, что флаг начинается на TulaCTF, ключевое слово было Pepelats.

  class Program
  {
    static void Main(string[] args)
       char pass = ' ';
      string str = "";
      for (int index = 0; index < "iAC4ntypSmIJ{JJLOH2Npr6wieoUv0*sad6S3(Mwa2V_j".Length; ++index)
      {
// pass = 'Pepelats';
        pass = ' ';
        for (int q = 0; q < 50; q ++ )
        {
          str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 !@#$%^&*(){}_"
            [("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 !@#$%^&*(){}_".IndexOf
            ("pSmIJ{JJLOH2Npr6wieoUv0*sad6S3(Mwa2V_j"[index])
            - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 !@#$%^&*(){}_"
            .IndexOf(pass) +
            "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 !@#$%^&*(){}_".Length) %
            "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 !@#$%^&*(){}_".Length].ToString();
          if (str.StartsWith("{", StringComparison.CurrentCulture) == true)
            str = str;
          str = str;
          pass = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 !@#$%^&*(){}_"[q];
        }
      }
    }
  }
}

Флаг: TulaCTF{DIr3k7or_1N7ERNETA_$KaZAL_R@StrELY4t}


Stegano

Omniscient (КК)

Условие задачи:

Решение задачи:

Использовать stegsolve или другие утилиты, которые раскладывают картинку на каналы, и в Alpha 1 - видно флаг.

Флаг: CODEBY{4nd_i_c4n_se3}

Letter (КК)

Условие задачи: Файл. Флаг должен быть в формате CODEBY{flag}.

Решение задачи: Беглый анализ файла показал, что некоторые буквы имеют отличный от остальных регистр.

t, e, g, a - маленькие

Искать глазами маленькие буквы тяжело, можно скопировать все в блокнот и поменять местами регистр, так будет немного проще, а можно запустить небольшой скрипт (большие тексты в питоне помещаем в тройные кавычки):

otvet = ""
for i in tops:
    if i >= 'a' and i <= 'z':
        otvet += i
print("CODEBY{%s}" % otvet)

и получаем:

Флаг: CODEBY{steganocomesinmanyforms}


Neural network (КК)

Условие задачи:

Решение: Спасибо команде zer00d4y за их writeup!

В глаза бросается разный регистр букв в одном предложении.

In TexT steGaNograpHY, the SECRet MEsSage Is tYPiCallY emBdded bY making suBtIE MOdiFIcATioNs

Надо было поменять в нем маленькие буквы на A, а большие на B

BA BAAB AAABABAAAAABB AAA BBBBAA BBABAAA BA ABBABAAAB AABAAAA AB AAAAAA AABABB BBAABBABBAABA

и скормить dCode как шифр Бэкона (обязательно почитайте его историю, могут быть большие и маленькие буквы, курсив и жирные, и другие варианты). Натолкнуть на это должен был TheB.AI. Но мы не догадались 😁

Флаг: CODEBY{URIGHTITISBAC?NS}

Мой первый пряник (TulaCTF, 180)

Условие задачи:

Решение: stegoveritas, stegsolve, или любой сервис, которые может выделить 0 бит синего канала (blue_0).

Это азбука Морзе. Расшифровывали руками. Хорошего сервиса для этой цели не нашли :(

Флаг: TulaCTF{morsecodecandomusic}

Купили жамки, а они .... (TulaCTF, 350)

Условие задачи:

Решение: Лучше всего StegVeritas, он делает файлики, которые потом можно скормить другим сервисам, но подойдут и любые другие, которые раскидывают каналы по битам. У нас есть 7 QR-кодов.

blue#3 (A_KUP)
blue#5 (VAATSAT)
green#1 (I_PYAT)
green#2 (ILA_J)
red#1 (_MAM)
red#2 (BEZ_D)
red#4

Большинство сканеров требуют, чтобы им специально вырезали кусок и скормили, но это очень долго и нудно. Для нашей цели очень хорошо подошел сервис. Он нам дал кучу разных кусочков: A_KUP, VAATSAT, I_PYAT, ILA_J, _MAM, BEZ_D, AMKI

А вот потом надо было сложить это в единую фразу. Четкого алгоритма мы не нашли, складывали по интуиции :)

Флаг: TulaCTF{BEZ_DVAATSATI_PYAT_MAMA_KUPILA_JAMKI}

Nyan Cat 1 (TulaCTF, 424)

Условие задачи: эта картинка не просто картинка, а целый сундук с информацией.

Решение задачи: смотрим в exif, либо в exiftools, либо на сайте

Подозрительное поле Source

Значение очень похоже на TulaCTF с наложенным шифром Цезаря. Переходим на dCode, пробуем шифр Цезаря и получаем флаг.

Флаг: TulaCTF{g00d_staRt}

Мой первый день (TulaCTF, 964)

Условие задачи: файл презентация с вирусом.

Решение задачи: нужно было добраться до кода макросов

там до кусочка сбора полезной нагрузки

и затем от команды взять md5

Флаг: TulaCTF{6981baa80ea61a7286ac65c46b6f7395}


Web

Old version

Условие задачи:

Решение: Спасибо команде zer00d4y за их writeup!

Если посмотреть ответ сервера на пустой запрос, то можно увидеть LFI ошибку

Чтобы ее эксплуатировать нужно в качестве параметра page передать следующую строку

 ' and die(system("cat index.php")) or '

то есть запрос будет выглядеть так (можно в браузере, а можно и Postman)

http://62.173.140.174:46005/index.php?page=' and die(system("cat index.php")) or '

Флаг: CODEBY{php_lf1_t0_rc3_d0ne}

Report Page