首页
社区
课程
招聘
[HTB]Dream Diary: Chapter 1
发表于: 2024-10-25 10:13 3281

[HTB]Dream Diary: Chapter 1

2024-10-25 10:13
3281

每日一题计划:督促自己练习,每日分享一题的练习!想一起刷题咱们可以一起练练练,以及,相互监督!

今天是第1天,希望能坚持下去

Hint: Xenial Xerus

这是ubuntu16.04lts的代号,意味着适用2.23的libc

菜单题:

运行起来是这样的菜单:

选项1:Allocate

申请内存,指定大小,填充数据,无溢出

选项2:edit:

编辑操作使用的长度来自strlen的结果,假定数据是满的,strlen会计算到next chunk size字段,导致1字节溢出

选项3:del:

这里会清空指针,没有UAF和Double-free了

第一步:指针数组位于0x0000000006020c0,上面就是got表,存在fake fastbin chunk 的条件,申请走fake fastbin chunk,从而控制指针数组

fake chunk:

打hook需要完成libc地址泄露,got可修改这个条件就可以用上了,能控制指针数组,就能任意地址写,那么就暂时不需要free了

第二步,打got,将free改成puts先用用

指针数组是可控的,那这随便就泄露出libc地址了,接下来就是打hook环节

第三步:打hook,drop shell

默认最大的fastbin chunk是0x68申请出来的,0x78申请出来的会进入unsortedbin

这里申请4个chunk,其中chunk0溢出1字节,将chunk1的大小修改为能刚好覆盖chunk2,chunk3用于分隔top chunk

此时的堆:

得到一个被unsortedbin chunk覆盖的fastbin chunk

接下来,修改fd指向got那里创造出来的fake chunk

申请一个0xe8把unsortedbin 完整申请走,向fastbin chunk.next写入fake chunk address

申请走之后,覆盖ptr指针数组

这里前8字节写入杂乱数据,是为了保留这个区域可以再次被修改,因为edit选项是基于对目标地址strlen获取长度来写入数据的

然后要保留一份方便再次修改的该数组

修改elf.got.free为elf.plt.puts,拿到libc地址泄露

最后drop shell的方法有很多,最简单的方法就是直接通过elf.got来劫持函数执行

有了libc地址泄露,可以劫持atoi为system,然后在输入选项的时候,输入bash字符即可(因为调用atoi之前的read函数接受6个字符的输入)

或者使用one_gadget也行,或者打io也行不过就比较麻烦了

本练习相关的知识:

off by one 创造重叠块

Fastbin Attack

Hijack Elf GOT

Arch:       amd64-64-little
RELRO:      Partial RELRO
Stack:      Canary found
NX:         NX enabled
PIE:        No PIE (0x3fe000)
Arch:       amd64-64-little
RELRO:      Partial RELRO
Stack:      Canary found
NX:         NX enabled
PIE:        No PIE (0x3fe000)
void __fastcall __noreturn main(int a1, char **a2, char **a3)
{
  int choose; // eax
  __int64 buf[2]; // [rsp+0h] [rbp-10h] BYREF
 
  buf[1] = __readfsqword(0x28u);
  buf[0] = 0LL;
  setvbuf(stdout, 0LL, 2, 0LL);
  setvbuf(stdin, 0LL, 2, 0LL);
  setvbuf(stderr, 0LL, 2, 0LL);
  while ( 1 )
  {
    while ( 1 )
    {
      menu();
      read(0, buf, 4uLL);
      choose = atoi((const char *)buf);
      if ( choose != 2 )
        break;
      edit(buf, buf);                           // 2
    }
    if ( choose > 2 )
    {
      if ( choose == 3 )
      {
        del(buf, buf);                          // 3
      }
      else
      {
        if ( choose == 4 )
          exit(0);
LABEL_13:
        puts("Invalid choice!");
      }
    }
    else
    {
      if ( choose != 1 )
        goto LABEL_13;
      add(buf, buf);                            // 1
    }
  }
}
void __fastcall __noreturn main(int a1, char **a2, char **a3)
{
  int choose; // eax
  __int64 buf[2]; // [rsp+0h] [rbp-10h] BYREF
 
  buf[1] = __readfsqword(0x28u);
  buf[0] = 0LL;
  setvbuf(stdout, 0LL, 2, 0LL);
  setvbuf(stdin, 0LL, 2, 0LL);
  setvbuf(stderr, 0LL, 2, 0LL);
  while ( 1 )
  {
    while ( 1 )
    {
      menu();
      read(0, buf, 4uLL);
      choose = atoi((const char *)buf);
      if ( choose != 2 )
        break;
      edit(buf, buf);                           // 2
    }
    if ( choose > 2 )
    {
      if ( choose == 3 )
      {
        del(buf, buf);                          // 3
      }
      else
      {
        if ( choose == 4 )
          exit(0);
LABEL_13:
        puts("Invalid choice!");
      }
    }
    else
    {
      if ( choose != 1 )
        goto LABEL_13;
      add(buf, buf);                            // 1
    }
  }
}
+------------------------------+
|         Dream Diary          |
+------------------------------+
| [1] Allocate                 |
| [2] Edit                     |
| [3] Delete                   |
| [4] Exit                     |
+------------------------------+
>>
+------------------------------+
|         Dream Diary          |
+------------------------------+
| [1] Allocate                 |
| [2] Edit                     |
| [3] Delete                   |
| [4] Exit                     |
+------------------------------+
>>
unsigned __int64 sub_4009A8()
{
  int i; // [rsp+4h] [rbp-1Ch]
  size_t size; // [rsp+8h] [rbp-18h]
  char nptr[8]; // [rsp+10h] [rbp-10h] BYREF
  unsigned __int64 v4; // [rsp+18h] [rbp-8h]
 
  v4 = __readfsqword(0x28u);
  *(_QWORD *)nptr = 0LL;
  for ( i = 0; ; ++i )
  {
    if ( i > 15 )                               // 最多15个
    {
      puts("Too many notes!");
      return __readfsqword(0x28u) ^ v4;
    }
    if ( !(&ptr)[i] )
      break;
  }
  printf("\nSize: ");
  read_(nptr, 6LL);
  size = atoi(nptr);
  (&ptr)[i] = (char *)malloc(size);             // 申请内存
  if ( !(&ptr)[i] )
  {
    puts("Malloc error!");
    exit(-1);
  }
  printf("Data: ");
  read_((&ptr)[i], size);                       // 写入数据,无溢出
  puts("Success!");
  return __readfsqword(0x28u) ^ v4;
}
unsigned __int64 sub_4009A8()
{
  int i; // [rsp+4h] [rbp-1Ch]
  size_t size; // [rsp+8h] [rbp-18h]
  char nptr[8]; // [rsp+10h] [rbp-10h] BYREF
  unsigned __int64 v4; // [rsp+18h] [rbp-8h]
 
  v4 = __readfsqword(0x28u);
  *(_QWORD *)nptr = 0LL;
  for ( i = 0; ; ++i )
  {
    if ( i > 15 )                               // 最多15个
    {
      puts("Too many notes!");
      return __readfsqword(0x28u) ^ v4;
    }
    if ( !(&ptr)[i] )
      break;
  }
  printf("\nSize: ");
  read_(nptr, 6LL);
  size = atoi(nptr);
  (&ptr)[i] = (char *)malloc(size);             // 申请内存
  if ( !(&ptr)[i] )
  {
    puts("Malloc error!");
    exit(-1);
  }
  printf("Data: ");
  read_((&ptr)[i], size);                       // 写入数据,无溢出
  puts("Success!");
  return __readfsqword(0x28u) ^ v4;
}
unsigned __int64 edit()
{
  unsigned int v1; // [rsp+4h] [rbp-1Ch]
  size_t v2; // [rsp+8h] [rbp-18h]
  __int64 buf; // [rsp+10h] [rbp-10h] BYREF
  unsigned __int64 v4; // [rsp+18h] [rbp-8h]
 
  v4 = __readfsqword(0x28u);
  buf = 0LL;
  printf("Index: ");
  read(0, &buf, 4uLL);
  v1 = atoi((const char *)&buf);
  if ( v1 < 0x10 )
  {
    if ( (&ptr)[v1] )
    {
      v2 = strlen((&ptr)[v1]);                  // 计算原本的长度
      printf("Data: ");
      read_((&ptr)[v1], v2);                    // 写入数据,长度上限是原本的长度
      puts("Done!");
    }
    else
    {
      puts("No UAF for you!");
    }
  }
  else
  {
    puts("Out of bounds!");
  }
  return __readfsqword(0x28u) ^ v4;
}
unsigned __int64 edit()
{
  unsigned int v1; // [rsp+4h] [rbp-1Ch]
  size_t v2; // [rsp+8h] [rbp-18h]
  __int64 buf; // [rsp+10h] [rbp-10h] BYREF
  unsigned __int64 v4; // [rsp+18h] [rbp-8h]
 
  v4 = __readfsqword(0x28u);
  buf = 0LL;
  printf("Index: ");
  read(0, &buf, 4uLL);
  v1 = atoi((const char *)&buf);
  if ( v1 < 0x10 )
  {
    if ( (&ptr)[v1] )
    {
      v2 = strlen((&ptr)[v1]);                  // 计算原本的长度
      printf("Data: ");
      read_((&ptr)[v1], v2);                    // 写入数据,长度上限是原本的长度
      puts("Done!");
    }
    else
    {
      puts("No UAF for you!");
    }
  }
  else
  {
    puts("Out of bounds!");
  }
  return __readfsqword(0x28u) ^ v4;
}
unsigned __int64 del()
{
  unsigned int v1; // [rsp+Ch] [rbp-14h]
  __int64 buf; // [rsp+10h] [rbp-10h] BYREF
  unsigned __int64 v3; // [rsp+18h] [rbp-8h]
 
  v3 = __readfsqword(0x28u);
  buf = 0LL;
  printf("Index: ");
  read(0, &buf, 4uLL);
  v1 = atoi((const char *)&buf);
  if ( v1 < 0x10 )
  {
    if ( (&ptr)[v1] )
    {
      free((&ptr)[v1]);                         // 释放内存
      (&ptr)[v1] = 0LL;                         // 指针清空,不存在UAF和double-free
      puts("Done!");
    }
    else
    {
      puts("No double-free for you!");
    }
  }
  else
  {
    puts("Out of bounds!");
  }
  return __readfsqword(0x28u) ^ v3;
}
unsigned __int64 del()
{
  unsigned int v1; // [rsp+Ch] [rbp-14h]
  __int64 buf; // [rsp+10h] [rbp-10h] BYREF
  unsigned __int64 v3; // [rsp+18h] [rbp-8h]
 
  v3 = __readfsqword(0x28u);
  buf = 0LL;
  printf("Index: ");
  read(0, &buf, 4uLL);
  v1 = atoi((const char *)&buf);
  if ( v1 < 0x10 )
  {
    if ( (&ptr)[v1] )
    {
      free((&ptr)[v1]);                         // 释放内存
      (&ptr)[v1] = 0LL;                         // 指针清空,不存在UAF和double-free
      puts("Done!");
    }
    else
    {
      puts("No double-free for you!");
    }
  }
  else
  {
    puts("Out of bounds!");
  }
  return __readfsqword(0x28u) ^ v3;
}
pwndbg> dq 0x602010 30
0000000000602010     00007ff9258de150 00007ff9257aa31a
0000000000602020     00007ff92579926f 00007ff9257af1e0
0000000000602030     0000000000400706 00007ff925780914
0000000000602040     00007ff9258084c0 00007ff9257532e1
0000000000602050     00007ff9257a9cd3 00007ff9257999c5
0000000000602060     00007ff925765fcb 0000000000400776
0000000000602070     0000000000000000 0000000000000000
0000000000602080     00007ff9258c3620 0000000000000000
0000000000602090     00007ff9258c28e0 0000000000000000
00000000006020a0     00007ff9258c3540 0000000000000000
00000000006020b0     0000000000000000 0000000000000000
00000000006020c0     0000000002458010 0000000000000000
00000000006020d0     0000000000000000 0000000002458180
00000000006020e0     0000000000000000 0000000000000000
00000000006020f0     0000000000000000 0000000000000000
pwndbg> dq 0x602010 30
0000000000602010     00007ff9258de150 00007ff9257aa31a
0000000000602020     00007ff92579926f 00007ff9257af1e0
0000000000602030     0000000000400706 00007ff925780914
0000000000602040     00007ff9258084c0 00007ff9257532e1
0000000000602050     00007ff9257a9cd3 00007ff9257999c5
0000000000602060     00007ff925765fcb 0000000000400776
0000000000602070     0000000000000000 0000000000000000
0000000000602080     00007ff9258c3620 0000000000000000
0000000000602090     00007ff9258c28e0 0000000000000000
00000000006020a0     00007ff9258c3540 0000000000000000
00000000006020b0     0000000000000000 0000000000000000
00000000006020c0     0000000002458010 0000000000000000
00000000006020d0     0000000000000000 0000000002458180
00000000006020e0     0000000000000000 0000000000000000
00000000006020f0     0000000000000000 0000000000000000
Fake chunk | PREV_INUSE | IS_MMAPED | NON_MAIN_ARENA
Addr: 0x60209d
prev_size: 0xf9258c3540000000
size: 0x78 (with flag bits: 0x7f)
fd: 0x00
bk: 0x00
fd_nextsize: 0x2458010000000
bk_nextsize: 0x00
Fake chunk | PREV_INUSE | IS_MMAPED | NON_MAIN_ARENA
Addr: 0x60209d
prev_size: 0xf9258c3540000000
size: 0x78 (with flag bits: 0x7f)

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 0
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//