CVE-2021-3156: Heap-Based Buffer Overflow in Sudo (Baron Samedit)
CVE-2021-3156簡介:
sudo是一個幾乎無處不在的實用程式,可用于主要的類Unix作業系統,通過利用此漏洞,任何未經授權的用戶都可以使用默認sudo配置在易受攻擊的主機上獲得root權限,
Sudo是一個強大的實用程式,它包含在大多數基于Unix和Linux的作業系統中,它允許用戶以另一個用戶的安全權限運行程式,近10年來,這個漏洞本身一直隱藏在人們的視線中,
根據安全研究員peter@haxx.in的報告:
受到威脅的系統有:
Ubuntu 18.04.5 (Bionic Beaver) - sudo 1.8.21, libc-2.27
Ubuntu 20.04.1 (Focal Fossa) - sudo 1.8.31, libc-2.31
Debian 10.0 (Buster) - sudo 1.8.27, libc-2.28
通過審計Sudo Mode模塊代碼:
571 if (ISSET(mode, MODE_RUN) && ISSET(flags, MODE_SHELL)) {
572 char **av, *cmnd = NULL;
573 int ac = 1;
...
581 cmnd = dst = reallocarray(NULL, cmnd_size, 2);
...
587 for (av = argv; *av != NULL; av++) {
588 for (src = *av; *src != '\0'; src++) {
589 /* quote potential meta characters */
590 if (!isalnum((unsigned char)*src) && *src != '_' && *src != '-' && *src != '$')
591 *dst++ = '\\';
592 *dst++ = *src;
593 }
594 *dst++ = ' ';
595 }
...
600 ac += 2; /* -c cmnd */
...
603 av = reallocarray(NULL, ac + 1, sizeof(char *));
...
609 av[0] = (char *)user_details.shell; /* plugin may override shell */
610 if (cmnd != NULL) {
611 av[1] = "-c";
612 av[2] = cmnd;
613 }
614 av[ac] = NULL;
615
616 argv = av;
617 argc = ac;
618 }
稍后,在sudoers\u policy\u main()中,set\cmnd()將命令列引數連接到基于堆的緩沖區“user\u args”(第864-871行)中,并取消對元字符(第866-867行)的scape,“用于sudoers匹配和日志記錄目的”:
819 if (sudo_mode & (MODE_RUN | MODE_EDIT | MODE_CHECK)) {
...
852 for (size = 0, av = NewArgv + 1; *av; av++)
853 size += strlen(*av) + 1;
854 if (size == 0 || (user_args = malloc(size)) == NULL) {
...
857 }
858 if (ISSET(sudo_mode, MODE_SHELL|MODE_LOGIN_SHELL)) {
...
864 for (to = user_args, av = NewArgv + 1; (from = *av); av++) {
865 while (*from) {
866 if (from[0] == '\\' && !isspace((unsigned char)from[1]))
867 from++;
868 *to++ = *from++;
869 }
870 *to++ = ' ';
871 }
...
884 }
...
886 }
在第866行,“from[0]”是反斜杠字符,“from[1]”是引數的空終止符(即,不是空格字符);
在第867行,“from”遞增并指向空終止符;
在第868行,空終止符被復制到“user\u args”緩沖區,“from”再次遞增并指向空終止符后面的第一個字符(即,超出引數的邊界);
第865-869行的“while”回圈讀取越界字符并將其復制到“user\u args”緩沖區,
換句話說,set\u cmnd()易受基于堆的緩沖區溢位的攻擊,因為復制到“user\u args”緩沖區的越界字符未包含在其大小中(在第852-853行計算),
但是,理論上,沒有命令列引數可以以單個反斜杠字符結尾:如果設定了MODE\u SHELL或MODE\u LOGIN\u SHELL(第858行,這是到達易受攻擊代碼的必要條件),則設定MODE\u SHELL(第571行),parse\u args()已經轉義了所有元字符,包括反斜杠(即,,它用第二個反斜杠逃過了每一個反斜杠),
但實際上,set\u cmnd()中的易受攻擊代碼和
parse\u args()中的轉義代碼被稍微不同的條件包圍:
819 if (sudo_mode & (MODE_RUN | MODE_EDIT | MODE_CHECK)) {
...
858 if (ISSET(sudo_mode, MODE_SHELL|MODE_LOGIN_SHELL)) {
571 if (ISSET(mode, MODE_RUN) && ISSET(flags, MODE_SHELL)) {
我們的問題是:我們是否可以設定模式\u SHELL和模式\u EDIT或模式\u CHECK(以訪問易受攻擊的代碼),而不是默認模式\u RUN(以避免轉義代碼)?
答案似乎是否定的:如果我們設定MODE_EDIT(-e option,第361行)或MODE_CHECK(-l option,第423行和第519行),那么parse_args()將MODE_SHELL從“valid_flags”(第363行和第424行)中洗掉,如果我們指定了MODE_SHELL(第532-533行)之類的無效標志,則回傳錯誤:
358 case 'e':
...
361 mode = MODE_EDIT;
362 sudo_settings[ARG_SUDOEDIT].value = "true";
363 valid_flags = MODE_NONINTERACTIVE;
364 break;
...
416 case 'l':
...
423 mode = MODE_LIST;
424 valid_flags = MODE_NONINTERACTIVE|MODE_LONG_LIST;
425 break;
...
518 if (argc > 0 && mode == MODE_LIST)
519 mode = MODE_CHECK;
...
532 if ((flags & valid_flags) != flags)
533 usage(1);
但是我們發現了一個漏洞:如果我們將Sudo作為“sudoedit”而不是“Sudo”執行,那么parse\u args()會自動設定模式\u EDIT(第270行),但不會重置“valid\u flags”,“valid\u flags”默認包括模式\u SHELL(第127行和第249行):
127 #define DEFAULT_VALID_FLAGS (MODE_BACKGROUND|MODE_PRESERVE_ENV|MODE_RESET_HOME|MODE_LOGIN_SHELL|MODE_NONINTERACTIVE|MODE_SHELL)
...
249 int valid_flags = DEFAULT_VALID_FLAGS;
...
267 proglen = strlen(progname);
268 if (proglen > 4 && strcmp(progname + proglen - 4, "edit") == 0) {
269 progname = "sudoedit";
270 mode = MODE_EDIT;
271 sudo_settings[ARG_SUDOEDIT].value = "true";
272 }
因此,如果我們執行“sudoedit-s”,那么我們同時設定模式\u EDIT和模式\u SHELL(而不是模式\u RUN),我們就避免了轉義代碼,到達易受攻擊的代碼,并通過以單個反斜杠字符結尾的命令列引數使基于堆的緩沖區“user \u args”溢位:
sudoedit-s'\'`perl-e'print“A”x 65536'
malloc(): corrupted top size
Aborted (core dumped)
從攻擊者的角度來看,這種緩沖區溢位非常理想,原因如下:
1) 攻擊者控制可以溢位的“user\u args”緩沖區的大小(在第852-854行連接的命令列引數的大小);
2) 攻擊者獨立控制溢位本身的大小和內容(最后一個命令列引數后面緊跟著第一個環境變數,這些變數不包括在第852-853行的大小計算中);
3) 攻擊者甚至可以將空位元組寫入溢位的緩沖區(每個以單個反斜杠結尾的命令列引數或環境變數都會將空位元組寫入第866-868行的“用戶引數”),
例如,在amd64 Linux上,下面的命令分配一個24位元組的“user\u args”緩沖區(一個32位元組的堆塊)并用,
歡迎關注CSDN:知柯資訊安全
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/256726.html
標籤:其他
