Copy Link
Add to Bookmark
Report

d3_0x02_CVE-2013-1858_exploit_analysis

eZine's profile picture
Published in 
Do not fuck with a hacker
 · 5 years ago

  

|=-----------------------------------------------------------------=|
|=-----=[ D O N O T F U C K W I T H A H A C K E R ]=-----=|
|=-----------------------------------------------------------------=|
|=------------------------[ #3 File 0x02 ]-------------------------=|
|=-----------------------------------------------------------------=|
|=------------------=[CVE-2013-1858 exploit analysis]=-------------=|
|=-----------------------------------------------------------------=|
|=-------------------------=[ By JU ]=---------------------------=|
|=-----------------------------------------------------------------=|

提要:

2013年3月13日,Suse的安全研究员Sebastian Krahmer发出一封名为:

"CLONE_NEWUSER|CLONE_FS root exploit"

的邮件,暴出3.8版本的Linux内核存在一个提权漏洞,并给出了poc:
http://www.openwall.com/lists/oss-security/2013/03/13/10

该exploit利用了3.8内核允许*普通用户*利用clone(... CLONE_NEWUSER | CLONE_FS,
...)创建新进程的漏洞,巧妙实现提权。该漏洞利用的精妙之处在于:只是利用两个概
念上的缺陷,不需要费尽心力写复杂的shellcode, 仅若干个普通API就实现了提权。而
且, 这个exploit完美地演绎了一个程序如何在不同的euid下3次运行,每次进行不同
的动作。三次运行环环相扣,一步步帮助获得系统的权限。

另一方面, 给力的是,当天内核开发者就及时给出了fix:
http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=e66eded8309ebf679d3d3c1f5820d1f2ca332c71


漏洞分析:

1.CLONE_NEWUSER与CLONE_FS狼狈为奸。

随着Linux 3.8版本释出,标志历经多年开发(从2007年的2.6.23版本开始)的用户名字
空间(user namespace)的开发工作基本完成。这是第6个完成的内核名字空间(
http://lwn.net/Articles/531114/#series_index)。它们是实现内核容器(container)
中的一部分。内核容器是用于分隔资源,系统监管以及虚拟化的一个轻量级工具,简单
来说,就是把系统资源进行分隔,这样不同容器中的资源互不感知对方,实现有效分隔
。而用户名字空间的完成,有着重大意义,因为每个普通用户都可以建立自己的名字空
间。每一个用户名字空间中,有一套独立的uid系统,这意味着每个空间中有各自的roo
t用户!也就意味着,在这个名字空间中,进程可以拥有任意权限(capabilities),包
括调用chroot切换根目录。而本来分隔的名字空间类似sandbox,不会带来太多安全问题
。但是,3.8内核允许普通用户创建名字空间!

对于CLONE_NEWUSER来说,它意味着创建的新进程需要独立的用户名字空间。
至于CLONE_FS标志,它表示创建的子进程要跟父进程共享文件系统属性,比如有相同的根目录...

独立与共享?!这隐隐约约就带来了坏味道!于是,隐患已经埋下,潘多拉的盒子即将被打开......

2.chroot, 罪恶之*根*

前面讲了,两个奇怪的标志一结合,立马带来了隐患。一个是独立的名字空间,一个是
共享的文件系统空间,如何让封印于盒子里的怪兽逃出生天呢。工具之一就是chroot!

chroot是在Linux系统中发挥根目录的切换作用的命令,它也带来系统的安全性等好处
。比如有玩过lfs或gentoo的同学都知道,当在host环境下搞定新环境的工具链后,一
条chroot命令就可以切换到新的环境,然后筚路蓝缕,开始打拼另一片天空。
 
如下:

   /( / : 原来的根目录)
     |
--------------------
| | |   |
bin lib home/lcx ......
|
newroot(/home/lcx/newroot : 新的环境的根目录)
|
-----------
| |  |
   bin lib usr .....

当执行:
chroot /home/lcx/newroot

就将原来的/home/lcx/newroot变为新环境的根目录。此时,原来的文件系统被掩盖。
压迫不再,曾经的旧民翻身,新的政治秩序铺开。

那此时如果还用原来的名号,会发生什么情况呢?很简单,发生了"坐标系平移"。比如
旧环境的/bin/su,将被映射成新环境的/home/lcx/newroot/bin/su;
旧环境的/lib/ld-linux.so.2,将被映射成/home/lcx/newroot/lib/ld-linux.so.2.

好,咱花开两朵,先表一枝。这一厢先按下,稍后再叙。

3.动态链接器ld-linux.so, 引狼入室

动态库顾名思义就是程序运行才加载依赖的库。在linux上,这是由一个叫ld-linux.so
的家伙来执行加载动态库这项工作的。粗略地讲,ld-linux.so把程序加载与开始执行之
间活动,搜索程序用到的库,并映射到程序的进程空间,以及完成一些符号解析等dirty
job, 然后,才把程序流控制权交到程序入口点开始执行。

此外,关于ld-linux.so还有一点需要强调, 它拥有与所执行程序相同的权限。意思就是
,当程序以有效用户ID(euid)为root的ID运行时,那ld-linux也以root权限运行.

那ld-linux.so在哪? 它不应该包含在程序的可执行文件中。因为,如果系统有上千个
要用到动态库的程序, 哪岂不是有上千份拷贝.

其实, ld-linux.so是在系统中。在程序运行时,它首先被加载,然后由它加载动态库。
 
$ ls /lib | grep ld-linux (或ls /lib64 | grep ld-linux)

可以看到,存在/lib/ld-linux.so.2(我系统32位的,纯64位系统会发现它在/lib64中)。
由它的路径与名称看来,它本身就是一个库(用file命令查它户口,发现它是shared
object, ELF格式中的一种:共享对象,其它库文件同样也是一这种格式)。

这里面隐含着,系统能加载ld-linux.so, 说明系统知道这个ld-linux.so的路径,它藏在哪呢,就在程序执行映象里:

$ readelf -l /bin/ls

以上命令读取ls程序的可执行映象,能发现输出结果中出现有Requesting program
interpreter:/lib/ld-linux.so.2的字样。

这里面,它作了一个假设: 我要找的动态链接器ld-linux.so它位于*根目录*下的lib目
录中。它硬编码了路径! 万一运行过程中这个根目录变了呢,这路径不就指到别的地方
去了?! 存在这种可能吗? 可能! 这就是这个exploit的妙处所在。

4. 打开魔盒

上面说的这个exploit妙在,它巧妙地在程序运行过程中,改变了根路径!

改变了根路径后,它执行了一个setuid程序su(运行ls -l /bin/su, 你会看到它的权限
是这样的:-rwsr-xr-x, 其中发现有一位变成了s。这个程序就叫setuid程序。至于这个
s的含义,涉及到真实用户ID与有效用户ID的关系,网上有详细解说,读者可以在网上找
到相关方面文章), 而这个su在运行前是先要运行ld-linux.so来加载动态库。

前面说了, ld-linux.so路径是硬编码成/lib/ld-linux.so.2的。但是, 现在根路径已
经变了! 所以, 此时的/lib/ld-linux.so.2已经不是指向真正的ld-linux.so了。它现
在指向了改变后的根目录下的lib/ld-linux.so.2。而这个位置, 放的就是exploit程序
自身! 这当然不是凑巧的,而是在改变根路径过程中使用了技巧而实现。

所以, 现在相当于又运行了exploit一次。不过, 这次的有效用户ID(EUID)是0。因为
前面说它执行了一个setuid的程序su。而在第3节说过, 执行ld-linux.so时, 它拥有跟
su一样的权限: 即EUID为0用户,也就是root的权限。这就是为什么要选用一个setuid权
限的程序的原因。

然后, 重新运行的exploit进程做了啥呢? 它把自己的uid设为0, 即让自己成为root用
户, 然后, 再运行一次bash。此时, 这个shell就是一个root权限的shell了。僭权成功
!!!

这就是这个exploit大概的思路, 至于是如何改变根路径的, 是重头戏, 有兴趣的读者
可以继续往下看。下面是对这个exploit更详细的讲解.

********************* 分隔线 *********************

它是这么做的:

我们先设定这个exploit程序叫evil, 它的路径不妨设为/home/lcx/evil。然后我们进
入到/home/lcx目录,执行
 
$ ./evil

我们以普通用户运行这个程序。一切都还显得是风平浪静。我们称此时的进程为A。
A莫名其妙地做了这几个动作.

1. 读取/proc/self/exe获取自己的路径,也就是/home/lcx/evil(这不是多此一举,因为
程序自身并不知首自己的路径,而即使我们把程序放别的地方,它还是能准确找
己的巢)。
2. fork了一个进程B, 然后它就去睡觉, 间隔1秒醒来看evil这个程序文件的用户
  ID是否变成root了。当然, 现在还不是,所以它去睡觉~~~

创建出来的B干嘛呢?
1. 在当前目录(/home/lcx)创建了一个chroot, 也就是/home/lcx/chroot。
2. 在chroot下再建了两个目录,是为/home/lcx/chroot/bin和
/home/lcx/chroot/lib。
3. 在/hom/lcx/chroot/bin目录下, 它生成一个链接/home/lcx/chroot/bin/su,
指向原来/bin/su。
4. 在/hom/lcx/chroot/lib目录下, 它生成一个链接
/hom/lcx/chroot/lib/ld-linux.so.2, 但是, 它指向evil自己:/home/lcx/evil。
5. 调用pipe API生成一个管道准备通信。和谁通信?这个稍后说。

不妨以图示说明:
       /
       |
 ------------------------
 |   |   |
bin  lib home/lcx ------
| | | |
su ld-linux.so chroot evil
^ | ^
| ------- |
| | | |
| bin lib |
| | | |
|________________ su ld-linux.so___|


觉得跟上面介绍chroot一节时画的图有些类似? 没错, chroot要登场了, 前面这些莫名
其妙的动作不过是为舞台布景!

不过, 我们现在还是普通用户, 是没有root权限执行chroot的(是的,evil程序就是要获
取root权限, 但现在还不是)。但是,没有权限也要创造权限, 方法就是利用clone的
CLONE_NEWUSER, 生成一个新的子进程C。前面说过,它生成的子进程将在一个新的用户
命名空间里, 它可以做任何事, 包括chroot。

但是, 不要忘了, 现在我们是在子进程C的新的名字空间中, 再闹得天翻地覆也没用。
所以, 另一个标志出来救场了, 就是CLONE_FS。利用它我们可以巧妙地把魔鬼释放到盒
子外面! 前面说了这个标志是让子进程与父进程共享文件系统的属性的。那么, 当我们
在子进程里chroot后, 改变了根目录。既然是共享, 父进程的根目录也被改变了!

进程C做了什么好事呢?
1. C从管道中读取一个字符。我们前面说过B创建了一个管道。管道是Linux中父子进
  程通信的一种方法。当一端读的时候,如果没数据,会被阻塞。所以,C从管道中读
  取什么信息不重要,关键是,C必须得等到它的父进程B往里面写入数据。

  那B写入数据前做了啥?
- 它创建了UID映射,简言之。它写了/proc/${Pc}/uid_ma文件, 把B的uid映射到
   到C的uid。这里${Pc}是指C的pid, 它是从clone返回的。
- 然后往管道中写了个字符。
- 调用waitpid()等待它的子进程C。

所以,等c读到这个字符时,实际上uid映射已经完成了。有什么用?接着看。
2. C用setuid()把自己uid设为root(记住此时C是在自己的名字空间中,所以是
  允许它这么做的)。由于前面作了uid映射,所以此时B的uid也是root!
3. 当然,C最后调用chroot()切换了根目录!

前面说过, A每睡1秒就醒来看自己的uid是不是变成root了。现在,终于变成root了!
于是,A开心地再一次执行了evil这个程序(这是第2次运行这个程序)。此时,它的有效
用户ID(euid)是0,于是,它把/lib/ld-linux.so.2的权限设为04755。这个值表示, 
这个程序现在是一个setuid程序了. 前面说过,C切换了根目录,并且CLONE_FS标志是
表示共享文件系统属性的,所以,这时修改的ld-linux.so.2其实就是evil!(参见上图)
。也就是, evil从一个普通的程序变成一个setuid程序! 然后,这个进程退出。

此时,C完成使命,它也退出。

另一方面,在管道中写入数据后就调用waitpid()等待C的B终于等到C退出, 它运行了一
个setuid程序su(前面通过uid映射,B此时的uid是0了,所以它能运行su)。如前面所说
, 这个su要调用/lib/ld-linux.so.2, 而当前根目录已经变为/home/lcx/chroot, 所以
,此处调用的是/home/lcx/chroot/lib/ld-linux.so.2。而前面已经将/home/lcx/chroo
t/lib/ld-linux.so.2链接到evil自身(见图).
 
所以,此时运行的还是evil自身.(这是evil这个程序第3次被运行了!)

不同的是此时运行的evil已经是一个setuid程序, 运行它时euid就是0! 还有,要注意,
现在是第三次运行eveil, 它已经是在chroot环境外了(受chroot影响的只有C和B)。

然后, evil把自己的uid设为0, 再运行bash。这是一个有root权限的bash, 并且是在
chroot环境外, 僭权成功!

← previous
next →
loading
sending ...
New to Neperos ? Sign Up for free
download Neperos App from Google Play
install Neperos as PWA

Let's discover also

Recent Articles

Recent Comments

Neperos cookies
This website uses cookies to store your preferences and improve the service. Cookies authorization will allow me and / or my partners to process personal data such as browsing behaviour.

By pressing OK you agree to the Terms of Service and acknowledge the Privacy Policy

By pressing REJECT you will be able to continue to use Neperos (like read articles or write comments) but some important cookies will not be set. This may affect certain features and functions of the platform.
OK
REJECT