本篇记录一些elf格式里面的利用小技巧~
elf结构 网上很多,例如:Keith Makan
ld.so 连接器,有些好用的参数有助于调试
LD_LIBRARY_PATH 指定so,优先级最高,例如:LD_LIBRARY_PATH=/root/libc.so.2 ./shell
,需要注意,若指定libc则须保证系统默认的ld版本要与之匹配,否则就不能正常运行。
LD_SHOW_AUXV 很有用的一个环境变量,可以输出一些关键的信息,首先先来看看栈布局:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 //参考[1] ... local variables of main saved registers of main return address of main argc argv envp stack from startup code argc argv pointers NULL that ends argv[] environment pointers NULL that ends envp[] ELF Auxiliary Table <=====auxvec argv strings environment strings program name NULL
看到它其实是位于栈上,env之后,要是可以泄露出这个的话,那么就可以拿到下面这些东西了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 ➜ ~ LD_SHOW_AUXV=1 ls AT_SYSINFO: 0x7fffb7dcfc80 AT_SYSINFO_EHDR: 0x7fffb7dcf000 AT_HWCAP: 1fabfbff AT_PAGESZ: 4096 AT_CLKTCK: 100 AT_PHDR: 0x55a7f773b040 AT_PHENT: 56 AT_PHNUM: 9 AT_BASE: 0x7f3140848000 AT_FLAGS: 0x0 AT_ENTRY: 0x55a7f7740430 AT_UID: 0 AT_EUID: 0 AT_GID: 0 AT_EGID: 0 AT_SECURE: 0 AT_RANDOM: 0x7fffb7ca7ee9 AT_EXECFN: /bin/ls AT_PLATFORM: x86_64
LD_PRELOAD 它指定的动态库最先被加载,于是可以用来hook动态库函数,首先编译hook函数库:
1 2 3 4 5 #include <stdio.h> unsigned int alarm (unsigned int seconds) { printf ("%d\n" ,seconds); }
接着hookLD_PRELOAD=./hook.so ./shellcode
__libc_stack_end 这是ld.so中的符号,指向了栈的起始位置,要是泄露出它,就可以通过栈起始位置加偏移泄露出auxv的地址,于是可以得到那里面的几个关键东西(向上看啦)。
瘦身 在学习elf格式时都提到section与segment是对于两种不同的环境而言的,前者是在文件中中,后者是在内存中,elf文件被加载到内存中,会通过文件头解析segment,但并没有用到section部分,于是可以把这部分删掉,程序仍然可以正常运行,但是却不能被readelf等工具分析了[3]: 于是可以对它做手脚来抵抗分析,emmmm,当然现在的一些工具已经能正常分析它了!那看看头里面有些什么:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 typedef struct elfhdr { unsigned char e_ident[EI_NIDENT]; Elf32_Half e_type; Elf32_Half e_machine; Elf32_Word e_version; Elf32_Addr e_entry; Elf32_Off e_phoff; Elf32_Off e_shoff; Elf32_Word e_flags; Elf32_Half e_ehsize; Elf32_Half e_phentsize; Elf32_Half e_phnum; Elf32_Half e_shentsize; Elf32_Half e_shnum; Elf32_Half e_shstrndx; } Elf32_Ehdr;
如上标记内容是在加载时未用到的,另外e_shoff
指向section header表,于是那些内容也可以删掉:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 typedef struct { Elf32_Word sh_name; Elf32_Word sh_type; Elf32_Word sh_flags; Elf32_Addr sh_addr; Elf32_Off sh_offset; Elf32_Word sh_size; Elf32_Word sh_link; Elf32_Word sh_info; Elf32_Word sh_addralign; Elf32_Word sh_entsize; } Elf32_Shdr;
当然还可以继续深入,Jonathan Salwan[3]大大的程序只删除到了这里,继续删除的效果应该会更好!
参考
[1]http://www.win.tue.nl/~aeb/linux/hh/stack-layout.html [2]http://www.man7.org/linux/man-pages/man8/ld.so.8.html [3]http://shell-storm.org/blog/Linux-process-execution-and-the-useless-ELF-header-fields/ [4]https://www.tuicool.com/articles/MNRJVj