NULL POINTER空指针安全漏洞

NULL POINTER空指针安全漏洞


在Linux的ELF文件格式中,GOT表会拥有稳定的内存地址,而里面保存了共享库函数的入口地址。因此我们可以通过操作指针来改写GOT表,从而使库函数被替换。下面是一个例子:

 include <malloc.h>
 
 int main() {
 memalign(2, 1);
 
 return 0;
 }


我们将代码命名为"got.c",并进行编译:

 cc -g got.c


得到可执行文件"a.out"。注意我们在程序中使用了库函数"memalign",它的入口地址将被保存在GOT表中。我们可以使用objdump命令来查看GOT表:

 $ objdump -R a.out
 
 a.out:     file format elf64-x86-64
 
 DYNAMIC RELOCATION RECORDS
 OFFSET           TYPE              VALUE
 0000000000600ff8 R_X86_64_GLOB_DAT  __gmon_start__
 0000000000601018 R_X86_64_JUMP_SLOT  __libc_start_main
 0000000000601020 R_X86_64_JUMP_SLOT  __gmon_start__
 0000000000601028 R_X86_64_JUMP_SLOT  memalign


可以看到memalign的入口地址保存在GOT表中,保存这个入口地址的地址为0x601028。可以通过gdb来验证它:

 [weli@localhost hack]$ gdb -q a.out
 Reading symbols from a.out...done.
 (gdb) x 0x601028
 0x601028 <[email protected]>: 0x00400446


可以看到0x601028中保存了memalign的入口地址为0x400446。然后我们可以验证0x400446确实是memalign的入口:

 (gdb) x 0x00400446
 0x400446 <memalign@plt+6>:   0x00000268
 (gdb)


我们可以看一下程序对应的汇编代码:

 $ objdump -d -Mintel a.out  | grep -A20 main
 ...
 0000000000400540 <main>:
   400540:    55                      push   rbp
   400541:    48 89 e5                mov    rbp,rsp
   400544:    be 01 00 00 00          mov    esi,0x1
   400549:    bf 02 00 00 00          mov    edi,0x2
   40054e:    e8 ed fe ff ff          call   400440 <memalign@plt>
   400553:    b8 00 00 00 00          mov    eax,0x0
   400558:    5d                      pop    rbp
   400559:    c3                      ret
   40055a:    66 0f 1f 44 00 00       nop    WORD PTR [rax+rax*1+0x0]


注意到这行:

   40054e:    e8 ed fe ff ff          call   400440 <memalign@plt>


可以看到程序通过查GOT表0x601028中的内容取得了memalign的入口地址为0x400440。因为GOT表通常被保存在.data段中,因此是可读写的,因此我们如果把0x601028中的内容改掉,那么它就不再指向0x400446。通过操纵这个入口地址,程序的执行过程就被篡改了。下面是示例代码:

 include <malloc.h>
 
 int main() {
 int *ptr = NULL;
 ptr = 0x601028;
 *ptr = 0xaaaaaa;
 
 memalign(2, 1);
 return 0;
 }


我们让空指针ptr指向GOT表中的位置:0x601028,也就是memalign的入口地址被保存的地方,然后把它改写成0xaaaaaa。通过这种方式,我们就劫持了IP指针,让程序执行的位置指到了0xaaaaaa这里。我们把程序进行编译,然后运行看看:

 [weli@localhost hack]$ cc -g got.c
 [weli@localhost hack]$ ./a.out
 Segmentation fault


可以看到程序发生了段错误,因为0xaaaaaa是个无效的地址,我们可以通过gdb来验证这一点:

 [weli@localhost hack]$ gdb -q a.out
 Reading symbols from a.out...done.
 (gdb) run
 Starting program: /home/weli/projs/hack/a.out
 
 Program received signal SIGSEGV, Segmentation fault.
 0x0000000000aaaaaa in ?? ()
 (gdb) i r rip
 rip            0xaaaaaa  0xaaaaaa
 (gdb)


如上所示,通过空指针的安全漏洞,我们便可以操作GOT,从而拿到对IP指针的控制权,最后控制整个程序。从这里我们学到,对于程序中的空指针要特别小心。造成空指针的原因可能包括:

1. 读入用户输入数据,不进行错误检测。
2. 数值超出正常范围导致逻辑出错,且逻辑中包含内存分配相关代码。

最后给出一个完整的例子和运行结果:


NULL POINTER空指针安全漏洞_第1张图片


源代码(运行于Fedora20):

 // work1.c
 #include <malloc.h>
 #include <stdio.h>
 
 int say_hello() {
   printf("Hello, Martian!\n");
 }
 
 int main() {
   int *ptr = NULL;
   ptr = 0x601030;
   *ptr = 0x400580;
 
   memalign(2, 1);
   return 0;
 }


编译过程:

 localhost:hack weli$ cc -g work1.c -o work1
 work1.c: In function ‘main’:
 work1.c:10:7: warning: assignment makes pointer from integer without a cast [enabled by default]
    ptr = 0x601030;
        ^


运行结果:

 localhost:hack weli$ ./work1
 Hello, Martian!
 localhost:hack weli$


你可能感兴趣的:(linux,elf,got)