首页
社区
课程
招聘
[原创]内核层偷天换日之hook openat进行文件重定向
发表于: 2021-10-11 11:44 20538

[原创]内核层偷天换日之hook openat进行文件重定向

2021-10-11 11:44
20538

目前很多防护系统做了自己openat实现不再依赖于libc.so, 我们进行一些简单的hook技术已经免得比较麻烦, 于是有底层文件重定向的想法. 简单的进行对应的记录.

openat重定向文件读写的一些问题

前段时间, 卓玛星球的强哥, 提出了在内核层进行文件重定向的想法. 但是他告诉我这里面有很多限制.比如__user, const等. 于是我就顺着思路撸了一下内核代码,具体相关情况如下:

  1. __user和const都是类型修饰符而已, 主要目标是进行编译器检查. 但是在运行时是没有这种检查,因此我们有N种方法进行处理

  2. 文件重定向就是进行文件路径修改, 我们不能直接修改的原因.得从arm内存访问以及代码实现说起.

do_sys_open底层在做什么事情

  • asmlinkage long sys_openat(int dfd, const char __user *filename, int flags, umode_t mode);
    • do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)
      • tmp = getname(filename);
        • getname_flags(filename, 0, NULL);
          • step1 检查是否可以重用, 如果可以复用直接返回
          • audit_reusename(filename);
            • 遍历current->audit_context->names_list
            • __audit_reusename(name) //fill out filename with info from existing entry
              • if (n->name->uptr == uptr) { //检查uptr地址是否一致,一致的话refcnt++
          • step2 embed the struct filename inside the names_cache
          • len = strncpy_from_user(kname, filename, EMBEDDED_NAME_MAX); //这里面有一次filename的访问, 这里是EMBEDDED_NAME_MAX
          • step3 接近PATH_MAX,拆分后在插入
          • len = strncpy_from_user(kname, filename, PATH_MAX); //这里是EMBEDDED_NAME_MAX

上面列出所有访问user filename的地方,到后面进入long strncpy_from_user(char *dst, const char user *src, long count),

strncpy_from_user底层到底在做什么事情

  • strncpy_from_user 前面主要是做一些合法性检查
    • do_strncpy_from_user(dst, src, count, max);
      • 判断字节对齐
      • 缺页处理
      • byte_at_a_time:
        • unsafe_get_user

最开始我想直接修改源码去掉user检查限制, 后面发现我太天真了, 层层限制,层层都有user检查.

 

不过还有个终极手段就是直接改掉__user修饰符, 思来想去还是没去做这个事情, 因为总感觉自己做的不对. 因此切换了思路, 我遇到的问题肯定别人也遇到过.

简单粗暴memcopy

A思路走不通, 那就走B思路呗. 我仅仅是想修改内存而已, 我都是有特权级别的人了, 啥不能搞呢? 先写个代码试试看

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
// access userspace in kernel
do
{           
    mm_segment_t fs;
    fs =get_fs();
    set_fs(KERNEL_DS);
    if(strstr(pathname, "a.txt"))
    {
        if(access_ok(VERIFY_WRITE, pathname, len))
        {
            memcpy(pathname+len-5, "b.txt", 5); //受CONFIG_ARM64_PAN配置限制
 
            if(copy_to_user(pathname+len-5, "b.txt", 5)) {
                printk("[i] bingo magic\n");
            } else {
                printk("[err] copy to usr error. %p len=%d\n", pathname, len);
            }
 
            len = strncpy_from_user(bufname, pathname, 255);
            printk("[i] bufname =%s\n", bufname);
 
        }
        else {
            printk("[e] access not ok\n");
        }
    }           
    set_fs(fs);
} while (0);

似乎结果并不太好, 内核层崩溃了. 为啥呢? 思来想去查了很多资料, 重要找到了答案, 内核层有一个配置开关CONFIG_ARM64_PAN

  1. CONFIG_ARM64_PAN 配置选项的功能是阻止内核态直接访问用户地址空间

具体核心代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// arch\arm64\include\asm\uaccess.h
#define __uaccess_disable(alt)                        \
do {                                    \
    if (!uaccess_ttbr0_disable())                    \
        asm(ALTERNATIVE("nop", SET_PSTATE_PAN(1), alt,        \
                CONFIG_ARM64_PAN));            \
} while (0)
 
#define __uaccess_enable(alt)                        \
do {                                    \
    if (!uaccess_ttbr0_enable())                    \
        asm(ALTERNATIVE("nop", SET_PSTATE_PAN(0), alt,        \
                CONFIG_ARM64_PAN));            \
} while (0)

修改后对应的风险(欢迎大佬提供思路)

因为我们直接更改了用户层的数据, 这里面就隐含了其他风险, 对应的用户层的路径名直接就变更了.用户层再拿着这个
数据进行处理, 就会遇到一些问题.

 

我后面仔细想了想还可以通过修改libc.so的方式, 但是很多防护系统都做了字段openat. 因此我们只能去手动修改对应的so了.

 

欢迎各群里有理解filesystem系统的大佬提供下对应的意见和想法.

具体源码参考与实现

https://github.com/yhnu/op7t

参考链接:

https://github.com/yhnu/op7t/commit/ec30f893b42aba551c84b7036aaa71f012703f4a

 

https://developer.ibm.com/articles/l-kernel-memory-access/

 

http://www.wowotech.net/memory_management/454.html


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 3
支持
分享
最新回复 (12)
雪    币: 12
活跃值: (1065)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
你把 linker 改掉,让它 #svc 的时候直接链到改过的 syscall 那,内核做逻辑还是不方便吧
2021-10-11 12:17
0
雪    币: 4715
活跃值: (4255)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
现在Android逆向都是做些什么工作
2021-10-11 12:28
0
雪    币: 891
活跃值: (591)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
在内核有一个函数把user层的数据copy到kernel的函数,基本所有路径相关的的系统调用都会用到
2021-10-11 17:41
0
雪    币: 116
活跃值: (1012)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
木志本柯 现在Android逆向都是做些什么工作
脚踢框架 手撕内核 aosp全源码研究
2021-10-11 19:39
0
雪    币: 4715
活跃值: (4255)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
万里星河 脚踢框架 手撕内核 aosp全源码研究
造国产手机系统??
2021-10-13 19:56
0
雪    币: 47
活跃值: (207)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
1. 内核申请用户空间,换文件地址; 2. 执行原openat; 3. 释放申请的用户空间。
2021-10-25 10:04
0
雪    币: 26
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
8
lanliqiang 1. 内核申请用户空间,换文件地址; 2. 执行原openat; 3. 释放申请的用户空间。
请教下对应的代码片段,希望有更好的方式解决这个问题
2021-10-25 11:11
0
雪    币: 26
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
9
在内核有一个函数把user层的数据copy到kernel的函数,基本所有路径相关的的系统调用都会用到
你可以看一下内核层代码,层层代码user检查.并不是copy到内核就能行的
2021-10-25 11:12
0
雪    币: 47
活跃值: (207)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
github_yhnu 请教下对应的代码片段,希望有更好的方式解决这个问题
1. 挂钩systable; 2 . 分配用内存 do_mmap;3. 把新地址拷贝进用户内存,并执行openat; 4. 释放用户内存do_munmap
2021-11-1 09:50
0
雪    币: 26
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
11
lanliqiang 1. 挂钩systable; 2 . 分配用内存 do_mmap;3. 把新地址拷贝进用户内存,并执行openat; 4. 释放用户内存do_munmap
一个人研究内核很痛苦, 能够私下大家一起交流么?
2021-11-6 10:06
0
雪    币: 138
活跃值: (497)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
大佬可以发下联系方式吗?我也想研究下内核。
2022-6-1 16:49
0
雪    币: 26
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
13
菱志漪 大佬可以发下联系方式吗?我也想研究下内核。
看id
2022-6-28 13:40
0
游客
登录 | 注册 方可回帖
返回
//