Payloads and shells
Шелл — это код, который выполняется после того, как эксплойт сработал. Reverse против bind — это вопрос о том, кто кому звонит, и именно этот выбор ловят egress-фильтрация и EDR. Изучи механизм, чтобы суметь разорвать канал.
На авторизованном пентесте эксплойт сработал. Указатель инструкций твой — но перехваченный адрес возврата — это поток, который проживёт несколько микросекунд, а потом процесс либо упадёт, либо пойдёт дальше. У тебя есть контроль над выполнением и почти нечего с ним делать. На самом деле тебе нужен разговор: терминал, в который можно печатать с другого конца сети и который переживёт возврат из функции. Этот второй этап — код, превращающий мимолётный миг контроля в устойчивую интерактивную сессию, — называется payload (полезная нагрузка), а сессия, которую он даёт, — это шелл. Интересно тут не то, как его написать. Интересно то, что в тот же миг, как твой payload пытается открыть этот разговор, он обязан установить сетевое соединение или открыть порт — а это ровно та единственная вещь, которую файрвол защитника и EDR были построены, байт за байтом, замечать.
К концу урока ты будешь знать, что такое payload и шелл на самом деле, почему «reverse против bind» сводится к тому, кто кому звонит, и как egress-фильтрация и EDR обнаруживают канал, — чтобы уметь рассуждать о его разрыве с любой из сторон.
Сначала авторизация — это механизм, а не оружие
Всё ниже — это теория того, как формируется канал пост-эксплуатации и как защитники его видят. Здесь нет рабочего payload, и он не нужен: можно полностью понять reverse-шеллы, bind-шеллы и то, как их ловят, ни разу не направив ни один на систему, которой ты не владеешь. Единственные законные места, где можно наблюдать, как шелл дозванивается обратно, — это CTF-машина, намеренно уязвимая VM, которую ты сам поднял, или входящий в скоуп пентест с письменной авторизацией. В терминах MITRE ATT&CK эксплойт купил нам плацдарм; payload — это то, что устанавливает Execution (выполнение), а затем Persistence (TA0003) — удержание этого кода доступным. Мы изучаем соединение и дерево процессов именно для того, чтобы защитник мог разорвать цепочку в самой узкой точке. Запусти шелл против цели, на которую у тебя нет авторизации, — и ты не изучаешь безопасность, а совершаешь преступление.
Payload — это что-выполнится-дальше; шелл — это разговор
Эксплойт отвечает на вопрос «как перенаправить выполнение». Payload отвечает на вопрос «выполнение моё — что теперь делать?». При переполнении стека байты, перезаписавшие адрес возврата, указывали куда-то; payload — это код, который ждёт в этой точке назначения. Исторически это был сырой shellcode, внедрённый в тот же буфер; на современных системах с неисполняемым стеком это чаще цепочка, вызывающая существующую функцию, чтобы породить дочерний процесс. В любом случае цель самого распространённого payload скромна и разрушительна: запустить командный интерпретатор — /bin/sh, bash, cmd.exe, powershell — и подключить его стандартный ввод и вывод к сетевому сокету. Эта подводка — вся суть. Локальный шелл бесполезен удалённому атакующему; шелл, чья клавиатура и экран — это TCP-соединение, — это удалённый терминал.
Шелл, таким образом, — это просто интерактивный командный интерпретатор, чей ввод-вывод перенаправлен по сети. Как только он у тебя есть, ты печатаешь команду на своей машине, она выполняется на их, а вывод возвращается обратно. Всё остальное в пост-эксплуатации — повышение привилегий, латеральное движение, доставка инструментов — происходит через этот канал. Вот почему именно сам канал — это место, где ведётся вся битва за обнаружение.
Reverse против bind: кто кому звонит
Подключить этот сокет можно двумя способами, и разница целиком в направлении, в котором инициируется соединение, — а это оказывается самым важным фактом в вопросе, переживёт ли канал реальную сеть.
Bind-шелл открывает слушающий порт на жертве и ждёт. Атакующий подключается входящим соединением к этому порту. Концептуально это самый простой вариант — и почти всегда неправильный на практике: входящие соединения из интернета на случайный высокий порт внутреннего хоста — это ровно то, что периметровый файрвол и NAT существуют блокировать. Жертва обычно за NAT, без публичного IP и без проброса входящих портов, так что подключаться попросту не к чему.
Reverse-шелл переворачивает направление. Жертва сама звонит наружу атакующему, который слушает. Это проходит мимо двух вещей, убивающих bind-шеллы: мимо NAT (исходящие соединения — это как работает любой нормальный клиент) и мимо входящих правил файрвола (которые обычно по умолчанию пропускают исходящий трафик). Вот почему «reverse» — это дефолт почти на каждом реальном пентесте: не потому, что он скрытнее, а потому, что это единственный, который вообще соединяется. Атакующий часто слушает на 443, чтобы трафик сливался с HTTPS и обычно выпускался наружу.
Как защитник его ловит: egress-фильтрация и EDR
Reverse-шелл работает только благодаря одному обычно-верному допущению: исходящий трафик разрешён по умолчанию. Большинство сетей жёстко контролируют то, что входит, и едва смотрят на то, что выходит. Egress-фильтрация — это поправка защитника: относиться к исходящему трафику с тем же подозрением, что и к входящему. Сделанная хорошо, она означает, что хост может дотянуться только до явного allowlist пунктов назначения и портов; всё остальное отбрасывается. Против этого жертва звонит наружу — и пакет упирается в стену: слушателя атакующего нет в allowlist, поэтому соединение никогда не завершается. Всё преимущество reverse-шелла — «исходящее бесплатно» — испаряется. Именно поэтому атакующие туннелируют через 443, DNS или настоящий облачный сервис: они пытаются выглядеть как трафик, который allowlist уже пропускает.
Вторая линия — это EDR (Endpoint Detection and Response) — агент, наблюдающий за самим хостом, а не за проводом. Даже идеально TLS-зашифрованный reverse-шелл на 443 оставляет на эндпойнте отпечатки, которых сеть никогда не видит:
- Аномальное дерево процессов. Процесс веб-сервера (
nginx,php-fpm,java) не должен быть родителем/bin/shилиcmd.exe. Это ребро «родитель — потомок» — одно из самых сигнальных обнаружений вообще: оно означает, что сервис, обрабатывающий запросы, только что породил интерактивный шелл. - Шелл с сокетом в качестве стандартного ввода-вывода. У нормального
bashна файловых дескрипторах терминал. У reverse-шелла на stdin/stdout — сетевой сокет. EDR, инспектирующий, на что указывают дескрипторы шелла, видит это сразу. - Поведенческая последовательность. Породился шелл, потом
whoami, потом сетевая разведка, потом загрузка — сам плейбук пост-эксплуатации и есть сигнатура.
| Тип шелла | Кто инициирует | Обходит NAT / входящий файрвол? | Что его останавливает |
|---|---|---|---|
| Bind-шелл | Атакующий звонит внутрь (входящее) | Нет — входящее на высокий порт блокируется | Периметровый файрвол + NAT (уже) |
| Reverse-шелл | Жертва звонит наружу (исходящее) | Да — пользуется «исходящее разрешено по умолчанию» | Egress-фильтрация (исходящий allowlist) |
| Reverse через 443/DNS | Жертва звонит наружу, похоже на HTTPS/DNS | Да — сливается с разрешённым трафиком | Egress + EDR (дерево процессов, сокет-как-stdio) |
▸Почему это работает
Почему атакующие всё время лезут выше по стеку — сырой TCP, потом 443, потом DNS-туннелирование, потом вебхук Slack/Telegram/Discord как командный канал? Потому что каждый шаг — это ответ на egress-фильтрацию. Плоская блокировка исходящего убивает сырой TCP на случайный порт. Тогда канал мигрирует на порты, которые обязаны быть открыты (443, 53), а затем на пункты назначения, которые уже в allowlist (SaaS-API, которым компания реально пользуется). Контр-ответ защитника тоже обязан расти: не просто «разрешён ли порт», а «должен ли этот хост вообще разговаривать с этим назначением, в таком объёме, с такой периодичностью». Именно поэтому современное обнаружение опирается на EDR и поведенческие базовые линии, а не только на правила портов, — канал всегда может одолжить порт, но подделать дерево процессов ему куда тяжелее.
Как рассуждает зрелый инженер
Будь ты атакующим на авторизованном пентесте или защитником, урок один и тот же: payload — это легко; канал — это узкое место. Атакующий, знающий лишь «reverse-шелл на 443», встаёт намертво перед сетью с исходящим allowlist и EDR. Защитник, блокирующий только входящее, оставил дверь reverse-шелла нараспашку. Устойчивая ментальная модель — мыслить в терминах направления соединения, его пункта назначения и процесса, которому оно принадлежит, — потому что каждое из этого есть место, где можно либо спрятаться, либо обнаружить. Дефолты тут важнее всего: сеть, разрешающая весь исходящий трафик, — это сеть, допускающая, что reverse-шелл сработает, а хост, чей веб-сервер может породить шелл незаметно, — это хост, допускающий, что payload выполнится тихо.
Ты харденишь внутренний сервер приложения так, чтобы даже при компрометации reverse-шелл не смог дозвониться домой. Хост за NAT с политикой «исходящее разрешено по умолчанию». Выбери контроль, который реально ломает канал reverse-шелла.
Почему reverse-шелл — дефолтный выбор поверх bind-шелла почти на каждом реальном пентесте?
Атакующий запускает полностью TLS-зашифрованный reverse-шелл наружу через порт 443, так что сеть не может прочесть payload. Как EDR всё равно может пометить его на эндпойнте?
Упорядочь этапы установления reverse-шелла и его последующего обнаружения, от первого к последнему:
- 1 Эксплойт срабатывает, выполнение перенаправляется на payload
- 2 Payload порождает командный интерпретатор (например, /bin/sh)
- 3 stdin/stdout интерпретатора подключаются к исходящему сокету
- 4 Жертва звонит наружу на слушатель атакующего на 443
- 5 Egress-allowlist отбрасывает соединение или EDR помечает дерево процессов
- 01Объясни разницу между bind-шеллом и reverse-шеллом и почему reverse — дефолт на реальных пентестах.
- 02Reverse-шелл полностью TLS-зашифрован и идёт наружу через 443. Назови два защитных слоя, которые всё равно могут его остановить или обнаружить, и на что опирается каждый.
Payload — это код, который выполняется в тот же миг, как эксплойт перенаправляет выполнение; самый распространённый порождает командный интерпретатор и подключает его стандартный ввод и вывод к сетевому сокету, давая атакующему шелл — удалённый интерактивный терминал. Выбор между bind-шеллом (жертва слушает, атакующий подключается входящим) и reverse-шеллом (жертва звонит наружу атакующему) — целиком про направление соединения, и reverse выигрывает на практике, потому что NAT и файрволы с «исходящее разрешено по умолчанию» пропускают исходящее соединение, убивая входящее; атакующие часто пользуются 443, чтобы слиться с HTTPS. У защитника два контр-ответа, точно ложащихся на то, что раскрывает канал: egress-фильтрация превращает исходящее в default-deny allowlist, так что reverse-соединению некуда идти, а EDR игнорирует зашифрованный провод и смотрит на хост — помечая аномальное дерево процессов (веб-сервер как родитель /bin/sh), шелл, чьи дескрипторы — это сокет, и поведенческую последовательность пост-эксплуатации. Поэтому, увидев хост с разрешённым всем исходящим и веб-сервером, который может породить шелл незаметно, твой первый вопрос: в каком направлении идёт соединение, куда ему разрешено идти и какой процесс им владеет, — потому что именно там ты либо прячешь канал, либо его ломаешь.
Практика
Начни сверху. Задачи идут от простого к сложному: вспомнить факт, применить к случаю, затем senior-уровень. Открой, попробуй, потом открой ответ.
Что-то непонятно?
Задай вопрос по этому уроку. Вопросы анонимны и попадают напрямую автору — урок станет лучше.