Init. Commit
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
<h1 align="center">GateKeeper</h1>
|
||||
|
||||
<p align="center">
|
||||
<img src="https://img.shields.io/badge/category-Web-blueviolet" alt="Web"/>
|
||||
<img src="https://img.shields.io/badge/difficulty-hard-critical" alt="hard"/>
|
||||
</p>
|
||||
|
||||
GateKeeper GW-7 — панель сетевого шлюза. Регистрации нет, есть только `admin` и `operator`. Флаг лежит в `/root/flag.txt`, а веб-приложение работает от `gk`. Для чтения файла используем утечку конфига, смену чужого пароля и синхронизацию пользователя.
|
||||
|
||||
## Решение
|
||||
|
||||
### Получение прав администратора
|
||||
|
||||
В статике находим `/static/config.json.bak`. Бэкап содержит пароль `operator`. Входим через `POST /login` с JSON-полями `username` и `password`, сохраняем cookie `gk_session`.
|
||||
|
||||
У оператора мало прав, но есть смена собственного пароля. Проверяем её запросом к `POST /account/password`. Обработчик ищет совпадение `old_password` с паролем любого пользователя, не связывая его с полем `username`.
|
||||
|
||||
С cookie оператора отправляем в `POST /account/password` имя администратора и известный пароль оператора:
|
||||
|
||||
```json
|
||||
{
|
||||
"username":"admin",
|
||||
"old_password":"<пароль operator из бэкапа>",
|
||||
"new_password":"gk_pwned_2026"
|
||||
}
|
||||
```
|
||||
|
||||
Проверка проходит, пароль `admin` меняется. Повторяем `POST /login` с `username=admin` и новым паролем `gk_pwned_2026`. Сохраняем новую cookie `gk_session` и используем её для административной синхронизации.
|
||||
|
||||
### Выполнение команды через email
|
||||
|
||||
`POST /admin/directory/sync` принимает `email` и вызывает `sudo /opt/gk/bin/sync_user.sh <email>`. У `gk` есть право запускать этот скрипт от root без пароля.
|
||||
|
||||
Фильтр исходной строки блокирует `;`, `|`, обратные кавычки и несколько других операторов. Но email-парсер принимает local-part в двойных кавычках и снимает их при нормализации. Затем скрипт подставляет результат в `eval` без кавычек.
|
||||
|
||||
Отправляем из администраторской сессии:
|
||||
|
||||
```bash
|
||||
curl -sS http://<host>:18113/admin/directory/sync \
|
||||
-b 'gk_session=<сессия admin>' \
|
||||
-H 'Content-Type: application/json' \
|
||||
--data '{"email":"\"x$(cp /root/flag.txt /opt/gk/www/public/f.txt)\"@gw.local"}'
|
||||
```
|
||||
|
||||
Сырой email проходит парсер задания. После нормализации и `eval` конструкция `$(cp ...)` исполняется от root и копирует флаг в каталог веб-раздачи.
|
||||
|
||||
Вывод скрипта в HTTP-ответе не показывают. Зато `/opt/gk/www/public` доступен как `/public/`, а скрипт выставляет права `a+rX`:
|
||||
|
||||
```bash
|
||||
curl -sS http://<host>:18113/public/f.txt
|
||||
```
|
||||
|
||||
Получаем содержимое закрытого файла. Ключевой переход здесь — от строки, допустимой для email-парсера, к той же строке как к части shell-команды.
|
||||
|
||||
[Солвер](solve/solve.py).
|
||||
|
||||
## Флаг
|
||||
|
||||
`CAPLAG{rfc5322_qu0t3d_sh3ll_1nj}`
|
||||
Reference in New Issue
Block a user