Категория > Новости > Реверс-шелл на 237 байт. Изучаем хаки Linux для уменьшения исполняемого файла - «Новости»
Реверс-шелл на 237 байт. Изучаем хаки Linux для уменьшения исполняемого файла - «Новости»26-08-2021, 00:02. Автор: Доминика |
tiny shell, prism и другие реверс‑шеллы. Те из них, что написаны на С, занимают лишь десятки‑сотни килобайт. Так к чему создавать еще один? А суть вот в чем. Цель данной статьи учебная: равно как разработка ядерных руткитов — один из наиболее наглядных способов разобраться с устройством самого ядра Linux, написание обратного шелла с дополнительной функциональностью и одновременно с ограничениями по размеру исполняемого файла позволяет изучить некоторые неожиданные особенности положения вещей в Linux, в частности касающихся ELF-файлов, их загрузки и запуска, наследования ресурсов в дочерних процессах и работы компоновщика (он же линкер, линковщик, редактор связей). По ходу дела нас ждет множество интересных открытий и любопытных хаков. А бонусом нам будет рабочий инструмент, который заодно можно допиливать и применять в пентесте. Посему начнем! infoРезультаты трудов доступны на гитхабе. warningНи автор, ни редакция не несут ответственности за любые последствия использования приведенных в этой публикации сведений. Вся информация предоставлена исключительно ради информирования читателя. Определяемся с ТЗИтак, наш реверс‑шелл помимо того, что подключаться к заданному хосту на заданный порт, также должен:
Сперва определимся с языком. Поскольку мы стремимся к минимально возможному размеру бинаря, в голову приходит лишь два варианта: С и ассемблер. Однако, как ты, вероятно, знаешь, хоть С и позволяет собирать крохотные по современным меркам Hello World’ы (примерно 17 и ~800 Кбайт при динамической и статической линковке соответственно против 2 Мбайт на Go), при компиляции С‑кода генерируется также код, отвечающий:
Конструкторы и деструкторыМассивы функций‑конструкторов и функций‑деструкторов запускаются перед и после В некоторых случаях секции, хранящие эти функции, могут иметь имена Также на выходе исполняемый файл может содержать секции с отладочной и прочей информацией (например, имена символов, версия компилятора), которая не используется непосредственно для его запуска и работы, но занимаемое файлом пространство увеличивает, и иногда значительно. О таких секциях мы поговорим немного позже. Данная обвязка неразрывно связана с С‑бинарями как минимум в Linux. Для нас же в рамках нашей задачи она — балласт, от которого необходимо нещадно избавляться. Так что реверс‑шелл наш будет написан на великом и ужасном языке ассемблера (естественно, под x86). План таков: сперва напишем рабочий код, а уже затем будет заниматься кардинальным уменьшением его размера. КодимМы будем использовать NASM. За основу возьмем простейший асмовый реверс‑шелл. Размышления на тему, должен ли наш код быть 32- или 64-битным, привели меня к выводу, что первый вариант предпочтительнее: инструкции в этом режиме меньше, а необходимой функциональности мы не теряем, ведь наша главная задача по сути состоит лишь в подключении к серверу и запуске оболочки, а сама она будет работать уже в 64-битном режиме. Код будет делать следующее:
Что ж, за дело! Что в имени тебе?В Linux можно встретить две «сущности», хранящие связанное с процессом имя. Назовем их «полное» и «краткое имя». Оба доступны через Краткое имя, согласно описанию, содержит имя исполняемого файла без пути до него. Это имя хранится в ядерной структуре Полное имя содержит аргументы запуска программы, они же Смена краткого имени сложностей не вызывает. Воспользуемся для этого системным вызовом Таким образом, для смены краткого имени нужно вызвать
mov eax, 0xac ; NR_PRCTL
mov ebx, 15 ; PR_SET_NAME
mov ecx, NEW_ARGV
int 0x80; syscall interrupt
...
NEW_ARGV:
db "s0l3g1t", 0
infoМного полезной информации о системных вызовах можно найти в Попробуем теперь переписать
mov edi, [esp]; edi = &argv[0]
mov esi, NEW_ARGV
mov ecx, _start - NEW_ARGV ; ecx = strlen(NEW_ARGV) + NULL-byte
_name_loop:
movsb; edi[i] = esi[i] ; i+=1
loop _name_loop
...
NEW_ARGV:
db "s0l3g1t", 0
_start:
...
Этот адрес помещается в регистр Вывод ps при перезаписи нулевого аргумента «в лоб» Как‑то не особо здорово. Попробуем его сначала заполнить нулями и лишь затем перезаписывать. Вывод ps при перезаписи зануленного нулевого аргумента Уже лучше — в выводе
А в По этой же причине замена адреса самого массива строк В общем, будем исходить из предположения, что реверс‑шелл запущен от имени простого пользователя и возможности установить Осталось разобраться с подменой имени
xor eax, eax
push dword 0x0068732f ; push "/sh"
push dword 0x6e69622f ; push /bin (="/bin/sh")
mov ebx, esp; ebx = ptr to "/bin/sh" into ebx
push edx; edx = 0x00000000
mov edx, esp; **envp = edx = ptr to NULL address
push ebx; pointer to /bin/sh
push 0
push NEW_ARGV
mov ecx, esp; ecx points to shell's argv[0] ( &NEW_ARGV )
mov al, 0xb
int 0x80; execve("/bin/sh", &{ NEW_ARGV, 0 }, 0)
Но сменить при этом и краткое имя через Перейти обратно к новости |