你们免ROOT可以解锁核吗?ROOT后是不是多了个叫CVE

著作权归作者所有,转载请联系作者获得授权。

你想在Linux下获取root权限的时候就是执行sudo或者su,接下来系统会提示你输入root用户的密码,密码正确就获得root权限了。Android本身就不想让你获得Root权限,大部分手机出厂的时候根本就没有su这个程序。所以你想获得Android的root权限,第一步就是要把编译好的su文件拷贝到Android手机的/system/bin或者/system/xbin/目录下。我们先假设你可以把su放在xbin下,接下来你可以在Android手机的adb shell或者串口下输入su了。
Linux下su以后输入密码就可以root了,但Android里的su和Linux里的su是不一样的,Android里的su不是靠验证密码的,而是看你原来的权限是什么。意思就是如果你是root,那你可以通过su切换到别的用户,比如说shell,wifi,audio什么的。但如果你是root之外的其他用户,就不能切换回root了,会提示你permission denied。(具体su是怎么做到这一点的,我准备过几天有时间的时候写在下面,单独说明)
也就说用root运行su才有用,但我这个时候还没有root怎么办呢?这就涉及到另外个问题。
一般我们在Linux的console下输入 ls -l 会列出所有文件的权限。
比如:-rwxr-xr-x,用过Linux的人都知道r代表该文件可读,w代表可写,x代表可执行,-就代表没有该权限。第一个rwx代表文件所有者的权限,第二个rwx代表和所有者同组人的权限,第三个rwx代表其他用户对该文件的权限。但下面这个文件就比较特殊。
rws,它的执行权限标志位是一个s,s代表当任何一个用户执行该文件的时候都拥有文件所有者的权限,这文件的所有者是root,简单点说就是不管谁执行这个文件,他执行的时候都是以root身份执行的。
也就说即使我不是root也有可能以root身份来执行程序,那么我就把一个所有者是root的su程序权限标志位置成-rwsr-xr-x,那么不管谁执行它,都是root身份执行,su就可以顺利执行成功了,执行成功之后我就是root身份了。

问题都清楚了,就是你需要把一个所有者是root的su拷贝到Android手机上,并且把su的权限标志位置成-rwsr-xr-x。能把这个事情搞定你就成功root了一个手机。
熟悉Android的同学都知道,执行上面的每一行代码都需要root权限才能成功。
意思就是说,你只有有root权限的情况下才能执行上面两行代码,而这两行代码就是为了让你获得root权限的,这是一个逻辑闭环,那么如何打破这个逻辑闭环呢?
一个办法就是找一个本身已经有root权限的进程来启动我上面的两行代码,那我这两行代码一启动就是root权限,就可以顺利执行了。但是已经有root权限的进程都是出厂时候就装到手机上的,代码写死了,你没法控制它执行你自己的代码啊。这个时候就需要你找漏洞了,比如用来破解Android2.3 root权限的zergRush漏洞就是利用一个拥有root权限的进程栈溢出漏洞。
* 栈溢出说白了就是这个进程读到了自有内存之外的地址空间,这段内存空间没分配给它,谁都能写
* 这段内存,那我就可以把自己的两行代码预先写到这里,运行zergRush代码,然后等那个倒霉的进
栈溢出这段也解释错了,关于栈溢出的解释大家可以看答案下面@张炬 的评论。上面有下划线的部分可以忽略。

如果各位有一定基础,能看懂我上面讲的,就基本知道原理其实并不难,难点在于找到漏洞。
有兴趣的可以看看,网上也有很多分析文章。

另外iphone的越狱其实和Android的root是一回事儿,都是越权操作。所以越狱的方式也都差不多,也是找IOS自带程序的漏洞,只不过IOS安全性强一点,所以也比较难找。如果你发现你的iphone的某个自带程序经过一些特定操作会出现系统崩溃重启的现象,并且是可以复现的,那就很有可能可以用来越狱了。
好像是IOS6出来的时候,由于比较难搞,某个越狱团队就号召大家来找茬,发现的漏洞可以报告给他们用来越狱。说明IOS越狱越来越难。直接体现就是现在越狱需要的时间越来越长。
不过如果你发现漏洞也可以报告给苹果,苹果会根据漏洞严重程度给予一定奖励。我记得看新闻说南非一个家伙靠给苹果找漏洞赚25万美元。发家致富的好路子啊,哈哈。

一个同事告诉我,这个问题我的解释是错的,su不能放在data分区原因是因为data分区在mount时就指定了不能给可执行程序加s位。你在adb shell里执行mount就可以看到,或者看我下面的截图。
下面有下划线的部分是我自己的解释,各位可以忽略。
* 首先,你当然可以把su这个程序copy到/data/分区,但你adb push进去的时候,su有这个程序的所
* 有者肯定不是root,一般是shell什么的(记不清了,应该是和adbd这个进程的所有者一样),这个时
* 候即使你把它权限置为-rwsr-xr-x,哪你运行它的时候也是shell身份运行的,su会提示你输入密码
* 第二我们root手机的目的是为了运行需要root权限的APP,比如goagent或者什么的。这些APP里代
* 码需要获得root的时候是这么写的:
* 也就是它们在代码里调用了一下su这个程序,哪可以写成下面这个样子吗?
* 我没写过APP,不太清楚,估计是不行的。换句话说你必须把su放到环境变量PATH所有的目录
* 里,APP才能调用到它。如果你不想放到bin或者xbin下,你就必须给PATH增加一个目录。PATH是
* root权限才能修改的,你如果能修改PATH,说明你已经有root权限了,修改PATH就没必要了,还
* 不如直接放到bin下面。

android的工程里没有sudo这个东西。sudo是为了给普通用户临时分配root权限的,Android里建立了很多用户,比如wifi,shell等等,这些用户可以访问那个文件,不可以访问那个文件,代码里已经写死了,权限也分配的很分明。它们在运行的过程中不需要临时获得root权限。所以Android不需要sudo这个程序。

1. Android的su确实是不验证密码的,是我想当然了。答案已经修改了。
3. 你的答案我看了,你没发觉你跟我说的是一回事吗?我觉得你应该是没仔细看我的答案吧。
4. 你叙述的 so call”一般的root流程”,只是一种方法,而这个问题是问原理。实际上不管你用什么漏洞获得了root,下面需要做的一样的,都是copy su到xbin, chown最后chmod。你的“一般的root流程”和别人不管用什么方法的二般流程有什么区别吗?不都是为了刚上面这些事吗?

  1. 要执行su(其他程序获取root权限默认执行su)必须将su放在系统环境变量里,bin和xbin目录,其他地方你需要加全路径

  2. bin和xbin目录在system分区,默认只读,所以要写入su必须重新挂在该分区为可写

知道这些再说如何root

  1. 通过漏洞将自己进程提权到root权限,具体做法要去了解漏洞利用原理

  2. 进程获取root权限后重新挂载system分区可读写

  3. 然后将su拷贝到bin目录或者xbin目录,由于su的所有者提权进程已经是root进程,所以su也具有root属性。然后设置su文件755属性,即所有者可读可写可执行,所在组和其他用户可读可执行,同时为了让一般用户在执行某些程序的时候,能够暂时具有该程序拥有者的权限,所以需要设置s标志位,即其他评论提到的chmod 4755 su,superuser拷贝system目录并安装,放在system目录下作为系统应用,防用户删除

  4. 这样其他程序调用su以后,先要经过superuser同意,用户点同意后,由于su拥有者为root所以其进程也拥有root权限,相应的它执行的命令也都是有root权限, 详细的做法可去github搜su源码阅读,最后执行的一句execv(ctx->to.shell, ctx->to.argv + argc);通过验证后将su进程直接替换成需要执行的命令

基本过程就是这样,重点在漏洞利用上,要考虑selinux等一些安全机制绕过,前边几个回答的都是漏洞利用提取以后的事情,这些操作大同小异,都是脚本来执行,可参考前边提到的root精灵脚本。
编辑于 添加评论 感谢
收藏 ? 没有帮助 ? 举报 ? 作者保留权利
巨芋 一流厨师,二流程序员,三流设计师,会泡…
作为补充,发一下之前从网上扒来的SU中的部分代码,以此解释Android是通过原有的权限来判断你有没资格执行su :

编辑于 添加评论 感谢
收藏 ? 没有帮助 ? 举报 ? 作者保留权利
简单点说,就是Android系统里面没有su这个可执行的文件,提权就是利用Android系统漏洞把su装入系统。
发布于 添加评论 感谢
收藏 ? 没有帮助 ? 举报 ? 作者保留权利
滚了几屏,算是看完了,这些都过时了;Android 4.2以后需要通过native service拉起su daemon之类的服务进程才能正常使用root相关功能;Android 5.x以后更需要搞定SELINUX才能正常使用root相关功能,所以新版本的授权管理一般都带有类似seinject的功能来注入安全策略,依靠替换系统服务如zygote等native service。
发布于 3 条评论 感谢
收藏 ? 没有帮助 ? 举报 ? 禁止转载
吴利文 计算机科学与技术,葡萄酒爱好者,(Θ…
@Kevin 的答案有问题,看来他并不知道root的原理

那怎么搞定这个事情呢?Android的system分区本身不可写,只有是root的权限才能改动它,执行不了啊。 获得root的时候是这么写的: 也就是它们在代码里调用了一下su这个程序,哪可以写成下面这个样子吗?

先看第一段,理解没有错误的话他是想说,只要system有了写入的权限,就可以执行这两行代码,进而获取root权限。既然Android的system分区不可写,那干脆不写system,等获取root权限再写入system就行了,第一条命令需要system可写入,命令一只是拷贝,其本身没有实质性意义。第二条命令把su设置成-rwsr-x-rx也其实只完成了一半——

su还需要所有者(Owner)是root才能正确的给其他程序赋予root权限。linux系统中,当前用户执行的程序,该程序进程的 有效用户ID(Effective UID)就是当前用户,但拥有s(set uid)权限的程序,其进程的有效用户ID是这个程序的所有者。换句话说,有set uid权限的程序,运行之后,就相当于所有者运行了这个程序,如果所有者是root,那这个进程也拥有root权限。能够正常授权的su,其所有者必须是root,否则不能正常授权。没有root权限的情况下,我们可以通过chmod来设置s权限,但是不能使用chown来修改su的所有者为root(提示Unable to chown su: Operation not permitted)。

所以通过zergRush破解权限的原因是,只有破解到了root权限,才能设置su的所有者是root,才能有可正常使用的su。

再看第二段,就算把代码改成Process p = Runtime.getRuntime().exec(“./data/tmp/su”);也不能获得root权限。正如我前面所说的,必须先修改su的所有者为root才能获取root权限,所以在破解到root权限之前,无论做什么都不能获得一个有效的su。

现在root流程一般是zergRush破解root权限,然后用root权限启动adbd,电脑端用adb登陆之后直接就拥有了root权限,然后设置su权限和所有者,重挂载system使system可写入,然后拷贝su到/system/xbin/并安装SuperSu,重启手机。这个过程还可以变成 安装SuperSu,破解root权限,设置su的权限和所有者,重启手机,执行su,重挂载system,拷贝su自身到/system/xbin。看到了吗,获取root权限跟system不可写没有关系,重挂载system并拷贝su到xbin只是为了让应用程序更容易调用su罢了

PPS:还有一点,Kevin说输入su要密码,安卓连/etc/passwd都没有,哪来的密码
编辑于 20 条评论 感谢
收藏 ? 没有帮助 ? 举报 ? 作者保留权利

其实在我的理解中应该是两个:

对于 1,提权 是利用系统的漏洞,获得原本获取不了的权限,提升本应用的权限。
1.a:之前提到的利用adbd的漏洞,在2.X时代有效。这个利用的过程还是比较复杂,时间也比较长;
1.b:三星CPU的漏洞,比如在Galaxy系上可以利用这个漏洞来ROOT,这个漏洞就比较好利用了,之接在APK代码里就可以利用。在我的Galaxy Note上用过。
提权不一定是对于主系统(Android系统),还有些是针对辅助系统(BOOTLOADER和RECOVERY)。
1.c:三星系的手机可以利用一个BOOTLOADER的漏洞(我不太清楚是不是漏洞,但是三星本身没有官方解锁工具这一说的,难道是官方提供的?),可以任意的刷包,这样我们就可以利用这个途径来修改SYSTEM分区了,都有权限修改SYSTEM分区了,往上放个文件还不是分分钟的事。官方解锁的就是提供方式,允许用户刷入自定义的文件。
1.d:OPhone系统的老版本(2.0、2.5)中(不知道还有没有人用这个系统)的RECOVERY存在一个关于路径的处理的漏洞。它有一个自己定义的upk升级包,只能处理/system/carrier下的文件,但在路径处理上估计是文本比较,你可以通过/system/carrier/../app这种方式来绕过它的管理系统,来修改/system/app下的文件。
一般情况下主系统的漏洞对用户的危害最大,因为它使一个普通权限的应用可以访问到本没有权限访问的资源。对于三星CPU漏洞,如果一个应用利用它提高自己的权限,直接访问短信的数据库文件,而不是通过Android提供的Provider,系统就没有使用沙盒检查的机会,而且用户也不知道它们做了什么,你从它的权限申请列表上也看不到它会读取短信。
对于辅助系统的漏洞,一个普通的应用就没有办法了,因为平时辅助系统是不启动的。但也并不是没有利用的可能。

在我理解就是安装ROOT管理工具,对于Linux的发行版本来说,本身提供了ROOT管理工具su还有sudo。但是对于Android来说本身没有提供ROOT管理工具,所以我们需要利用提权的这个过程在系统中插入ROOT管理工具,以方便我们使用更高的权限。因为毕竟提权这个过程一般来说不是很容易实现的。比如我们提到的BOOTLOADER或RECOVERY的漏洞,是没有办法在主系统中使用的,所以需要安装ROOT管理工具以在主系统中使用。
ROOT之后因为可以修改系统,所以我们也有机会修复已知的漏洞,比如上面提到的三星CPU的漏洞。

以下由于本身半桶水水平,可能不正确,请轻拍:
对于ROOT本身来说不会降低系统安全性,除非ROOT管理器本身又有漏洞。所以通过官方解锁的方式,使用安全的RECOVERY和安全的ROOT管理器,与官方的安全性一致。

但是两个黑色的“安全”提醒着我们,市面上鱼龙混杂的ROOT工具并不是都安全的,所以使用时一定选用大家认可的,安全的方式。例如说我们平时用的SuperU.apk和与其相配的su应用,在应用层申请ROOT权限时,都会提示用户许可。但是针对一些黑色的ROOT的管理工具,它如果留下后门,对于一些特定的请求不提示直接同意,而且不记录日志的话,这样就像在自己的设备中下了一个定时炸弹一样。
编辑于 3 条评论 感谢
收藏 ? 没有帮助 ? 举报 ? 作者保留权利
肖剑 烧锅炉的工科男,正在成为程序员
发布于 11 条评论 感谢
收藏 ? 没有帮助 ? 举报 ? 作者保留权利
lambda喵 喜欢是放肆,爱是克制
根本的问题在于获取root权限,然后执行什么都是次要的了。

至于答案中提到的su啊sudo啊,之类的都是获取了root权限后的事情,不是问题的根本。

获取root权限不是你按照常规的在命令行执行一些命令或者运行一个程序就可以得到的。因为这些都是在linux的既定规则内玩,怎末可能破坏其规则?

所以只有一条路:非正常路径,比如:找到bug和漏洞,让规则破坏,从而获得提权。或者在系统之外进行操作,比如系统还没启动就操作其磁盘上的文件系统,让某些你安排的程序发生规则外的特性。这时候由于系统还没启动,任你摆布(他睡着完全没有知觉和抵抗以及运行规则的能力)所以你可以换掉系统(涮rom把自己改过的系统刷上去)不过如果硬件上不允许那么此路不通。

所以无论安卓、ios还是pc系统的linux,windows等都是一样的。必须找到漏洞或走非常规路线才能取得特权。

而取得特权对于系统安全是十分严重的事情,即如果普通用户很容易获取到特权,那将是严重性的安全灾难。
你想想如果运行于企业服务器集群上的linux如果某个版本发现提权漏洞,那被黑客黑掉拿到数据的风险后果非常严重。
发布于 添加评论 感谢
收藏 ? 没有帮助 ? 举报 ? 作者保留权利
卖口粥 创业公司联合创始人
对于ARM平台的root已经毫无压力了,但是对于X86平台,就算将su和suuserapk给拷贝进去并赋予正确的权限,也还是无法进行root的。不知道这个大家有啥办法?
发布于 2 条评论 感谢
收藏 ? 没有帮助 ? 举报 ? 作者保留权利
席琴女 捍卫自己的梦想

简单来说,其实就是linux系统里面的su命令,切换root用户,等于window系统的超级管理员。
安卓基于linux,su命令的效果一样。
root就是在你的安卓系统里面添加一个su二进制文件,当app需要使用root权限时(一般都是涉及系统文件),就通过执行su文件获取一个root的权限。
而我们需要一个管理app获取root权限的管理软件,这个就是平时用到的超级用户等app。只有安装了这个管理软件之后,我们才可以限制app的root权限,不然的话,如果系统本身不识别你安装的su文件,app就可以直接使用root权限。

发布于 添加评论 感谢
收藏 ? 没有帮助 ? 举报 ? 作者保留权利
最近也在捣鼓这个问题,想弄明白如何获取最初的root权限。很多命令比如mount,chown都需root权限才能执行的。这些命令能够执行成功,说明已经获取到了临时的root权限了。

拷贝一段root精灵的执行脚本:

编辑于 1 条评论 感谢
收藏 ? 没有帮助 ? 举报 ? 作者保留权利
在Android里通常是在程序中执行su去获取root权限,而就是在这个su中调用了setUid(0)和setGid(0),大概是,记不清了,通过这两个函数把你进程的uid设为和root一样(root的uid就是0),所以也就是说你自己随便写一个可执行文件,去调用这两个函数就能提权。
而要成功调用这两个函数,需要特殊权限,一般我们可以见到chmod 0777 xxx这样的形式,前面的那个0就是对应的setUid和setGid的权限,可以用chmod 4777 xxx去改。

其实看透了之后原理很简单,一些操作可以在adb shell中实现,试试就知道了~
编辑于 3 条评论 感谢
收藏 ? 没有帮助 ? 举报 ? 作者保留权利

看了这么久终于看完了,不过还是不是特别理解!

想问下,第一种需要输入su才变为root用户
第二种直接是root用户

这两种用户区别在哪里?
发布于 1 条评论 感谢
收藏 ? 没有帮助 ? 举报 ? 作者保留权利
一句话解释:添加拥有最高权限的su binary文件用于进行最高权限操作。

在另一个终端开启gdb远程调试。
利用Metasploit生成的代码进行测试,看到内核崩溃的信息如下。

这部分的内容主要来自[1],这里仅仅做了个整理和翻译。

newval)尝试去锁住uaddr,它的实现的含义是如果uaddr中存储的值为0,那么就说明没有线程占用锁,成功获取锁之后将当前线程的id写进去。这里就存在一个问题,那就是uaddr是用户空间的变量,我们可以在程序中手动设置为0,从而达到释放锁而不必通过futex_unlock_pi。这必然是存在一些问题的,因为futex_unlock_pi中有一些收尾工作没有做。如果线程A先锁住了uaddr,用户将uaddr的值设为0,然后在线程B中再次去锁住uaddr,结果会成功而不会阻塞,这个时候线程A和B都拥有锁uaddr,从而造成了relock漏洞。下面编写一个小程序证明一下。


 


 

这个时候如果我们再次调用下面的语句将失败而直接返回,并不会进入系统调用。

 
而requeue漏洞允许我们在以上两条语句执行之后,继续执行下面这样的语句。


这个语句中所有地址都变成了uaddr2,也就是说将等待在uaddr2上的线程重排到uaddr2上,这是不合逻辑的,但是Futex没有检查这样的调用,也就是说没有检查uaddr1==uaddr2的情况,从而造成了我们可以二次进入
futex_requeue中进行唤醒操作。

 
表面上看上去这两个漏洞似乎影响都不是很大,对内核没有构成直接威胁,不过聪明的攻击者对这两个漏洞进行了组合,获取了一种不错的效果。
1.线程1调用futex_lock_pi锁住uaddr2,此时没有其他竞争,所以成功锁住uaddr2;
2.创建线程2,并等待线程2进入系统调用状态。同时线程2调用futex_wait_requeue_pi(uaddr1,uaddr2)等待被唤醒,在futex_wait_requeue_pi中会在栈上分配一个rt_waiter,这个rt_waiter会通过futex_q传给
为了理解利用的过程,我们还需要掌握一些相关技巧,这部分的内容主要来自[2],这里仅仅做了个整理和翻译。

 
我们来看一个简单的例子(编译时不使用任何优化选项)。

 
这段代码很简单,函数foo和bar具有完全相同的函数体,调用bar(1,12),然后再调用foo(0,0),结果打印的是bar设置的12。为什么foo会打印出bar里面的值,而不是之前foo里面的值?因为它们具有完全相同的函数体,从而函数栈也相同,在main函数中每次调用都会使用相同的栈,而栈内的内容不会在函数返回时清空,这样在foo(0,0)的时候,没有去赋值而是直接使用栈上的值,这个栈刚刚被bar使用过,所以就造成了foo获取到了bar内的值。这就是一个简单的栈上内容的控制。在链表中也是一样,如下面的例子所示(以gcc


 
 
 
 
 
这段代码依然利用了前面例子中说明的栈重用的情况,后面的函数使用了前面函数的栈,只不过用链表的形式展示了出来。代码的bug在于那个
buggy_print_with_end_of_list
函数和a_function_to_exploit函数,前者造成漏洞,后者利用漏洞。正常情况下,链表里的节点都是在list_add_new中生成的,生成的节点存储在堆中,而buggy_print_with_end_of_list的节点 是在栈上临时存放的,本应该在函数返回前,将这个临时节点从链表中摘除,但是它没有,结果就造成了一个存在与栈上的节点,而当调用a_function_to_exploit时,这个栈又会被重用,例子中对这个节点进行了赋值,从而导致我们不需要知道这个链表的头指针,就可以修改这个节点的内容。

 

fakenode,最终在X处写入了Y。这样的堆利用技巧非常常见,不再细说了。关键问题是说了这么多,和这个漏洞有什么关系呢?通过栈重用可以修改栈上的rt_waiter,只不过rt_waiter在内核栈中,修改它要麻烦一些,不能直接写个函数去修改,因为我们写的函数都是用户空间的,进不去内核,所以需要一个内核函数去修改它。这个内核函数要满足下面两个条件:
1.它的函数内核栈足够的大以至于可以覆盖到rt_waiter的地址;
2.我们能够向这个栈上写东西,函数会将我们传递的参数复制到栈上。
TowelRoot中使用的sendmmsg函数就满足这两个要求。函数最后在内核中调用的是___sys_sendmsg。该函数栈上数据与rt_waiter的重叠部分如下图。
很明显,通过写入特定的msgvec.msg_namemsgvec.msg_iov,就可以改写rt_waiter节点的内容,使之按照我们的路径去执行。在plist链表中有两个链,一个是prio链,一个是节点链。那么一个节点, 为什么要两个链?因为他们具有不同的视图,用途不一样。链表中的每个节点都不同,但是他们的prio值是可以相同的(具有相同的优先级),所以node_list链接了所有节点,而prio_list仅链接了prio不同的节点。内核在利用优先级选择节点的时候,会选择链接在prio_list上的节点,例如prio为20的节点,如果节点被成功唤醒,该节点将被清除,然后内核会修改该链表,将另外一个prio=20的节点链接到prio_list上。如果我们可以插入节点的话就可以利用prio的值来控制插入节点的位置。如果修改rt_waiter节点的prio.next指针指向共享内存中事先被填充了作为一个plist节点的必要数据的一个特定位置(fake_node),再调用futex_lock_pi向链表中添加rt_waiter节点,假设fake_node节点优先级为35,新的节点优先级为34,过程如下。
插入之前fake_node.prev的值设置为要修改的内核地址-offset。
根据前面的讲解不难理解插入之后可以看到红色的node.next指向后继节点,也就是说地址A中的值被修改成了新节点的地址。虽然只能修改为新节点的地址,但是确实是实现了内核任意地址写指定值。

 
thread_info.addr_limit变量规定了特定线程的用户空间地址最大值,超过这个值的地址,用户空间代码不能访问。所以把addr_limit改成0xffffffff就可以对内核为所欲为了。rt_waiter这个结构是在内核栈上分配的,而又由于thread_info与内核栈共用8K的内存空间,因此任意内核栈的地址与上0xffffe000,就会得到thread_info的地址。现在我们可以对它进行写入一个新rt_waiter的地址,但是还没有能力写入0xffffffff。不过既然可以修改一次addr_limit,自然还可以多次修改addr_limit,关键是每个rt_waiter的地址又是不同的,但是请注意,这个rt_waiter的地址却不一定的递减的,因为不同线程具有独立的内核栈,所以不同线程的rt_waiter不在同一个栈上,地址是随机分布的。这样就有了一个方法,可以将0xffffffff写进去,如下所示。
首先主线程创建线程A,用于提权操作。线程A创建后,调用futex_lock_pi产生rt_waiter然后进入等待,这个时候,主线程向其发送信号,唤醒它继续执行信号处理程序。在信号处理程序中,线程A开始获取addr_limit的地址,然后尝试读取其内容直到成功;这个时候主线程开始创建新的线程B,用以产生新的rt_waiter,并利用上面的技术将这个新的rt_waiter的地址写进线程A的addr_limit。循环执行这个 过程,直到线程A成功读取addr_limit的内容。如果线程A的内核栈的地址低于线程B的内核栈的地址的话,我们将新的rt_waiter的地址写进线程A的addr_limit的话,这个时候线程A的用户空间的最大值就会变成线程B的内核栈上的地址,而由于B的内核栈高于A的内核栈,所以这个时候, 线程A便可以访问addr_limit了,addr_limit的地址已经属于用户空间了。既然是用户空间,那么就可以将0xffffffff写进addr_limit中,从而将线程A的所有地址都对用户空间开放,来进一步执行提权操作了。所以最终我们在线程A中获得了内核空间的任意访问能力,请注意,只限于线程A,因为每个线程在内核看来是独立的,是具有不同内核栈和thread_info(addr_limit)的。

 
既然可以对内核数据随意修改了,那么现在的问题就是获取要修改数据的地址。thread_info包含了线程的主要信息,当然也就包括了线程的task_struct。而task_struct结构体包含了该线程的所有信息。这其中就包括权限方面的重要信息cred,该结构体是线程权限的管理者,标识了当前线程的权限。修改uid,gid,suid的值为0从而实现提权。


补丁代码很简单,只是在futex_requeue函数里添加个判断,当uaddr1和uaddr2相等时,则返回失败。

1.
2.
3.
4.《漏洞战争》及其配套资料
5.

我要回帖

更多关于 ROOT可以解锁核吗? 的文章

 

随机推荐