CVE-2021-3156漏洞分析与利用
前言
这个CVE-2021-3156算是真正意义上的第一个洞吧,亲自上手调了下,当然关于参数到底怎么变化的还没有去搞清楚,不过光是理清调试方法以及调用链就花了好久,也积累了好多经验,希望后面复现其他能熟练点吧。
sudoedit
sudoedit允许用户安全地编辑文件,命令格式是sudoedit file
,该命令首先创建你要编辑的文件的临时副本,然后搜索SUDO_EDITOR,VISUAL和EDITOR环境变量(按此顺序),以确定应调用哪个编辑器来打开刚刚创建的临时副本。 用户完成修改工作后,更改将复制回原始文件。
另外,sudoedit其实是sudo程序的软链接,但使用sudoedit启动会设置其mode为MODE_EDIT。
sudo版本
1 | Sudo version 1.8.21p2 |
漏洞点
在set_cmnd
函数中,当from
为\\
时,会自增,跳过NULL字符,继续复制envp参数,从而可构造堆溢出:
1 | for (to = user_args, av = NewArgv + 1; (from = *av); av++) { |
调试过程
第一次尝试cve,调试过程中遇到了好多问题。
第一个是去符号了,这个通过字符串等搜索可以确定基本的main函数和parse_args函数(0x11760)。
另外在代码中找不到set_cmnd函数的入口,尝试步过确定范围,最终在0x5674处发现程序报错:
进入函数发现调用了/usr/lib/sudo/sudoers.so动态库中的函数,并通过字符串确定是sudoers_policy_check函数地址为0x171A0,sudoers_policy_main函数地址为0x1D8A0,不过set_cmnd内联在sudoers_policy_main函数里了,大概漏洞点在0x1DC68处。
另外可以通过在gdb中catch exec
再c
进入sudo程序的调试。
漏洞利用原理
总的利用过程为:利用堆溢出,修改堆中service_user
结构中的动态库名,然后通过nss_load_library
函数调用该动态库,最后提权。
service_user结构如下:
1 | typedef struct service_user |
下面是nss_load_library函数的部分代码,可以看到将libc名称自动补全为"libnss_"+name+".so"
,然后载入内存。
1 | static int |
注:在Linux中通过locale来设置程序运行的不同语言环境,LC_ALL=C.UTF-8@
即去除所有本地化的设置,其中C
是系统默认的locale,UTF-8
表示字符集。
参考文章
CVE-2021-3156: Heap-Based Buffer Overflow in Sudo (Baron Samedit)