Вчора закінчився перший етап Всеукраїнської олімпіади з програмування 2021 і прийшов час розкрити таємниці секретного завдання від E-Olymp.
З перших днів олімпіади, на одній зі сторінок, я розмістив невеличке завдання для кмітливих учасників. Його суть полягала в тому, щоб знайти вразливе місце у коді сайту і використати його. Можна сказати, задача полягала в тому, щоб зламати (хакнути) сайт, але звісно в спосіб передбачений розробниками сайту.
Такого роду завдання є досить популярними, вони називаються “захоплення прапора” (capture the flag) та спрямовані на вивчення та отримання досвіду з машинного захисту і кібербезпеки. Існують цілі змагання, в яких учасникам пропонується знайти всі вразливі місця в системі у найкоротший час.
Ця стаття є досить технічною і містить багато термінології, яка, можливо, буде новою для вас. Я розмістив короткі та досить поверхневі пояснення для найбільш важливих термінів у блоках подібних цьому. Якщо у вас виникнуть додаткові запитання, спробуйте знайти більше інформації в інтернеті, зверніться з запитаннями до вчителя, друзів або напишіть мені через форму зворотного зв’язку.
Секретне завдання вимагає знань, які не входять у шкільну програму з інформатики. Тому багато з концептів та технологій є абсолютно новими для більшості учнів. Я спробував зробити завдання і цю статтю якомога простіше і зрозуміліше, але можливо, у вас все одно будуть труднощі з його виконанням. Якщо у вас не виходить зрозуміти та виконати це завдання, не переживайте, воно складне. Але якщо у вас вийде, я сподіваюсь вам сподобається і ви вивчите щось нове.
Увага! Такого роду завдання не будуть доступні під час наступних етапів олімпіади, тому не шукайте завдання під час олімпіади, а сфокусуйтеся на розв’язанні задач. Більш того, дії пов’язані з пошуком вразливих місць під час етапу олімпіади можуть бути розцінені, як спроба втручання в роботу системи, за що вас може бути дискваліфіковано. Я розміщу ще, як мінімум, одне завдання такого роду, але воно буде доступне лише в дні, коли не проходять етапи олімпіади. Підпишіться на нашу сторінку у Facebook та телеграм канал олімпіади, щоб дізнатися коли буде доступне наступне завдання.
За сценарієм, в нашому завданні один з розробників створив API (див. пояснення нижче) за допомогою якого організатори олімпіади можуть давати учасникам спеціальну позначку у вигляді корони. Ця позначка відображається у рейтингу поруч з іменем учасника.
Для того щоб не забути посилання на API, розробник вирішив записати його у вихідному коді сайту stats.uoi2021.org як коментар. Розробник вирішив, що оскільки посилання записане як коментар, ніхто з користувачів його не побачить.
API повинен використовуватися тільки організаторами олімпіади, але розробник забув додати перевірку на те, чи користувач є організатором. Таким чином розробник створив вразливий, не захищений API, який може бути використаний хакером.
API (application programming interface) - це інтерфейс для взаємодії між програмами, тобто спосіб для однієї програми виконати якусь дію в іншій.
Вам скоріш за все відоме поняття GUI (графічний інтерфейс користувача), коли ви запускаєте програму, ви бачите перед собою вікно з кнопками, полями вводу, картинками, текстом і тд. Це інтерфейс користувача, він створений для того, щоб людям було зручно взаємодіяти з програмою. Такий інтерфейс зручний для людей, але не зручний для інших програм. Для того, щоб програми могли взаємодіяти між собою необхідно створити API.
Є дуже багато різних типів API. Деякі з них дозволяють взаємодіяти програмам, які виконуються на одному комп’ютері, інші дозволяють програмам взаємодіяти через мережу, тобто між різними комп’ютерами. В нашому випадку розробник створив HTTP API, це API який використовує мережевий протокол HTTP.
Щоб використати вразливе місце, для початку нам необхідно знайти посилання на API.
Сторінки на сайтах використовують мову розмітки HTML. У мові HTML передбачені коментарі, тобто блоки тексту які ігноруються браузером і використовуються для того, щоб залишити замітки для інших розробників. Недолік HTML коментарів в тому, що вони передаються разом з іншими частинами документу як відкритий текст, тобто будь-хто може побачити їх зміст. Тому якщо ви залишаєте коментарі в HTML коді, пам’ятайте, що вони будуть доступні всім.
Для того, щоб переглянути вихідний код сторінки, відкрийте її в браузері, зробіть правий клік будь-де на сторінці та виберіть пункт меню “Переглянути вихідний код” (View Page Source). Після цього ви побачите HTML код документу та коментарі в ньому.
Якщо перейти на сторінку https://stats.uoi2021.org і переглянути її вихідний код, можна знайти таке повідомлення:
...
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<!-- Возак Кус завжди забуває важливі API посилання, тому записав їх тут. Секретне посилання: https://api.e-olymp.com/uoi/crown (НІКОМУ НЕ ДАВАТИ!!!!) -->
<div id="root"></div>
...
Не обов’язково використовувати браузер для того, щоб побачити вихідний код сайту. Насправді можна використати будь-який HTTP клієнт. HTML код це просто текстові дані, які передаються з сервера до користувача. Нижче ми розглянемо, як зробити HTTP запит за допомогою інших HTTP клієнтів. Спробуйте зробити запити до різних сайтів, щоб побачити їх зміст.
HTTP клієнт це програма, яка може робити запити до сервера, використовуючи HTTP протокол. Наприклад, ваш браузер є HTTP клієнтом.
Також в усіх мовах програмування є бібліотеки, які реалізовують HTTP клієнт. Наприклад, в мові програмування Python є бібліотека requests.
Тепер ми можемо зробити запит за цим посиланням і дізнатись більше інформації про нього. Для початку можна спробувати використовувати браузер. Якщо ми відкриємо посилання https://api.e-olymp.com/uoi/crown в браузері, ми побачимо таке повідомлення:
Only POST method is allowed, if you are using curl make sure to add `-X POST` to the request.
Англійська мова - стандарт у програмному забезпеченні, тому дуже важливо вільно нею володіти. Але якщо у вас виникають труднощі, ви можете спробувати використовувати перекладач.
Отже, відкривши посилання, ми побачили повідомлення про помилку. Це повідомлення містить фразу “Тільки метод POST дозволено”. Якщо ви не знайомі з протоколом, вам доведеться пошукати інформацію про нього в мережі інтернет. Спробуйте пошукати за словами “HTTP POST” чи “method POST”. Наприклад, можна знайти інформацію про HTTP протокол на сторінці вікіпедії.
Для виконання завдання вам треба знати, що протокол HTTP - це мережевий протокол. За допомогою HTTP протоколу ви можете зробити запит до ресурсів, розміщених на HTTP сервері, використовуючи один з HTTP методів.
HTTP прокол є найпопулярнішим протоколом у світі, він використовується мережею Інтернет для обміну даними між вебсервером та браузером. Дуже часто через нього передаються HTML, CSS та JavaScript файли, які використовуються для того, щоб показати зміст сайтів, але сам HTTP протокол може бути використаний для будь-яких даних.
Браузер за замовчуванням робить GET запит до URL який ви вводите в рядок адреси. Э багато способів зробити POST запит, скоріш за все ви знайдете такі методи:
- Зробити запит за допомогою додатку з командного рядку (CLI), наприклад
curl
. - Зробити запит за допомогою бібліотеки в мові програмування. Спробуйте додати назву мови програмування в пошуковий запит, щоб отримати більше прикладів.
- Зробити запит за допомогою графічного додатка, наприклад Postman, чи вебдодатку, наприклад https://reqbin.com/.
Всі ці методи підходять і ви можете використовувати будь-який з них. Протокол HTTP дуже поширений і має досить строгий стандарт.
curl спосіб
Повідомлення про помилку згадує програму curl, тому спробуємо використовувати її. Curl це програма з інтерфейсом командного рядка (cli або command-line interface) і один з найпоширеніших HTTP клієнтів. Вона встановлена за замовчуванням майже у всіх версіях Linux. Для Windows її доведеться встановлювати окремо.
Якщо у вас виникають труднощі з використанням curl, нижче наведений приклад з використанням Python.
Відкрийте термінал (інтерфейс командного рядка) та спробуйте виконати:
curl https://api.e-olymp.com/uoi/crown
Ця команда робить запит до https://api.e-olymp.com/uoi/crown використовуючи метод GET. Ви повинні побачити таке ж повідомлення, що і раніше:
Only POST method is allowed, if you are using curl make sure to add `-X POST` to the request.
В повідомленні написано, що необхідно додати флаг -X
. Згідно з документацією цей флаг дозволяє вказати HTTP метод. Саме те, що нам треба! Спробуймо додати флаг -X POST
, як вказано в повідомленні.
curl https://api.e-olymp.com/uoi/crown -X POST
Ми отримаємо інше повідомлення:
Payload (request body) has to be a valid JSON object (https://uk.wikipedia.org/wiki/JSON). If you are using curl add `-d '{}'` options. During parsing an error occurred: EOF.
Схоже метод для запиту правильний, але ми отримали інше повідомлення про помилку. В ньому написано, що зміст запиту повинен бути правильним JSON об’єктом. Там також є посилання на вікіпедію, де є більше інформації про JSON формат.
Тепер в повідомленні написано, що треба використовувати флаг -d
. Згідно з документацією цей флаг дозволяє вказати зміст запиту. Таким чином -d '{}'
додасть {}
у зміст запиту, у форматі JSON це відповідає “пустому” об’єкту.
curl https://api.e-olymp.com/uoi/crown -X POST -d '{}'
Нове повідомлення від системи:
Request must contain a valid participant_id. Make sure this participant is registered in UOI and has at least 500 points. You must find participant_id and pass it in request body like so: {"participant_id": "...not a very secret value which can be found when inspecting requests..."}
Схоже нам необхідно вказати participant_id
, в повідомленні. Спробуємо використати приклад з повідомлення про помилку.
curl https://api.e-olymp.com/uoi/crown -X POST -d '{"participant_id": "...not a very secret value which can be found when inspecting requests..."}'
Знову та сама помилка:
Request must contain a valid participant_id. Make sure this participant is registered in UOI and has at least 500 points. You must find participant_id and pass it in request body like so: {"participant_id": "...not a very secret value which can be found when inspecting requests..."}
Що ж, тепер нам треба знайти коректне значення для ідентифікатора учасника (participant_id). Перегляньте секцію “Як знайти participant_id” нижче, щоб дізнатись як це зробити.
Коли ми отримали наш participant_id, спробуймо підставити його замість рядку “…not a very secret value which can be found when inspecting requests…”.
$ curl https://api.e-olymp.com/uoi/crown -X POST -d '{"participant_id": "00000000-0000-0000-000-00000000000"}'
У відповідь ми отримаємо повідомлення:
C0ngr4tz! Y0u h4ve c0mpleted the t4sk! The crown 1s y0ur5!
Вітаю! Ви виконали завдання, корона ваша!
Python спосіб
Багато хто з учасників обрав саме цей метод, тому що багато хто знайомий з мовою програмування python і має налаштований інтерпретатор на своєму комп’ютері.
В інтернеті досить просто знайти приклади того, як зробити POST запит за допомогою python. Код, який ви знайдете, буде виглядати приблизно так:
import requests
resp = requests.post(url="https://api.e-olymp.com/uoi/crown")
print(resp.content)
Щоб він працював, вам знадобиться встановити бібліотеку requests
. Функція requests.post
виконує HTTP запит, використовуючи метод POST, і повертає відповідь від сервера. У відповіді з сервера нас цікавить поле content
, тобто зміст.
Якщо ви виконаєте програму наведену вище, ви отримаєте таке повідомлення.
b"Payload (request body) has to be a valid JSON object (https://uk.wikipedia.org/wiki/JSON). If you are using curl add `-d '{}'` options. During parsing an error occurred: EOF."
Нам треба передати JSON об’єкт у змісті запиту. В Python це можна зробити двома способами, використовуючи параметр data
або параметр json
.
import requests
resp = requests.post(url="https://api.e-olymp.com/uoi/crown", data="{}")
# або
resp = requests.post(url="https://api.e-olymp.com/uoi/crown", json={})
print(resp.content)
Параметр data
передає зміст запиту як рядок, а параметр json
дозволяє передати зміст запиту як Python об’єкт. Бібліотека requests самостійно конвертує Python об’єкт в JSON об’єкт.
Обидва методи передадуть до сервера ідентичний запит і отримають таке повідомлення.
b'Request must contain a valid participant_id. Make sure this participant is registered in UOI and has at least 500 points. You must find participant_id and pass it in request body like so: {"participant_id": "...not a very secret value which can be found when inspecting requests..."}'
Тепер нам треба знайти коректне значення для ідентифікатора учасника (participant_id). Перегляньте секцію “Як знайти participant_id” нижче, щоб дізнатись як це зробити.
import requests
resp = requests.post(url="https://api.e-olymp.com/uoi/crown", json={"participant_id": "00000000-0000-0000-000-00000000000"})
print(resp.content)
У відповідь ми отримаємо повідомлення:
C0ngr4tz! Y0u h4ve c0mpleted the t4sk! The crown 1s y0ur5!
Вітаю! Ви виконали завдання, корона ваша!
Як знайти participant_id?
Під час першого етапу олімпіади змагання було розмішене за посиланням https://uoi2021.org/, але після закінчення етапу змагання було перенесено на https://uoi2021-1.eolymp.io/. Тому зараз participant_id можна знайти саме за цим посиланням. Не забудьте увійти в систему перед тим як шукати значення.
На останньому кроці ви отримуєте повідомлення:
Request must contain a valid participant_id. Make sure this participant is registered in UOI and has at least 500 points. You must find participant_id and pass it in request body like so: {"participant_id": "...not a very secret value which can be found when inspecting requests..."}
Щоб завершити завдання, вам необхідно знайти ваш унікальний ідентифікатор учасника (participant_id). В повідомленні вказано що participant_id
це “не дуже секретне значення, яке можна знайти переглядаючи запити”. Можна здогадатись, що participant_id повинен бути доступний десь на сайті олімпіади https://uoi2021-1.eolymp.io/. Не забудьте увійти в систему перед тим як шукати значення.
Нам також треба знайти спосіб, як переглядати запити. Насправді в кожному браузері є інструменти для перегляду HTTP запитів. Зазвичай ці інструменти можна активувати через F12 або через пункт контекстного меню “Inspect”. Вибравши цей пункт меню, ви побачите вікно відладки сайту. В різних браузерах це вікно буде виглядати трохи інакше, але його елементи будуть подібні.
В цьому вікні доступні різні інструменти для відладки сайту. Ви можете переглядати HTML код сторінки, можете переглянути CSS стилі чи JavaScript. Але вкладка яка нас цікавить називається Network (мережа). На цій вкладці ми можемо переглянути всі HTTP запити, які робить сторінка.
На зображені вище видно список запитів, які зробив браузер. Якщо ми клацнемо на одному з них, ми можемо побачити параметри запиту, зміст запиту та відповіді.
Наприклад отак виглядає запит до серверу E-Olymp. Ви можете помітити, сторінка повторює ці запити час від часу, щоб оновити дані про змагання. Можна побачити HTTP метод, адресу і, якщо спуститися вниз, можна побачити дані які передаються до сервера.
Якщо перейти на вкладку “Preview” чи “Response”, ви можете побачити зміст відповіді від сервера.
Оригінальний розв’язок передбачав, що participant_id можна буде знайти на сторінці “Відправки”. Ця сторінка була доступна лише під час першого етапу, але значення participant_id все ще можна знайти у запиті graphql у відповіді з сервера у секції, яка називається
introspect
.
Переглядаючи запити на різних сторінках, ви можете знайти параметр який називається participant_id. На сторінці “Відправки” можна побачити запит ListSubmissions, а в змісті цього запиту параметр participantId
.
Значення на знімку вище замальовано, але якщо ви повторите ці кроки, ви зможете побачити власне значення participantId.
Це значення також присутнє у запиті graphql
, але там воно знаходиться у відповіді з сервера у секції, яка називається introspect
.
Увага! Такого роду завдання не будуть доступні під час наступних етапів олімпіади, тому не шукайте завдання під час олімпіади, а сфокусуйтеся на розв’язанні задач. Більш того, дії пов’язані з пошуком вразливих місць під час етапу олімпіади можуть бути розцінені, як спроба втручання в роботу системи, за що вас може бути дискваліфіковано. Я розміщу ще, як мінімум, одне завдання такого роду, але воно буде доступне лише в дні, коли не проходять етапи олімпіади. Підпишіться на нашу сторінку у Facebook та телеграм канал олімпіади, щоб дізнатися коли буде доступне наступне завдання.
Я сподіваюсь, вам сподобалася ця стаття і я дуже хотів би поділитись з вами ще чимось. Якщо вам цікава якась тема чи у вас є запитання про цю статтю, Ви можете зв’язатись зі мною через форму зворотного зв’язку.