0%

FILE Structure exploit

0x00 前言

这几天在看ctftime看一篇writeup时候,看到一篇论文学到了一些新姿势总结一下

writeup链接:

论文链接:

0x01 文件流

当你想利用read()函数,write()函数从文件写入或者读出一些内容的时候,并不是立即写到文件里面的,而是,先写到一个kernel buf,当kernel buf满的时候,才会一次性写到文件中。

而你用fread()或者fwrite()读写文件的时候,并不会直接读写到kernel buf里面,而是在libc里面有一块buf,当buf满的时候,才会调用read()或者write()读写kernel buf,那么问题来了,这个kernel buf是不是一个固定的位置呢,还是kmalloc出来的呢,如果是固定的,是不是可以作为一个kernel exploit的一个跳板,

然后这就需要追踪kernel sys_read和sys_write的实现,linux syscall定义于

1
/include/linux/syscalls.h

然后搜索 sys_read 然后发现定义于 fs/read_write.c

1
2
3
4
5
6
7
8
9
/* fs/read_write.c */
asmlinkage long sys_llseek(unsigned int fd, unsigned long offset_high,
unsigned long offset_low, loff_t __user *result,
unsigned int whence);
asmlinkage long sys_lseek(unsigned int fd, off_t offset,
unsigned int whence);
asmlinkage long sys_read(unsigned int fd, char __user *buf, size_t count);
asmlinkage long sys_write(unsigned int fd, const char __user *buf,
size_t count);

fs/read_write.c 中继续搜索 sys_read

1
2
3
4
SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count)
{
return ksys_read(fd, buf, count);
}

发现调用了ksys_read

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
ssize_t ksys_read(unsigned int fd, char __user *buf, size_t count)
{
struct fd f = fdget_pos(fd);
ssize_t ret = -EBADF;

if (f.file) {
loff_t pos, *ppos = file_ppos(f.file);
if (ppos) {
pos = *ppos;
ppos = &pos;
}
ret = vfs_read(f.file, buf, count, ppos);
if (ret >= 0 && ppos)
f.file->f_pos = pos;
fdput_pos(f);
}
return ret;
}

可以看到ksys_read函数首先取得当前文件的偏移,然后调用vfs_read()

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
ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
{
ssize_t ret;

if (!(file->f_mode & FMODE_READ))
return -EBADF;
if (!(file->f_mode & FMODE_CAN_READ))
return -EINVAL;
if (unlikely(!access_ok(buf, count)))
return -EFAULT;

ret = rw_verify_area(READ, file, pos, count);
if (!ret) {
if (count > MAX_RW_COUNT)
count = MAX_RW_COUNT;
ret = __vfs_read(file, buf, count, pos);
if (ret > 0) {
fsnotify_access(file);
add_rchar(current, ret);
}
inc_syscr(current);
}

return ret;
}

可以看到这个函数主要是检查权限,然后调用 __vfs_read

1
2
3
4
5
6
7
8
9
10
ssize_t __vfs_read(struct file *file, char __user *buf, size_t count,
loff_t *pos)
{
if (file->f_op->read)
return file->f_op->read(file, buf, count, pos);
else if (file->f_op->read_iter)
return new_sync_read(file, buf, count, pos);
else
return -EINVAL;
}

然后发现他根据不同的文件类型调用read(),然后,就得找不同类型的文件,去找read()函数,我在 /fs/ext4/file.c 里面找到实现的read函数,并没有找到buf 23333

由于还没有想法去验证,待补

0x02 新姿势

利用unsorted bin attack的任意地址写libc,高libc版本可以用small attack那个任意地址写libc,去修改stdin 结构体IO_buf_end,这样的话,stdin的buf范围为IO_buf_end到main_arena中unsorted bin链表的位置,可以直接写malloc hook从而实现开shell,我觉得高版本的libc small bin attack更为强大,因为他能修改top chunk的指针,从而实现任意地址malloc,有点强大