type
status
date
slug
summary
tags
category
icon
password
Property
Mar 29, 2023 01:31 AM
针对GKI设备已有更好解决方案:https://github.com/tiann/KernelSU
本文主体内容来自2022年2月的个人笔记,可能具体实现步骤有记录不详细的地方,自己稍微研究一下就能解决。
核心原理
通过静态修改内核,将自定义后门逻辑嵌入内核,从而达到提权的目的。
人话:挂个inline hook来提权
优点
高隐蔽性
无需内核源码
缺点
功能单一,无模块系统支持
不支持其他应用的授权
开发困难
直接的汇编操作容易因错误而导致死机
前置知识
IDA分析内核镜像
没符号很难受是吧,提取kallsyms导进去就好了
提取kallsyms
静态提取
动态提取
将kallsyms导入IDA
获取current指针
一行汇编即可
内核分段及权限设定
一、分了哪些段?
- _text → _etext 之间是代码段
- __start_rodata → __end_rodata 之间是只读数据段
- __init_begin → __init_end 之间是内核初始化相关的段,包括代码和数据,这个段的特点是只在内核初始化的时候用,内核初始化完成后就可以释放了。
- _data → _end 之间是可读可写的数据段
二、各个段的权限设定
见 arch/arm64/mm/mmu.c 的 map_kernel 函数
PTE_PXN:特权模式下不可执行
PTE_UXN:用户模式下不可执行
PTE_NG:地址翻译是否是全局的,1非全局,0全局
可以通过静态修改 rodata_enabled 为 0 来让syscall table可写
- 代码段:_text → _etext
rodata_enabled ? PAGE_KERNEL_ROX : PAGE_KERNEL_EXEC;
可读特权模式可执行,rodata_enabled为假时可写
- 只读数据段
PAGE_KERNEL
可读可写不可执行
- 初始化代码段:
rodata_enabled ? PAGE_KERNEL_ROX : PAGE_KERNEL_EXEC;
可读特权模式可执行,rodata_enabled为假时可写
- 初始化数据段:
PAGE_KERNEL
可读可写不可执行
- 数据段:
PAGE_KERNEL
可读可写不可执行
三、自定义代码添加到哪里
只能塞到代码段里面,不然没执行权限的。
如何生成ShellCode
写到一个函数内,然后编译生成
g++ tmp.cpp -fno-stack-protector -O3 -o tmp
实现思路
一、修改SELinux状态
定位 selinux_state
通过函数定位,如:avc_has_perm、avc_has_extended_perms,搜索引用,X0即为对应地址
在内核源码中搜素:&selinux_state查看所有引用
ShellCode
二、给予进程ROOT权限
获取real_cred偏移
exit_creds
函数在内核代码中搜索 ->real_cred 查找其他调用也可
提权
权限位值1,其他置0即可
权限判断:
cred->uid.val == 0 || cred->uid.val == 2000 || cred->gid.val == 0 || cred->gid.val == 2000
三、绕过SELinux
原理:修改avc_denied函数判断uid=0时直接返回0
缺陷:只能让root为主动方的规则被绕过