Авторские курсы Михаила Тарасова

XSPA (Cross-Site Port Attack) — внутренний сканер портов через img/fetch на закрытые IP, Redis/Memcached/Elasticsearch привет

XSPA (Cross-Site Port Attack) - внутренний сканер портов через img/fetch на закрытые IP, Redis/Memcached/Elasticsearch привет

Слушай, братан, щас расскажу про XSPA (Cross-Site Port Attack) — древнее зло, которое живёт в каждом веб-приложении с функцией «загрузить по URL». Это когда ты заставляешь сервер жертвы сканировать свою внутреннюю сеть, а потом ещё и пиздить данные из Redis/Memcached/Elasticsearch. Красота в том, что файрволы бессильны — запрос-то идёт изнутри.

Суть прикола

XSPA — это подвид SSRF, но с фокусом на port scanning. Ты находишь функцию типа «загрузить аватарку по URL» или fetch() в API, пихаешь туда http://127.0.0.1:6379, и смотришь на timing/error response. Разница в миллисекундах скажет, открыт порт или закрыт.

Почему это работает:

  • Внутренние сервисы (Redis, Memcached, Elasticsearch) обычно без аутентификации

  • Same Origin Policy не касается server-side запросов

  • Браузер можешь использовать для сканирования локальной сети жертвы через JavaScript

Точка входа: как поймать

Что вижу:

Видишь параметр, который fetch’ит внешний ресурс? Это — золотая жила.

Как поймал:

  1. Burp Suite → Intercept запрос с URL-параметром

  2. Меняешь на http://127.0.0.1:22 (SSH обычно открыт)

  3. Замеряешь время ответа: closed port = быстрая ошибка (~50ms)open port = долгий timeout (~5-10s)

  4. Автоматизируешь через Python:

Чем пахнет: SSRF + Internal Port Scan, вероятность 9/10 на легаси-приложениях.

Че почем: эксплойт топ-сервисов

Redis (порт 6379) → RCE через Gopher

Redis без auth’а — это как банковский сейф с табличкой «Возьмите, пожалуйста».

Payload через Gopher protocol:

Теперь иди на http://target.com/shell.php?cmd=id — uid=0(root) if lucky.

Альтернатива — CVE-2022-0543 (Redis Lua Sandbox Escape):

Instant RCE, если Redis версии < 6.2.7.

Memcached (порт 11211) → Cache Poisoning

Memcached слушает dict:// protocol.

Payload:

Дамп статистики покажет размер кеша, количество ключей, версию. Дальше — cache poisoning для session hijacking.

Elasticsearch (порт 9200) → RCE через Dynamic Scripting

Elasticsearch до версии 1.2.0 позволяет выполнять Java-код без auth’а.

PoC через браузер (да, блять, через <img>):

Жертва открывает страницу → браузер делает GET-запрос → создаётся файл /tmp/pwned на её локальной машине. Это работает, потому что Elasticsearch по дефолту слушает 0.0.0.0:9200.

Через SSRF для RCE:

Timing-Based Port Scanner через JavaScript

Для browser-based XSPA:

Заливаешь это на свой сайт, жертва открывает — ты получаешь карту её внутренней сети.

Защита (для дев-братков)

  • Whitelist схем — только http:// и https://, нахуй gopher/dict/file

  • Blacklist internal IP-ranges:

  • Bind internal services на localhost — Redis/Memcached/ES должны слушать только 127.0.0.1, не 0.0.0.0

  • Disable dynamic scripting в Elasticsearch:

Советы

3 вектора для добивания:

  1. Если timing-based не работает — попробуй error-based: открытые порты дают HTTP errors (400/500), закрытые — connection refused. Разные error codes = разные сервисы.

  2. Cloud metadata endpoints — если цель в AWS/GCP/Azure:

Выдернешь токены — будешь владеть всей инфраструктурой.

  1. Combine с XXE/CSRF — если SSRF не работает напрямую, попробуй через XXE для file read или CSRF для authenticated requests.

План атаки (если зацепка есть):

  1. Найди endpoint с URL-fetch функцией (/api/upload/webhooks/avatar и тд)

  2. Запусти port scan через Burp Intruder (payload: http://127.0.0.1:§PORT§, числа 1-65535)

  3. Нашёл Redis (6379) / Memcached (11211) / ES (9200)? Генерируй Gopher/dict payload через Gopherus tool:

  1. Эксплуатируй найденный сервис

  2. Если всё ещё нет RCE — ищи другие internal endpoints через fuzzing:

  1. Найденный internal admin panel? Готовь screenshoty для bug bounty репорта

Иди топтать баунти-программы — SSRF до сих пор в топ-3 критикалов.

Мои курсы