Bash открывает TCP-сокет и подделывает HTTP-запрос без curl

Инженеру нужно было пинговать health-эндпоинт между Docker-контейнерами. В образе не было ни curl, ни wget, ни nc. Тогда он открыл /dev/tcp/service/8642 и набрал HTTP-запрос руками.

Вкратце

Трюк в трёх строках: открыть дескриптор 3 на /dev/tcp, printf'нуть сырой GET с CRLF-заголовками, затем считать дескриптор обратно через cat. Заголовок Connection: close несущий — убери его, и cat будет ждать вечно.

Но самый громкий ответ в обсуждении был поправкой: Bash не говорит на HTTP. Он открывает сокет, а на HTTP — плохо — говоришь ты. Игрушечный клиент не разбирает ответы и ломается на редиректах, чанках и TLS.

Контейнер без curl, без wget, без чего-либо вообще

Автор упёрся в знакомую стену: проверить связь между контейнерами во внутренней Docker-сети, где образ собран без curl и без wget. Его удивило, что у самого Bash есть /dev/tcp: путь, через который можно открыть сырой сокет и руками написать HTTP-запрос.

HTTP-запрос через Bash /dev/tcp
HTTP-запрос через Bash /dev/tcp

Три строки, которые это делают

Рецепт короткий. Открыть дескриптор на чтение-запись на волшебном пути, printf'нуть строку запроса и CRLF-заголовки, затем считать дескриптор обратно:

exec 3<>/dev/tcp/service/8642
printf 'GET /health HTTP/1.1\r\nHost: service\r\nConnection: close\r\n\r\n' >&3
cat <&3

Пост прямо говорит, чем это не является: «Это не настоящий HTTP-клиент. Он не разбирает HTTP как положено, не обрабатывает редиректы, чанкованные ответы, сжатие, повторы, TLS». Заголовок Connection: close обязателен: без него сервер держит соединение открытым, и cat <&3 ждёт вечно. Ещё нужен Bash, собранный с --enable-net-redirections, так что dash и прочие POSIX-оболочки не подходят.

Саймон Уиллисон попробовал это в обсуждении и наткнулся на современную загвоздку: HTTPS повсюду.

Работает против example.com… Я для таких штук всегда сваливаюсь на example.com, потому что сегодня почти не осталось доменов, которые не принуждают к https! — Саймон Уиллисон, создатель Datasette

«Нет, не может»: спор о формулировке

Самый острый ответ отверг заявление самого заголовка о том, что Bash говорит на HTTP.

Bash позволяет открывать TCP-сокеты. То, что ты тут делаешь, — это попытка самому говорить на HTTP… ты прострелишь себе ногу, если попробуешь использовать этот псевдо-HTTP-клиент без присмотра в реальности. — комментатор, прикладывающий полноценный веб-сервер на чистом Bash как доказательство, насколько далеко заходит хак

Затем обсуждение свернуло туда, куда автор не задумывал. Комментарий за комментарием описывали, как через /dev/tcp выбираются из закрытых машин: образ Envoy без curl, роутер на 4 МБ без места под libcurl, порт на Powershell, который зацепил CrowdStrike и заставил принять разработчика за вредонос.

Любопытно, что большинство комментариев тут — про использование этой фичи для обхода ограничений безопасности… Это многое говорит о поверхности атаки GNU-утилит, раздутой фичеризмом. — Дмитрий Честных, основатель Coding Robots

Этот трюк — классика после взлома

Один аккаунт с низкой кармой прямо назвал тёмную сторону: это старый приём после компрометации, к нему прибегают, когда атакующий уже на машине, а curl, wget и nc отсутствуют. То же свойство, что спасает сисадмина при отладке health-чека (сетевой клиент, который всегда на месте и ничего не требует ставить), ровно то, что делает урезанную оболочку менее безопасной, чем кажется. Точнее читать это не как «Bash говорит на HTTP». А как то, что сокет-примитив, вшитый в каждую оболочку, — одновременно удобство и поверхность атаки.

Получайте такие разборы каждый день

Главные истории Hacker News — на email, в Telegram или RSS.

Следующая новость · 20 из 23 Читать дальше
🚀Tech

Тим Феррис: продажи его книг рухнули на 57% из-за ИИ

Человек, во многом построивший современную индустрию селф-хелпа, теперь смотрит, как она утекает. Бэк-лист самого Ферриса: −5% в 2023-м, −13% в 2024-м, −46% в 2025-м и темп −57% в 2026-м.

★ 164 · 💬 173 · tim.blog · 3 мин