首页
论坛
课程
招聘
[原创]内核改机[二]:文件权限、隐藏、替换
2022-6-18 17:21 6360

[原创]内核改机[二]:文件权限、隐藏、替换

2022-6-18 17:21
6360

目录

内核读文件

1.绕过文件权限限制

调用链如下
open.c(filp_open)->open.c(filp_open_name_no_perm)->namei.c(do_filp_open_no_perm)->namei.c(path_openat_no_perm)
其中namei.c(link_path_walk)去除掉may_lookup的检测
namei.c(do_last)去除may_open的检测
把这条调用链新开一份,去掉这两个检测,即可绕过权限限制,在内核里读文件的时候就调用新开的函数。

2.读文件代码

这个代码比较老生常谈,很基础的东西。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
mm_segment_t old_fs;
struct inode* inode;
struct file* filp;
int readSize = 0;
char* buf = 0;
old_fs = get_fs();
set_fs(KERNEL_DS);
filp = my_filp_open(path,O_RDONLY,0644);
inode = file_inode(filp);
if(inode->i_size == 0)
{
    filp_close(filp,NULL);
}
buf = kvzalloc(inode->i_size+1,GFP_KERNEL);
readSize = vfs_read(filp,buf,inode->i_size,&(filp->f_pos));
if(readSize == 0)
{
    kvfree(buf);
    filp_close(filp,NULL);
    //faild
    //......
}
set_fs(old_fs);

这一步最好自己做一个内存管理,一次性vmalloc开辟好所有的内存,然后在这一块内存里填所有的东西。

获取文件的绝对路径

1
2
3
4
char buf[len];
struct file* file;
char* strPath = NULL;
strPath = d_path(&file->f_path,buf,len);

非打开文件相关

所有用户层能访问的与文件相关的非打开的操作,基本都绕不开一个地方
fs/namei.c里的getname_flags(),我们可以从这里着手

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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
struct filename *
getname_flags(const char __user *filename, int flags, int *empty)
{
    struct filename *result;
    char *kname;
    int len;
 
    result = audit_reusename(filename);
    if (result)
        return result;
 
    result = __getname();
    if (unlikely(!result))
        return ERR_PTR(-ENOMEM);
 
    kname = (char *)result->iname;
    result->name = kname;
 
    len = strncpy_from_user(kname, filename, EMBEDDED_NAME_MAX);
    if (unlikely(len < 0)) {
        __putname(result);
        return ERR_PTR(len);
    }
    //change begin add
    //只看这部分即可,file_hash和getFileInfo()就只是自己用哈希表做了下信息管理
    if(isTarget() && len < EMBEDDED_NAME_MAX)
    {
        struct file_hash ret;
        ret.id = 0;
        getFileInfo(kname,&ret);
        if(ret.id != 0)
        {
            if(ret.flag & _FILE_REPLACE
            || ret.flag & _FILE_HAVE
            || ret.flag & _FILE_STAT)
            {
                if(ret.replacePath != 0)
                {
                    strcpy(kname,ret.replacePath);
                }
            }
        }
    }
    //change end add
 
    if (unlikely(len == EMBEDDED_NAME_MAX)) {
        const size_t size = offsetof(struct filename, iname[1]);
        kname = (char *)result;
        result = kzalloc(size, GFP_KERNEL);
        if (unlikely(!result)) {
            __putname(kname);
            return ERR_PTR(-ENOMEM);
        }
        result->name = kname;
        len = strncpy_from_user(kname, filename, PATH_MAX);
        if (unlikely(len < 0)) {
            __putname(kname);
            kfree(result);
            return ERR_PTR(len);
        }
        if (unlikely(len == PATH_MAX)) {
            __putname(kname);
            kfree(result);
            return ERR_PTR(-ENAMETOOLONG);
        }
    }
 
    result->refcnt = 1;
    if (unlikely(!len)) {
        if (empty)
            *empty = 1;
        if (!(flags & LOOKUP_EMPTY)) {
            putname(result);
            return ERR_PTR(-ENOENT);
        }
    }
 
    result->uptr = filename;
    result->aname = NULL;
    audit_getname(result);
    return result;
}

另外一个地方为fs/open.c里的SYSCALL_DEFINE3(faccessat)
此种为针对access()和shell which等方法
也是很简单的d_path()取绝对路径,然后根据业务逻辑判断文件是否需要隐藏即可

打开文件相关

只要涉及到打开文件,都绕不开fs/open.c的这个函数,以下是我魔改过的

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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
long do_sys_open2(int dfd, const char __user *filename, int flags, umode_t mode)
{
    struct open_flags op;
    int flags2 = flags & ~O_CREAT;
    int fd = 0;
    struct filename *tmp;
    struct open_flags op2;
    struct filename *cheatFileName = 0;
    struct file *f;
    struct file *f2;
    char* kname[1024] = {0};
    copy_from_user(kname,filename,strnlen_user(filename,1024));
 
    fd = build_open_flags(flags, mode, &op);
    if (fd)
        return fd;
    fd = build_open_flags(flags2,mode,&op2);
    if (fd)
        return fd;
    tmp = getname(filename,false);
    if (IS_ERR(tmp))
        return PTR_ERR(tmp);
 
    fd = get_unused_fd_flags(flags);
    if(isTarget())
    {
        bool isCheat = false;
        struct file_hash obj;
        struct file* replace = 0;
        if(fd > 0)
        {
            f = do_filp_open(dfd, tmp, &op);
            if(IS_ERR(f))
            {
                //假设没开文件权限,要读取特定机型特有的文件
                f2 = do_filp_open_no_perm(dfd, tmp, &op2);
                isCheat = true;
                if(IS_ERR(f2))
                {
                    goto FAIL_FINISH;
                }
            }
            obj.id = 0;
            if(!IS_ERR(f))
            {
                __getFileInfoHash(&(f->f_path),&obj);
            }
            else
            {
                __getFileInfoHash(&(f2->f_path),&obj);
            }
            if(isCheat)
            {
                if(obj.id != 0 && obj.flag & _FILE_READ)
                {
                    f = f2;
                    goto SUCC_FINISH;
                }
                else
                {
                    filp_close(f2,0);
                    goto FAIL_FINISH;
                }
            }
            if(obj.id != 0)
            {
                if(obj.flag & _FILE_HIDE)
                {
                    if(!IS_ERR(f))
                    {
                        filp_close(f,0);
                    }
                    put_unused_fd(fd);
                    putname(tmp);
                    return -ENOENT;
                }
                else if(obj.flag & _FILE_REPLACE)    //不会把无权限访问的文件添加进替换表,所以不用考虑原文件是否存在
                {
                    cheatFileName = getname_kernel(obj.replacePath);
                    if(!IS_ERR(cheatFileName))
                    {
                        build_open_flags(flags, mode, &op);
                        replace = do_filp_open_no_perm(dfd, cheatFileName, &op);
                        if(!IS_ERR(replace))
                        {
                            filp_close(f,0);
                            f = replace;
                        }
                    }
                }
            }
            fsnotify_open(f);
            fd_install(fd, f);
            goto FINISH;
        }
    }
    else
    {
        struct file *f = do_filp_open(dfd, tmp, &op);
        if (IS_ERR(f)) {
            put_unused_fd(fd);
            fd = PTR_ERR(f);
        } else
        {
            fsnotify_open(f);
            fd_install(fd, f);
        }
    }
    goto FINISH;
FAIL_FINISH:
    put_unused_fd(fd);
    fd = PTR_ERR(f);
    goto FINISH;
SUCC_FINISH:
    fsnotify_open(f);
    fd_install(fd, f);
FINISH:
    putname(tmp);
    if(cheatFileName != 0 && !IS_ERR(cheatFileName) )
    {
        putname(cheatFileName);
    }
    return fd;
}

未完成目录:

文件属性
基于真实内存伪造maps
修改网卡mac等相关信息
修改已启动时间
使用hash表管理读入的需要使用的信息
rsa验证信息
暂时能想到的就这么多,其他的别人讲的少的东西都挺零零散散的,或者解决起来很简单一两句话搞定,到时候一篇文章搞定

 

有兴趣的欢迎探讨


恭喜ID[飞翔的猫咪]获看雪安卓应用安全能力认证高级安全工程师!!

最后于 2022-6-19 12:38 被又一个小菜鸟编辑 ,原因:
收藏
点赞4
打赏
分享
最新回复 (4)
雪    币: 38
活跃值: 活跃值 (119)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
cnhuaWu 活跃值 2022-8-9 14:36
2
0
共同学习
雪    币: 219
活跃值: 活跃值 (91)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
cs1001 活跃值 2022-8-12 10:04
3
0
牛,学习!
雪    币: 362
活跃值: 活跃值 (225)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
月影小子 活跃值 2022-8-12 23:50
4
0
学习
雪    币: 38
活跃值: 活跃值 (119)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
cnhuaWu 活跃值 2022-8-16 13:47
5
0
想请教下想要屏蔽File.list中的结果,现在不知道在kernfs_dir_pos中怎么操作;
游客
登录 | 注册 方可回帖
返回