.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()
{
/* 初始化栈指针 */
init_sp (stack + sizeof (stack));
/* 初始化已初始化的数据 */
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;
...
}
注: 我们可以在payload.bin中包含一个完全功能的ELF,这在创建包含多个工具包元素的“胖”二进制文件时非常重要。
注: 存在更符合人体工程学的工具来完成此任务,例如@graphitemaster的INCBIN [链接]
该主题的变体是内联汇编,如下所示:
/* 所有嵌入图像的原始图像数据 */
#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
/* 所有嵌入图像的图像结构 */
#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,它很重要。
基于编译器/链接器的有效负载二进制包含并不理想
存在权衡:

包含新数据的节段的类型和设置的标志决定了OS加载器在可执行文件启动时是否将其加载到内存中。某些节段默认被自动加载,其他则不会(例如,.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在我们需要使用时提供了结构(我们将在后续使用):

到目前为止,我们能够创建一个节段,并避免OS加载器将其加载到内存中。该节段当前在ELF镜像中处于休眠状态。我们稍后将讨论如何加载它。 然而,更紧迫的问题是,我们仍然在编译器和链接器层面操作,节段是一个被编织到最终ELF结构中的对象,从而创建了从加载器代码到其内容的引用关系和内存地址。

如果我们能够在加载器编译工作流之外创建一个包含嵌入有效负载的ELF节段,并在之后将那个节段附加到加载器二进制文件上,会怎么样?
这将打破加载器代码与节段交互的关系。然后我们教会加载器如何找到并加载它的外来数据节段,从而以松散耦合的方式将有效负载“对接”到加载器上。
从概念上讲,我们的目标是:
加载器/有效负载(在节段中)的关系现在看起来像这样:

然后我们可以创建一个注入器,它将向加载器引入一个有效负载节段,而两者都不在代码级别操作,仅靠二进制兼容性(并且加载器知道如何加载任何有效负载节段)。

这种通用ELF节段对接设置带来的一些成果:
让我们更详细地讨论ELF节段对接组件。
部署位置:后端或现场 优势:
部署位置:现场 优势:
优势:
加强ELF节段型注入器/打包器:
加强ELF加载器:
关于ELF节段加载器与有效负载启动器协作的一些说明:
加载器可以利用两种内存中有效负载执行机制之一:
选项A:SYS_Memfd_create ()
选项B:用户态Exec (https://grugq.github.io/docs/ul_exec.txt)
工作流运行:

ELF节段化有效负载与MSF有效负载相比,Binwalk的规避机会:

eBPF规避与ELF节段打包器对比:

YARA验证器和测试:


STIX工具定义:
