作者:0431实验室
公众号:https://mp.weixin.qq.com/s/UwJPjsIYAU-U__QWCYN1zQ

0x01.漏洞描述

在GUN Bash 5.0 补丁11 shell.c的diable_priv_mode()中发现一个问题,默认情况下,如果Bash运行时其有效UID不等于其实际UID,它将通过将其有效UID设置为其真实UID来放弃特权。但是,这样仍存在安全问题。在Linux和其他支持“保存的UID”功能的系统上,保存的UID不会被删除。攻击者可以在bash中执行命令"enable -f"在执行时加载新的内置组件,该组件可以使调用setuid()的共享对象并且重新获得特权。然而,UID为0运行的二进制文件不受影响。

0x02.漏洞影响版本

version : < Bash 5.0补丁11版本

0x03.漏洞原理

1.shell.c的disable_priv_mode()是造成漏洞的函数

这里可以看到euid和uid不相等时,直接将uid赋值给了euid,对于原来的uid没有进行任何处理,也就造成了euid和uid可能不相等

2.利用脚本原理

这里了是利用脚本的核心,使用C语言编写。

void __attribute__((constructor))语法:这种特殊的GCC语法与函数一起使用时,在程序启动时即在main()函数之前执行相同的函数

void __attribute __((destructor))语法:这种特殊的GCC语法与函数一起使用时,在程序通过_exit终止之前即在main()函数之后执行相同的函数

说明: 构造函数和析构函数的工作方式是,共享库文件包含特殊节(ELF上的.ctors和.dtors),这些节分别包含对标记有构造函数和析构函数属性的函数的引用。在加载/卸载库时,动态加载程序会检查是否存在此类部分,如果存在,则调用其中引用的函数。

关于这些方面的几点值得注意:

  1. void __attribute__((constructor))在加载共享库时运行,通常在程序启动期间运行。
  2. void __attribute __((destructor))在共享库卸载时运行,通常在程序退出时运行。
  3. 这两个括号可能是为了将它们与函数调用区分开。
  4. __attribute__是GCC特定的语法;不是函数或宏

initLibrary(void):能够使得动态链接库在main函数之前运行

这里先进行gcc -c -fPIC 表示程序在编译阶段先编译不进行链接,然后再通过-share 选项生成动态链接库libpwn.so

最后使用,enable -f ./libpwn.so qwe加载新的内置组件,从libpwn.so中重新执行setuid(),这时的$euid已将变成了攻击者的uid,然后攻击者的euid被重新设置为新的uid,这时攻击者uid没有变化,但是euid已经变成了被攻击者的uid的了,这时就可以修改查看被攻击者的文件。

0x04.漏洞利用

1.新建两个用户

2.bash版本也符合

3.在attacked用户的根目录下有一个security.txt文件,文件的权限如下图所示

4.用户hacker无法读取文件

5.用户hacker,查看/bin/bash的权限,如下图所示

在这里我们可以看到,/bin/bash的所有者和所属组是attacked和bash的权限,这里关键的是用户的s权限。这里介绍一下s权限 ,包含S_ISUID、S_ISGID两个常量在内,叫做强制位权限,作用在于设置使文件在执行阶段具有文件所有者的权限,相当于临时拥有文件所有者的身份。这里hacker用户所使用的bash是attacked权限的bash。

6.这里我们查看用户的id

hacker-id-6

这里我们可以看到攻击者和被攻击者的uid,gid,group不一致,并且hacker的/bin/bash权限符合漏洞的要求

7.执行exp,更改攻击者的有效id

这里可以看到成功执行EXP,攻击者的所有id如下图所示

hacker的euid已经变成了被攻击者的uid,并且攻击者的uid被保留了下来。

8.hacker用户查看attacked用户下的security.txt文件

这里我们已经能查看attacked用户的security.txt文件

0x05.漏洞修复原理

这里我们可以看到使用了setresuid(),setresgid(),定义在 <unistd.h>头文件中 setresgid:分别设置真实的,有效的和保存过的组标识号

int setresuid(uid_t ruid ,uid_t euid ,uid_t suid );

setresuid:分别设置真实的,有效的和保存过的用户标号

int setresgid(gid_t rgid ,gid_t egid ,gid_t sgid );

setresuid:非特权进程可以将其实际UID,有效UID和已保存的设置用户ID更改为以下之一:当前实际UID,当前有效UID或当前已保存的设置用户ID,特权进程(在Linux上,具有CAP_SETUID功能)可以将其实际UID,有效UID和已保存的set-user-ID设置为任意值,如果参数之一等于-1,则相应的值不会更改。setresgid的原理和setresuid的类似。

0x06.参考

https://www.exploit-db.com/exploits/47726


Paper 本文由 Seebug Paper 发布,如需转载请注明来源。本文地址:https://paper.seebug.org/1093/