简介

ELFGuard是一个针对ELF文件的shellcode执行框架,可以在ELF二进制文件中插入你想要的shellcode,例如:SECCOMP来限制系统调用,reverseshell来留后门。

项目地址:https://github.com/thinkycx/elfguard

创建时间:2019-12-16
更新时间:2025-01-16

演示视频

攻,基于elfguard留下反弹 shell 后门:

防,基于elfguard限制系统调用防止反弹 shell:

关键技术

为了实现以上目的,所需步骤和关键技术如下:

  1. 在ELF文件中扩展空间用来存储shellcode
  2. 开发满足需求的shellcode
  3. hook程序执行流跳转到shellcode执行

storage模块

expand a segment

semgent是ELF程序在OS load起来后,实际的内存空间,由相同权限的.section组成。
根据ELF文件格式可知,.text段所在的segment,它的映射地址和长度由Program Header Table中PT_LOAD为1的Program Header确定,因此将这两个值改大(p_filesz,p_memsz)即可。

add a segment

通常expand a segment就已经足够,这里介绍一个在ELF文件中增加一个segment的办法。增加的好处就是:权限我们都可以自己控制,可以修改成(rwx)。

增加segment(Program Header)必然会影响到其后面的数据,为了不影响, 因此可以将Program Header Table复制到最后,再在其中增加一个segment。

  1. 复制Program Header Table到文件末尾,同时修正ELF Header中的p_offset。
  2. 修正new Program Header Table中第一个segment(用来映射new Program Header Table)。
  3. 在PT_LOAD segment后增加一个segment,修改其中的各个字段,建议从当前new Program Header Table处开始映射。实际的映射地址会页对齐,屏蔽低3位。

具体细节请看代码,修正前后对比如下所示:

注:原始的Program Header Table中,第一个entry映射Program Headre Table; 第二个映射interpreter path,第三个映射PT_LOAD segment(r-xp)。在第三个之后增加新的segment只是个人习惯,你可以尝试在Program Header Table之后新加一个entry。

.eh_frame

这是ELF二进制文件中程序用不到的一个segment,可以通过readelf -l <filename>来查看。虽然图中GNU_EH_FRAME的长度为0x64,但是实际ELF在映射时,该段之后的空间也可以使用,长度通常会大于0x64,因此可以通过debug来确认。

shellcode模块

对应shellcode/下的每一个文件夹,例如SECCOMP/ reverseshell/等。

SECCOMP是基于linux kernel提供的SECCOMP安全机制,shellcode基于prctl syscall将生成的SECCOMP bpf 规则导入到kernel中,实现限制execve syscall,多用于CTF PWN中的通防。

reverseshell 中的shellcode是基于pwntools中shellcraft模块快速实现的。基于socket connect dup execve等系统调用实现的反弹shell的汇编代码。同时增加了两次fork系统调用,保证了shellcode在执行时不会影响到原parent进程的逻辑。

注意shellcode模块需要保证:shellcode执行前后,保证函数需要用到的寄存器没有被破坏。例如seccomp shellcode中需要在调用钱后保存现场。reverseshell shellcode中由于用到了fork系统调用,因此只会破坏rax寄存器,对于函数调用参数没有影响。

controller模块

controller模块就是为了修改程序的执行流,对应代码中的lib/controller.py。

ENTRY POINT HOOK

ELF程序的入口点在ELF Header中指定,因此修改ENTRY POINT为shellcode,就可以在控制执行流。hook ENTRY的好处就是不用保存寄存器信息。

PLT HOOK

PLT HOOK就是通过修改程序的PLT表来劫持程序执行流。

HOOK时需要将shellcode wrapper:CONDITION + shellcode + JMP_BACK_TO_PLT
其中CONDITION保证shellcode只被调用一次,JMP_BACK_TO_PLT在shellcode调用完后跳转到原始的PLT执行。

调用时可以执行func_name hook,或者指定hook第几个函数(func_plt_number)。

注意,部分程序没有Lazy Binding的过程,因此不能用PLT HOOK。

参考

  1. https://docs.pwntools.com/en/stable/shellcraft.html
  2. https://github.com/Gallopsled/pwntools/tree/292b81af179e25e7810e068b3c06a567256afd1d/pwnlib/shellcraft/templates/amd64/linux