本文译自:
2021年1月26日,sudo被曝存在一个“新”漏洞,但是实际上这个漏洞可能已经存在10年了。该漏洞可以使攻击者通过堆缓冲区溢出来进行权限提升。但是漏洞发布并没有exploit/POC,笔者所以决定自己构建一个。
脆弱性
简要介绍该漏洞,本质上攻击者可以通过在给sudo的任何argv或env参数的末尾插入一个反斜杠来让堆溢出,从而导致参数超出范围,来看一下简化版本的代码片段。
之一个for循环中,正在遍历每个参数,并使用strlen判断其大小(加上空终止符),现在我们假设有空字符串“AAAA\”(\是一个字符),大小为5,并且加上这是唯一的参数,仅分配5个字节。
在下一部分中,我们将有一个用于参数的外部for循环和一个将所有参数的内容复制到单个缓冲区user_args中的内部循环,本质上是将所有参数串联在一起。
考虑与前面相同的字符串“AAAA\”,当[0]=='\'成立时,进入if并从from++递增,因为它指向空终止符,所以导致递增。之后,我们使用下一条语句*to++=*from++;继续循环。复制空终止符,复制字节,最终产出界限。
之所以会发生这种情况,是因为它希望每个\后面都有一个元字符,作者提出了一种巧妙的绕过 *** ,使它容易溢出。如果您想知道为什么以及进入该块时我们最终在参数中只有\的原因,请阅读本文。
通过使用符号链接sudoedit到sudo,我们可以做到这一点:
溢出的属性
作者陈述了有关此溢出的3个重要属性,这些属性使其非常强大。
首先,最简单的就是控制user_args的分配大小,因此选择sudo参数的数量和时间属性。
其次,控制溢出区域的内容。可以通过使用提供的环境变量来实现。环境变量实际上存储在最后一个参数传递给sudoedit之后,这意味着如果我们执行env -i'A=BBBB'sudoedit -s'CCCCCCCCCCCCCCCC',我们会将C插入到user_args缓冲区中,而A=BBBB将紧随其后插入到边界区域。请注意,块大小应与0x10大小保持一致,例如env -i'A=BB'sudoedit-s'CCCCBBBBBBBB'仅填充缓冲区。
如果密切关注串联块中的内部循环,您可能会注意到可以多次利用它。通过用\结束环境变量,可以再次跳到下一个环境变量。那为什么要那样?因为随着from++的增加,在以下to++=*from++上指向空终止符的指针,它将插入该空终止符。这能够在不结束溢出的情况下插入0x0,从而使该溢出功能极为强大。
作者的例子:
env -i'AA=a ''B=b ''C=c ''D=d ''E=e ''F=f'sudoedit-s'1234567890123456789012 '
这样最终会在缓冲区中结束:
因此,我们将不讨论堆块的正向(fd)或反向(bk)指针的含义,因为我们仅在使用内存中进行利用。
之一个大小是后续块的大小。它等于给malloc的0x10+参数,因为还需要本身和对齐/以前大小的空间。
下一个大小是连续的块大小。
fd和bk分别指向此释放块链接列表中的下一个和上一个块的指针。这仅适用于释放的块。否则,malloc的调用者可以使用这个空间。
关于空终止符插入,这里需要注意的一点是,我认为原稿中缺少的是,我们也可以插入多个连续的空字节。
首先要了解的是,环境变量不必以SOMETHING=SOMETHING_more的形式出现。与其他所有内容一样,这些只是字符数组,我们可以在C语言中使用它们。例如:
在这里,我们使用execve在完全控制环境变量的情况下执行过程。在内部for循环中,我们在””\””处插入if语句,并通过from++反斜杠跳过一个字符,然后仅将null插入到下一个“\”,然后在a中插入两个null字节。
开发
尽管作者在本文中提到了3个可能的目标,但我们仅涵盖第二个目标。
原因:
与之一种选择相反,它们没有暴力破解,在之一种选择中,它们部分溢出了以暴力破解击败ASLR的函数指针。
他们说,他们成功地在3个操作系统上成功做到了这一点,而其他两个操作系统都只有一个。
在第二个选项中,我们尝试溢出到存储在堆中的service_user结构中。
nss_load_library在溢出加载新的动态链接库后,libc中经常使用此结构,我们可以使文件名溢出,然后控制要加载的库。然后,我们可以针对我们可以 *** 的将以root特权运行的非特权库为目标。
该函数如下所示:
此功能的目标是点击ni->library->lib_handle=__libc_dlopen(shlib_name)加载一个我们控制的新库。
这里有两件事要注意,之一件事是本文提到的。如果ni->library不为NULL,我们将在ni->library->lib_handle中使用该指针,并且由于ASLR是一个X子,因此我们无法预测没有泄漏的有效指针。幸运的是,此结构存在一个初始情况,如果该结构为null,则可以通过ni->library=nss_new_service来设置它,现在,多个空字节写入就派上用场了!
然后,我们只需要将此结构完全溢出到其名称字段,即可将其更改为我们控制的非特权库。
第二个挑战是我们拥有下一个指针struct service_user * next;。在结构内部形成一个链表,当加载发生时将遍历该链表。因此,如果我们在过程中意外溢出另一个service_user结构,则当我们因fx A溢出而导致错误时,就将编写垃圾指针。可以通过在该位置插入空字节来避免这种情况,但这会带来另一个问题,现在断开链表,并且可以从列表中完全删除目标结构,而在整个内存空间中都没有指向它的指针。
这意味着我们必须定位到分配区域之后的链表中的之一个结构。事实证明,这是要克服的更大挑战,因为您可以想象这需要对堆分配进行很好的控制。
在本文中,它们service_user以systemd我们绝对无法定位的名称为目标。因此,我们在分配之前设置了一个断点来检查链表。然后,我们搜索systemd并向后遍历该列表,直到找到靠近我们的分配的之一个service_user为止。(结合A的一些反复试验,以了解其崩溃的结构))
在这里,我service_user在内存中显示了不同的名称,并在vmmaps下面显示了相同的名称。如图所示,第二个vmmap对应于systemd,其偏移量为距堆基0x47e0。这显然是一个问题,因为我们service_user在列表0x4790之前的列表中看到了另一个,而两个结构之间只有0x50的空间,所以两个结构之间只有0的空间。这使得不可能针对这一目标,但是我们可以只选择之前的目标。但是,为什么不针对其他一些fx某些0x2000结构呢?好吧……您根本无法进行那么早的分配。
堆修饰
那么,如何在接近目标的内存区域分配内存呢?因此,这篇文章中的任务似乎并不明确,听起来好像他们“蛮力”尝试了很多,直到解决方案崩溃。如果不正确,请随时与我们的团队联系。
无论如何,我们都不希望尝试各种不同的分配方式。但是,他们确实提到了在我们控制大小的sudo进程中尽早进行分配的巧妙 *** 。
此技巧利用了以下事实:setlocale被称为之一件事,并且它们声明:在154行的setlocale()中,我们malloc()ate和free()几个LC环境变量(LC_CTYPE,LC_MESSAGES,LC_TIME等),从而在sudo堆的开始处创建了小洞(空闲的fast或tcache块)
这是一个巧妙的技巧,我们通过打破setlocale和以下所有免费代码来研究此大小,以检查将要释放的大小块。
之一个有趣的测试:
第二个有趣的测试:
现在,实际上第二个被分配并在setlocale内不久之后再次释放。这使我相信它比之一个更加不可靠(可能是因为它同样稳定)。
但是有趣的是,我们没有发现本文所期望的其他LC变量中的其他自由变量,这很可能是libc依赖的,或者我完全不在本地使用。
这意味着我们只有这个分配可以使用。令人遗憾的是,现在可以使用的malloc更少了,但同时也限制了搜索空间。
现在,您还记得我说过的关于前向和后向指针的事情,我们应该不在乎。是的..现在我们需要这些知识。因此,这里介绍了世界上最快的垃圾箱介绍。
实际上,释放的块并不存储在单个链表中,而是分成多个链表,这些链表按边上的块大小排序。更糟糕的是,我们提供了5种不同的列表:
tcache适用于大小从0x20到0x408的超快速分配
fast bins也是从0x20到0x80的超快速分配
*** all bins比tcache和fastbins大的小分配
large bins大的可变大小的块
unsorted bin一个包含尚未分类到其他箱中的块的箱
我们将仅关注tcache和fast bins,因为其他箱中的数据块可能会合并,这意味着连续的数据块可以合并为一个更大的数据块,这使得以后很难预测垃圾箱的状态。在这两类箱中,块大小每0x10增量存在一个箱。(bin==链表)
现在,我们要使用LC_MESSAGE分配一个块,并在setlocale中再次释放它,以使该块可在以后执行溢出时使用。这样,我们就可以在堆上获得更大的块。
我不希望在我的分配之前释放的容器中的块,而当我们进行最终的溢出分配时,容器中的块仍然存在,因为它们可能来自sudo中的其他位置。
因此,在setlocale的末尾和最后的分配之前中断,让我对sudo期间使用了哪些bin有了一个了解。请注意,这并不能说明所有分配情况,实际上与分配情况相去甚远,因此仍会涉及一些反复试验。
我试图说明搜索空间,我们将首先尝试:
现在,这是一个粗略的计划,我没有完全坚持下去。
经过令人惊讶的几次尝试之后,我们就在溢出分配之前将这一块可用了:
上面的是我们的分配,下面是目标字符串mymachine。仅相隔0x4790-0x4370==0x420字节。不错,这似乎可行。
现在,我们只需要使用null进行溢出,直到命中该结构并重新组合具有ni-library null和另一个名称的相同结构即可。
我们首先通过如下设置args来进行分配,以匹配之前找到的大小。以前面所述的分配取决于提供给sudoedit的之一个参数的长度。我们将尝试将此大小与LC_MESSAGE释放的块进行匹配。[核对原件]
char *args[] = {
"/usr/bin/sudoedit",
"-s",
"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAA\",
NULL
}; //B and A's to match the chunk size we want freed in thebeginning
然后,我们创建一长串环境变量以放入null并以伪造的service_user结构结尾:
char *extra_args[] = {
"\\",
"\\",
"\\",
"\\",
"\\",
"\\",
"\\",
"\\",
"\\",
"\\",
"\\",
"\\",
"\\",
"\\",
"\\",
"\\",
"\\",
"\\",
"\\",
"\\",
"\\",
"\x01\\",
"\\",
"\\",
"\x01\\",
"\\",
"\\",
"\\",
"\\",
"\\",
"\\",
"\\",
"\\",
"\\",
"\\",
"\\",
"\\",
"\\",
"\\",
"\\",
"\\",
"\\",
"\\",
"\\",
"\\",
"\\",
"\\",
"X/X\\",
"a",
"LC_MESSAGES=C.UTF-8@AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
NULL,
};
然后,nss_load_library中的_st***y序列将基于上面的X/X\arg创建路径libnss_X/X.so.2:
现在我们只需要创建一个简单的库即可加载。我们只是创建一个带有初始化函数设置ID(不确定是否需要)的小型库,并执行/bin/sh并在nss_load_library中的ld_open时生成根shell。使用gcc-Os-Wall-Wextra-fPIC-sharednss.c-oX.so.2进行编译。
看到这个我真高兴!!
shell终于弹出了
结论
最终的利用是100%可靠的,并且可以在我的环境中使用libc2.32启用ASLR,这在ubuntu 20.10中也可以找到,并且可能很容易在许多发行版中进行了重新设计。由于许多系统仍然容易受到攻击,我们目前尚未发布最终的利用代码。感谢所有参与发现此漏洞并加以利用的研究人员。
参考链接
编辑导读:需求通气会指的是邀请需求相关方介入,向需求相关方透露接下来筹备开展的需求,并请求列位相关方在开拓进程中予以支持的集会会议。对付初入产物坑的新人PM来说,需求通气会全流程该做些什么?本文作者对...
用iPhone拍的照片,要如何传送到电脑上呢?其实方法有非常多种,使用USB连接线,连接到电脑后,开启“iTunes”同步资料夹,还是开启“iPhoto”汇入照片,还是开启“预览程式”只汇入某一些照片...
果林山地养鸡是这几年在养鸡行业中比较热门的一种养殖方法。和传统的室内养殖相比,果林山地养鸡能够有效利用果园、山林内的资源,搭盖简易鸡棚,雏鸡在棚内饲养,脱温后一般在棚外自然放养。那么,要怎么利用果园山...
本文导读目录: 1、手机被黑客入侵有什么显示 2、黑客进入了手机会有哪些反应 3、我的手机被黑客了怎么办? 4、手机被黑客攻击的特征 5、手机被黑客攻击了,怎么办? 6、手机被黑客...
本文目录一览: 1、QQ被盗了怎么办? 2、谁能帮我找回QQ密码找黑客盗号一般多少钱 3、我的QQ被盗了,我一定要找出幕后黑手!!哪位好心人帮帮忙,大恩永生难忘!!怎样能找出幕后黑手?? Q...
《隐秘而伟大》正在热播中,是由陈伟霆金晨出演,在剧里陈伟霆的警员品牌形象還是十分非常好的,里边的一些经典台词语句令人潸然泪下,下边我就产生剧里经典对白经典话语摘录。 《隐秘而伟大》打动内心经典对...