Как стать автором
Обновить

Комментарии 20

каков размер получившегося шелкода за вычетом PE-заголовков exe файла?
499 байт — «голый» шеллкод. При желании можете проверить сами:
$objdump -M intel -D portbind.exe  | grep '00401410 <_main>:' -A 221 | grep '[0-9a-f]:' | grep -v 'file' | cut -f2 -d: | cut -f1-7 -d' ' | tr -s ' ' | tr '\t' ' ' | sed 's/ $//g' | sed 's/ /\\x/g' | paste -d '' -s
почему нет проверок на возврат из функций значения NULL при их запуске?
Это шеллкод и для него размер имеет важное значение. Создание дополнительных обработчиков ошибок и проверок увеличат его длину. Поэтому при написании шеллкодов такими вещами обычно пренебрегают.
В то же время я решил оставить, например, создание стекового фрейма для функций, чтобы пример был понятнее. В большинстве руководств по созданию шеллкодов Вы также не найдете этих проверок по вышеупомянутой причине.
малый размер это следствие из необходимости действовать скрытно.
значить это часть системы вторжения, которая может не пойманным исключением раскрыть сам факт.
в свою очередь эксплойт может в случае не успеха запуска шеллкода действовать автономно по заложенному сценарию.
но ваше объяснение вполне можно было бы добавить в статью.
Вы правы, отчасти. Основная причина по который шеллкод должен быть маленьким — отсутствие достаточного места в коде программы в которую внедряется шеллкод. Именно поэтому и существуют техники, например, Socket reuse, egghunter, которые иногда позволяют использовать бОльшие шеллкоды.
Думаю, размер шеллкода играет лишь незначительную роль в скрытности всего эксплоита, поскольку даже эксплоиты для «ванильных» переполнений буферов чаще всего имеют строку, вызывающее переполнение, гораздо большей длины, чем тело самого шеллкода (в качестве примера, можете рассмотреть vulnserver или посмотреть примеры эксплоитов на exploit-db). И если говорить о скрытности, то можно упомянуть об обфускации тела шеллкода, чтобы сигнатурный анализ не выявил угроз, полиморфизма, использовании нестандартных системных вызовов для установления соединения (такой пример можете рассмотреть вот здесь) и т.д.

Целью статьи было рассмотрение наиболее общего примера создания шеллкода — программы, которая позволяет получить удаленный доступ в командную оболочку в самом общем её понимании и это написано в начале статьи. Различные доработки, например такие как: избавление от нулевых байтов (а ведь с ними шеллкод не будет работать при передаче его по сети), уменьшения размера за счёт избавления от «ненужных» команд, возможность многократного подключения, обработка всех исключений и т.д. во-первых, изучаются после основ, а во-вторых, применяются далеко не всегда.
Хорошо, что он stageless кроме всего. Сейчас со всеми тулзами ручками очень редко приходится возиться, если только не red team.
Статья хорошая, как миниму потому что не забывают про ассемблер.
Немного позанудствую:
Стековый фрейм и аргументы на стеке это не общепринятые правила программирования на ассемблер, это stdcall с ногами из C/WinAPI, ассемблеру ближе передача на регистрах и как можно меньше стека.
Для компиляции по мне удобнее fasm, он и в PE сразу умеет, и чистый бинарный код может выдать без заголовков.
Про стэковый фрейм я узнал из этой книги. Мне показалось это удобным, компилятор NASM — по той же причине)
Про fasm спасибо, посмотрю.
Спасибо, приятно читать. Чуть добавлю, что кроме обхода AV, сейчас еще EDR добавился, поэтому просто шифрования будет мало.
Тоже позанудствую.
1. Зачем xor esi, esi? Для хотпатча, так там нужно mov esi, да и смысл. Я уже молчу, что stdcall должен сохранять этот регистр.
2. в реальном шк желательно проверять (strcmp самопальный) действительно ли мы нашли kernel32 (кстати, на семерке там вроде как kernelbase, но не суть), т.к. аверы могут встроить свою длл.
1. Этот регистр используется в инструкциях:
	mov esi, [ebx + 4*ecx]	; get RVA of next function name
	add esi, [ebp + 0x0C]	; base of function name

Т.к. мы не знаем какое значение хранится в этом регистре, его необходимо обнулить, иначе это может нарушить логику программы: «должен» не значит «всегда».
2. «Аверы могут встроить свою длл», AV может проанализировать код и не дать его выполнить еще до начала работы программы, фаервол может не дать соединиться к 4444 порту, EDR может заблокировать некоторые системные вызовы и т.д. и т.п. — это всё, конечно, верно, но выходит за рамки общего шеллкода.
1. mov перезапишет предыдущее значение в любом случае.
Проверил, вы правы. Видимо, осталось с прошлых тестирований. Спасибо за внимательность

Про то что можно выковырять список загруженых длл через fs не знал. Похоже что рандомизация адресов превратилась в тыкву

ASLR работает, дело не в этом; если раньше (в ХР) мы могли захардкодить какой-то 0x77880000 как адрес кернела, и обращаться туда напрямую, то сейчас нужно его найти. В данном примере, возможно, не особо понятна разница (ну что такого, нашел и нашел), но допустим RCE с включенным ASLR практически нереально написать (имею ввиду стабильное работающее решение).

Прикольная статейка, но практическая польза не очень большая, уже давно все 64 битное, а тут 32 битный код :(

Смотря в какой процесс будем класть как пэйлоад, но про 64 справедливо чаще всего.
общие принципы одинаковые, на мой взгляд, начинать изучение легче с 32 битного кода. Да и для «боевого» шеллкода нужны еще доработки)
Да, согласен; надо учиться с 32 бит, понять суть, а там и на 64 переходить. Поменять fs на gs, другие регистры и т.д.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации